424 lines
12 KiB
C
424 lines
12 KiB
C
/*
|
|
*********************************************************************************************************
|
|
* uC/GUI
|
|
* Universal graphic software for embedded applications
|
|
*
|
|
* (c) Copyright 2002, Micrium Inc., Weston, FL
|
|
* (c) Copyright 2002, SEGGER Microcontroller Systeme GmbH
|
|
*
|
|
* µC/GUI is protected by international copyright laws. Knowledge of the
|
|
* source code may not be used to write a similar product. This file may
|
|
* only be used in accordance with a license and should not be redistributed
|
|
* in any way. We appreciate your understanding and fairness.
|
|
*
|
|
----------------------------------------------------------------------
|
|
File : GUICurs.C
|
|
Purpose : Cursor routines of the graphics library
|
|
---------------------------END-OF-HEADER------------------------------
|
|
*/
|
|
|
|
#include <stddef.h> /* needed for definition of NULL */
|
|
#include "GUI_Private.h"
|
|
|
|
#if GUI_SUPPORT_CURSOR
|
|
|
|
/*********************************************************************
|
|
*
|
|
* static data
|
|
*
|
|
**********************************************************************
|
|
*/
|
|
|
|
static GUI_HMEM _hBuffer;
|
|
static GUI_RECT _Rect;
|
|
static char _CursorIsVis; /* Currently visible ? */
|
|
static char _CursorOn;
|
|
static const GUI_CURSOR GUI_UNI_PTR * _pCursor;
|
|
static U8 _CursorDeActCnt;
|
|
static int _AllocSize;
|
|
static int _x, _y; /* Position of hot spot */
|
|
static GUI_RECT _ClipRect;
|
|
static LCD_PIXELINDEX _ColorIndex[4]; /* Color-Cache */
|
|
|
|
/*********************************************************************
|
|
*
|
|
* static code, helper functions
|
|
*
|
|
**********************************************************************
|
|
*/
|
|
/*********************************************************************
|
|
*
|
|
* _SetPixelIndex
|
|
*
|
|
* Purpose
|
|
* Sets the pixel index for the Cursor.
|
|
* Note the following:
|
|
* - We do the clipping in this routine
|
|
* - We do NOT call the driver directly, but thru its API table.
|
|
* This allows others (e.g. the VNC server) to be in the loop-
|
|
*/
|
|
static void _SetPixelIndex(int x, int y, int Index) {
|
|
if ((y >= _ClipRect.y0) && (y <= _ClipRect.y1)) {
|
|
if ((x >= _ClipRect.x0) && (x <= _ClipRect.x1)) {
|
|
LCD_aAPI[0]->pfSetPixelIndex(x, y, Index);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*********************************************************************
|
|
*
|
|
* _GetPixelIndex
|
|
*
|
|
* Purpose
|
|
* Gets a pixel index for the Cursor.
|
|
*/
|
|
static int _GetPixelIndex(int x, int y) {
|
|
if ((y >= _ClipRect.y0) && (y <= _ClipRect.y1)) {
|
|
if ((x >= _ClipRect.x0) && (x <= _ClipRect.x1)) {
|
|
return LCD_L0_GetPixelIndex(x, y);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*********************************************************************
|
|
*
|
|
* _Undraw
|
|
*
|
|
* Purpose
|
|
* Remove the cursors
|
|
*/
|
|
static void _Undraw(void) {
|
|
int x, y, xSize, ySize;
|
|
LCD_PIXELINDEX* pData;
|
|
/* Save bitmap data */
|
|
GUI_LOCK();
|
|
if (_hBuffer) {
|
|
pData = (LCD_PIXELINDEX*)GUI_ALLOC_h2p(_hBuffer);
|
|
xSize = _Rect.x1 - _Rect.x0 + 1;
|
|
ySize = _Rect.y1 - _Rect.y0 + 1;
|
|
for (y = 0; y < ySize; y++) {
|
|
for (x = 0; x < xSize; x++) {
|
|
_SetPixelIndex(x + _Rect.x0, y + _Rect.y0, *(pData + x));
|
|
}
|
|
pData += _pCursor->pBitmap->XSize;
|
|
}
|
|
}
|
|
GUI_UNLOCK();
|
|
}
|
|
|
|
/*********************************************************************
|
|
*
|
|
* _Log2Phys
|
|
*/
|
|
static int _Log2Phys(int Index) {
|
|
if (Index < 4) {
|
|
return _ColorIndex[Index];
|
|
} else {
|
|
LCD_COLOR Color = *(_pCursor->pBitmap->pPal->pPalEntries + Index);
|
|
return LCD_Color2Index(Color);
|
|
}
|
|
}
|
|
|
|
/*********************************************************************
|
|
*
|
|
* _Draw
|
|
*/
|
|
static void _Draw(void) {
|
|
int x, y, xSize, ySize;
|
|
LCD_PIXELINDEX* pData;
|
|
const GUI_BITMAP GUI_UNI_PTR * pBM;
|
|
GUI_LOCK();
|
|
if (_hBuffer) {
|
|
/* Save bitmap data */
|
|
pBM = _pCursor->pBitmap;
|
|
pData = (LCD_PIXELINDEX*)GUI_ALLOC_h2p(_hBuffer);
|
|
xSize = _Rect.x1 - _Rect.x0 + 1;
|
|
ySize = _Rect.y1 - _Rect.y0 + 1;
|
|
for (y = 0; y < ySize; y++) {
|
|
for (x = 0; x < xSize; x++) {
|
|
int BitmapPixel;
|
|
*(pData + x) = _GetPixelIndex(_Rect.x0 + x, _Rect.y0 + y);
|
|
BitmapPixel = GUI_GetBitmapPixelIndex(pBM, x, y);
|
|
if (BitmapPixel) {
|
|
_SetPixelIndex(_Rect.x0 + x, _Rect.y0 + y, _Log2Phys(BitmapPixel));
|
|
}
|
|
}
|
|
pData += pBM->XSize;
|
|
}
|
|
}
|
|
GUI_UNLOCK();
|
|
}
|
|
|
|
/*********************************************************************
|
|
*
|
|
* _CalcRect
|
|
*/
|
|
static void _CalcRect(void) {
|
|
if (_pCursor) {
|
|
_Rect.x0 = _x - _pCursor->xHot;
|
|
_Rect.y0 = _y - _pCursor->yHot;
|
|
_Rect.x1 = _Rect.x0 + _pCursor->pBitmap->XSize - 1;
|
|
_Rect.y1 = _Rect.y0 + _pCursor->pBitmap->YSize - 1;
|
|
}
|
|
}
|
|
|
|
/*********************************************************************
|
|
*
|
|
* _Hide
|
|
*/
|
|
static void _Hide(void) {
|
|
if (_CursorIsVis) {
|
|
_Undraw();
|
|
_CursorIsVis = 0;
|
|
}
|
|
}
|
|
|
|
/*********************************************************************
|
|
*
|
|
* _Show
|
|
*/
|
|
static void _Show(void) {
|
|
if (_CursorOn && (_CursorDeActCnt==0)) {
|
|
_CursorIsVis = 1;
|
|
_Draw();
|
|
}
|
|
}
|
|
|
|
/*********************************************************************
|
|
*
|
|
* _TempHide
|
|
*
|
|
* Purpose:
|
|
* Hide cursor if a part of the given rectangle is located in the
|
|
* rectangle used for the cursor. This routine is called automatically
|
|
* by the window manager. This way the window manager can
|
|
* automatically make sure that the cursor is always displayed
|
|
* correctly.
|
|
*
|
|
* Params:
|
|
* pRect Rectangle under consideration
|
|
*
|
|
* Return value:
|
|
* 0: No action taken
|
|
* Cursor was not visible or not affected because rectangles
|
|
* did not overlap
|
|
* 1: Cursor hidden -> WM needs to restore cursor after
|
|
* drawing operation
|
|
*/
|
|
static char _TempHide(const GUI_RECT* pRect) {
|
|
if (!_CursorIsVis) {
|
|
return 0; /* Cursor not visible -> nothing to do */
|
|
}
|
|
if ((pRect == NULL) || GUI_RectsIntersect(pRect, &_Rect)) {
|
|
_Hide(); /* Cursor needs to be hidden */
|
|
return 1;
|
|
}
|
|
return 0; /* Cursor not affected -> nothing to do */
|
|
}
|
|
|
|
/*********************************************************************
|
|
*
|
|
* _TempUnhide
|
|
*/
|
|
static void _TempUnhide(void) {
|
|
_Show();
|
|
}
|
|
|
|
/*********************************************************************
|
|
*
|
|
* Public code
|
|
*
|
|
**********************************************************************
|
|
*/
|
|
/*********************************************************************
|
|
*
|
|
* GUI_CURSOR_Activate
|
|
*/
|
|
void GUI_CURSOR_Activate(void) {
|
|
GUI_LOCK();
|
|
if ((--_CursorDeActCnt) ==0) {
|
|
_Show();
|
|
}
|
|
GUI_UNLOCK();
|
|
}
|
|
|
|
/*********************************************************************
|
|
*
|
|
* GUI_CURSOR_Deactivate
|
|
*/
|
|
void GUI_CURSOR_Deactivate(void) {
|
|
GUI_LOCK();
|
|
if (_CursorDeActCnt++ ==0)
|
|
_Hide();
|
|
GUI_UNLOCK();
|
|
}
|
|
|
|
/*********************************************************************
|
|
*
|
|
* GUI_CURSOR_Select
|
|
*/
|
|
const GUI_CURSOR GUI_UNI_PTR * GUI_CURSOR_Select(const GUI_CURSOR GUI_UNI_PTR * pCursor) {
|
|
int AllocSize;
|
|
const GUI_BITMAP GUI_UNI_PTR * pBM;
|
|
const GUI_CURSOR GUI_UNI_PTR * pOldCursor;
|
|
GUI_LOCK();
|
|
pOldCursor = _pCursor;
|
|
if (pCursor != _pCursor) {
|
|
int i;
|
|
pBM = pCursor->pBitmap;
|
|
i = pBM->pPal->NumEntries > 4 ? 4 : pBM->pPal->NumEntries;
|
|
while (i--) {
|
|
LCD_COLOR Color = *(pBM->pPal->pPalEntries + i);
|
|
_ColorIndex[i] = LCD_Color2Index(Color);
|
|
}
|
|
_Hide();
|
|
AllocSize = pBM->XSize * pBM->YSize * sizeof(LCD_PIXELINDEX);
|
|
if (AllocSize != _AllocSize) {
|
|
GUI_ALLOC_Free(_hBuffer);
|
|
_hBuffer = 0;
|
|
}
|
|
_hBuffer = GUI_ALLOC_AllocZero(AllocSize);
|
|
_CursorOn = 1;
|
|
_pCursor = pCursor;
|
|
_CalcRect();
|
|
_Show();
|
|
}
|
|
GUI_UNLOCK();
|
|
return pOldCursor;
|
|
}
|
|
|
|
/*********************************************************************
|
|
*
|
|
* GUI_CURSOR_Hide
|
|
*/
|
|
void GUI_CURSOR_Hide(void) {
|
|
GUI_LOCK();
|
|
_Hide();
|
|
_CursorOn = 0;
|
|
/* Set function pointer which window manager can use */
|
|
GUI_CURSOR_pfTempHide = NULL;
|
|
GUI_CURSOR_pfTempUnhide = NULL;
|
|
GUI_UNLOCK();
|
|
}
|
|
|
|
/*********************************************************************
|
|
*
|
|
* GUI_CURSOR_Show
|
|
*/
|
|
void GUI_CURSOR_Show(void) {
|
|
GUI_LOCK();
|
|
LCDDEV_L0_GetRect(&_ClipRect);
|
|
_Hide();
|
|
_CursorOn = 1;
|
|
/* Set function pointer which window manager can use */
|
|
GUI_CURSOR_pfTempHide = _TempHide;
|
|
GUI_CURSOR_pfTempUnhide = _TempUnhide;
|
|
if (!_pCursor) {
|
|
GUI_CURSOR_Select(GUI_DEFAULT_CURSOR);
|
|
} else {
|
|
_Show();
|
|
}
|
|
GUI_UNLOCK();
|
|
}
|
|
|
|
/*********************************************************************
|
|
*
|
|
* GUI_CURSOR_SetPosition
|
|
*/
|
|
void GUI_CURSOR_SetPosition(int xNewPos, int yNewPos) {
|
|
int x, xStart, xStep, xEnd, xOff, xOverlapMin, xOverlapMax;
|
|
int y, yStart, yStep, yEnd, yOff, yOverlapMin, yOverlapMax;
|
|
int xSize;
|
|
LCD_PIXELINDEX* pData;
|
|
GUI_LOCK();
|
|
if (_hBuffer) {
|
|
if ((_x != xNewPos) | (_y != yNewPos)) {
|
|
if (_CursorOn) {
|
|
const GUI_BITMAP GUI_UNI_PTR * pBM = _pCursor->pBitmap;
|
|
/* Save & set clip rect */
|
|
/* Compute helper variables */
|
|
pData = (LCD_PIXELINDEX*)GUI_ALLOC_h2p(_hBuffer);
|
|
xSize = _pCursor->pBitmap->XSize;
|
|
xOff = xNewPos - _x;
|
|
if (xOff > 0) {
|
|
xStep = 1;
|
|
xStart = 0;
|
|
xEnd = _pCursor->pBitmap->XSize;
|
|
xOverlapMax = xEnd -1;
|
|
xOverlapMin = xOff;
|
|
} else {
|
|
xStep = -1;
|
|
xStart = xSize - 1;
|
|
xEnd = -1;
|
|
xOverlapMin = 0;
|
|
xOverlapMax = xStart + xOff;
|
|
}
|
|
yOff = yNewPos - _y;
|
|
if (yOff > 0) {
|
|
yStep = 1;
|
|
yStart = 0;
|
|
yEnd = _pCursor->pBitmap->YSize;
|
|
yOverlapMax = yEnd -1;
|
|
yOverlapMin = yOff;
|
|
} else {
|
|
yStep = -1;
|
|
yStart = _pCursor->pBitmap->YSize - 1;
|
|
yEnd = -1;
|
|
yOverlapMin = 0;
|
|
yOverlapMax = yStart + yOff;
|
|
}
|
|
/* Restore & Draw */
|
|
for (y = yStart; y != yEnd; y += yStep) {
|
|
char yOverlaps;
|
|
char yNewOverlaps;
|
|
int yNew = y + yOff;
|
|
yOverlaps = (y >= yOverlapMin) && (y <= yOverlapMax);
|
|
yNewOverlaps = (yNew >= yOverlapMin) && (yNew <= yOverlapMax);
|
|
for (x= xStart; x != xEnd; x += xStep) {
|
|
char xyOverlaps, xyNewOverlaps;
|
|
int BitmapPixel;
|
|
LCD_PIXELINDEX Pixel;
|
|
LCD_PIXELINDEX* pSave = pData + x + y * xSize;
|
|
int xNew = x + xOff;
|
|
BitmapPixel = GUI_GetBitmapPixelIndex(pBM, x, y);
|
|
xyOverlaps = (x >= xOverlapMin) && (x <= xOverlapMax) && yOverlaps;
|
|
xyNewOverlaps = (xNew >= xOverlapMin) && (xNew <= xOverlapMax) && yNewOverlaps;
|
|
/* Restore old pixel if it was not transparent */
|
|
if (BitmapPixel) {
|
|
if (!xyOverlaps || (GUI_GetBitmapPixelIndex(pBM, x - xOff, y - yOff) == 0)) {
|
|
_SetPixelIndex(x + _Rect.x0, y + _Rect.y0, *(pSave));
|
|
}
|
|
}
|
|
/* Save */
|
|
if (xyNewOverlaps) {
|
|
Pixel = *(pData + xNew + yNew * xSize);
|
|
} else {
|
|
Pixel = _GetPixelIndex(_Rect.x0 + xNew, _Rect.y0 + yNew);
|
|
}
|
|
*pSave = Pixel;
|
|
/* Write new ... We could write pixel by pixel here */
|
|
if (BitmapPixel) {
|
|
LCD_PIXELINDEX NewPixel = _Log2Phys(BitmapPixel);
|
|
_SetPixelIndex(_Rect.x0 + xNew, _Rect.y0 + yNew, NewPixel);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
_x = xNewPos;
|
|
_y = yNewPos;
|
|
_CalcRect();
|
|
}
|
|
}
|
|
GUI_UNLOCK();
|
|
}
|
|
|
|
#else
|
|
|
|
void GUICurs_C(void);
|
|
void GUICurs_C(void) {} /* avoid empty object files */
|
|
|
|
#endif /* GUI_SUPPORT_CURSOR */
|
|
|
|
/*************************** End of file ****************************/
|