Exemplo n.º 1
0
static void onDraw(tContext *pContext)
{
  // first draw the datetime
  uint8_t totalgrid = window_readconfig()->sports_grid + 3;

  GrContextForegroundSet(pContext, ClrWhite);
  switch(window_readconfig()->sports_grid)
  {
  case GRID_3:
    GrRectFill(pContext, &region_3grid[0]);
    GrLineDrawV(pContext, region_3grid[1].sXMax, region_3grid[1].sYMin, region_3grid[1].sYMax);
    break;
  case GRID_4:
    GrRectFill(pContext, &region_4grid[0]);
    GrLineDrawH(pContext, region_4grid[1].sXMin, region_4grid[1].sXMax, region_4grid[1].sYMax);
    GrLineDrawH(pContext, region_4grid[2].sXMin, region_4grid[2].sXMax, region_4grid[2].sYMax);
    break;
  case GRID_5:
    GrRectFill(pContext, &region_5grid[0]);
    GrLineDrawH(pContext, region_5grid[1].sXMin, region_5grid[2].sXMax, region_5grid[1].sYMax);
    GrLineDrawV(pContext, region_5grid[1].sXMax, region_5grid[1].sYMin, region_5grid[3].sYMax);
    break;
  }

  GrContextForegroundSet(pContext, ClrWhite);
  for(uint8_t g = 0; g < totalgrid; g++)
  {
    drawGridData(pContext, window_readconfig()->sports_grid_data[g] , grid_data[g]);
  }
}
Exemplo n.º 2
0
//*****************************************************************************
//
//! Draws a rectangle.
//!
//! \param pContext is a pointer to the drawing context to use.
//! \param pRect is a pointer to the structure containing the extents of the
//! rectangle.
//!
//! This function draws a rectangle.  The rectangle will extend from \e i32XMin
//! to \e i32XMax and \e i32YMin to \e i32YMax, inclusive.
//!
//! \return None.
//
//*****************************************************************************
void
GrRectDraw(const tContext *pContext, const tRectangle *pRect)
{
    //
    // Check the arguments.
    //
    ASSERT(pContext);
    ASSERT(pRect);

    //
    // Draw a line across the top of the rectangle.
    //
    GrLineDrawH(pContext, pRect->i16XMin, pRect->i16XMax, pRect->i16YMin);

    //
    // Return if the rectangle is one pixel tall.
    //
    if(pRect->i16YMin == pRect->i16YMax)
    {
        return;
    }

    //
    // Draw a line down the right side of the rectangle.
    //
    GrLineDrawV(pContext, pRect->i16XMax, pRect->i16YMin + 1, pRect->i16YMax);

    //
    // Return if the rectangle is one pixel wide.
    //
    if(pRect->i16XMin == pRect->i16XMax)
    {
        return;
    }

    //
    // Draw a line across the bottom of the rectangle.
    //
    GrLineDrawH(pContext, pRect->i16XMax - 1, pRect->i16XMin, pRect->i16YMax);

    //
    // Return if the rectangle is two pixels tall.
    //
    if((pRect->i16YMin + 1) == pRect->i16YMax)
    {
        return;
    }

    //
    // Draw a line up the left side of the rectangle.
    //
    GrLineDrawV(pContext, pRect->i16XMin, pRect->i16YMax - 1,
                pRect->i16YMin + 1);
}
Exemplo n.º 3
0
//*****************************************************************************
//
// Handle keyboard updates.
//
//*****************************************************************************
void
HandleKeyboard(void)
{
    //
    // Nothing to do if the keyboard is not active.
    //
    if(g_i32ScreenIdx != SCREEN_KEYBOARD) {
        return;
    }

    //
    // If the mid value is hit then clear the cursor.
    //
    if(g_ui32CursorDelay == KEYBOARD_BLINK_RATE / 2) {
        GrContextForegroundSet(&g_sContext, ClrBlack);

        //
        // Keep the counter moving now that the clearing has been handled.
        //
        g_ui32CursorDelay--;
    } else if(g_ui32CursorDelay == 0) {
        GrContextForegroundSet(&g_sContext, ClrWhite);

        //
        // Reset the blink delay now that the drawing of the cursor has been
        // handled.
        //
        g_ui32CursorDelay = KEYBOARD_BLINK_RATE;
    } else {
        return;
    }

    //
    // Draw the cursor only if it is time.
    //
    GrLineDrawV(&g_sContext, BG_MIN_X + g_i32StringWidth , BG_MIN_Y + 20,
                BG_MIN_Y + 40);
}
Exemplo n.º 4
0
//*****************************************************************************
//
//! Draws a line.
//!
//! \param pContext is a pointer to the drawing context to use.
//! \param i32X1 is the X coordinate of the start of the line.
//! \param i32Y1 is the Y coordinate of the start of the line.
//! \param i32X2 is the X coordinate of the end of the line.
//! \param i32Y2 is the Y coordinate of the end of the line.
//!
//! This function draws a line, utilizing GrLineDrawH() and GrLineDrawV() to
//! draw the line as efficiently as possible.  The line is clipped to the
//! clippping rectangle using the Cohen-Sutherland clipping algorithm, and then
//! scan converted using Bresenham's line drawing algorithm.
//!
//! \return None.
//
//*****************************************************************************
void
GrLineDraw(const tContext *pContext, int32_t i32X1, int32_t i32Y1,
           int32_t i32X2, int32_t i32Y2)
{
    int32_t i32Error, i32DeltaX, i32DeltaY, i32YStep, bSteep;

    //
    // Check the arguments.
    //
    ASSERT(pContext);

    //
    // See if this is a vertical line.
    //
    if(i32X1 == i32X2)
    {
        //
        // It is more efficient to avoid Bresenham's algorithm when drawing a
        // vertical line, so use the vertical line routine to draw this line.
        //
        GrLineDrawV(pContext, i32X1, i32Y1, i32Y2);

        //
        // The line has ben drawn, so return.
        //
        return;
    }

    //
    // See if this is a horizontal line.
    //
    if(i32Y1 == i32Y2)
    {
        //
        // It is more efficient to avoid Bresenham's algorithm when drawing a
        // horizontal line, so use the horizontal line routien to draw this
        // line.
        //
        GrLineDrawH(pContext, i32X1, i32X2, i32Y1);

        //
        // The line has ben drawn, so return.
        //
        return;
    }

    //
    // Clip this line if necessary, and return without drawing anything if the
    // line does not cross the clipping region.
    //
    if(GrLineClip(pContext, &i32X1, &i32Y1, &i32X2, &i32Y2) == 0)
    {
        return;
    }

    //
    // Determine if the line is steep.  A steep line has more motion in the Y
    // direction than the X direction.
    //
    if(((i32Y2 > i32Y1) ? (i32Y2 - i32Y1) : (i32Y1 - i32Y2)) >
       ((i32X2 > i32X1) ? (i32X2 - i32X1) : (i32X1 - i32X2)))
    {
        bSteep = 1;
    }
    else
    {
        bSteep = 0;
    }

    //
    // If the line is steep, then swap the X and Y coordinates.
    //
    if(bSteep)
    {
        i32Error = i32X1;
        i32X1 = i32Y1;
        i32Y1 = i32Error;
        i32Error = i32X2;
        i32X2 = i32Y2;
        i32Y2 = i32Error;
    }

    //
    // If the starting X coordinate is larger than the ending X coordinate,
    // then swap the start and end coordinates.
    //
    if(i32X1 > i32X2)
    {
        i32Error = i32X1;
        i32X1 = i32X2;
        i32X2 = i32Error;
        i32Error = i32Y1;
        i32Y1 = i32Y2;
        i32Y2 = i32Error;
    }

    //
    // Compute the difference between the start and end coordinates in each
    // axis.
    //
    i32DeltaX = i32X2 - i32X1;
    i32DeltaY = (i32Y2 > i32Y1) ? (i32Y2 - i32Y1) : (i32Y1 - i32Y2);

    //
    // Initialize the error term to negative half the X delta.
    //
    i32Error = -i32DeltaX / 2;

    //
    // Determine the direction to step in the Y axis when required.
    //
    if(i32Y1 < i32Y2)
    {
        i32YStep = 1;
    }
    else
    {
        i32YStep = -1;
    }

    //
    // Loop through all the points along the X axis of the line.
    //
    for(; i32X1 <= i32X2; i32X1++)
    {
        //
        // See if this is a steep line.
        //
        if(bSteep)
        {
            //
            // Plot this point of the line, swapping the X and Y coordinates.
            //
            DpyPixelDraw(pContext->psDisplay, i32Y1, i32X1,
                           pContext->ui32Foreground);
        }
        else
        {
            //
            // Plot this point of the line, using the coordinates as is.
            //
            DpyPixelDraw(pContext->psDisplay, i32X1, i32Y1,
                         pContext->ui32Foreground);
        }

        //
        // Increment the error term by the Y delta.
        //
        i32Error += i32DeltaY;

        //
        // See if the error term is now greater than zero.
        //
        if(i32Error > 0)
        {
            //
            // Take a step in the Y axis.
            //
            i32Y1 += i32YStep;

            //
            // Decrement the error term by the X delta.
            //
            i32Error -= i32DeltaX;
        }
    }
}
Exemplo n.º 5
0
//*****************************************************************************
//
//! Draws the strip chart into a drawing context, off-screen buffer.
//!
//! \param psChartWidget points at the StripsChartWidget being processed.
//! \param psContext points to the context where all drawing should be done.
//!
//! This function renders a strip chart into a drawing context.
//! It assumes that the drawing context is an off-screen buffer, and that
//! the entire buffer belongs to this widget.
//!
//! \return None.
//
//*****************************************************************************
void
StripChartDraw(tStripChartWidget *psChartWidget, tContext *psContext)
{
    tStripChartAxis *psAxisY;
    int32_t i32Y;
    int32_t i32Ygrid;
    int32_t i32X;
    int32_t i32GridRange;
    int32_t i32DispRange;
    int32_t i32GridMin;
    int32_t i32DispMax;
    tStripChartSeries *psSeries;

    //
    // Check the parameters
    //
    ASSERT(psChartWidget);
    ASSERT(psContext);
    ASSERT(psChartWidget->psAxisY);

    //
    // Get handy pointer to Y axis
    //
    psAxisY = psChartWidget->psAxisY;

    //
    // Find the range of Y axis in Y axis units
    //
    i32GridRange = psAxisY->i32Max - psAxisY->i32Min;

    //
    // Find the range of the Y axis in display units (pixels)
    //
    i32DispRange = (psContext->sClipRegion.i16YMax -
                    psContext->sClipRegion.i16YMin);

    //
    // Find the minimum Y units value to be shown, and the maximum of the
    // clipping region.
    //
    i32GridMin = psAxisY->i32Min;
    i32DispMax = psContext->sClipRegion.i16YMax;

    //
    // Set the fg color for the rectangle fill to match what we want as the
    // chart background.
    //
    GrContextForegroundSet(psContext, psChartWidget->ui32BackgroundColor);
    GrRectFill(psContext, &psContext->sClipRegion);

    //
    // Draw vertical grid lines
    //
    GrContextForegroundSet(psContext, psChartWidget->ui32GridColor);
    for(i32X = psChartWidget->i32GridX; i32X < psContext->sClipRegion.i16XMax;
        i32X += psChartWidget->psAxisX->i32GridInterval)
    {
        GrLineDrawV(psContext, psContext->sClipRegion.i16XMax - i32X,
                    psContext->sClipRegion.i16YMin,
                    psContext->sClipRegion.i16YMax);
    }

    //
    // Draw horizontal grid lines
    //
    for(i32Ygrid = psAxisY->i32Min; i32Ygrid < psAxisY->i32Max;
        i32Ygrid += psAxisY->i32GridInterval)
    {
        i32Y = ((i32Ygrid - i32GridMin) * i32DispRange) / i32GridRange;
        i32Y = i32DispMax - i32Y;
        GrLineDrawH(psContext, psContext->sClipRegion.i16XMin,
                    psContext->sClipRegion.i16XMax, i32Y);
    }

    //
    // Compute location of Y=0 line, and draw it
    //
    i32Y = ((-i32GridMin) * i32DispRange) / i32GridRange;
    i32Y = i32DispMax - i32Y;
    GrLineDrawH(psContext, psContext->sClipRegion.i16XMin,
                psContext->sClipRegion.i16XMax, i32Y);

    //
    // Iterate through each series to draw it
    //
    psSeries = psChartWidget->psSeries;
    while(psSeries)
    {
        int idx = 0;

        //
        // Find the starting X position on the display for this series.
        // If the series has less data points than can fit on the display
        // then starting X can be somewhere in the middle of the screen.
        //
        i32X = 1 + psContext->sClipRegion.i16XMax - psSeries->ui16NumItems;

        //
        // If the starting X is off the left side of the screen, then the
        // staring index (idx) for reading data needs to be adjusted to the
        // first value in the series that will be visible on the screen
        //
        if(i32X < psContext->sClipRegion.i16XMin)
        {
            idx = psContext->sClipRegion.i16XMin - i32X;
            i32X = psContext->sClipRegion.i16XMin;
        }

        //
        // Set the drawing color for this series
        //
        GrContextForegroundSet(psContext, psSeries->ui32Color);

        //
        // Scan through all possible X values, find the Y value, and draw the
        // pixel.
        //
        for(; i32X <= psContext->sClipRegion.i16XMax; i32X++)
        {
            //
            // Find the Y value at each position in the data series.  Take into
            // account the data size and the stride
            //
            if(psSeries->ui8DataTypeSize == 1)
            {
                i32Y =
                    ((int8_t *)psSeries->pvData)[idx * psSeries->ui8Stride];
            }
            else if(psSeries->ui8DataTypeSize == 2)
            {
                i32Y =
                    ((int16_t *)psSeries->pvData)[idx * psSeries->ui8Stride];
            }
            else if(psSeries->ui8DataTypeSize == 4)
            {
                i32Y =
                    ((int32_t *)psSeries->pvData)[idx * psSeries->ui8Stride];
            }
            else
            {
                //
                // If there is an invalid data size, then just force Y value
                // to be off the display
                //
                i32Y = i32DispMax + 1;
                break;
            }

            //
            // Advance to the next position in the data series.
            //
            idx++;

            //
            // Now scale the Y value according to the axis scaling
            //
            i32Y = ((i32Y - i32GridMin) * i32DispRange) / i32GridRange;
            i32Y = i32DispMax - i32Y;

            //
            // Draw the pixel on the display
            //
            GrPixelDraw(psContext, i32X, i32Y);
        }

        //
        // Advance to the next series until there are no more.
        //
        psSeries = psSeries->psNextSeries;
    }

    //
    // Draw a frame around the entire chart.
    //
    GrContextForegroundSet(psContext, psChartWidget->ui32Y0Color);
    GrRectDraw(psContext, &psContext->sClipRegion);

    //
    // Draw titles
    //
    GrContextForegroundSet(psContext, psChartWidget->ui32TextColor);
    GrContextFontSet(psContext, psChartWidget->psFont);

    //
    // Draw the chart title, if there is one
    //
    if(psChartWidget->pcTitle)
    {
        GrStringDrawCentered(psContext, psChartWidget->pcTitle, -1,
                             psContext->sClipRegion.i16XMax / 2,
                             GrFontHeightGet(psChartWidget->psFont), 0);
    }

    //
    // Draw the Y axis max label, if there is one
    //
    if(psChartWidget->psAxisY->pcMaxLabel)
    {
        GrStringDraw(psContext, psChartWidget->psAxisY->pcMaxLabel, -1,
                     psContext->sClipRegion.i16XMin +
                     GrFontMaxWidthGet(psChartWidget->psFont) / 2,
                     GrFontHeightGet(psChartWidget->psFont) / 2, 0);
    }

    //
    // Draw the Y axis min label, if there is one
    //
    if(psChartWidget->psAxisY->pcMinLabel)
    {
        GrStringDraw(psContext, psChartWidget->psAxisY->pcMinLabel, -1,
                     psContext->sClipRegion.i16XMin +
                     GrFontMaxWidthGet(psChartWidget->psFont) / 2,
                     psContext->sClipRegion.i16YMax -
                     (GrFontHeightGet(psChartWidget->psFont) +
                      (GrFontHeightGet(psChartWidget->psFont) / 2)),
                     0);
    }

    //
    // Draw a label for the name of the Y axis, if there is one
    //
    if(psChartWidget->psAxisY->pcName)
    {
        GrStringDraw(psContext, psChartWidget->psAxisY->pcName, -1,
                     psContext->sClipRegion.i16XMin + 1,
                     (psContext->sClipRegion.i16YMax / 2) -
                     (GrFontHeightGet(psChartWidget->psFont) / 2),
                     1);
    }
}
Exemplo n.º 6
0
void window_button(tContext *pContext, uint8_t key, uint8_t icon_type, const char* text)
{
	int width;
	int i;
  	long forecolor, backcolor;
	uint8_t upshift = 0;
	
  	if (key & 0x80)
  	{
    		forecolor = ClrBlack;
    		backcolor = ClrWhite;
    		key &= ~(0x80);
  	}
  	else
  	{
    		forecolor = ClrWhite;
    		backcolor = ClrBlack;
  	}
	const tRectangle *rect= &button_rect[key];
	if((icon_type&0x80) == 0x80)
		upshift = 13;
	//Draw button text
	GrContextFontSet(pContext, &g_sFontBaby16);
	if (text)
	{
		GrContextForegroundSet(pContext, backcolor);
		if(key == KEY_EXIT)
			GrStringDraw(pContext, text, -1, rect->sXMax+3, rect->sYMin - upshift  , 0);		
		else
		{
			width = GrStringWidthGet(pContext, text, -1);		
			if(icon_type == BUTTON_NO_ICON)
				GrStringDraw(pContext, text, -1, (rect->sXMax - width ), rect->sYMin- upshift  , 0);					
			else	
				GrStringDraw(pContext, text, -1, (rect->sXMin - width - 3), rect->sYMin- upshift  , 0);					

		}	
	}	
	
	//Draw button icon image
	switch(icon_type&0x0f)
	{
	case TRIANGLE_UP:
		for(i=0; i<7;i++)
		{
			GrLineDrawH(pContext, rect->sXMin+i, rect->sXMax-i, rect->sYMax - 2 - upshift - i);
		}
		break;	
	case TRIANGLE_DOWN:
		for(i=0; i<7;i++)
		{
			GrLineDrawH(pContext, rect->sXMin+i, rect->sXMax-i, rect->sYMin + 2 - upshift + i);
		}
		break;
	case TRIANGLE_RIGHT:
		for(i=0; i<7;i++)
		{
			GrLineDrawV(pContext, rect->sXMin+i, rect->sYMin - upshift +i , rect->sYMax - upshift -i);
		}
		break;
		
	case TRIANGLE_LEFT:
		for(i=0; i<7;i++)
		{
			GrLineDrawV(pContext, rect->sXMax-i, rect->sYMin - upshift +i , rect->sYMax - upshift -i);
		}		
		break;
		
	case MUSIC_PAUSE:
		{
			tRectangle rect1 = {rect->sXMin, rect->sYMin - upshift , rect->sXMin + 3 , rect->sYMax - upshift};
			GrRectFill(pContext,  &rect1);
			
			tRectangle rect2 = {rect->sXMin+6 , rect->sYMin - upshift , rect->sXMin + 9 , rect->sYMax - upshift};
			GrRectFill(pContext,  &rect2);
		}
		break;
	case MUSIC_NEXT:
		for(i=0; i<7;i++)
		{
			GrLineDrawV(pContext, rect->sXMin+i, rect->sYMin - upshift + i , rect->sYMax - upshift - i);
		}
		
		GrLineDrawV(pContext, rect->sXMax+2, rect->sYMin - upshift , rect->sYMax - upshift );
		break;
		
	case MUSIC_PREVIOUS:
		for(i=0; i<7;i++)
		{
			GrLineDrawV(pContext, rect->sXMax-i, rect->sYMin- upshift + i , rect->sYMax - upshift -i);
		}				
		
		GrLineDrawV(pContext, rect->sXMin-2, rect->sYMin - upshift , rect->sYMax - upshift);
		break;
	case BUTTON_NO_ICON:
	default:		
		break;
	}
}
Exemplo n.º 7
0
static void OnDraw(tContext *pContext)
{
  char buf[20];
  // clear screen
  GrContextForegroundSet(pContext, ClrBlack);
  GrContextBackgroundSet(pContext, ClrWhite);
  GrRectFill(pContext, &fullscreen_clip);

  // draw table title
  GrContextForegroundSet(pContext, ClrWhite);
  GrContextBackgroundSet(pContext, ClrBlack);
  const tRectangle rect = {0, 27, 255, 41};
  GrRectFill(pContext, &rect);

  // draw the title bar
  GrContextFontSet(pContext, &g_sFontGothic18b);
  sprintf(buf, "%s %d", toMonthName(month, 1), year);
  GrStringDrawCentered(pContext, buf, -1, LCD_WIDTH / 2, 15, 0);

  GrContextForegroundSet(pContext, ClrBlack);
  GrContextBackgroundSet(pContext, ClrWhite);
  GrContextFontSet(pContext, &g_sFontGothic18);
  for(int i = 0; i < 7; i++)
  {
    GrStringDrawCentered( pContext, week_shortname[i], -1, i * 20 + 11, 35, 0);
    // draw line in title bar
    GrLineDrawV(pContext, i * 20, 28, 42);
  }

  GrContextFontSet(pContext, &g_sFontGothic18);
  GrContextForegroundSet(pContext, ClrWhite);
  GrContextBackgroundSet(pContext, ClrBlack);

  // get the start point of this month
  uint8_t weekday = rtc_getweekday(year, month, 1) - 1; // use 0 as index
  uint8_t maxday = rtc_getmaxday(year, month);
  uint8_t y = 50;

  for(int day = 1; day <= maxday; day++)
  {
    sprintf(buf, "%d", day);

    uint8_t today = now_year == year && now_month == month && now_day == day;
    if (today)
    {
      const tRectangle rect = {weekday * 20 + 1, y - 7, 20 + weekday * 20 - 1, y + 7};
      GrRectFill(pContext, &rect);
      GrContextForegroundSet(pContext, ClrBlack);
      GrContextBackgroundSet(pContext, ClrWhite);
    }
    GrStringDrawCentered( pContext, buf, -1, weekday * 20 + 11, y, 0);
    if (today)
    {
      const tRectangle rect2 = {weekday * 20 + 16, y - 5, weekday * 20 + 17, y - 4};
      GrRectFill(pContext, &rect2);

      GrContextForegroundSet(pContext, ClrWhite);
      GrContextBackgroundSet(pContext, ClrBlack);
    }

    if (weekday != 6)
      GrLineDrawV(pContext, (weekday + 1 ) * 20, 42, y + 7);

    weekday++;
    if (weekday == 7)
    {
      GrLineDrawH(pContext, 0, LCD_WIDTH, y + 8);

      weekday = 0;
      y += 20;
    }
  }

  GrLineDrawH(pContext, 0, weekday * 20, y + 8);

  // draw the buttons
  if (month == 1)
    sprintf(buf, "%s %d", toMonthName(12, 0), year - 1);
  else
    sprintf(buf, "%s %d", toMonthName(month - 1, 0), year);
  window_button(pContext, KEY_ENTER, buf);

  if (month == 12)
    sprintf(buf, "%s %d", toMonthName(1, 0), year + 1);
  else
    sprintf(buf, "%s %d", toMonthName(month + 1, 0), year);
  window_button(pContext, KEY_DOWN, buf);
}
Exemplo n.º 8
0
//*****************************************************************************
//
//! Draws a line.
//!
//! \param pContext is a pointer to the drawing context to use.
//! \param lX1 is the X coordinate of the start of the line.
//! \param lY1 is the Y coordinate of the start of the line.
//! \param lX2 is the X coordinate of the end of the line.
//! \param lY2 is the Y coordinate of the end of the line.
//!
//! This function draws a line, utilizing GrLineDrawH() and GrLineDrawV() to
//! draw the line as efficiently as possible.  The line is clipped to the
//! clippping rectangle using the Cohen-Sutherland clipping algorithm, and then
//! scan converted using Bresenham's line drawing algorithm.
//!
//! \return None.
//
//*****************************************************************************
void
GrLineFill(const tContext *pContext, long lX1, long lY1, long lX2, long lY2, long width)
{
    long lError, lDeltaX, lDeltaY, lYStep, bSteep;
    long lWStart, lWEnd;

    lWEnd = width/2;
    lWStart = lWEnd - width;
    //
    // Check the arguments.
    //
    ASSERT(pContext);

    GrCircleFill(pContext, lX1, lY1, width/2);
    GrCircleFill(pContext, lX2, lY2, width/2);

    //
    // See if this is a vertical line.
    //
    if(lX1 == lX2)
    {
        //
        // It is more efficient to avoid Bresenham's algorithm when drawing a
        // vertical line, so use the vertical line routine to draw this line.
        //
        for(long i = lWStart; i <= lWEnd; i++)
            GrLineDrawV(pContext, lX1 + i, lY1, lY2);

        //
        // The line has ben drawn, so return.
        //
        return;
    }

    //
    // See if this is a horizontal line.
    //
    if(lY1 == lY2)
    {
        //
        // It is more efficient to avoid Bresenham's algorithm when drawing a
        // horizontal line, so use the horizontal line routien to draw this
        // line.
        //
        for(long i = lWStart; i <= lWEnd; i++)
            GrLineDrawH(pContext, lX1, lX2, lY1+i);

        //
        // The line has ben drawn, so return.
        //
        return;
    }

    //
    // Clip this line if necessary, and return without drawing anything if the
    // line does not cross the clipping region.
    //
    if(GrLineClip(pContext, &lX1, &lY1, &lX2, &lY2) == 0)
    {
        return;
    }

    //
    // Determine if the line is steep.  A steep line has more motion in the Y
    // direction than the X direction.
    //
    if(((lY2 > lY1) ? (lY2 - lY1) : (lY1 - lY2)) >
            ((lX2 > lX1) ? (lX2 - lX1) : (lX1 - lX2)))
    {
        bSteep = 1;
    }
    else
    {
        bSteep = 0;
    }

    //
    // If the line is steep, then swap the X and Y coordinates.
    //
    if(bSteep)
    {
        lError = lX1;
        lX1 = lY1;
        lY1 = lError;
        lError = lX2;
        lX2 = lY2;
        lY2 = lError;
    }

    //
    // If the starting X coordinate is larger than the ending X coordinate,
    // then swap the start and end coordinates.
    //
    if(lX1 > lX2)
    {
        lError = lX1;
        lX1 = lX2;
        lX2 = lError;
        lError = lY1;
        lY1 = lY2;
        lY2 = lError;
    }

    //
    // Compute the difference between the start and end coordinates in each
    // axis.
    //
    lDeltaX = lX2 - lX1;
    lDeltaY = (lY2 > lY1) ? (lY2 - lY1) : (lY1 - lY2);

    //
    // Initialize the error term to negative half the X delta.
    //
    lError = -lDeltaX / 2;

    //
    // Determine the direction to step in the Y axis when required.
    //
    if(lY1 < lY2)
    {
        lYStep = 1;
    }
    else
    {
        lYStep = -1;
    }

    //
    // Loop through all the points along the X axis of the line.
    //
    for(; lX1 <= lX2; lX1++)
    {
        //
        // See if this is a steep line.
        //
        if(bSteep)
        {
            //
            // Plot this point of the line, swapping the X and Y coordinates.
            //
            //DpyPixelDraw(pContext->pDisplay, lY1, lX1, pContext->ulForeground);
            GrLineDrawH(pContext, lY1 + lWStart, lY1 + lWEnd, lX1);
        }
        else
        {
            //
            // Plot this point of the line, using the coordinates as is.
            //
            //DpyPixelDraw(pContext->pDisplay, lX1, lY1, pContext->ulForeground);
            GrLineDrawV(pContext, lX1, lY1 + lWStart, lY1 + lWEnd);
        }

        //
        // Increment the error term by the Y delta.
        //
        lError += lDeltaY;

        //
        // See if the error term is now greater than zero.
        //
        if(lError > 0)
        {
            //
            // Take a step in the Y axis.
            //
            lY1 += lYStep;

            //
            // Decrement the error term by the X delta.
            //
            lError -= lDeltaX;
        }
    }
}