722 lines
22 KiB
C
722 lines
22 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 : LISTVIEW.c
|
|
Purpose : Implementation of listview widget
|
|
---------------------------END-OF-HEADER------------------------------
|
|
*/
|
|
|
|
#include "GUI_ARRAY.h"
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "LISTVIEW_Private.h"
|
|
#include "HEADER.h"
|
|
#include "WIDGET.h"
|
|
#include "SCROLLBAR.h"
|
|
#include "GUIDebug.h"
|
|
#include "GUI_Protected.h"
|
|
#include "WM_Intern.h"
|
|
|
|
#if GUI_WINSUPPORT
|
|
|
|
/*********************************************************************
|
|
*
|
|
* Private config defaults
|
|
*
|
|
**********************************************************************
|
|
*/
|
|
|
|
/* Define default fonts */
|
|
#ifndef LISTVIEW_FONT_DEFAULT
|
|
#define LISTVIEW_FONT_DEFAULT &GUI_Font13_1
|
|
#endif
|
|
|
|
/* Define colors */
|
|
#ifndef LISTVIEW_BKCOLOR0_DEFAULT
|
|
#define LISTVIEW_BKCOLOR0_DEFAULT GUI_WHITE /* Not selected */
|
|
#endif
|
|
|
|
#ifndef LISTVIEW_BKCOLOR1_DEFAULT
|
|
#define LISTVIEW_BKCOLOR1_DEFAULT GUI_GRAY /* Selected, no focus */
|
|
#endif
|
|
|
|
#ifndef LISTVIEW_BKCOLOR2_DEFAULT
|
|
#define LISTVIEW_BKCOLOR2_DEFAULT GUI_BLUE /* Selected, focus */
|
|
#endif
|
|
|
|
#ifndef LISTVIEW_TEXTCOLOR0_DEFAULT
|
|
#define LISTVIEW_TEXTCOLOR0_DEFAULT GUI_BLACK /* Not selected */
|
|
#endif
|
|
|
|
#ifndef LISTVIEW_TEXTCOLOR1_DEFAULT
|
|
#define LISTVIEW_TEXTCOLOR1_DEFAULT GUI_WHITE /* Selected, no focus */
|
|
#endif
|
|
|
|
#ifndef LISTVIEW_TEXTCOLOR2_DEFAULT
|
|
#define LISTVIEW_TEXTCOLOR2_DEFAULT GUI_WHITE /* Selected, focus */
|
|
#endif
|
|
|
|
#ifndef LISTVIEW_GRIDCOLOR_DEFAULT
|
|
#define LISTVIEW_GRIDCOLOR_DEFAULT GUI_LIGHTGRAY
|
|
#endif
|
|
|
|
/* Define default alignment */
|
|
#ifndef LISTVIEW_ALIGN_DEFAULT
|
|
#define LISTVIEW_ALIGN_DEFAULT (GUI_TA_VCENTER | GUI_TA_HCENTER)
|
|
#endif
|
|
|
|
/*********************************************************************
|
|
*
|
|
* Static data
|
|
*
|
|
**********************************************************************
|
|
*/
|
|
LISTVIEW_PROPS LISTVIEW_DefaultProps = {
|
|
LISTVIEW_BKCOLOR0_DEFAULT,
|
|
LISTVIEW_BKCOLOR1_DEFAULT,
|
|
LISTVIEW_BKCOLOR2_DEFAULT,
|
|
LISTVIEW_TEXTCOLOR0_DEFAULT,
|
|
LISTVIEW_TEXTCOLOR1_DEFAULT,
|
|
LISTVIEW_TEXTCOLOR2_DEFAULT,
|
|
LISTVIEW_GRIDCOLOR_DEFAULT,
|
|
LISTVIEW_FONT_DEFAULT
|
|
};
|
|
|
|
/*********************************************************************
|
|
*
|
|
* Static routines
|
|
*
|
|
**********************************************************************
|
|
*/
|
|
/*********************************************************************
|
|
*
|
|
* LISTVIEW__GetRowDistY
|
|
*/
|
|
unsigned LISTVIEW__GetRowDistY(const LISTVIEW_Obj* pObj) {
|
|
unsigned RowDistY;
|
|
if (pObj->RowDistY) {
|
|
RowDistY = pObj->RowDistY;
|
|
} else {
|
|
RowDistY = GUI_GetYDistOfFont(pObj->Props.pFont);
|
|
if (pObj->ShowGrid) {
|
|
RowDistY++;
|
|
}
|
|
}
|
|
return RowDistY;
|
|
}
|
|
|
|
/*********************************************************************
|
|
*
|
|
* _GetNumVisibleRows
|
|
*
|
|
* Purpose:
|
|
* Returns the number of visible rows according the header
|
|
* and (if exist) horizontal scrollbar.
|
|
*
|
|
* Return value:
|
|
* Number of visible rows. If no entire row can be displayed, this
|
|
* function will return one.
|
|
*/
|
|
static unsigned _GetNumVisibleRows(LISTVIEW_Handle hObj, const LISTVIEW_Obj* pObj) {
|
|
unsigned RowDistY, ySize, r = 1;
|
|
GUI_RECT Rect;
|
|
WM_GetInsideRectExScrollbar(hObj, &Rect);
|
|
ySize = Rect.y1 - Rect.y0 + 1 - HEADER_GetHeight(pObj->hHeader);
|
|
RowDistY = LISTVIEW__GetRowDistY(pObj);
|
|
if (RowDistY) {
|
|
r = ySize / RowDistY;
|
|
r = (r == 0) ? 1 : r;
|
|
}
|
|
return r;
|
|
}
|
|
|
|
/*********************************************************************
|
|
*
|
|
* _Paint
|
|
*/
|
|
static void _Paint(LISTVIEW_Handle hObj, LISTVIEW_Obj* pObj, WM_MESSAGE* pMsg) {
|
|
const GUI_ARRAY* pRow;
|
|
GUI_RECT ClipRect, Rect;
|
|
int NumRows, NumVisRows, NumColumns;
|
|
int LBorder, RBorder, EffectSize;
|
|
int xPos, yPos, Width, RowDistY;
|
|
int Align, i, j, EndRow;
|
|
/* Init some values */
|
|
NumColumns = HEADER_GetNumItems(pObj->hHeader);
|
|
NumRows = GUI_ARRAY_GetNumItems(&pObj->RowArray);
|
|
NumVisRows = _GetNumVisibleRows(hObj, pObj);
|
|
RowDistY = LISTVIEW__GetRowDistY(pObj);
|
|
LBorder = pObj->LBorder;
|
|
RBorder = pObj->RBorder;
|
|
EffectSize = pObj->Widget.pEffect->EffectSize;
|
|
yPos = HEADER_GetHeight(pObj->hHeader) + EffectSize;
|
|
EndRow = pObj->ScrollStateV.v + (((NumVisRows + 1) > NumRows) ? NumRows : NumVisRows + 1);
|
|
/* Calculate clipping rectangle */
|
|
ClipRect = *(const GUI_RECT*)pMsg->Data.p;
|
|
GUI_MoveRect(&ClipRect, -pObj->Widget.Win.Rect.x0, -pObj->Widget.Win.Rect.y0);
|
|
WM_GetInsideRectExScrollbar(hObj, &Rect);
|
|
GUI__IntersectRect(&ClipRect, &Rect);
|
|
/* Set drawing color, font and text mode */
|
|
LCD_SetColor(pObj->Props.aTextColor[0]);
|
|
GUI_SetFont(pObj->Props.pFont);
|
|
GUI_SetTextMode(GUI_TM_TRANS);
|
|
/* Do the drawing */
|
|
for (i = pObj->ScrollStateV.v; i < EndRow; i++) {
|
|
pRow = (const GUI_ARRAY*)GUI_ARRAY_GetpItem(&pObj->RowArray, i);
|
|
if (pRow) {
|
|
Rect.y0 = yPos;
|
|
/* Break when all other rows are outside the drawing area */
|
|
if (Rect.y0 > ClipRect.y1) {
|
|
break;
|
|
}
|
|
Rect.y1 = yPos + RowDistY - 1;
|
|
/* Make sure that we draw only when row is in drawing area */
|
|
if (Rect.y1 >= ClipRect.y0) {
|
|
int ColorIndex;
|
|
/* Set background color */
|
|
if (i == pObj->Sel) {
|
|
ColorIndex = (pObj->Widget.State & WIDGET_STATE_FOCUS) ? 2 : 1;
|
|
} else {
|
|
ColorIndex = 0;
|
|
}
|
|
LCD_SetBkColor(pObj->Props.aBkColor[ColorIndex]);
|
|
/* Iterate over all columns */
|
|
if (pObj->ShowGrid) {
|
|
Rect.y1--;
|
|
}
|
|
xPos = EffectSize - pObj->ScrollStateH.v;
|
|
for (j = 0; j < NumColumns; j++) {
|
|
Width = HEADER_GetItemWidth(pObj->hHeader, j);
|
|
Rect.x0 = xPos;
|
|
/* Break when all other columns are outside the drawing area */
|
|
if (Rect.x0 > ClipRect.x1) {
|
|
break;
|
|
}
|
|
Rect.x1 = xPos + Width - 1;
|
|
/* Make sure that we draw only when column is in drawing area */
|
|
if (Rect.x1 >= ClipRect.x0) {
|
|
LISTVIEW_ITEM * pItem;
|
|
pItem = (LISTVIEW_ITEM *)GUI_ARRAY_GetpItem(pRow, j);
|
|
if (pItem->hItemInfo) {
|
|
LISTVIEW_ITEM_INFO * pItemInfo;
|
|
pItemInfo = (LISTVIEW_ITEM_INFO *)GUI_ALLOC_h2p(pItem->hItemInfo);
|
|
LCD_SetBkColor(pItemInfo->aBkColor[ColorIndex]);
|
|
LCD_SetColor(pItemInfo->aTextColor[ColorIndex]);
|
|
} else {
|
|
LCD_SetColor(pObj->Props.aTextColor[ColorIndex]);
|
|
}
|
|
/* Clear background */
|
|
GUI_ClearRect(Rect.x0, Rect.y0, Rect.x1, Rect.y1);
|
|
/* Draw text */
|
|
Rect.x0 += LBorder;
|
|
Rect.x1 -= RBorder;
|
|
Align = *((int*)GUI_ARRAY_GetpItem(&pObj->AlignArray, j));
|
|
GUI_DispStringInRect(pItem->acText, &Rect, Align);
|
|
if (pItem->hItemInfo) {
|
|
LCD_SetBkColor(pObj->Props.aBkColor[ColorIndex]);
|
|
}
|
|
}
|
|
xPos += Width;
|
|
}
|
|
/* Clear unused area to the right of items */
|
|
if (xPos <= ClipRect.x1) {
|
|
GUI_ClearRect(xPos, Rect.y0, ClipRect.x1, Rect.y1);
|
|
}
|
|
}
|
|
yPos += RowDistY;
|
|
}
|
|
}
|
|
/* Clear unused area below items */
|
|
if (yPos <= ClipRect.y1) {
|
|
LCD_SetBkColor(pObj->Props.aBkColor[0]);
|
|
GUI_ClearRect(ClipRect.x0, yPos, ClipRect.x1, ClipRect.y1);
|
|
}
|
|
/* Draw grid */
|
|
if (pObj->ShowGrid) {
|
|
LCD_SetColor(pObj->Props.GridColor);
|
|
yPos = HEADER_GetHeight(pObj->hHeader) + EffectSize - 1;
|
|
for (i = 0; i < NumVisRows; i++) {
|
|
yPos += RowDistY;
|
|
/* Break when all other rows are outside the drawing area */
|
|
if (yPos > ClipRect.y1) {
|
|
break;
|
|
}
|
|
/* Make sure that we draw only when row is in drawing area */
|
|
if (yPos >= ClipRect.y0) {
|
|
GUI_DrawHLine(yPos, ClipRect.x0, ClipRect.x1);
|
|
}
|
|
}
|
|
xPos = EffectSize - pObj->ScrollStateH.v;
|
|
for (i = 0; i < NumColumns; i++) {
|
|
xPos += HEADER_GetItemWidth(pObj->hHeader, i);
|
|
/* Break when all other columns are outside the drawing area */
|
|
if (xPos > ClipRect.x1) {
|
|
break;
|
|
}
|
|
/* Make sure that we draw only when column is in drawing area */
|
|
if (xPos >= ClipRect.x0) {
|
|
GUI_DrawVLine(xPos, ClipRect.y0, ClipRect.y1);
|
|
}
|
|
}
|
|
}
|
|
/* Draw the effect */
|
|
WIDGET__EFFECT_DrawDown(&pObj->Widget);
|
|
}
|
|
|
|
/*********************************************************************
|
|
*
|
|
* LISTVIEW__InvalidateInsideArea
|
|
*/
|
|
void LISTVIEW__InvalidateInsideArea(LISTVIEW_Handle hObj, LISTVIEW_Obj* pObj) {
|
|
GUI_RECT Rect;
|
|
int HeaderHeight;
|
|
HeaderHeight = HEADER_GetHeight(pObj->hHeader);
|
|
WM_GetInsideRectExScrollbar(hObj, &Rect);
|
|
Rect.y0 += HeaderHeight;
|
|
WM_InvalidateRect(hObj, &Rect);
|
|
}
|
|
|
|
/*********************************************************************
|
|
*
|
|
* LISTVIEW__InvalidateRow
|
|
*/
|
|
void LISTVIEW__InvalidateRow(LISTVIEW_Handle hObj, LISTVIEW_Obj* pObj, int Sel) {
|
|
if (Sel >= 0) {
|
|
GUI_RECT Rect;
|
|
int HeaderHeight, RowDistY;
|
|
HeaderHeight = HEADER_GetHeight(pObj->hHeader);
|
|
RowDistY = LISTVIEW__GetRowDistY(pObj);
|
|
WM_GetInsideRectExScrollbar(hObj, &Rect);
|
|
Rect.y0 += HeaderHeight + (Sel - pObj->ScrollStateV.v) * RowDistY;
|
|
Rect.y1 = Rect.y0 + RowDistY - 1;
|
|
WM_InvalidateRect(hObj, &Rect);
|
|
}
|
|
}
|
|
|
|
/*********************************************************************
|
|
*
|
|
* _SetSelFromPos
|
|
*/
|
|
static void _SetSelFromPos(LISTVIEW_Handle hObj, LISTVIEW_Obj* pObj, const GUI_PID_STATE* pState) {
|
|
GUI_RECT Rect;
|
|
int x, y, HeaderHeight;
|
|
HeaderHeight = HEADER_GetHeight(pObj->hHeader);
|
|
WM_GetInsideRectExScrollbar(hObj, &Rect);
|
|
x = pState->x - Rect.x0;
|
|
y = pState->y - Rect.y0 - HeaderHeight;
|
|
Rect.x1 -= Rect.x0;
|
|
Rect.y1 -= Rect.y0;
|
|
if ((x >= 0) && (x <= Rect.x1) && (y >= 0) && (y <= (Rect.y1 - HeaderHeight))) {
|
|
unsigned Sel;
|
|
Sel = (y / LISTVIEW__GetRowDistY(pObj)) + pObj->ScrollStateV.v;
|
|
if (Sel < GUI_ARRAY_GetNumItems(&pObj->RowArray)) {
|
|
LISTVIEW_SetSel(hObj, Sel);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*********************************************************************
|
|
*
|
|
* _NotifyOwner
|
|
*
|
|
* Purpose:
|
|
* Notify owner of the window.
|
|
* If no owner is registered, the parent is considered owner.
|
|
*/
|
|
static void _NotifyOwner(WM_HWIN hObj, int Notification) {
|
|
WM_MESSAGE Msg = {0};
|
|
WM_HWIN hOwner;
|
|
LISTVIEW_Obj* pObj = LISTVIEW_H2P(hObj);
|
|
hOwner = pObj->hOwner ? pObj->hOwner : WM_GetParent(hObj);
|
|
Msg.MsgId = WM_NOTIFY_PARENT;
|
|
Msg.Data.v = Notification;
|
|
Msg.hWin = hObj;
|
|
WM_SendMessage(hOwner, &Msg);
|
|
}
|
|
|
|
/*********************************************************************
|
|
*
|
|
* _OnTouch
|
|
*/
|
|
static void _OnTouch(LISTVIEW_Handle hObj, LISTVIEW_Obj* pObj, WM_MESSAGE*pMsg) {
|
|
int Notification;
|
|
const GUI_PID_STATE* pState = (const GUI_PID_STATE*)pMsg->Data.p;
|
|
GUI_USE_PARA(pObj);
|
|
if (pMsg->Data.p) { /* Something happened in our area (pressed or released) */
|
|
if (pState->Pressed) {
|
|
_SetSelFromPos(hObj, pObj, pState);
|
|
Notification = WM_NOTIFICATION_CLICKED;
|
|
WM_SetFocus(hObj);
|
|
} else {
|
|
Notification = WM_NOTIFICATION_RELEASED;
|
|
}
|
|
} else {
|
|
Notification = WM_NOTIFICATION_MOVED_OUT;
|
|
}
|
|
_NotifyOwner(hObj, Notification);
|
|
}
|
|
|
|
/*********************************************************************
|
|
*
|
|
* _GetXSize
|
|
*
|
|
* Purpose:
|
|
* Returns the width of the inside listview area.
|
|
*/
|
|
static int _GetXSize(LISTVIEW_Handle hObj) {
|
|
GUI_RECT Rect;
|
|
WM_GetInsideRectExScrollbar(hObj, &Rect);
|
|
return Rect.x1 + 1;
|
|
}
|
|
|
|
/*********************************************************************
|
|
*
|
|
* _GetHeaderWidth
|
|
*
|
|
* Purpose:
|
|
* Returns the width of all items in header.
|
|
*
|
|
* Return value:
|
|
* NumItems > 0: width of all items.
|
|
* NumItems = 0: 1 (to avoid problem with horizontal scrollbar)
|
|
*/
|
|
static int _GetHeaderWidth(LISTVIEW_Obj* pObj, HEADER_Handle hHeader) {
|
|
int NumItems, i, r = 1;
|
|
NumItems = HEADER_GetNumItems(hHeader);
|
|
if (NumItems) {
|
|
for (i = 0, r = 0; i < NumItems; i++) {
|
|
r += HEADER_GetItemWidth(hHeader, i);
|
|
}
|
|
}
|
|
if (pObj->ScrollStateH.v > (r - pObj->ScrollStateH.PageSize)) {
|
|
r += pObj->ScrollStateH.PageSize - (r - pObj->ScrollStateH.v);
|
|
}
|
|
return r;
|
|
}
|
|
|
|
/*********************************************************************
|
|
*
|
|
* LISTVIEW__UpdateScrollPos
|
|
*
|
|
* Purpose:
|
|
* Checks whether if we must scroll up or scroll down to ensure
|
|
* that selection is in the visible area. This function also
|
|
* makes sure that scroll positions are in valid ranges.
|
|
*
|
|
* Return value:
|
|
* Difference between old and new vertical scroll pos.
|
|
*/
|
|
int LISTVIEW__UpdateScrollPos(LISTVIEW_Handle hObj, LISTVIEW_Obj* pObj) {
|
|
int PrevScrollStateV;
|
|
PrevScrollStateV = pObj->ScrollStateV.v;
|
|
if (pObj->Sel >= 0) {
|
|
WM_CheckScrollPos(&pObj->ScrollStateV, pObj->Sel, 0, 0);
|
|
} else {
|
|
WM_CheckScrollBounds(&pObj->ScrollStateV);
|
|
}
|
|
WM_CheckScrollBounds(&pObj->ScrollStateH);
|
|
WIDGET__SetScrollState(hObj, &pObj->ScrollStateV, &pObj->ScrollStateH);
|
|
return pObj->ScrollStateV.v - PrevScrollStateV;
|
|
}
|
|
|
|
/*********************************************************************
|
|
*
|
|
* LISTVIEW__UpdateScrollParas
|
|
*
|
|
* Purpose:
|
|
* Calculates number of items and page size of both vertical
|
|
* and horizontal scrollbar. After this LISTVIEW__UpdateScrollPos will
|
|
* be called to ensure scroll positions are in valid ranges.
|
|
*/
|
|
int LISTVIEW__UpdateScrollParas(LISTVIEW_Handle hObj, LISTVIEW_Obj* pObj) {
|
|
int NumRows;
|
|
NumRows = GUI_ARRAY_GetNumItems(&pObj->RowArray);
|
|
/* update vertical scrollbar */
|
|
pObj->ScrollStateV.PageSize = _GetNumVisibleRows(hObj, pObj);
|
|
pObj->ScrollStateV.NumItems = (NumRows) ? NumRows : 1;
|
|
/* update horizontal scrollbar */
|
|
pObj->ScrollStateH.PageSize = _GetXSize(hObj);
|
|
pObj->ScrollStateH.NumItems = _GetHeaderWidth(pObj, pObj->hHeader);
|
|
return LISTVIEW__UpdateScrollPos(hObj, pObj);
|
|
}
|
|
|
|
/*********************************************************************
|
|
*
|
|
* _FreeAttached
|
|
*
|
|
* Purpose:
|
|
* Delete attached objects (if any).
|
|
*/
|
|
static void _FreeAttached(LISTVIEW_Obj * pObj) {
|
|
int i, j, NumRows, NumColumns;
|
|
NumRows = GUI_ARRAY_GetNumItems(&pObj->RowArray);
|
|
NumColumns = GUI_ARRAY_GetNumItems(&pObj->AlignArray);
|
|
for (i = 0; i < NumRows; i++) {
|
|
GUI_ARRAY * pRow;
|
|
pRow = (GUI_ARRAY *)GUI_ARRAY_GetpItem(&pObj->RowArray, i);
|
|
/* Delete attached info items */
|
|
for (j = 0; j < NumColumns; j++) {
|
|
LISTVIEW_ITEM * pItem;
|
|
pItem = (LISTVIEW_ITEM *)GUI_ARRAY_GetpItem(pRow, j);
|
|
if (pItem->hItemInfo) {
|
|
GUI_ALLOC_Free(pItem->hItemInfo);
|
|
}
|
|
}
|
|
/* Delete row */
|
|
GUI_ARRAY_Delete(pRow);
|
|
}
|
|
GUI_ARRAY_Delete(&pObj->AlignArray);
|
|
GUI_ARRAY_Delete(&pObj->RowArray);
|
|
}
|
|
|
|
/*********************************************************************
|
|
*
|
|
* _AddKey
|
|
*
|
|
* Returns: 1 if Key has been consumed
|
|
* 0 else
|
|
*/
|
|
static int _AddKey(LISTVIEW_Handle hObj, int Key) {
|
|
switch (Key) {
|
|
case GUI_KEY_DOWN:
|
|
LISTVIEW_IncSel(hObj);
|
|
return 1; /* Key has been consumed */
|
|
case GUI_KEY_UP:
|
|
LISTVIEW_DecSel(hObj);
|
|
return 1; /* Key has been consumed */
|
|
}
|
|
return 0; /* Key has NOT been consumed */
|
|
}
|
|
|
|
/*********************************************************************
|
|
*
|
|
* _LISTVIEW_Callback
|
|
*/
|
|
static void _LISTVIEW_Callback (WM_MESSAGE *pMsg) {
|
|
LISTVIEW_Handle hObj;
|
|
LISTVIEW_Obj* pObj;
|
|
WM_SCROLL_STATE ScrollState;
|
|
hObj = pMsg->hWin;
|
|
/* Let widget handle the standard messages */
|
|
if (WIDGET_HandleActive(hObj, pMsg) == 0) {
|
|
return;
|
|
}
|
|
pObj = LISTVIEW_H2P(hObj);
|
|
switch (pMsg->MsgId) {
|
|
case WM_NOTIFY_CLIENTCHANGE:
|
|
case WM_SIZE:
|
|
LISTVIEW__UpdateScrollParas(hObj, pObj);
|
|
return;
|
|
case WM_NOTIFY_PARENT:
|
|
switch (pMsg->Data.v) {
|
|
case WM_NOTIFICATION_CHILD_DELETED:
|
|
/* make sure we do not send any messages to the header child once it has been deleted */
|
|
if (pMsg->hWinSrc == pObj->hHeader) {
|
|
pObj->hHeader = 0;
|
|
}
|
|
break;
|
|
case WM_NOTIFICATION_VALUE_CHANGED:
|
|
if (pMsg->hWinSrc == WM_GetScrollbarV(hObj)) {
|
|
WM_GetScrollState(pMsg->hWinSrc, &ScrollState);
|
|
pObj->ScrollStateV.v = ScrollState.v;
|
|
LISTVIEW__InvalidateInsideArea(hObj, pObj);
|
|
_NotifyOwner(hObj, WM_NOTIFICATION_SCROLL_CHANGED);
|
|
} else if (pMsg->hWinSrc == WM_GetScrollbarH(hObj)) {
|
|
WM_GetScrollState(pMsg->hWinSrc, &ScrollState);
|
|
pObj->ScrollStateH.v = ScrollState.v;
|
|
LISTVIEW__UpdateScrollParas(hObj, pObj);
|
|
HEADER_SetScrollPos(pObj->hHeader, pObj->ScrollStateH.v);
|
|
_NotifyOwner(hObj, WM_NOTIFICATION_SCROLL_CHANGED);
|
|
}
|
|
break;
|
|
case WM_NOTIFICATION_SCROLLBAR_ADDED:
|
|
LISTVIEW__UpdateScrollParas(hObj, pObj);
|
|
break;
|
|
}
|
|
return;
|
|
case WM_PAINT:
|
|
_Paint(hObj, pObj, pMsg);
|
|
return;
|
|
case WM_TOUCH:
|
|
_OnTouch(hObj, pObj, pMsg);
|
|
return; /* Important: message handled ! */
|
|
case WM_KEY:
|
|
if (((const WM_KEY_INFO*)(pMsg->Data.p))->PressedCnt > 0) {
|
|
int Key;
|
|
Key = ((const WM_KEY_INFO*)(pMsg->Data.p))->Key;
|
|
if (_AddKey(hObj, Key)) {
|
|
return;
|
|
}
|
|
}
|
|
break; /* No return here ... WM_DefaultProc needs to be called */
|
|
case WM_DELETE:
|
|
_FreeAttached(pObj);
|
|
break; /* No return here ... WM_DefaultProc needs to be called */
|
|
}
|
|
WM_DefaultProc(pMsg);
|
|
}
|
|
|
|
/*********************************************************************
|
|
*
|
|
* Exported routines: Create
|
|
*
|
|
**********************************************************************
|
|
*/
|
|
|
|
/* Note: the parameters to a create function may vary.
|
|
Some widgets may have multiple create functions */
|
|
|
|
/*********************************************************************
|
|
*
|
|
* LISTVIEW_CreateEx
|
|
*/
|
|
LISTVIEW_Handle LISTVIEW_CreateEx(int x0, int y0, int xsize, int ysize, WM_HWIN hParent,
|
|
int WinFlags, int ExFlags, int Id)
|
|
{
|
|
LISTVIEW_Handle hObj;
|
|
GUI_USE_PARA(ExFlags);
|
|
/* Create the window */
|
|
if ((xsize == 0) && (ysize == 0) && (x0 == 0) && (y0 == 0)) {
|
|
GUI_RECT Rect;
|
|
WM_GetClientRectEx(hParent, &Rect);
|
|
xsize = Rect.x1 - Rect.x0 + 1;
|
|
ysize = Rect.y1 - Rect.y0 + 1;
|
|
}
|
|
hObj = WM_CreateWindowAsChild(x0, y0, xsize, ysize, hParent, WinFlags, &_LISTVIEW_Callback,
|
|
sizeof(LISTVIEW_Obj) - sizeof(WM_Obj));
|
|
if (hObj) {
|
|
LISTVIEW_Obj* pObj;
|
|
WM_LOCK();
|
|
pObj = LISTVIEW_H2P(hObj);
|
|
/* Init sub-classes */
|
|
GUI_ARRAY_CREATE(&pObj->RowArray);
|
|
GUI_ARRAY_CREATE(&pObj->AlignArray);
|
|
/* Init widget specific variables */
|
|
WIDGET__Init(&pObj->Widget, Id, WIDGET_STATE_FOCUSSABLE);
|
|
/* Init member variables */
|
|
LISTVIEW_INIT_ID(pObj);
|
|
pObj->Props = LISTVIEW_DefaultProps;
|
|
pObj->ShowGrid = 0;
|
|
pObj->RowDistY = 0;
|
|
pObj->Sel = -1;
|
|
pObj->LBorder = 1;
|
|
pObj->RBorder = 1;
|
|
pObj->hHeader = HEADER_CreateEx(0, 0, 0, 0, hObj, WM_CF_SHOW, 0, 0);
|
|
LISTVIEW__UpdateScrollParas(hObj, pObj);
|
|
WM_UNLOCK();
|
|
} else {
|
|
GUI_DEBUG_ERROROUT_IF(hObj==0, "LISTVIEW_Create failed")
|
|
}
|
|
return hObj;
|
|
}
|
|
|
|
/*********************************************************************
|
|
*
|
|
* Exported routines: Member functions
|
|
*
|
|
**********************************************************************
|
|
*/
|
|
/*********************************************************************
|
|
*
|
|
* LISTVIEW_IncSel
|
|
*/
|
|
void LISTVIEW_IncSel(LISTVIEW_Handle hObj) {
|
|
int Sel = LISTVIEW_GetSel(hObj);
|
|
LISTVIEW_SetSel(hObj, Sel + 1);
|
|
}
|
|
|
|
/*********************************************************************
|
|
*
|
|
* LISTVIEW_DecSel
|
|
*/
|
|
void LISTVIEW_DecSel(LISTVIEW_Handle hObj) {
|
|
int Sel = LISTVIEW_GetSel(hObj);
|
|
if (Sel) {
|
|
LISTVIEW_SetSel(hObj, Sel - 1);
|
|
}
|
|
}
|
|
|
|
/*********************************************************************
|
|
*
|
|
* LISTVIEW_AddColumn
|
|
*/
|
|
void LISTVIEW_AddColumn(LISTVIEW_Handle hObj, int Width, const char * s, int Align) {
|
|
if (hObj) {
|
|
LISTVIEW_Obj* pObj;
|
|
unsigned NumRows;
|
|
WM_LOCK();
|
|
pObj = LISTVIEW_H2P(hObj);
|
|
HEADER_AddItem(pObj->hHeader, Width, s, Align); /* Modify header */
|
|
GUI_ARRAY_AddItem(&pObj->AlignArray, &Align, sizeof(int));
|
|
NumRows = LISTVIEW_GetNumRows(hObj);
|
|
if (NumRows) {
|
|
GUI_ARRAY* pRow;
|
|
unsigned i;
|
|
for (i = 0; i < NumRows; i++) {
|
|
pRow = (GUI_ARRAY*) GUI_ARRAY_GetpItem(&pObj->RowArray, i);
|
|
GUI_ARRAY_AddItem(pRow, NULL, sizeof(LISTVIEW_ITEM) + 1);
|
|
}
|
|
}
|
|
LISTVIEW__UpdateScrollParas(hObj, pObj);
|
|
LISTVIEW__InvalidateInsideArea(hObj, pObj);
|
|
WM_UNLOCK();
|
|
}
|
|
}
|
|
|
|
/*********************************************************************
|
|
*
|
|
* LISTVIEW_AddRow
|
|
*/
|
|
void LISTVIEW_AddRow(LISTVIEW_Handle hObj, const GUI_ConstString* ppText) {
|
|
if (hObj) {
|
|
LISTVIEW_Obj* pObj;
|
|
int NumRows;
|
|
WM_LOCK();
|
|
pObj = LISTVIEW_H2P(hObj);
|
|
NumRows = GUI_ARRAY_GetNumItems(&pObj->RowArray);
|
|
|
|
/* Create GUI_ARRAY for the new row */
|
|
if (GUI_ARRAY_AddItem(&pObj->RowArray, NULL, sizeof(GUI_ARRAY)) == 0) {
|
|
int i, NumColumns, NumBytes;
|
|
GUI_ARRAY* pRow;
|
|
const char* s;
|
|
GUI_ARRAY_CREATE((GUI_ARRAY *)GUI_ARRAY_GetpItem(&pObj->RowArray, NumRows)); /* For higher debug levels only */
|
|
/* Add columns for the new row */
|
|
NumColumns = HEADER_GetNumItems(pObj->hHeader);
|
|
for (i = 0; i < NumColumns; i++) {
|
|
LISTVIEW_ITEM * pItem;
|
|
pRow = (GUI_ARRAY *)GUI_ARRAY_GetpItem(&pObj->RowArray, NumRows);
|
|
s = (ppText) ? *ppText++ : 0;
|
|
if (s == 0) {
|
|
ppText = 0;
|
|
}
|
|
NumBytes = GUI__strlen(s) + 1; /* 0 if no string is specified (s == NULL) */
|
|
GUI_ARRAY_AddItem(pRow, NULL, sizeof(LISTVIEW_ITEM) + NumBytes);
|
|
pItem = (LISTVIEW_ITEM *)GUI_ARRAY_GetpItem(pRow, i);
|
|
if (NumBytes > 1) {
|
|
strcpy(pItem->acText, s);
|
|
}
|
|
}
|
|
LISTVIEW__UpdateScrollParas(hObj, pObj);
|
|
LISTVIEW__InvalidateRow(hObj, pObj, NumRows);
|
|
}
|
|
WM_UNLOCK();
|
|
}
|
|
}
|
|
|
|
#else
|
|
void LISTVIEW_C(void);
|
|
void LISTVIEW_C(void) {}
|
|
#endif /* #if GUI_WINSUPPORT */
|