_t nDxE = (int32_t)nRadEnd   * gslc_sinFX(n64Ang)/32768;
  int16_t nDyE = (int32_t)nRadEnd   * gslc_cosFX(n64Ang)/32768;
  gslc_DrawLine(pGui,nX+nDxS,nY-nDyS,nX+nDxE,nY-nDyE,nCol);
}


void gslc_DrawFrameRect(gslc_tsGui* pGui,gslc_tsRect rRect,gslc_tsColor nCol)
{
  // Ensure dimensions are valid
  if ((rRect.w == 0) || (rRect.h == 0)) {
    return;
  }

#if (DRV_HAS_DRAW_RECT_FRAME)
  // Call optimized driver implementation
  gslc_DrvDrawFrameRect(pGui,rRect,nCol);
#else
  // Emulate rect frame with four lines
  int16_t   nX,nY;
  uint16_t  nH,nW;
  nX = rRect.x;
  nY = rRect.y;
  nW = rRect.w;
  nH = rRect.h;
  gslc_DrawLineH(pGui,nX,nY,nW-1,nCol);                 // Top
  gslc_DrawLineH(pGui,nX,(int16_t)(nY+nH-1),nW-1,nCol); // Bottom
  gslc_DrawLineV(pGui,nX,nY,nH-1,nCol);                 // Left
  gslc_DrawLineV(pGui,(int16_t)(nX+nW-1),nY,nH-1,nCol); // Right
#endif

  gslc_PageFlipSet(pGui,true);
}

void gslc_DrawFrameRoundRect(gslc_tsGui* pGui,gslc_tsRect rRect,int16_t nRadius,gslc_tsColor nCol)
{
  // Ensure dimensions are valid
  if ((rRect.w == 0) || (rRect.h == 0)) {
    return;
  }

#if (DRV_HAS_DRAW_RECT_ROUND_FRAME)
  // Call optimized driver implementation
  gslc_DrvDrawFrameRoundRect(pGui,rRect,nRadius,nCol);
#else
  // TODO: Add emulation of rounded rects. For now fallback to square corners
  gslc_DrvDrawFrameRect(pGui,rRect,nCol);
#endif

  gslc_PageFlipSet(pGui,true);
}


void gslc_DrawFillRect(gslc_tsGui* pGui,gslc_tsRect rRect,gslc_tsColor nCol)
{
  // Ensure dimensions are valid
  if ((rRect.w == 0) || (rRect.h == 0)) {
    return;
  }

#if (DRV_HAS_DRAW_RECT_FILL)
  // Call optimized driver implementation
  gslc_DrvDrawFillRect(pGui,rRect,nCol);
#else
  // Emulate it with individual line draws
  // TODO: This should be avoided as it will generally be very inefficient
  int nRow;
  for (nRow=0;nRow<rRect.h;nRow++) {
    gslc_DrawLineH(pGui, rRect.x, rRect.y+nRow, rRect.w, nCol);
  }

#endif

  gslc_PageFlipSet(pGui,true);
}

void gslc_DrawFillRoundRect(gslc_tsGui* pGui,gslc_tsRect rRect,int16_t nRadius,gslc_tsColor nCol)
{
  // Ensure dimensions are valid
  if ((rRect.w == 0) || (rRect.h == 0)) {
    return;
  }

#if (DRV_HAS_DRAW_RECT_ROUND_FILL)
  // Call optimized driver implementation
  gslc_DrvDrawFillRoundRect(pGui,rRect,nRadius,nCol);
#else
  // TODO: Add emulation of rounded rects. For now fallback to square corners
  gslc_DrvDrawFillRect(pGui,rRect,nCol);
#endif

  gslc_PageFlipSet(pGui,true);
}



// Expand or contract a rectangle in width and/or height (equal
// amounts on both side), based on the centerpoint of the rectangle.
gslc_tsRect gslc_ExpandRect(gslc_tsRect rRect,int16_t nExpandW,int16_t nExpandH)
{
  gslc_tsRect rNew = {0,0,0,0};

  // Detect error case of contracting region too far
  if ( ((int16_t)rRect.w < (-2*nExpandW)) || ((int16_t)rRect.h < (-2*nExpandH)) ) {
    // Return an empty coordinate box (which won't be drawn)
    //GSLC_DEBUG2_PRINT("ERROR: ExpandRect(%d,%d) contracts too far\n",nExpandW,nExpandH);
    return rNew;
  }

  // Adjust the new width/height
  // Note that the overall width/height changes by a factor of
  // two since we are applying the adjustment on both sides (ie.
  // top/bottom or left/right) equally.
  rNew.w = rRect.w + (2*nExpandW);
  rNew.h = rRect.h + (2*nExpandH);

  // Adjust the rectangle coordinate to allow for new dimensions
  // Note that this moves the coordinate in the opposite
  // direction of the expansion/contraction.
  rNew.x = rRect.x - nExpandW;
  rNew.y = rRect.y - nExpandH;

  return rNew;
}


// Expand the current rect (pRect) to enclose the additional rect region (rAddRect)
void gslc_UnionRect(gslc_tsRect* pRect,gslc_tsRect rAddRect)
{
  int16_t nSrcX0, nSrcY0, nSrcX1, nSrcY1;
  int16_t nAddX0, nAddY0, nAddX1, nAddY1;

  // If the source rect has zero dimensions, then treat as empty
  if ((pRect->w == 0) || (pRect->h == 0)) {
    // No source region defined, simply copy add region
    *pRect = rAddRect;
    return;
  }

  // Source region valid, so increase dimensions

  // Calculate the rect boundary coordinates
  nSrcX0 = pRect->x;
  nSrcY0 = pRect->y;
  nSrcX1 = pRect->x + pRect->w - 1;
  nSrcY1 = pRect->y + pRect->h - 1;
  nAddX0 = rAddRect.x;
  nAddY0 = rAddRect.y;
  nAddX1 = rAddRect.x + rAddRect.w - 1;
  nAddY1 = rAddRect.y + rAddRect.h - 1;

  // Find the new maximal dimensions
  nSrcX0 = (nAddX0 < nSrcX0)? nAddX0 : nSrcX0;
  nSrcY0 = (nAddY0 < nSrcY0)? nAddY0 : nSrcY0;
  nSrcX1 = (nAddX1 > nSrcX1)? nAddX1 : nSrcX1;
  nSrcY1 = (nAddY1 > nSrcY1)? nAddY1 : nSrcY1;

  // Update the original rect region
  pRect->x = nSrcX0;
  pRect->y = nSrcY0;
  pRect->w = nSrcX1 - nSrcX0 + 1;
  pRect->h = nSrcY1 - nSrcY0 + 1;

}

void gslc_InvalidateRgnReset(gslc_tsGui* pGui)
{
#if defined(DBG_REDRAW)
  GSLC_DEBUG_PRINT