/*****************************************************************************
* Module for Microchip Graphics Library
* GOL Layer
* List Box
*****************************************************************************
* FileName: ListBox.c
* Dependencies: None
* Processor: PIC24F, PIC24H, dsPIC, PIC32
* Compiler: MPLAB C30 V3.00, MPLAB C32
* Linker: MPLAB LINK30, MPLAB LINK32
* Company: Microchip Technology Incorporated
*
* Software License Agreement
*
* Copyright © 2008 Microchip Technology Inc. All rights reserved.
* Microchip licenses to you the right to use, modify, copy and distribute
* Software only when embedded on a Microchip microcontroller or digital
* signal controller, which is integrated into your product or third party
* product (pursuant to the sublicense terms in the accompanying license
* agreement).
*
* You should refer to the license agreement accompanying this Software
* for additional information regarding your rights and obligations.
*
* SOFTWARE AND DOCUMENTATION ARE PROVIDED AS IS WITHOUT WARRANTY OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY WARRANTY
* OF MERCHANTABILITY, TITLE, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR
* PURPOSE. IN NO EVENT SHALL MICROCHIP OR ITS LICENSORS BE LIABLE OR
* OBLIGATED UNDER CONTRACT, NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION,
* BREACH OF WARRANTY, OR OTHER LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT
* DAMAGES OR EXPENSES INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL,
* INDIRECT, PUNITIVE OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA,
* COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY
* CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF),
* OR OTHER SIMILAR COSTS.
*
* Author Date Comment
*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Anton Alkhimenok 11/12/07 Version 1.0 release
*****************************************************************************/
#include "Graphics\Graphics.h"
#ifdef USE_LISTBOX
/*********************************************************************
* Function: LISTBOX *LbCreate(WORD ID, SHORT left, SHORT top, SHORT right, SHORT bottom,
* WORD state, XCHAR* pText, GOL_SCHEME *pScheme)
*
* Overview: creates the list box
*
********************************************************************/
LISTBOX *LbCreate
(
WORD ID,
SHORT left,
SHORT top,
SHORT right,
SHORT bottom,
WORD state,
XCHAR *pText,
GOL_SCHEME *pScheme
)
{
LISTBOX *pLb = NULL;
XCHAR *pointer;
WORD counter;
pLb = (LISTBOX *)GFX_malloc(sizeof(LISTBOX));
if(pLb == NULL)
return (pLb);
pLb->hdr.ID = ID;
pLb->hdr.pNxtObj = NULL;
pLb->hdr.type = OBJ_LISTBOX;
pLb->hdr.left = left;
pLb->hdr.top = top;
pLb->hdr.right = right;
pLb->hdr.bottom = bottom;
pLb->hdr.state = state;
pLb->pItemList = NULL;
pLb->scrollY = 0;
pLb->itemsNumber = 0;
// Set the style scheme to be used
if(pScheme == NULL)
pLb->hdr.pGolScheme = _pDefaultGolScheme;
else
pLb->hdr.pGolScheme = (GOL_SCHEME *)pScheme;
pLb->textHeight = GetTextHeight(pLb->hdr.pGolScheme->pFont);
GOLAddObject((OBJ_HEADER *)pLb);
// Add items if there's an initialization text (each line will become one item,
// lines must be separated by '\n' character)
if(pText != NULL)
{
pointer = pText;
counter = 0;
while(*pointer)
{
if(NULL == LbAddItem(pLb, NULL, pointer, NULL, 0, counter))
break;
while((XCHAR) *pointer++ > (XCHAR)31);
if(*(pointer - 1) == 0)
break;
counter++;
}
}
pLb->pFocusItem = pLb->pItemList;
// Set focus for the object if FOCUSED state is set
#ifdef USE_FOCUS
if(GetState(pLb, LB_FOCUSED))
GOLSetFocus((OBJ_HEADER *)pLb);
#endif
return (pLb);
}
/*********************************************************************
* Function: LISTITEM* LbAddItem(LISTBOX *pLb, LISTITEM *pPrevItem, XCHAR *pText, void* pBitmap, WORD status, WORD data)
*
* Input: pLb - the pointer to the list box,
* pPrevItem - pointer to the item after which a new item must be inserted,
* if this pointer is NULL, the item will be appended at the end of the items list,
* pText - pointer to the text,
* pBitmap - pointer to the bitmap,
* status - status after creation,
* data - some data associated with the item
*
* Output: pointer to the item created, NULL if the operation was not successful
*
* Overview: allocates memory for a new item and adds it to the list box
*
********************************************************************/
LISTITEM *LbAddItem(LISTBOX *pLb, LISTITEM *pPrevItem, XCHAR *pText, void *pBitmap, WORD status, WORD data)
{
LISTITEM *pItem;
LISTITEM *pCurItem;
pItem = (LISTITEM *)GFX_malloc(sizeof(LISTITEM));
if(pItem == NULL)
{
return (NULL);
}
pLb->itemsNumber++;
if(pLb->pItemList == NULL)
{
pLb->pItemList = pItem;
pItem->pNextItem = NULL;
pItem->pPrevItem = NULL;
}
else
{
if(pPrevItem == NULL)
{
// Find last item
pCurItem = (LISTITEM *)pLb->pItemList;
while(pCurItem->pNextItem != NULL)
pCurItem = (LISTITEM *)pCurItem->pNextItem;
}
else
{
pCurItem = (LISTITEM *)pPrevItem;
}
// Insert a new item
pItem->pNextItem = pCurItem->pNextItem;
pItem->pPrevItem = pCurItem;
pCurItem->pNextItem = pItem;
}
pItem->pText = pText;
pItem->pBitmap = pBitmap;
pItem->status = status;
pItem->data = data;
return (pItem);
}
/*********************************************************************
* Function: void LbDelItem(LISTBOX *pLb, LISTITEM *pItem)
*
* Input: pLb - the pointer to the object,
* pItem - the pointer to the item must be deleted
*
* Output: none
*
* Overview: removes an item from the list box and frees memory
*
********************************************************************/
void LbDelItem(LISTBOX *pLb, LISTITEM *pItem)
{
if(pItem->pNextItem != NULL)
{
((LISTITEM *)pItem->pNextItem)->pPrevItem = pItem->pPrevItem;
if(pItem->pPrevItem == NULL)
pLb->pItemList = (LISTITEM *)pItem->pNextItem;
}
if(pItem->pPrevItem != NULL)
((LISTITEM *)pItem->pPrevItem)->pNextItem = pItem->pNextItem;
GFX_free(pItem);
pLb->itemsNumber--;
if(pLb->itemsNumber == 0)
pLb->pItemList = NULL;
}
/*********************************************************************
* Function: void LbDelItemsList(LISTBOX *pLb)
*
* Input: pLb - the pointer to the object
*
* Output: none
*
* Overview: removes all items from list box and frees memory
*
********************************************************************/
void LbDelItemsList(LISTBOX *pLb)
{
LISTITEM *pCurItem;
LISTITEM *pItem;
pCurItem = pLb->pItemList;
while(pCurItem != NULL)
{
pItem = pCurItem;
pCurItem = (LISTITEM *)pCurItem->pNextItem;
GFX_free(pItem);
}
pLb->pItemList = NULL;
}
/*********************************************************************
* Function: LISTITEM* LbGetSel(LISTBOX *pLb, LISTITEM *pFromItem)
*
* Input: pLb - the pointer to the object,
* pFromItem - pointer to the item the seach must start from,
* if the pointer is NULL the search begins from the start of the items list
*
* Output: pointer to the selected item, NULL if there are no items selected
*
* Overview: seaches for selected items
*
********************************************************************/
LISTITEM *LbGetSel(LISTBOX *pLb, LISTITEM *pFromItem)
{
if(pFromItem == NULL)
{
pFromItem = pLb->pItemList;
}
while(pFromItem != NULL)
{
if(pFromItem->status & LB_STS_SELECTED)
break;
pFromItem = (LISTITEM *)pFromItem->pNextItem;
}
return (pFromItem);
}
/*********************************************************************
* Function: void LbChangeSel(LISTBOX *pLb, LISTITEM *pItem)
*
* Input: pLb - the pointer to the object,
* pItem - pointer to the item the selection status will be changed
*
* Output: none
*
* Overview: changes selection status of an item
*
********************************************************************/
void LbChangeSel(LISTBOX *pLb, LISTITEM *pItem)
{
LISTITEM *pCurItem;
if(GetState(pLb, LB_SINGLE_SEL))
{
// Remove selection from all items
pCurItem = pLb->pItemList;
while(pCurItem != NULL)
{
if(pCurItem->status & LB_STS_SELECTED)
{
pCurItem->status &= ~LB_STS_SELECTED;
pCurItem->status |= LB_STS_REDRAW;
}
pCurItem = (LISTITEM *)pCurItem->pNextItem;
}
}
pItem->status ^= LB_STS_SELECTED;
pItem->status |= LB_STS_REDRAW;
}
/*********************************************************************
* Function: void LbSetFocusedItem(LISTBOX* pLb, SHORT index)
*
* Input: pLb - the pointer to the object
* index - item number from the list beginning
*
* Output: none
*
* Overview: sets focus for the item with index defined
*
********************************************************************/
void LbSetFocusedItem(LISTBOX *pLb, SHORT index)
{
LISTITEM *pCurItem;
// Look for item to be focused
pCurItem = pLb->pItemList;
if(pCurItem == NULL)
return;
while(pCurItem->pNextItem != NULL)
{
if(index <= 0)
break;
index--;
pCurItem = (LISTITEM *)pCurItem->pNextItem;
}
if(pCurItem != NULL)
{
if(pLb->pFocusItem != NULL)
{
pLb->pFocusItem->status |= LB_STS_REDRAW;
}
pLb->pFocusItem = pCurItem;
pCurItem->status |= LB_STS_REDRAW;
}
}
/*********************************************************************
* Function: SHORT LbGetFocusedItem(LISTBOX* pLb)
*
* Input: pLb - the pointer to the list box
*
* Output: index of the focused item, -1 if there's no item in focus
*
* Overview: returns focused item number from the list beginning
*
********************************************************************/
SHORT LbGetFocusedItem(LISTBOX *pLb)
{
LISTITEM *pCurItem;
SHORT index;
if(pLb->pFocusItem == NULL)
return (-1);
// Look for the focused item index
index = 0;
pCurItem = pLb->pItemList;
while(pCurItem->pNextItem != NULL)
{
if(pCurItem == pLb->pFocusItem)
break;
index++;
pCurItem = (LISTITEM *)pCurItem->pNextItem;
}
return (index);
}
/*********************************************************************
* Function: WORD LbTranslateMsg(LISTBOX *pLb, GOL_MSG *pMsg)
*
* Overview: translates the GOL message for the list box
*
********************************************************************/
WORD LbTranslateMsg(LISTBOX *pLb, GOL_MSG *pMsg)
{
// Evaluate if the message is for the list box
// Check if disabled first
if(GetState(pLb, LB_DISABLED))
return (OBJ_MSG_INVALID);
#ifdef USE_TOUCHSCREEN
if(pMsg->type == TYPE_TOUCHSCREEN)
{
// Check if it falls in list box borders
if
(
(pLb->hdr.left < pMsg->param1) &&
(pLb->hdr.right > pMsg->param1) &&
(pLb->hdr.top < pMsg->param2) &&
(pLb->hdr.bottom > pMsg->param2)
) return (LB_MSG_TOUCHSCREEN);
return (OBJ_MSG_INVALID);
}
#endif
#ifdef USE_KEYBOARD
if(pMsg->type == TYPE_KEYBOARD)
if(pMsg->param1 == pLb->hdr.ID)
{
if(pMsg->uiEvent == EVENT_KEYSCAN)
{
if((pMsg->param2 == SCAN_UP_PRESSED) || (pMsg->param2 == SCAN_DOWN_PRESSED))
return (LB_MSG_MOVE);
if((pMsg->param2 == SCAN_SPACE_PRESSED) || (pMsg->param2 == SCAN_CR_PRESSED))
return (LB_MSG_SEL);
}
return (OBJ_MSG_INVALID);
}
#endif
return (OBJ_MSG_INVALID);
}
/*********************************************************************
* Function: void LbMsgDefault(WORD translatedMsg, LISTBOX *pLb, GOL_MSG *pMsg)
*
* Overview: changes the state of the list box by default
*
********************************************************************/
void LbMsgDefault(WORD translatedMsg, LISTBOX *pLb, GOL_MSG *pMsg)
{
#ifdef USE_TOUCHSCREEN
SHORT pos;
LISTITEM *pItem;
if(pMsg->type == TYPE_TOUCHSCREEN)
{
#ifdef USE_FOCUS
if(pMsg->type == TYPE_TOUCHSCREEN)
{
if(!GetState(pLb, LB_FOCUSED))
{
GOLSetFocus((OBJ_HEADER *)pLb);
}
}
#endif
if(pMsg->uiEvent == EVENT_PRESS)
{
pos = (pMsg->param2 - pLb->scrollY - pLb->hdr.top - LB_INDENT - GOL_EMBOSS_SIZE) / pLb->textHeight;
pItem = (LISTITEM *)pLb->pItemList;
while(pos)
{
if(pItem == NULL)
break;
if(pItem->pNextItem == NULL)
break;
pItem = (LISTITEM *)pItem->pNextItem;
pos--;
}
if(pLb->pFocusItem != pItem)
{
pItem->status |= LB_STS_REDRAW;
pLb->pFocusItem->status |= LB_STS_REDRAW;
pLb->pFocusItem = pItem;
SetState(pLb, LB_DRAW_ITEMS);
}
LbChangeSel(pLb, pItem);
SetState(pLb, LB_DRAW_ITEMS);
}
}
#endif
#ifdef USE_KEYBOARD
if(pMsg->type == TYPE_KEYBOARD)
{
switch(translatedMsg)
{
case LB_MSG_SEL:
if(pLb->pFocusItem != NULL)
LbChangeSel(pLb, pLb->pFocusItem);
SetState(pLb, LB_DRAW_ITEMS);
break;
case LB_MSG_MOVE:
switch(pMsg->param2)
{
case SCAN_UP_PRESSED:
LbSetFocusedItem(pLb, LbGetFocusedItem(pLb) - 1);
SetState(pLb, LB_DRAW_ITEMS);
break;
case SCAN_DOWN_PRESSED:
LbSetFocusedItem(pLb, LbGetFocusedItem(pLb) + 1);
SetState(pLb, LB_DRAW_ITEMS);
break;
}
break;
}
} // end of if
#endif
}
/*********************************************************************
* Function: WORD LbDraw(LISTBOX *pLb)
*
* Output: returns the status of the drawing
* 0 - not completed
* 1 - done
*
* Overview: draws edit box
*
********************************************************************/
WORD LbDraw(LISTBOX *pLb)
{
typedef enum
{
LB_STATE_START,
LB_STATE_PANEL,
LB_STATE_ERASEITEM,
LB_STATE_ITEMFOCUS,
LB_STATE_BITMAP,
LB_STATE_TEXT
} LB_DRAW_STATES;
static LB_DRAW_STATES state = LB_STATE_START;
static LISTITEM *pCurItem;
static SHORT temp;
switch(state)
{
/////////////////////////////////////////////////////////////////////
// REMOVE FROM SCREEN
/////////////////////////////////////////////////////////////////////
case LB_STATE_START:
if(GetState(pLb, LB_HIDE))
{
SetColor(pLb->hdr.pGolScheme->CommonBkColor);
if(!Bar(pLb->hdr.left, pLb->hdr.top, pLb->hdr.right, pLb->hdr.bottom))
return (0);
return (1);
}
if(GetState(pLb, LB_DRAW_FOCUS))
{
if(pLb->pFocusItem != NULL)
((LISTITEM *)pLb->pFocusItem)->status |= LB_STS_REDRAW;
SetState(pLb, LB_DRAW_ITEMS);
}
/////////////////////////////////////////////////////////////////////
// DRAW PANEL
/////////////////////////////////////////////////////////////////////
if(GetState(pLb, LB_DRAW))
{
if(GetState(pLb, LB_DISABLED))
{
temp = pLb->hdr.pGolScheme->ColorDisabled;
}
else
{
temp = pLb->hdr.pGolScheme->Color0;
}
GOLPanelDraw
(
pLb->hdr.left,
pLb->hdr.top,
pLb->hdr.right,
pLb->hdr.bottom,
0,
temp,
pLb->hdr.pGolScheme->EmbossDkColor,
pLb->hdr.pGolScheme->EmbossLtColor,
NULL,
GOL_EMBOSS_SIZE
);
state = LB_STATE_PANEL;
case LB_STATE_PANEL:
if(!GOLPanelDrawTsk())
return (0);
}
/////////////////////////////////////////////////////////////////////
// DRAW ITEMS
/////////////////////////////////////////////////////////////////////
L_LB_DRAW:
SetClip(CLIP_ENABLE);
SetClipRgn
(
pLb->hdr.left + GOL_EMBOSS_SIZE + LB_INDENT,
pLb->hdr.top + GOL_EMBOSS_SIZE + LB_INDENT,
pLb->hdr.right - GOL_EMBOSS_SIZE - LB_INDENT,
pLb->hdr.bottom - GOL_EMBOSS_SIZE - LB_INDENT
);
SetFont(pLb->hdr.pGolScheme->pFont);
// Set graphics cursor
MoveTo(pLb->hdr.left + GOL_EMBOSS_SIZE + LB_INDENT, pLb->hdr.top + GOL_EMBOSS_SIZE + LB_INDENT + pLb->scrollY);
pCurItem = pLb->pItemList;
/////////////////////////////////////////////////////////////////////
// DRAW CURRENT ITEM
/////////////////////////////////////////////////////////////////////
L_LB_DRAWITEM:
if(pCurItem == NULL)
{
state = LB_STATE_START;
SetClip(CLIP_DISABLE);
return (1);
}
/////////////////////////////////////////////////////////////////////
if(GetY() < pLb->hdr.bottom - GOL_EMBOSS_SIZE - LB_INDENT)
if((GetY() + pLb->textHeight) >= (pLb->hdr.top + GOL_EMBOSS_SIZE + LB_INDENT))
{
if(!GetState(pLb, LB_DRAW))
if(!(pCurItem->status & LB_STS_REDRAW))
goto L_LB_NEXTITEM;
pCurItem->status &= ~LB_STS_REDRAW;
state = LB_STATE_ERASEITEM;
case LB_STATE_ERASEITEM:
if(IsDeviceBusy())
return (0);
if(GetState(pLb, LB_DISABLED))
{
SetColor(pLb->hdr.pGolScheme->ColorDisabled);
}
else
{
SetColor(pLb->hdr.pGolScheme->Color0);
if(pCurItem != NULL)
if(pCurItem->status & LB_STS_SELECTED)
{
SetColor(pLb->hdr.pGolScheme->Color1);
}
}
if
(
!Bar
(
pLb->hdr.left + GOL_EMBOSS_SIZE + LB_INDENT,
GetY(),
pLb->hdr.right - GOL_EMBOSS_SIZE - LB_INDENT,
GetY() + pLb->textHeight
)
) return (0);
if(!GetState(pLb, LB_CENTER_ALIGN | LB_RIGHT_ALIGN))
{
MoveTo(pLb->hdr.left + GOL_EMBOSS_SIZE + LB_INDENT, GetY());
}
else
{
temp = GetTextWidth(pCurItem->pText, pLb->hdr.pGolScheme->pFont);
if(pCurItem->pBitmap != NULL)
{
temp += GetImageWidth(pCurItem->pBitmap) + LB_INDENT;
}
if(GetState(pLb, LB_RIGHT_ALIGN))
{
MoveTo(pLb->hdr.right - temp - LB_INDENT - GOL_EMBOSS_SIZE, GetY());
}
else
{
MoveTo((pLb->hdr.left + pLb->hdr.right - temp) >> 1, GetY());
}
}
if(GetState(pLb, LB_DISABLED))
{
SetColor(pLb->hdr.pGolScheme->TextColorDisabled);
}
else
{
if(pCurItem->status & LB_STS_SELECTED)
{
SetColor(pLb->hdr.pGolScheme->TextColor1);
}
else
{
SetColor(pLb->hdr.pGolScheme->TextColor0);
}
}
state = LB_STATE_BITMAP;
case LB_STATE_BITMAP:
if(pCurItem->pBitmap != NULL)
{
if
(
!PutImage
(
GetX(),
GetY() + ((pLb->textHeight - GetImageHeight(pCurItem->pBitmap)) >> 1),
pCurItem->pBitmap,
1
)
) return (0);
MoveRel(GetImageWidth(pCurItem->pBitmap) + LB_INDENT, 0);
}
state = LB_STATE_TEXT;
case LB_STATE_TEXT:
if(!OutText(pCurItem->pText))
return (0);
}
/////////////////////////////////////////////////////////////////////
L_LB_NEXTITEM:
state = LB_STATE_ITEMFOCUS;
case LB_STATE_ITEMFOCUS:
if(pLb->pFocusItem == pCurItem)
{
if(IsDeviceBusy())
return (0);
if(GetState(pLb, LB_FOCUSED))
{
SetColor(pLb->hdr.pGolScheme->TextColor1);
}
else
{
SetColor(pLb->hdr.pGolScheme->TextColor0);
}
SetLineType(FOCUS_LINE);
temp = GetY();
if
(
!Rectangle
(
pLb->hdr.left + GOL_EMBOSS_SIZE + LB_INDENT,
GetY(),
pLb->hdr.right - GOL_EMBOSS_SIZE - LB_INDENT,
GetY() + pLb->textHeight - 1
)
) return (0);
MoveTo(0, temp);
SetLineType(SOLID_LINE);
// Scroll if needed
if(GetY() < (pLb->hdr.top + GOL_EMBOSS_SIZE + LB_INDENT))
{
pLb->scrollY += (pLb->hdr.top + GOL_EMBOSS_SIZE + LB_INDENT) - GetY();
SetState(pLb, LB_DRAW);
goto L_LB_DRAW;
}
if((GetY() + pLb->textHeight) > (pLb->hdr.bottom - GOL_EMBOSS_SIZE - LB_INDENT))
{
pLb->scrollY += pLb->hdr.bottom - GetY() - pLb->textHeight - GOL_EMBOSS_SIZE - LB_INDENT;
SetState(pLb, LB_DRAW);
goto L_LB_DRAW;
}
}
pCurItem = (LISTITEM *)pCurItem->pNextItem;
MoveRel(0, pLb->textHeight);
goto L_LB_DRAWITEM;
} // end of switch
return (1);
}
#endif // USE_LISTBOX
|