mirror of
https://github.com/VincentWei/MiniGUI.git
synced 2026-09-28 16:17:09 +08:00
2283 lines
66 KiB
C
2283 lines
66 KiB
C
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// IMPORTANT NOTICE
|
|
//
|
|
// The following open source license statement does not apply to any
|
|
// entity in the Exception List published by FMSoft.
|
|
//
|
|
// For more information, please visit:
|
|
//
|
|
// https://www.fmsoft.cn/exception-list
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
/*
|
|
* This file is part of MiniGUI, a mature cross-platform windowing
|
|
* and Graphics User Interface (GUI) support system for embedded systems
|
|
* and smart IoT devices.
|
|
*
|
|
* Copyright (C) 2002~2018, Beijing FMSoft Technologies Co., Ltd.
|
|
* Copyright (C) 1998~2002, WEI Yongming
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
* Or,
|
|
*
|
|
* As this program is a library, any link to this program must follow
|
|
* GNU General Public License version 3 (GPLv3). If you cannot accept
|
|
* GPLv3, you need to be licensed from FMSoft.
|
|
*
|
|
* If you have got a commercial license of this program, please use it
|
|
* under the terms and conditions of the commercial license.
|
|
*
|
|
* For more information about the commercial license, please refer to
|
|
* <http://www.minigui.com/en/about/licensing-policy/>.
|
|
*/
|
|
/*
|
|
** listbox.c: the List Box Control module.
|
|
**
|
|
** Created by Jiao Libo at 1999/8/31
|
|
**
|
|
** TODO:
|
|
** * Multiple columns support.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "common.h"
|
|
|
|
#ifdef _MGCTRL_LISTBOX
|
|
#include "minigui.h"
|
|
#include "gdi.h"
|
|
#include "window.h"
|
|
#include "ctrl/ctrlhelper.h"
|
|
#include "ctrl/listbox.h"
|
|
#include "ctrl/scrollview.h"
|
|
#include "cliprect.h"
|
|
#include "internals.h"
|
|
#include "ctrlclass.h"
|
|
|
|
#include "ctrlmisc.h"
|
|
#include "listbox_impl.h"
|
|
|
|
#define _USE_FIXSTR 1
|
|
|
|
#define ITEM_BOTTOM(x) (x->itemTop + x->itemVisibles - 1)
|
|
|
|
#define LST_INTER_BMPTEXT 2
|
|
|
|
/** minimum height of checkmark */
|
|
#define LFRDR_LB_CHECKBMP_MIN 6
|
|
|
|
static LRESULT ListboxCtrlProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
|
|
|
|
BOOL RegisterListboxControl (void)
|
|
{
|
|
WNDCLASS WndClass;
|
|
WndClass.spClassName = CTRL_LISTBOX;
|
|
WndClass.dwStyle = WS_NONE;
|
|
WndClass.dwExStyle = WS_EX_NONE;
|
|
WndClass.hCursor = GetSystemCursor (0);
|
|
WndClass.iBkColor = GetWindowElementPixel (HWND_NULL, WE_BGC_WINDOW);
|
|
WndClass.WinProc = ListboxCtrlProc;
|
|
return AddNewControlClass (&WndClass) == ERR_OK;
|
|
}
|
|
|
|
/*
|
|
* Get height of listbox checkmark bmp
|
|
*
|
|
* Author : NuohuaZhou
|
|
* Date : 2007-11-29
|
|
*/
|
|
static int CheckMarkHeight (int item_height)
|
|
{
|
|
int checkmark_height =
|
|
item_height - LFRDR_LB_CHECKBMP_MIN;
|
|
|
|
if (0 < checkmark_height)
|
|
checkmark_height += checkmark_height >> 2;
|
|
|
|
return checkmark_height;
|
|
}
|
|
|
|
static BOOL lstInitListBoxData (HWND hwnd, PCONTROL pCtrl, LISTBOXDATA* pData, int len)
|
|
{
|
|
int i;
|
|
PLISTBOXITEM plbi;
|
|
|
|
pData->itemHeight = pCtrl->pLogFont->size;
|
|
pData->itemHilighted = -1;
|
|
pData->selItem = pData->itemHilighted;
|
|
pData->itemCount = 0;
|
|
|
|
pData->str_cmp = strncmp;
|
|
|
|
/* init item buffer. */
|
|
if (!(pData->buffStart = malloc (len * sizeof (LISTBOXITEM))))
|
|
return FALSE;
|
|
|
|
pData->buffLen = len;
|
|
pData->buffEnd = pData->buffStart + len;
|
|
pData->freeList = pData->buffStart;
|
|
|
|
plbi = pData->freeList;
|
|
for (i = 0; i < len - 1; i++) {
|
|
plbi->next = plbi + 1;
|
|
plbi ++;
|
|
}
|
|
plbi->next = NULL;
|
|
|
|
if (GetWindowStyle (hwnd) & LBS_SBALWAYS)
|
|
pData->sbPolicy = SB_POLICY_ALWAYS;
|
|
else
|
|
pData->sbPolicy = SB_POLICY_AUTOMATIC;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void lstListBoxCleanUp (LISTBOXDATA* pData)
|
|
{
|
|
PLISTBOXITEM plbi;
|
|
PLISTBOXITEM next;
|
|
|
|
plbi = pData->head;
|
|
while (plbi) {
|
|
#if _USE_FIXSTR
|
|
FreeFixStr (plbi->key);
|
|
#else
|
|
free (plbi->key);
|
|
#endif
|
|
next = plbi->next;
|
|
if (plbi < pData->buffStart || plbi > pData->buffEnd)
|
|
free (plbi);
|
|
|
|
plbi = next;
|
|
}
|
|
|
|
free (pData->buffStart);
|
|
}
|
|
|
|
static void lstResetListBoxContent (PLISTBOXDATA pData)
|
|
{
|
|
int i;
|
|
PLISTBOXITEM plbi, next;
|
|
|
|
pData->itemLeft = 0;
|
|
pData->itemWidth = 0;
|
|
pData->itemMaxWidth = 0;
|
|
|
|
pData->itemCount = 0;
|
|
pData->itemTop = 0;
|
|
pData->itemHilighted = -1;
|
|
pData->selItem = pData->itemHilighted;
|
|
|
|
plbi = pData->head;
|
|
while (plbi) {
|
|
#if _USE_FIXSTR
|
|
FreeFixStr (plbi->key);
|
|
#else
|
|
free (plbi->key);
|
|
#endif
|
|
next = plbi->next;
|
|
if (plbi < pData->buffStart || plbi > pData->buffEnd)
|
|
free (plbi);
|
|
|
|
plbi = next;
|
|
}
|
|
|
|
pData->head = NULL;
|
|
pData->freeList = pData->buffStart;
|
|
|
|
plbi = pData->freeList;
|
|
for (i = 0; i < pData->buffLen - 1; i++) {
|
|
plbi->next = plbi + 1;
|
|
plbi ++;
|
|
}
|
|
plbi->next = NULL;
|
|
|
|
return;
|
|
}
|
|
|
|
static PLISTBOXITEM lstAllocItem (PLISTBOXDATA pData)
|
|
{
|
|
PLISTBOXITEM plbi;
|
|
|
|
if (pData->freeList) {
|
|
plbi = pData->freeList;
|
|
pData->freeList = plbi->next;
|
|
}
|
|
else
|
|
plbi = (PLISTBOXITEM) malloc (sizeof (LISTBOXITEM));
|
|
|
|
return plbi;
|
|
}
|
|
|
|
static void lstFreeItem (PLISTBOXDATA pData, PLISTBOXITEM plbi)
|
|
{
|
|
if (plbi < pData->buffStart || plbi > pData->buffEnd)
|
|
free (plbi);
|
|
else {
|
|
plbi->next = pData->freeList;
|
|
pData->freeList = plbi;
|
|
}
|
|
}
|
|
|
|
static int lstGetItemWidth (HWND hwnd, PLISTBOXITEM plbi, int item_height)
|
|
{
|
|
PCONTROL pCtrl;
|
|
DWORD dwStyle;
|
|
|
|
int x = 0;
|
|
|
|
pCtrl = gui_Control (hwnd);
|
|
dwStyle = pCtrl->dwStyle;
|
|
|
|
x = LST_INTER_BMPTEXT;
|
|
|
|
if (dwStyle & LBS_CHECKBOX)
|
|
x += CheckMarkHeight (item_height) + LST_INTER_BMPTEXT;
|
|
|
|
if (dwStyle & LBS_USEICON && plbi->dwImage) {
|
|
if (plbi->dwFlags &LBIF_USEBITMAP)
|
|
x += ((PBITMAP)(plbi->dwImage))->bmWidth;
|
|
else {
|
|
int width;
|
|
GetIconSize ((HICON) plbi->dwImage, &width, NULL);
|
|
x += width;
|
|
}
|
|
x += LST_INTER_BMPTEXT;
|
|
}
|
|
|
|
if (plbi->key && plbi->key[0] != '\0') {
|
|
SIZE size;
|
|
HDC hdc;
|
|
hdc = GetClientDC (hwnd);
|
|
GetTabbedTextExtent (hdc, plbi->key, -1, &size);
|
|
ReleaseDC (hdc);
|
|
x += size.cx + LST_INTER_BMPTEXT;
|
|
}
|
|
|
|
return x;
|
|
}
|
|
|
|
static int lstGetMaxWidth(HWND hwnd, PLISTBOXDATA pData)
|
|
{
|
|
PLISTBOXITEM plbi;
|
|
int max = 0;
|
|
int width;
|
|
|
|
plbi = pData->head;
|
|
|
|
while (plbi) {
|
|
width = lstGetItemWidth (hwnd, plbi, pData->itemHeight);
|
|
max = MAX(max, width);
|
|
plbi = plbi->next;
|
|
}
|
|
|
|
return max;
|
|
}
|
|
|
|
static int lstAddNewItem (DWORD dwStyle,
|
|
PLISTBOXDATA pData, PLISTBOXITEM newItem, int pos)
|
|
{
|
|
PLISTBOXITEM plbi;
|
|
PLISTBOXITEM insPosItem = NULL;
|
|
int insPos = 0;
|
|
|
|
newItem->next = NULL;
|
|
if (!pData->head)
|
|
insPosItem = NULL;
|
|
else if (dwStyle & LBS_SORT) {
|
|
plbi = pData->head;
|
|
|
|
if (pData->str_cmp (newItem->key, plbi->key, (size_t)-1) < 0) {
|
|
insPosItem = NULL;
|
|
insPos = 0;
|
|
}
|
|
else {
|
|
while (plbi->next) {
|
|
if (pData->str_cmp (newItem->key, plbi->next->key, (size_t)-1) <= 0)
|
|
break;
|
|
|
|
plbi = plbi->next;
|
|
insPos ++;
|
|
}
|
|
insPosItem = plbi;
|
|
}
|
|
}
|
|
else {
|
|
plbi = pData->head;
|
|
|
|
if (pos < 0) {
|
|
while (plbi->next) {
|
|
plbi = plbi->next;
|
|
insPos ++;
|
|
}
|
|
insPosItem = plbi;
|
|
}
|
|
else if (pos == 0) {
|
|
insPosItem = NULL;
|
|
insPos = 0;
|
|
}
|
|
else {
|
|
int index = 1;
|
|
|
|
while (plbi) {
|
|
if (pos == index)
|
|
break;
|
|
plbi = plbi->next;
|
|
index ++;
|
|
insPos ++;
|
|
}
|
|
insPosItem = plbi;
|
|
}
|
|
}
|
|
|
|
if (insPosItem) {
|
|
plbi = insPosItem->next;
|
|
insPosItem->next = newItem;
|
|
newItem->next = plbi;
|
|
|
|
insPos ++;
|
|
}
|
|
else {
|
|
plbi = pData->head;
|
|
pData->head = newItem;
|
|
newItem->next = plbi;
|
|
}
|
|
|
|
pData->itemCount ++;
|
|
|
|
return insPos;
|
|
}
|
|
|
|
static PLISTBOXITEM lstRemoveItem (PLISTBOXDATA pData, int* pos)
|
|
{
|
|
int index = 0;
|
|
PLISTBOXITEM plbi, prev;
|
|
|
|
if (!pData->head)
|
|
return NULL;
|
|
|
|
if (*pos < 0 || *pos >= pData->itemCount)
|
|
return NULL;
|
|
|
|
/*
|
|
if (*pos < 0) {
|
|
prev = pData->head;
|
|
plbi = pData->head;
|
|
while (plbi->next) {
|
|
prev = plbi;
|
|
plbi = plbi->next;
|
|
index ++;
|
|
}
|
|
|
|
if (plbi == pData->head) {
|
|
pData->head = pData->head->next;
|
|
*pos = 0;
|
|
return plbi;
|
|
}
|
|
else {
|
|
prev->next = plbi->next;
|
|
*pos = index;
|
|
return plbi;
|
|
}
|
|
}
|
|
else
|
|
*/
|
|
if (*pos == 0) {
|
|
plbi = pData->head;
|
|
pData->head = plbi->next;
|
|
return plbi;
|
|
}
|
|
else {
|
|
index = 0;
|
|
prev = pData->head;
|
|
plbi = pData->head;
|
|
while (plbi->next) {
|
|
if (*pos == index)
|
|
break;
|
|
|
|
prev = plbi;
|
|
plbi = plbi->next;
|
|
index ++;
|
|
}
|
|
|
|
if (plbi == pData->head) {
|
|
pData->head = pData->head->next;
|
|
*pos = 0;
|
|
return plbi;
|
|
}
|
|
else {
|
|
prev->next = plbi->next;
|
|
*pos = index;
|
|
return plbi;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static void lstGetItemsRect (PLISTBOXDATA pData,
|
|
int start, int end, RECT* prc)
|
|
{
|
|
if (start < 0)
|
|
start = 0;
|
|
|
|
prc->top = (start - pData->itemTop)*pData->itemHeight;
|
|
|
|
if (end >= 0)
|
|
prc->bottom = (end - pData->itemTop + 1)*pData->itemHeight;
|
|
|
|
}
|
|
|
|
static void lstInvalidateItem (HWND hwnd, PLISTBOXDATA pData, int pos)
|
|
{
|
|
RECT rcInv;
|
|
|
|
if (pos < pData->itemTop || pos > (pData->itemTop + pData->itemVisibles))
|
|
return;
|
|
|
|
GetClientRect (hwnd, &rcInv);
|
|
rcInv.top = (pos - pData->itemTop)*pData->itemHeight;
|
|
rcInv.bottom = rcInv.top + pData->itemHeight;
|
|
|
|
InvalidateRect (hwnd, &rcInv, TRUE);
|
|
}
|
|
|
|
static BOOL
|
|
lstInvalidateUnderMultiItem (HWND hwnd,
|
|
PLISTBOXDATA pData, int start, int end)
|
|
{
|
|
RECT rcInv;
|
|
int pos;
|
|
int max;
|
|
|
|
if (start < 0) start = 0;
|
|
if (end < 0) end = 0;
|
|
|
|
pos = start > end ? end : start;
|
|
max = start > end ? start : end;
|
|
|
|
if (pos > (pData->itemTop + pData->itemVisibles))
|
|
return FALSE;
|
|
|
|
if (max < pData->itemTop)
|
|
return FALSE;
|
|
|
|
GetClientRect (hwnd, &rcInv);
|
|
lstGetItemsRect (pData, pos, max, &rcInv);
|
|
|
|
if (rcInv.top < rcInv.bottom) {
|
|
InvalidateRect (hwnd, &rcInv, TRUE);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static BOOL
|
|
lstInvalidateUnderItem (HWND hwnd, PLISTBOXDATA pData, int pos)
|
|
{
|
|
RECT rcInv;
|
|
|
|
if (pos > (pData->itemTop + pData->itemVisibles))
|
|
return FALSE;
|
|
|
|
if (pos < pData->itemTop)
|
|
return FALSE;
|
|
|
|
GetClientRect (hwnd, &rcInv);
|
|
|
|
lstGetItemsRect (pData, pos, -1, &rcInv);
|
|
|
|
if (rcInv.top < rcInv.bottom)
|
|
InvalidateRect (hwnd, &rcInv, TRUE);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static PLISTBOXITEM lstGetItem (PLISTBOXDATA pData, int pos)
|
|
{
|
|
int i;
|
|
PLISTBOXITEM plbi;
|
|
|
|
plbi = pData->head;
|
|
for (i=0; i < pos && plbi; i++)
|
|
plbi = plbi->next;
|
|
|
|
return plbi;
|
|
}
|
|
|
|
static int lstFindItem (PLISTBOXDATA pData, int start, char* key, BOOL bExact)
|
|
{
|
|
PLISTBOXITEM plbi;
|
|
int keylen = strlen (key);
|
|
|
|
if (start >= pData->itemCount)
|
|
start = 0;
|
|
else if (start < 0)
|
|
start = 0;
|
|
|
|
plbi = lstGetItem (pData, start);
|
|
|
|
while (plbi)
|
|
{
|
|
if (bExact && (keylen != strlen (plbi->key))) {
|
|
plbi = plbi->next;
|
|
start ++;
|
|
continue;
|
|
}
|
|
|
|
if (pData->str_cmp (key, plbi->key, keylen) == 0)
|
|
return start;
|
|
|
|
plbi = plbi->next;
|
|
start ++;
|
|
}
|
|
|
|
return LB_ERR;
|
|
}
|
|
|
|
static void lstOnDrawSListBoxItems (HWND hWnd, HDC hdc,
|
|
PLISTBOXDATA pData, int width)
|
|
{
|
|
DWORD dwStyle = GetWindowStyle (hWnd);
|
|
PLISTBOXITEM plbi;
|
|
PCONTROL pWin;
|
|
RECT rect;
|
|
int i;
|
|
int x = 0, y = 0;
|
|
int checkmark_height; /** checkmark bmp height */
|
|
int checkmark_status; /** checkmark bmp status */
|
|
|
|
gal_pixel gp_hilite_bgc;
|
|
gal_pixel gp_hilite_fgc;
|
|
gal_pixel gp_sign_bgc;
|
|
gal_pixel gp_sign_fgc;
|
|
gal_pixel gp_disabled_bgc;
|
|
gal_pixel gp_disabled_fgc;
|
|
gal_pixel gp_normal_bgc;
|
|
gal_pixel gp_normal_fgc;
|
|
gal_pixel gp_bkcolor;
|
|
|
|
pWin = (PCONTROL) hWnd;
|
|
if (NULL == pWin) return;
|
|
|
|
if (!pWin->we_rdr)
|
|
{
|
|
_WRN_PRINTF ("NULL LFRDR.");
|
|
return;
|
|
}
|
|
|
|
checkmark_height = CheckMarkHeight (pData->itemHeight);
|
|
plbi = lstGetItem (pData, pData->itemTop);
|
|
|
|
gp_hilite_bgc = GetWindowElementPixelEx
|
|
(hWnd, hdc, WE_BGC_HIGHLIGHT_ITEM);
|
|
gp_hilite_fgc = GetWindowElementPixelEx
|
|
(hWnd, hdc, WE_FGC_HIGHLIGHT_ITEM);
|
|
gp_sign_bgc = GetWindowElementPixelEx
|
|
(hWnd, hdc, WE_BGC_SIGNIFICANT_ITEM);
|
|
gp_sign_fgc = GetWindowElementPixelEx
|
|
(hWnd, hdc, WE_FGC_SIGNIFICANT_ITEM);
|
|
gp_disabled_bgc = GetWindowElementPixelEx
|
|
(hWnd, hdc, WE_BGC_DISABLED_ITEM);
|
|
gp_disabled_fgc = GetWindowElementPixelEx
|
|
(hWnd, hdc, WE_FGC_DISABLED_ITEM);
|
|
gp_normal_bgc = GetWindowElementPixelEx
|
|
(hWnd, hdc, WE_BGC_WINDOW);
|
|
gp_normal_fgc = GetWindowElementPixelEx
|
|
(hWnd, hdc, WE_FGC_WINDOW);
|
|
|
|
(void)SetBkMode (hdc, BM_TRANSPARENT);
|
|
|
|
gp_bkcolor = GetBkColor (hdc);
|
|
|
|
for (i = 0; plbi && i < (pData->itemVisibles + 1); i++) {
|
|
rect.left = 0;
|
|
rect.top = y;
|
|
rect.right = width;
|
|
rect.bottom = rect.top + pData->itemHeight;
|
|
|
|
if (plbi->dwFlags & LBIF_DISABLE) {
|
|
SetBkColor (hdc, gp_disabled_fgc);
|
|
SetTextColor (hdc, gp_disabled_fgc);
|
|
SetBrushColor (hdc, gp_disabled_bgc);
|
|
|
|
/** render disabled item */
|
|
pWin->we_rdr->draw_disabled_item (hWnd, hdc, &rect,
|
|
GetWindowElementAttr (hWnd, WE_BGC_DISABLED_ITEM));
|
|
}
|
|
else if (plbi->dwFlags & LBIF_SELECTED) {
|
|
SetBkColor (hdc, gp_hilite_bgc);
|
|
SetTextColor (hdc, gp_hilite_fgc);
|
|
SetBrushColor (hdc, gp_hilite_bgc);
|
|
|
|
/** render hilited item */
|
|
pWin->we_rdr->draw_hilite_item (hWnd, hdc, &rect,
|
|
GetWindowElementAttr (hWnd, WE_BGC_HIGHLIGHT_ITEM));
|
|
}
|
|
else {
|
|
//SetBkColor (hdc, gp_normal_fgc);
|
|
SetTextColor (hdc, gp_normal_fgc);
|
|
SetBrushColor (hdc, gp_normal_bgc);
|
|
|
|
/** render normal item */
|
|
if (!(pWin->dwExStyle & WS_EX_TRANSPARENT))
|
|
pWin->we_rdr->draw_normal_item (hWnd, hdc, &rect,
|
|
GetWindowElementAttr (hWnd, WE_BGC_WINDOW));
|
|
}
|
|
|
|
/** render significant item */
|
|
if ( (plbi->dwFlags & LBIF_SIGNIFICANT) &&
|
|
!(plbi->dwFlags & LBIF_DISABLE)
|
|
) {
|
|
SetBkColor (hdc, gp_sign_bgc);
|
|
SetTextColor (hdc, gp_sign_fgc);
|
|
SetBrushColor (hdc, gp_sign_bgc);
|
|
|
|
pWin->we_rdr->draw_significant_item (hWnd, hdc, &rect,
|
|
GetWindowElementAttr (hWnd, WE_BGC_SIGNIFICANT_ITEM));
|
|
}
|
|
|
|
if (pData->lst_font != INV_LOGFONT) {
|
|
if (plbi->dwFlags & LBIF_BOLDSTYLE)
|
|
pData->lst_font->style |= FS_WEIGHT_BOLD;
|
|
else
|
|
pData->lst_font->style &= ~FS_WEIGHT_BOLD;
|
|
}
|
|
|
|
x = LST_INTER_BMPTEXT - pData->itemLeft;
|
|
|
|
if (dwStyle & LBS_CHECKBOX) {
|
|
checkmark_status = LFRDR_MARK_HAVESHELL;
|
|
|
|
rect.left = x;
|
|
rect.top = y + ((pData->itemHeight - checkmark_height) >> 1);
|
|
rect.right = x + checkmark_height;
|
|
rect.bottom = rect.top + checkmark_height;
|
|
|
|
if (plbi->dwFlags & LBIF_CHECKED)
|
|
checkmark_status |= LFRDR_MARK_ALL_SELECTED;
|
|
else if (plbi->dwFlags & LBIF_PARTCHECKED)
|
|
checkmark_status |= LFRDR_MARK_HALF_SELECTED;
|
|
|
|
gp_bkcolor = SetBkColor (hdc, gp_bkcolor);
|
|
|
|
pWin->we_rdr->draw_checkmark (hdc, &rect,
|
|
GetWindowElementAttr (hWnd, WE_FGC_WINDOW),
|
|
checkmark_status);
|
|
|
|
gp_bkcolor = SetBkColor (hdc, gp_bkcolor);
|
|
|
|
x += checkmark_height + LST_INTER_BMPTEXT;
|
|
}
|
|
|
|
if (dwStyle & LBS_USEICON && plbi->dwImage) {
|
|
if (plbi->dwFlags & LBIF_USEBITMAP) {
|
|
FillBoxWithBitmap (hdc, x, y, 0, pData->itemHeight,
|
|
(PBITMAP) plbi->dwImage);
|
|
x += ((PBITMAP)(plbi->dwImage))->bmWidth;
|
|
}
|
|
else {
|
|
int width;
|
|
DrawIcon (hdc, x, y, 0, pData->itemHeight,
|
|
(HICON) plbi->dwImage);
|
|
GetIconSize ((HICON) plbi->dwImage, &width, NULL);
|
|
x += width;
|
|
}
|
|
x += LST_INTER_BMPTEXT;
|
|
}
|
|
|
|
TextOut (hdc, x, y + ((pData->itemHeight - GetCurFont (hdc)->size) >> 1), plbi->key);
|
|
|
|
y += pData->itemHeight;
|
|
plbi = plbi->next;
|
|
}
|
|
|
|
SetBkColor (hdc, gp_bkcolor);
|
|
}
|
|
|
|
static int lstSelectItem (HWND hwnd, PLISTBOXDATA pData, int newSel)
|
|
{
|
|
PLISTBOXITEM plbi, newItem;
|
|
int index;
|
|
|
|
newItem = lstGetItem (pData, newSel);
|
|
|
|
if (newItem->dwFlags & LBIF_DISABLE)
|
|
return newSel;
|
|
|
|
#ifdef _DEBUG
|
|
if (!newItem)
|
|
_WRN_PRINTF ("return value of lstGetItem is NULL.");
|
|
#endif
|
|
|
|
if (GetWindowStyle (hwnd) & LBS_MULTIPLESEL) {
|
|
newItem->dwFlags ^= LBIF_SELECTED;
|
|
return newSel;
|
|
}
|
|
|
|
index = 0;
|
|
plbi = pData->head;
|
|
while (plbi) {
|
|
if (plbi->dwFlags & LBIF_SELECTED) {
|
|
if (index != newSel) {
|
|
plbi->dwFlags &= ~LBIF_SELECTED;
|
|
newItem->dwFlags |= LBIF_SELECTED;
|
|
return index;
|
|
}
|
|
break;
|
|
}
|
|
|
|
plbi = plbi->next;
|
|
index ++;
|
|
}
|
|
|
|
newItem->dwFlags |= LBIF_SELECTED;
|
|
return pData->itemHilighted;
|
|
}
|
|
|
|
static int lstCancelSelected (HWND hwnd, PLISTBOXDATA pData)
|
|
{
|
|
PLISTBOXITEM plbi;
|
|
int index;
|
|
|
|
index = 0;
|
|
plbi = pData->head;
|
|
while (plbi) {
|
|
if (plbi->dwFlags & LBIF_SELECTED) {
|
|
RECT rc;
|
|
|
|
plbi->dwFlags &= ~LBIF_SELECTED;
|
|
lstGetItemsRect (pData, index, index, &rc);
|
|
InvalidateRect (hwnd, &rc, TRUE);
|
|
return index;
|
|
}
|
|
|
|
plbi = plbi->next;
|
|
index ++;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
static void lstDrawFocusRect (HWND hwnd, HDC hdc, PLISTBOXDATA pData)
|
|
{
|
|
RECT rc;
|
|
PCONTROL pWin;
|
|
DWORD light_dword;
|
|
pWin = (PCONTROL) hwnd;
|
|
if (!pWin || !pWin->we_rdr) return;
|
|
|
|
if (pData->itemHilighted < pData->itemTop
|
|
|| pData->itemHilighted > (pData->itemTop + pData->itemVisibles))
|
|
return;
|
|
|
|
if (pData->dwFlags & LBF_FOCUS) {
|
|
GetClientRect (hwnd, &rc);
|
|
lstGetItemsRect (pData,
|
|
pData->itemHilighted, pData->itemHilighted,
|
|
&rc);
|
|
InflateRect (&rc, -1, -1);
|
|
light_dword = pWin->we_rdr->calc_3dbox_color
|
|
(GetWindowElementAttr (hwnd, WE_BGC_WINDOW),
|
|
LFRDR_3DBOX_COLOR_LIGHTEST);
|
|
pWin->we_rdr->draw_focus_frame (hdc, &rc, light_dword);
|
|
}
|
|
}
|
|
|
|
static void lstCalcParams (const RECT* rcClient, PLISTBOXDATA pData)
|
|
{
|
|
pData->itemVisibles = (RECTHP (rcClient)) / pData->itemHeight;
|
|
pData->itemWidth = RECTWP(rcClient);
|
|
}
|
|
|
|
static void change_scrollbar (HWND hwnd, PLISTBOXDATA pData, BOOL bShow, int iSBar)
|
|
{
|
|
if (pData->sbPolicy == SB_POLICY_ALWAYS) {
|
|
if (iSBar != SB_VERT)
|
|
EnableScrollBar (hwnd, iSBar, bShow);
|
|
}
|
|
else if (pData->sbPolicy == SB_POLICY_AUTOMATIC)
|
|
ShowScrollBar (hwnd, iSBar, bShow);
|
|
}
|
|
|
|
static void lstSetVScrollInfo (HWND hwnd, PLISTBOXDATA pData, BOOL fRedraw)
|
|
{
|
|
SCROLLINFO si={0};
|
|
|
|
if (pData->sbPolicy == SB_POLICY_NEVER) {
|
|
ShowScrollBar (hwnd, SB_VERT, FALSE);
|
|
return;
|
|
}
|
|
|
|
if (pData->itemVisibles >= pData->itemCount) {
|
|
SetScrollPos (hwnd, SB_VERT, 0);
|
|
|
|
if (pData->sbPolicy == SB_POLICY_ALWAYS) {
|
|
si.fMask = SIF_PAGE;
|
|
si.nMax = 1;
|
|
si.nMin = 0;
|
|
si.nPage = 0;
|
|
SetScrollInfo (hwnd, SB_VERT, &si, fRedraw);
|
|
}
|
|
change_scrollbar (hwnd, pData, FALSE, SB_VERT);
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
|
|
si.nMax = pData->itemCount*pData->itemHeight - 1;
|
|
if (si.nMax < 0) si.nMax = 0; /*when Init. itemcount is 0*/
|
|
si.nMin = 0;
|
|
si.nPage = MIN (pData->itemVisibles, pData->itemCount)*pData->itemHeight;
|
|
si.nPos = pData->itemTop*pData->itemHeight;
|
|
|
|
SetScrollInfo (hwnd, SB_VERT, &si, fRedraw);
|
|
EnableScrollBar (hwnd, SB_VERT, TRUE);
|
|
change_scrollbar (hwnd, pData, TRUE, SB_VERT);
|
|
}
|
|
|
|
static void lstSetHScrollInfo (HWND hwnd, PLISTBOXDATA pData, BOOL fRedraw)
|
|
{
|
|
SCROLLINFO si={0};
|
|
|
|
if (pData->sbPolicy == SB_POLICY_NEVER) {
|
|
ShowScrollBar (hwnd, SB_HORZ, FALSE);
|
|
return;
|
|
}
|
|
|
|
if (pData->itemWidth >= pData->itemMaxWidth) {
|
|
SetScrollPos (hwnd, SB_HORZ, 0);
|
|
change_scrollbar (hwnd, pData, FALSE, SB_HORZ);
|
|
return;
|
|
}
|
|
|
|
si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
|
|
si.nMax = pData->itemMaxWidth;
|
|
si.nMin = 0;
|
|
si.nPage = pData->itemWidth;
|
|
si.nPos = pData->itemLeft;
|
|
|
|
SetScrollInfo (hwnd, SB_HORZ, &si, fRedraw);
|
|
EnableScrollBar (hwnd, SB_HORZ, TRUE);
|
|
change_scrollbar (hwnd, pData, TRUE, SB_HORZ);
|
|
}
|
|
|
|
static void lstSetScrollInfo (HWND hwnd, PLISTBOXDATA pData, BOOL fRedraw)
|
|
{
|
|
lstSetVScrollInfo (hwnd, pData, fRedraw);
|
|
lstSetHScrollInfo (hwnd, pData, fRedraw);
|
|
}
|
|
|
|
static LRESULT ListboxCtrlProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
HDC hdc;
|
|
PCONTROL pCtrl;
|
|
PLISTBOXDATA pData;
|
|
DWORD dwStyle;
|
|
#if _USE_FIXSTR
|
|
int len;
|
|
#endif
|
|
|
|
pCtrl = gui_Control(hwnd);
|
|
dwStyle = pCtrl->dwStyle;
|
|
|
|
switch (message)
|
|
{
|
|
case MSG_CREATE:
|
|
pData = (LISTBOXDATA*) calloc (1, sizeof(LISTBOXDATA));
|
|
if (pData == NULL)
|
|
return -1;
|
|
|
|
pData->lst_font = CreateLogFontIndirect(
|
|
(PLOGFONT)GetWindowElementAttr (hwnd, WE_FONT_MENU));
|
|
|
|
pCtrl->dwAddData2 = (DWORD)pData;
|
|
if (!lstInitListBoxData (hwnd, pCtrl, pData, DEF_LB_BUFFER_LEN)) {
|
|
free (pData);
|
|
return -1;
|
|
}
|
|
|
|
lstSetScrollInfo (hwnd, pData, FALSE);
|
|
break;
|
|
|
|
case MSG_SIZECHANGED:
|
|
{
|
|
int oldvisible, oldwidth;
|
|
const RECT *rc = (const RECT*)lParam;
|
|
|
|
pData = (PLISTBOXDATA)pCtrl->dwAddData2;
|
|
|
|
oldvisible = pData->itemVisibles;
|
|
oldwidth = pData->itemWidth;
|
|
|
|
/*from mpeer data is abnormal*/
|
|
if ( (rc->left >= rc->right) ||
|
|
(rc->top >= rc->bottom))
|
|
break;
|
|
|
|
lstCalcParams (rc, pData);
|
|
|
|
if (oldvisible != pData->itemVisibles ||
|
|
oldwidth != pData->itemWidth )
|
|
lstSetScrollInfo (hwnd, pData, FALSE);
|
|
|
|
break;
|
|
}
|
|
case MSG_DESTROY:
|
|
pData = (PLISTBOXDATA)pCtrl->dwAddData2;
|
|
if(pData->lst_font != INV_LOGFONT)
|
|
DestroyLogFont(pData->lst_font);
|
|
lstListBoxCleanUp (pData);
|
|
free (pData);
|
|
break;
|
|
|
|
case LB_SETSTRCMPFUNC:
|
|
pData = (PLISTBOXDATA)pCtrl->dwAddData2;
|
|
if (pData->itemCount == 0 && lParam) {
|
|
pData->str_cmp = (STRCMP)lParam;
|
|
return LB_OKAY;
|
|
}
|
|
return LB_ERR;
|
|
|
|
case LB_RESETCONTENT:
|
|
pData = (PLISTBOXDATA)pCtrl->dwAddData2;
|
|
lstResetListBoxContent (pData);
|
|
lstSetScrollInfo (hwnd, pData, TRUE);
|
|
InvalidateRect (hwnd, NULL, TRUE);
|
|
return 0;
|
|
|
|
case LB_ADDSTRING:
|
|
case LB_INSERTSTRING:
|
|
{
|
|
char* string = NULL;
|
|
PLISTBOXITEMINFO plbii = NULL;
|
|
|
|
PLISTBOXITEM newItem;
|
|
int itemWidth;
|
|
int pos;
|
|
|
|
if (dwStyle & LBS_CHECKBOX || dwStyle & LBS_USEICON) {
|
|
plbii = (PLISTBOXITEMINFO)lParam;
|
|
if (!plbii)
|
|
return LB_ERR;
|
|
|
|
string = plbii->string;
|
|
}
|
|
else {
|
|
string = (char*)lParam;
|
|
if (string == NULL || string [0] == '\0')
|
|
return LB_ERR;
|
|
}
|
|
|
|
pData = (PLISTBOXDATA)pCtrl->dwAddData2;
|
|
newItem = lstAllocItem (pData);
|
|
if (!newItem) {
|
|
if (dwStyle & LBS_NOTIFY)
|
|
NotifyParent (hwnd, pCtrl->id, LBN_ERRSPACE);
|
|
return LB_ERRSPACE;
|
|
}
|
|
|
|
#if _USE_FIXSTR
|
|
len = strlen (string);
|
|
newItem->key = FixStrAlloc (len);
|
|
if (!newItem->key) {
|
|
lstFreeItem (pData, newItem);
|
|
return LB_ERRSPACE;
|
|
}
|
|
if (len > 0)
|
|
strcpy (newItem->key, string);
|
|
#else
|
|
newItem->key = strdup (string);
|
|
if (!newItem->key) {
|
|
lstFreeItem (pData, newItem);
|
|
return LB_ERRSPACE;
|
|
}
|
|
#endif
|
|
newItem->dwFlags = LBIF_NORMAL;
|
|
if (plbii) {
|
|
|
|
if (plbii->cmFlag & CMFLAG_CHECKED)
|
|
newItem->dwFlags |= LBIF_CHECKED;
|
|
else if (plbii->cmFlag & CMFLAG_PARTCHECKED)
|
|
newItem->dwFlags |= LBIF_PARTCHECKED;
|
|
|
|
if (plbii->cmFlag & IMGFLAG_BITMAP)
|
|
newItem->dwFlags |= LBIF_USEBITMAP;
|
|
|
|
if (plbii->cmFlag & LBIS_SIGNIFICANT)
|
|
newItem->dwFlags |= LBIF_SIGNIFICANT;
|
|
|
|
if (dwStyle & LBS_USEICON)
|
|
newItem->dwImage = (DWORD)plbii->hIcon;
|
|
else
|
|
newItem->dwImage = 0L;
|
|
}
|
|
newItem->dwAddData = 0L;
|
|
|
|
if (message == LB_ADDSTRING)
|
|
pos = lstAddNewItem (dwStyle, pData, newItem, -1);
|
|
else
|
|
pos = lstAddNewItem (dwStyle, pData, newItem, (int)wParam);
|
|
|
|
itemWidth = lstGetItemWidth (hwnd, newItem, pData->itemHeight);
|
|
if (pData->itemMaxWidth < itemWidth)
|
|
pData->itemMaxWidth = itemWidth;
|
|
|
|
lstInvalidateUnderItem (hwnd, pData, pos);
|
|
|
|
lstSetScrollInfo (hwnd, pData, TRUE);
|
|
return pos;
|
|
}
|
|
|
|
case LB_DELETESTRING:
|
|
{
|
|
PLISTBOXITEM removed;
|
|
int delete;
|
|
|
|
delete = (int)wParam;
|
|
|
|
pData = (PLISTBOXDATA)pCtrl->dwAddData2;
|
|
removed = lstRemoveItem (pData, &delete);
|
|
if (removed) {
|
|
int width;
|
|
width = lstGetItemWidth (hwnd, removed, pData->itemHeight);
|
|
if (width >= pData->itemMaxWidth)
|
|
pData->itemMaxWidth = lstGetMaxWidth(hwnd, pData);
|
|
#if _USE_FIXSTR
|
|
FreeFixStr (removed->key);
|
|
#else
|
|
free (removed->key);
|
|
#endif
|
|
lstFreeItem (pData, removed);
|
|
|
|
pData->itemCount --;
|
|
|
|
if (pData->itemTop != 0
|
|
&& pData->itemCount <= pData->itemVisibles) {
|
|
pData->itemTop = 0;
|
|
InvalidateRect (hwnd, NULL, TRUE);
|
|
}
|
|
else {
|
|
lstInvalidateUnderItem (hwnd, pData, delete);
|
|
if (delete <= pData->itemTop) {
|
|
pData->itemTop --;
|
|
if (pData->itemTop < 0)
|
|
pData->itemTop = 0;
|
|
}
|
|
}
|
|
|
|
if (pData->itemHilighted >= pData->itemCount) {
|
|
pData->itemHilighted = pData->itemCount - 1;
|
|
if (pData->itemHilighted < 0)
|
|
pData->itemHilighted = 0;
|
|
}
|
|
|
|
if (pData->itemHilighted < pData->itemTop)
|
|
pData->itemHilighted = pData->itemTop;
|
|
if (pData->itemHilighted > ITEM_BOTTOM (pData))
|
|
pData->itemHilighted = ITEM_BOTTOM (pData);
|
|
|
|
pData->selItem = pData->itemHilighted;
|
|
lstSetScrollInfo (hwnd, pData, TRUE);
|
|
return LB_OKAY;
|
|
}
|
|
|
|
return LB_ERR;
|
|
}
|
|
|
|
case LB_FINDSTRING:
|
|
if( *(char*)lParam == '\0' )
|
|
return LB_ERR;
|
|
|
|
pData = (PLISTBOXDATA)pCtrl->dwAddData2;
|
|
return lstFindItem(pData, (int)wParam, (char*)lParam, FALSE);
|
|
|
|
case LB_FINDSTRINGEXACT:
|
|
if( *(char*)lParam == '\0' )
|
|
return LB_ERR;
|
|
|
|
pData = (PLISTBOXDATA)pCtrl->dwAddData2;
|
|
return lstFindItem(pData, (int)wParam, (char*)lParam, TRUE);
|
|
|
|
case LB_SETTOPINDEX:
|
|
{
|
|
int newTop = (int) wParam;
|
|
|
|
pData = (PLISTBOXDATA)pCtrl->dwAddData2;
|
|
|
|
if (newTop <0)
|
|
newTop = 0;
|
|
else if (newTop > pData->itemCount - pData->itemVisibles)
|
|
newTop = pData->itemCount - pData->itemVisibles;
|
|
|
|
if (pData->itemTop != newTop) {
|
|
pData->itemTop = newTop;
|
|
|
|
if (pData->itemHilighted < pData->itemTop)
|
|
pData->itemHilighted = pData->itemTop;
|
|
if (pData->itemHilighted > ITEM_BOTTOM (pData))
|
|
pData->itemHilighted = ITEM_BOTTOM (pData);
|
|
|
|
pData->selItem = pData->itemHilighted;
|
|
lstSetScrollInfo (hwnd, pData, TRUE);
|
|
InvalidateRect (hwnd, NULL, TRUE);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
case LB_SETCURSEL:
|
|
case LB_SETCARETINDEX:
|
|
{
|
|
int new = (int)wParam;
|
|
int old, newTop;
|
|
pData = (PLISTBOXDATA)pCtrl->dwAddData2;
|
|
if (new < 0 || new > pData->itemCount - 1) {
|
|
if (dwStyle & LBS_MULTIPLESEL)
|
|
return LB_ERR;
|
|
else
|
|
return lstCancelSelected (hwnd, pData);
|
|
}
|
|
|
|
old = pData->itemHilighted;
|
|
if (new >= 0 && new != old) {
|
|
if (pData->itemCount - new >= pData->itemVisibles)
|
|
newTop = new;
|
|
else
|
|
newTop = MAX (pData->itemCount - pData->itemVisibles, 0);
|
|
|
|
pData->itemTop = newTop;
|
|
pData->itemHilighted = new;
|
|
pData->selItem = pData->itemHilighted;
|
|
lstSetScrollInfo (hwnd, pData, TRUE);
|
|
}
|
|
if (!(dwStyle & LBS_MULTIPLESEL))
|
|
{
|
|
PLISTBOXITEM newItem = lstGetItem (pData, new);
|
|
if (newItem->dwFlags & LBIF_DISABLE) {
|
|
lstCancelSelected(hwnd, pData);
|
|
return old;
|
|
}
|
|
else
|
|
lstSelectItem (hwnd, pData, new);
|
|
}
|
|
InvalidateRect (hwnd, NULL, TRUE);
|
|
return old;
|
|
}
|
|
|
|
case LB_GETCOUNT:
|
|
pData = (PLISTBOXDATA)pCtrl->dwAddData2;
|
|
return pData->itemCount;
|
|
|
|
case LB_GETCURSEL:
|
|
{
|
|
PLISTBOXITEM plbi;
|
|
int index = 0;
|
|
|
|
pData = (PLISTBOXDATA)pCtrl->dwAddData2;
|
|
if (dwStyle & LBS_MULTIPLESEL)
|
|
return pData->itemHilighted;
|
|
|
|
plbi = pData->head;
|
|
while (plbi) {
|
|
if (plbi->dwFlags & LBIF_SELECTED)
|
|
return index;
|
|
|
|
index ++;
|
|
plbi = plbi->next;
|
|
}
|
|
|
|
return LB_ERR;
|
|
}
|
|
|
|
case LB_GETSELCOUNT:
|
|
{
|
|
int nSel;
|
|
PLISTBOXITEM plbi;
|
|
|
|
pData = (PLISTBOXDATA)pCtrl->dwAddData2;
|
|
|
|
nSel = 0;
|
|
plbi = pData->head;
|
|
while (plbi) {
|
|
if (plbi->dwFlags & LBIF_SELECTED)
|
|
nSel ++;
|
|
plbi = plbi->next;
|
|
}
|
|
|
|
return nSel;
|
|
}
|
|
|
|
case LB_GETTOPINDEX:
|
|
pData = (PLISTBOXDATA)pCtrl->dwAddData2;
|
|
return pData->itemTop;
|
|
|
|
case LB_GETCARETINDEX:
|
|
pData = (PLISTBOXDATA)pCtrl->dwAddData2;
|
|
return pData->itemHilighted;
|
|
|
|
case LB_GETTEXTLEN:
|
|
{
|
|
PLISTBOXITEM plbi;
|
|
|
|
pData = (PLISTBOXDATA)pCtrl->dwAddData2;
|
|
plbi = lstGetItem (pData, (int)wParam);
|
|
if (plbi)
|
|
return strlen (plbi->key);
|
|
|
|
return LB_ERR;
|
|
}
|
|
|
|
case LB_GETTEXT:
|
|
{
|
|
PLISTBOXITEM plbi;
|
|
|
|
pData = (PLISTBOXDATA)pCtrl->dwAddData2;
|
|
plbi = lstGetItem (pData, (int)wParam);
|
|
if (plbi) {
|
|
strcpy ((char*)lParam, plbi->key);
|
|
return LB_OKAY;
|
|
}
|
|
|
|
return LB_ERR;
|
|
}
|
|
|
|
case LB_SETTEXT:
|
|
{
|
|
PLISTBOXITEM plbi;
|
|
char* newStr;
|
|
|
|
pData = (PLISTBOXDATA)pCtrl->dwAddData2;
|
|
plbi = lstGetItem (pData, (int)wParam);
|
|
if (plbi) {
|
|
#if _USE_FIXSTR
|
|
len = strlen ((char*)lParam);
|
|
newStr = FixStrAlloc (len);
|
|
if (newStr) {
|
|
FreeFixStr (plbi->key);
|
|
plbi->key = newStr;
|
|
if (len > 0)
|
|
strcpy (plbi->key, (char*)lParam);
|
|
#else
|
|
newStr = strdup ((const char*)lParam);
|
|
if (newStr) {
|
|
free (plbi->key);
|
|
plbi->key = newStr;
|
|
#endif
|
|
lstInvalidateItem (hwnd, pData, (int)wParam);
|
|
}
|
|
else
|
|
return LB_ERR;
|
|
}
|
|
|
|
return LB_ERR;
|
|
}
|
|
|
|
case LB_GETITEMDATA:
|
|
{
|
|
PLISTBOXITEM plbi;
|
|
PLISTBOXITEMINFO plbii;
|
|
|
|
if (!(dwStyle & LBS_CHECKBOX || dwStyle & LBS_USEICON)) {
|
|
return LB_ERR;
|
|
}
|
|
|
|
pData = (PLISTBOXDATA)pCtrl->dwAddData2;
|
|
if (!(plbi = lstGetItem (pData, (int)wParam)))
|
|
return LB_ERR;
|
|
|
|
plbii = (PLISTBOXITEMINFO)lParam;
|
|
if (!plbii)
|
|
return LB_ERR;
|
|
|
|
if (plbi->dwFlags & LBIF_CHECKED)
|
|
plbii->cmFlag = CMFLAG_CHECKED;
|
|
else if (plbi->dwFlags & LBIF_PARTCHECKED)
|
|
plbii->cmFlag = CMFLAG_PARTCHECKED;
|
|
else
|
|
plbii->cmFlag = CMFLAG_BLANK;
|
|
|
|
if (plbi->dwFlags & LBIF_USEBITMAP)
|
|
plbii->cmFlag |= IMGFLAG_BITMAP;
|
|
|
|
if (plbi->dwFlags & LBIF_SIGNIFICANT)
|
|
plbii->cmFlag |= LBIS_SIGNIFICANT;
|
|
|
|
plbii->hIcon = (HICON)plbi->dwImage;
|
|
|
|
return LB_OKAY;
|
|
}
|
|
|
|
case LB_SETITEMDATA:
|
|
{
|
|
PLISTBOXITEM plbi;
|
|
PLISTBOXITEMINFO plbii;
|
|
|
|
if (!(dwStyle & LBS_CHECKBOX || dwStyle & LBS_USEICON)) {
|
|
return LB_ERR;
|
|
}
|
|
|
|
pData = (PLISTBOXDATA)pCtrl->dwAddData2;
|
|
if (!(plbi = lstGetItem (pData, (int)wParam)))
|
|
return LB_ERR;
|
|
|
|
plbii = (PLISTBOXITEMINFO)lParam;
|
|
if (!plbii)
|
|
return LB_ERR;
|
|
|
|
plbi->dwFlags &= ~LBIF_CHECKMARKMASK;
|
|
|
|
if (plbii->cmFlag & CMFLAG_CHECKED)
|
|
plbi->dwFlags |= LBIF_CHECKED;
|
|
if (plbii->cmFlag & CMFLAG_PARTCHECKED)
|
|
plbi->dwFlags |= LBIF_PARTCHECKED;
|
|
if (plbii->cmFlag & IMGFLAG_BITMAP)
|
|
plbi->dwFlags |= LBIF_USEBITMAP;
|
|
if (plbii->cmFlag & LBIS_SIGNIFICANT)
|
|
plbi->dwFlags |= LBIF_SIGNIFICANT;
|
|
|
|
if (dwStyle & LBS_USEICON)
|
|
plbi->dwImage = (DWORD)plbii->hIcon;
|
|
else
|
|
plbi->dwImage = 0;
|
|
|
|
if (plbii->string && plbii->string[0] != '\0') {
|
|
int oldlen = strlen (plbi->key);
|
|
int newlen = strlen (plbii->string);
|
|
|
|
if (oldlen >= newlen) {
|
|
memcpy (plbi->key, plbii->string, newlen);
|
|
plbi->key[newlen] = '\0';
|
|
}
|
|
else {
|
|
#if _USE_FIXSTR
|
|
FreeFixStr (plbi->key);
|
|
plbi->key = FixStrAlloc (newlen + 1);
|
|
pData = (PLISTBOXDATA)pCtrl->dwAddData2;
|
|
if (!plbi->key) {
|
|
lstFreeItem (pData, plbi);
|
|
return LB_ERRSPACE;
|
|
}
|
|
|
|
strcpy (plbi->key, plbii->string);
|
|
plbi->key[newlen] = '\0';
|
|
#else
|
|
free (plbi->key);
|
|
plbi->key = strdup (plbii->string);
|
|
if (!plbi->key) {
|
|
lstFreeItem (pData, plbi);
|
|
return LB_ERRSPACE;
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
lstInvalidateItem (hwnd, pData, (int)wParam);
|
|
|
|
return LB_OKAY;
|
|
}
|
|
|
|
case LB_GETITEMADDDATA:
|
|
{
|
|
PLISTBOXITEM plbi;
|
|
|
|
pData = (PLISTBOXDATA)pCtrl->dwAddData2;
|
|
if (!(plbi = lstGetItem (pData, (int)wParam)))
|
|
return LB_ERR;
|
|
|
|
return plbi->dwAddData;
|
|
}
|
|
|
|
case LB_SETITEMADDDATA:
|
|
{
|
|
PLISTBOXITEM plbi;
|
|
|
|
pData = (PLISTBOXDATA)pCtrl->dwAddData2;
|
|
if (!(plbi = lstGetItem (pData, (int)wParam)))
|
|
return LB_ERR;
|
|
|
|
plbi->dwAddData = (DWORD)lParam;
|
|
|
|
return LB_OKAY;
|
|
}
|
|
|
|
case LB_GETCHECKMARK:
|
|
{
|
|
PLISTBOXITEM plbi;
|
|
|
|
if (!(dwStyle & LBS_CHECKBOX))
|
|
return LB_ERR;
|
|
|
|
pData = (PLISTBOXDATA)pCtrl->dwAddData2;
|
|
if (!(plbi = lstGetItem (pData, (int)wParam)))
|
|
return LB_ERR;
|
|
|
|
if (plbi->dwFlags & LBIF_CHECKED)
|
|
return CMFLAG_CHECKED;
|
|
|
|
if (plbi->dwFlags & LBIF_PARTCHECKED)
|
|
return CMFLAG_PARTCHECKED;
|
|
|
|
return CMFLAG_BLANK;
|
|
}
|
|
|
|
case LB_SETCHECKMARK:
|
|
{
|
|
PLISTBOXITEM plbi;
|
|
|
|
if (!(dwStyle & LBS_CHECKBOX))
|
|
return LB_ERR;
|
|
|
|
pData = (PLISTBOXDATA)pCtrl->dwAddData2;
|
|
if (!(plbi = lstGetItem (pData, (int)wParam)))
|
|
return LB_ERR;
|
|
|
|
plbi->dwFlags &= ~LBIF_CHECKMARKMASK;
|
|
switch (lParam) {
|
|
case CMFLAG_CHECKED:
|
|
plbi->dwFlags |= LBIF_CHECKED;
|
|
break;
|
|
case CMFLAG_PARTCHECKED:
|
|
plbi->dwFlags |= LBIF_PARTCHECKED;
|
|
break;
|
|
}
|
|
|
|
lstInvalidateItem (hwnd, pData, (int)wParam);
|
|
|
|
return LB_OKAY;
|
|
}
|
|
|
|
case LB_GETSELITEMS:
|
|
{
|
|
int nItem;
|
|
int nSel = 0;
|
|
int index = 0;
|
|
int* pInt;
|
|
PLISTBOXITEM plbi;
|
|
|
|
nItem = (int)wParam;
|
|
pInt = (int*)lParam;
|
|
|
|
pData = (PLISTBOXDATA)pCtrl->dwAddData2;
|
|
plbi = pData->head;
|
|
while (plbi) {
|
|
|
|
if (plbi->dwFlags & LBIF_SELECTED) {
|
|
if (pInt) {
|
|
if (nSel < nItem)
|
|
*(pInt + nSel) = index;
|
|
else
|
|
return nItem;
|
|
}
|
|
nSel ++;
|
|
}
|
|
|
|
plbi = plbi->next;
|
|
index ++;
|
|
}
|
|
|
|
return nSel;
|
|
}
|
|
break;
|
|
|
|
case LB_GETSEL:
|
|
{
|
|
PLISTBOXITEM plbi;
|
|
|
|
pData = (PLISTBOXDATA)pCtrl->dwAddData2;
|
|
plbi = lstGetItem (pData, (int)wParam);
|
|
if (plbi)
|
|
return plbi->dwFlags & LBIF_SELECTED;
|
|
|
|
return LB_ERR;
|
|
}
|
|
|
|
case LB_SETSEL:
|
|
{
|
|
PLISTBOXITEM plbi;
|
|
|
|
if (!(dwStyle & LBS_MULTIPLESEL))
|
|
return LB_ERR;
|
|
|
|
pData = (PLISTBOXDATA)pCtrl->dwAddData2;
|
|
plbi = lstGetItem (pData, (int)lParam);
|
|
if (plbi) {
|
|
if (plbi->dwFlags & LBIF_DISABLE)
|
|
return LB_ERR;
|
|
|
|
if (wParam == -1)
|
|
plbi->dwFlags ^= LBIF_SELECTED;
|
|
else if (wParam == 0)
|
|
plbi->dwFlags &= ~LBIF_SELECTED;
|
|
else
|
|
plbi->dwFlags |= LBIF_SELECTED;
|
|
|
|
lstInvalidateItem (hwnd, pData, (int)lParam);
|
|
}
|
|
|
|
return LB_ERR;
|
|
}
|
|
|
|
case LB_GETITEMHEIGHT:
|
|
pData = (PLISTBOXDATA)pCtrl->dwAddData2;
|
|
return pData->itemHeight;
|
|
|
|
case LB_SETITEMHEIGHT:
|
|
pData = (PLISTBOXDATA)pCtrl->dwAddData2;
|
|
if (pData->itemHeight != LOWORD (lParam)) {
|
|
RECT rcClient;
|
|
|
|
pData->itemHeight = LOWORD (lParam);
|
|
if (pData->itemHeight < pCtrl->pLogFont->size)
|
|
pData->itemHeight = pCtrl->pLogFont->size;
|
|
|
|
GetClientRect (hwnd, &rcClient);
|
|
lstCalcParams (&rcClient, pData);
|
|
|
|
lstSetScrollInfo (hwnd, pData, TRUE);
|
|
InvalidateRect (hwnd, NULL, TRUE);
|
|
}
|
|
|
|
return pData->itemHeight;
|
|
|
|
case MSG_SETFOCUS:
|
|
{
|
|
RECT rc;
|
|
|
|
pData = (PLISTBOXDATA)pCtrl->dwAddData2;
|
|
|
|
if (pData->dwFlags & LBF_FOCUS)
|
|
break;
|
|
|
|
pData->dwFlags |= LBF_FOCUS;
|
|
|
|
if (pData->itemHilighted >= 0) {
|
|
GetClientRect (hwnd, &rc);
|
|
lstGetItemsRect (pData, pData->itemHilighted, pData->itemHilighted, &rc);
|
|
InvalidateRect (hwnd, &rc, TRUE);
|
|
}
|
|
|
|
if (dwStyle & LBS_NOTIFY)
|
|
NotifyParent (hwnd, pCtrl->id, LBN_SETFOCUS);
|
|
break;
|
|
}
|
|
|
|
case MSG_KILLFOCUS:
|
|
{
|
|
RECT rc;
|
|
|
|
pData = (PLISTBOXDATA)pCtrl->dwAddData2;
|
|
|
|
if (pData->itemHilighted >= 0) {
|
|
GetClientRect (hwnd, &rc);
|
|
lstGetItemsRect (pData, pData->itemHilighted, pData->itemHilighted, &rc);
|
|
InvalidateRect (hwnd, &rc, TRUE);
|
|
}
|
|
|
|
pData->dwFlags &= ~LBF_FOCUS;
|
|
|
|
if (dwStyle & LBS_NOTIFY)
|
|
{
|
|
NotifyParent (hwnd, pCtrl->id, LBN_SELCANCEL);
|
|
NotifyParent (hwnd, pCtrl->id, LBN_KILLFOCUS);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case MSG_GETDLGCODE:
|
|
return DLGC_WANTARROWS | DLGC_WANTCHARS | DLGC_WANTENTER;
|
|
|
|
case MSG_FONTCHANGED:
|
|
{
|
|
RECT rcClient;
|
|
|
|
pData = (PLISTBOXDATA)pCtrl->dwAddData2;
|
|
if (pData->itemHeight < pCtrl->pLogFont->size)
|
|
pData->itemHeight = pCtrl->pLogFont->size;
|
|
|
|
if (pData->lst_font != INV_LOGFONT) {
|
|
DestroyLogFont(pData->lst_font);
|
|
pData->lst_font = INV_LOGFONT;
|
|
}
|
|
pData->lst_font = CreateLogFontIndirect(GetWindowFont(hwnd));
|
|
|
|
GetClientRect (hwnd, &rcClient);
|
|
lstCalcParams (&rcClient, pData);
|
|
|
|
lstSetScrollInfo (hwnd, pData, TRUE);
|
|
InvalidateRect (hwnd, NULL, TRUE);
|
|
return 0;
|
|
}
|
|
|
|
case MSG_GETTEXTLENGTH:
|
|
case MSG_GETTEXT:
|
|
case MSG_SETTEXT:
|
|
return -1;
|
|
|
|
case MSG_PAINT:
|
|
{
|
|
RECT rc;
|
|
|
|
hdc = BeginPaint (hwnd);
|
|
GetClientRect (hwnd, &rc);
|
|
pData = (PLISTBOXDATA)pCtrl->dwAddData2;
|
|
if (pData->lst_font != INV_LOGFONT) {
|
|
SelectFont(hdc, pData->lst_font);
|
|
}
|
|
lstOnDrawSListBoxItems (hwnd, hdc, pData, RECTW (rc));
|
|
lstDrawFocusRect (hwnd, hdc, pData);
|
|
|
|
EndPaint (hwnd, hdc);
|
|
}
|
|
return 0;
|
|
|
|
case MSG_LBUTTONDBLCLK:
|
|
if (dwStyle & LBS_NOTIFY)
|
|
NotifyParent (hwnd, pCtrl->id, LBN_DBLCLK);
|
|
break;
|
|
|
|
case MSG_MOUSEMOVE:
|
|
case MSG_LBUTTONDOWN:
|
|
if ((dwStyle & LBS_MULTIPLESEL)
|
|
|| !(dwStyle & LBS_MOUSEFOLLOW))
|
|
break;
|
|
|
|
case MSG_LBUTTONUP:
|
|
{
|
|
int oldSel, mouseX, mouseY, hit;
|
|
RECT rcInv;
|
|
BOOL click_mark = FALSE;
|
|
PLISTBOXITEM hitItem;
|
|
|
|
pData = (PLISTBOXDATA)pCtrl->dwAddData2;
|
|
if (pData->itemCount == 0)
|
|
break;
|
|
|
|
mouseX = LOSWORD (lParam);
|
|
mouseY = HISWORD (lParam);
|
|
hit = mouseY / pData->itemHeight;
|
|
hit += pData->itemTop;
|
|
|
|
if (hit >= pData->itemCount)
|
|
break;
|
|
|
|
hitItem = lstGetItem (pData, hit);
|
|
if (hitItem->dwFlags & LBIF_DISABLE)
|
|
break;
|
|
|
|
oldSel = lstSelectItem (hwnd, pData, hit);
|
|
|
|
if (dwStyle & LBS_CHECKBOX) {
|
|
if (mouseX > 0 && mouseX <
|
|
CheckMarkHeight (pData->itemHeight)) {
|
|
click_mark = TRUE;
|
|
if (message == MSG_LBUTTONUP && dwStyle & LBS_NOTIFY)
|
|
NotifyParent (hwnd, pCtrl->id, LBN_CLICKCHECKMARK);
|
|
|
|
if (dwStyle & LBS_AUTOCHECK) {
|
|
if (message == MSG_LBUTTONUP) {
|
|
PLISTBOXITEM plbi;
|
|
|
|
plbi = lstGetItem (pData, hit);
|
|
|
|
switch (plbi->dwFlags & LBIF_CHECKMARKMASK) {
|
|
case LBIF_CHECKED:
|
|
plbi->dwFlags &= ~LBIF_CHECKMARKMASK;
|
|
if (message == MSG_LBUTTONUP && dwStyle & LBS_NOTIFY)
|
|
NotifyParent (hwnd, pCtrl->id, LBN_SELCANCEL);
|
|
break;
|
|
default:
|
|
plbi->dwFlags &= ~LBIF_CHECKMARKMASK;
|
|
plbi->dwFlags |= LBIF_CHECKED;
|
|
break;
|
|
}
|
|
}
|
|
|
|
lstInvalidateItem (hwnd, pData, hit);
|
|
}
|
|
}
|
|
}
|
|
|
|
GetClientRect (hwnd, &rcInv);
|
|
if (oldSel >= 0) {
|
|
if (oldSel >= pData->itemTop
|
|
&& (oldSel <= pData->itemTop + pData->itemVisibles)) {
|
|
lstGetItemsRect (pData, oldSel, oldSel, &rcInv);
|
|
InvalidateRect (hwnd, &rcInv, TRUE);
|
|
}
|
|
}
|
|
|
|
lstGetItemsRect (pData, pData->itemHilighted, pData->itemHilighted, &rcInv);
|
|
InvalidateRect (hwnd, &rcInv, TRUE);
|
|
pData->itemHilighted = hit;
|
|
|
|
lstGetItemsRect (pData, hit, hit, &rcInv);
|
|
InvalidateRect (hwnd, &rcInv, TRUE);
|
|
|
|
lstSetScrollInfo (hwnd, pData, TRUE);
|
|
|
|
if ( message == MSG_LBUTTONUP && (dwStyle & LBS_NOTIFY) ) {
|
|
if (dwStyle & LBS_MOUSEFOLLOW) {
|
|
oldSel = pData->selItem;
|
|
pData->selItem = hit;
|
|
}
|
|
if (oldSel != hit)
|
|
NotifyParent (hwnd, pCtrl->id, LBN_SELCHANGE);
|
|
if (!click_mark)
|
|
NotifyParent (hwnd, pCtrl->id, LBN_CLICKED);
|
|
}
|
|
}
|
|
return 0;
|
|
|
|
case LB_GETITEMRECT:
|
|
{
|
|
RECT rcClient, *rcItem;
|
|
int index;
|
|
|
|
rcItem = (RECT*)lParam;
|
|
index = (int)wParam;
|
|
|
|
pData = (PLISTBOXDATA)pCtrl->dwAddData2;
|
|
if (pData->itemCount == 0 || index > pData->itemCount)
|
|
return LB_ERR;
|
|
|
|
GetClientRect ( hwnd, &rcClient );
|
|
rcItem->right = rcClient.right;
|
|
rcItem->left = rcClient.left;
|
|
rcItem->top = (index-pData->itemTop)*pData->itemHeight;
|
|
rcItem->bottom = (index-pData->itemTop+1)*(pData->itemHeight);
|
|
return LB_OKAY;
|
|
}
|
|
|
|
case MSG_KEYDOWN:
|
|
{
|
|
int oldSel, newSel, newTop;
|
|
RECT rcInv;
|
|
PLISTBOXITEM pnewItem;
|
|
|
|
pData = (PLISTBOXDATA)pCtrl->dwAddData2;
|
|
if (pData->itemCount == 0)
|
|
break;
|
|
|
|
newTop = pData->itemTop;
|
|
newSel = pData->itemHilighted;
|
|
|
|
switch (LOWORD (wParam))
|
|
{
|
|
case SCANCODE_HOME:
|
|
newSel = 0;
|
|
newTop = 0;
|
|
break;
|
|
|
|
case SCANCODE_END:
|
|
newSel = pData->itemCount - 1;
|
|
if (pData->itemCount > pData->itemVisibles)
|
|
newTop = pData->itemCount - pData->itemVisibles;
|
|
else
|
|
newTop = 0;
|
|
break;
|
|
|
|
case SCANCODE_CURSORBLOCKDOWN:
|
|
newSel ++;
|
|
if (newSel >= pData->itemCount)
|
|
return 0;
|
|
if (newSel > ITEM_BOTTOM (pData))
|
|
newTop ++;
|
|
#if 0
|
|
newTop = newSel-pData->itemVisibles+1; /* sure to newsel is at bottom */
|
|
#endif
|
|
break;
|
|
|
|
case SCANCODE_CURSORBLOCKUP:
|
|
newSel --;
|
|
if (newSel < 0)
|
|
return 0;
|
|
if (newSel < pData->itemTop)
|
|
newTop --;
|
|
#if 0
|
|
newTop = newSel;
|
|
#endif
|
|
break;
|
|
|
|
case SCANCODE_PAGEDOWN:
|
|
newSel += pData->itemVisibles;
|
|
if (newSel >= pData->itemCount)
|
|
newSel = pData->itemCount - 1;
|
|
|
|
if (pData->itemCount - newSel >= pData->itemVisibles)
|
|
newTop = newSel;
|
|
else
|
|
newTop = MAX (pData->itemCount-pData->itemVisibles, 0);
|
|
break;
|
|
|
|
case SCANCODE_PAGEUP:
|
|
newSel -= pData->itemVisibles;
|
|
if (newSel < 0)
|
|
newSel = 0;
|
|
|
|
newTop -= pData->itemVisibles;
|
|
if (newTop < 0)
|
|
newTop = 0;
|
|
break;
|
|
|
|
case SCANCODE_KEYPADENTER:
|
|
case SCANCODE_ENTER:
|
|
if (dwStyle & LBS_NOTIFY)
|
|
NotifyParent (hwnd, pCtrl->id, LBN_ENTER);
|
|
return 0;
|
|
|
|
default:
|
|
return 0;
|
|
}
|
|
GetClientRect (hwnd, &rcInv);
|
|
if (pData->itemHilighted != newSel) {
|
|
if (pData->itemTop != newTop) {
|
|
pData->itemTop = newTop;
|
|
pData->itemHilighted = newSel;
|
|
pData->selItem = pData->itemHilighted;
|
|
if (!(dwStyle & LBS_MULTIPLESEL)) {
|
|
pnewItem = lstGetItem(pData, newSel);
|
|
if(pnewItem->dwFlags&LBIF_DISABLE)
|
|
lstCancelSelected(hwnd, pData);
|
|
else
|
|
{
|
|
oldSel = lstSelectItem (hwnd, pData, newSel);
|
|
if ((dwStyle & LBS_NOTIFY) && (oldSel != newSel))
|
|
NotifyParent (hwnd, pCtrl->id, LBN_SELCHANGE);
|
|
}
|
|
}
|
|
InvalidateRect (hwnd, NULL, TRUE);
|
|
}
|
|
else {
|
|
if (!(dwStyle & LBS_MULTIPLESEL)) {
|
|
pnewItem = lstGetItem(pData, newSel);
|
|
if(pnewItem->dwFlags&LBIF_DISABLE) {
|
|
lstCancelSelected(hwnd, pData);
|
|
InvalidateRect(hwnd, NULL, TRUE);
|
|
}
|
|
else
|
|
{
|
|
oldSel = lstSelectItem (hwnd, pData, newSel);
|
|
if ((dwStyle & LBS_NOTIFY) && (oldSel != newSel))
|
|
NotifyParent (hwnd, pCtrl->id, LBN_SELCHANGE);
|
|
if (oldSel >= 0) {
|
|
if (oldSel >= pData->itemTop
|
|
&& oldSel <= (ITEM_BOTTOM (pData) + 1)) {
|
|
lstGetItemsRect (pData, oldSel, oldSel, &rcInv);
|
|
InvalidateRect (hwnd, &rcInv, TRUE);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (newSel < newTop) {
|
|
pData->itemHilighted = newSel;
|
|
pData->selItem = pData->itemHilighted;
|
|
break;
|
|
}
|
|
|
|
pData->itemHilighted = newSel;
|
|
pData->selItem = pData->itemHilighted;
|
|
lstGetItemsRect (pData, newSel, newSel, &rcInv);
|
|
InvalidateRect (hwnd, &rcInv, TRUE);
|
|
}
|
|
else {
|
|
pnewItem = lstGetItem(pData, newSel);
|
|
if(pnewItem->dwFlags&LBIF_DISABLE)
|
|
break;
|
|
lstGetItemsRect (pData, pData->itemHilighted, pData->itemHilighted, &rcInv);
|
|
InvalidateRect (hwnd, &rcInv, TRUE);
|
|
pData->itemHilighted = newSel;
|
|
lstGetItemsRect (pData, newSel, newSel, &rcInv);
|
|
InvalidateRect (hwnd, &rcInv, TRUE);
|
|
}
|
|
}
|
|
lstSetScrollInfo (hwnd, pData, TRUE);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case MSG_CHAR:
|
|
{
|
|
unsigned char head [2];
|
|
int index;
|
|
int newTop;
|
|
PLISTBOXITEM plbi;
|
|
|
|
if (HIBYTE (wParam))
|
|
break;
|
|
|
|
head [0] = LOBYTE (wParam);
|
|
head [1] = '\0';
|
|
|
|
pData = (PLISTBOXDATA)pCtrl->dwAddData2;
|
|
|
|
if (head[0] == ' ') {
|
|
plbi = lstGetItem (pData, pData->itemHilighted);
|
|
if (plbi->dwFlags & LBIF_DISABLE)
|
|
break;
|
|
|
|
if (dwStyle & LBS_MULTIPLESEL) {
|
|
RECT rcInv;
|
|
GetClientRect (hwnd, &rcInv);
|
|
lstSelectItem (hwnd, pData, pData->itemHilighted);
|
|
lstGetItemsRect (pData,
|
|
pData->itemHilighted,
|
|
pData->itemHilighted,
|
|
&rcInv);
|
|
InvalidateRect (hwnd, &rcInv, TRUE);
|
|
}
|
|
else if (dwStyle & LBS_CHECKBOX) {
|
|
if (dwStyle & LBS_NOTIFY)
|
|
NotifyParent (hwnd, pCtrl->id, LBN_CLICKCHECKMARK);
|
|
|
|
if (dwStyle & LBS_AUTOCHECK) {
|
|
#if 0
|
|
PLISTBOXITEM plbi;
|
|
plbi = lstGetItem (pData, pData->itemHilighted);
|
|
#endif
|
|
|
|
switch (plbi->dwFlags & LBIF_CHECKMARKMASK) {
|
|
case LBIF_CHECKED:
|
|
plbi->dwFlags &= ~LBIF_CHECKMARKMASK;
|
|
if (dwStyle & LBS_NOTIFY)
|
|
NotifyParent (hwnd, pCtrl->id, LBN_SELCANCEL);
|
|
break;
|
|
default:
|
|
plbi->dwFlags &= ~LBIF_CHECKMARKMASK;
|
|
plbi->dwFlags |= LBIF_CHECKED;
|
|
break;
|
|
}
|
|
|
|
lstInvalidateItem (hwnd, pData, pData->itemHilighted);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
index = lstFindItem (pData, pData->itemHilighted + 1, (char*)head, FALSE);
|
|
if (index < 0) {
|
|
index = lstFindItem (pData, 0, (char*)head, FALSE);
|
|
}
|
|
|
|
if (index >= 0) {
|
|
if (pData->itemCount - index >= pData->itemVisibles)
|
|
newTop = index;
|
|
else
|
|
newTop = MAX (pData->itemCount - pData->itemVisibles, 0);
|
|
|
|
pData->itemTop = newTop;
|
|
pData->itemHilighted = index;
|
|
pData->selItem = pData->itemHilighted;
|
|
if (!(dwStyle & LBS_MULTIPLESEL)) {
|
|
plbi = lstGetItem(pData, index);
|
|
if(plbi->dwFlags & LBIF_DISABLE)
|
|
lstCancelSelected(hwnd, pData);
|
|
else {
|
|
int oldSel = lstSelectItem (hwnd, pData, index);
|
|
if ((dwStyle & LBS_NOTIFY) && (oldSel != index))
|
|
NotifyParent (hwnd, pCtrl->id, LBN_SELCHANGE);
|
|
}
|
|
}
|
|
InvalidateRect (hwnd, NULL, TRUE);
|
|
lstSetScrollInfo (hwnd, pData, TRUE);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case MSG_VSCROLL:
|
|
{
|
|
int newTop;
|
|
int scrollHeight = 0;
|
|
|
|
pData = (PLISTBOXDATA)pCtrl->dwAddData2;
|
|
newTop = pData->itemTop;
|
|
switch(wParam)
|
|
{
|
|
case SB_LINEDOWN:
|
|
if (ITEM_BOTTOM (pData) < (pData->itemCount - 1)) {
|
|
newTop ++;
|
|
scrollHeight = -pData->itemHeight;
|
|
}
|
|
break;
|
|
|
|
case SB_LINEUP:
|
|
if (pData->itemTop > 0) {
|
|
newTop --;
|
|
scrollHeight = pData->itemHeight;
|
|
}
|
|
break;
|
|
|
|
case SB_PAGEDOWN:
|
|
if ((pData->itemTop + (pData->itemVisibles << 1)) <=
|
|
pData->itemCount)
|
|
newTop += pData->itemVisibles;
|
|
else
|
|
newTop = pData->itemCount - pData->itemVisibles;
|
|
|
|
if (newTop < 0)
|
|
return 0;
|
|
|
|
scrollHeight = -(newTop - pData->itemTop)
|
|
*pData->itemHeight;
|
|
break;
|
|
|
|
case SB_PAGEUP:
|
|
if (pData->itemTop >= pData->itemVisibles)
|
|
newTop -= pData->itemVisibles;
|
|
else
|
|
newTop = 0;
|
|
|
|
scrollHeight = (pData->itemTop - newTop)*pData->itemHeight;
|
|
break;
|
|
|
|
case SB_THUMBTRACK:
|
|
newTop = MIN ((int)lParam/pData->itemHeight,
|
|
(pData->itemCount - pData->itemVisibles));
|
|
scrollHeight = (pData->itemTop - newTop)*pData->itemHeight;
|
|
break;
|
|
}
|
|
|
|
if (scrollHeight) {
|
|
pData->itemTop = newTop;
|
|
lstSetScrollInfo (hwnd, pData, TRUE);
|
|
InvalidateRect (hwnd, NULL, TRUE);
|
|
return 0;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case MSG_HSCROLL:
|
|
{
|
|
int newLeft;
|
|
int scrollWidth = 0;
|
|
|
|
pData = (PLISTBOXDATA)pCtrl->dwAddData2;
|
|
newLeft = pData->itemLeft;
|
|
switch (wParam)
|
|
{
|
|
case SB_LINERIGHT:
|
|
if (pData->itemMaxWidth > (pData->itemWidth + newLeft)) {
|
|
newLeft++;
|
|
scrollWidth = 1;
|
|
}
|
|
|
|
break;
|
|
|
|
case SB_LINELEFT:
|
|
if (newLeft > 0) {
|
|
newLeft--;
|
|
scrollWidth = 1;
|
|
}
|
|
|
|
break;
|
|
|
|
case SB_PAGELEFT:
|
|
if (newLeft >= pData->itemWidth) {
|
|
newLeft -= pData->itemWidth;
|
|
scrollWidth = 1;
|
|
}
|
|
else if (newLeft > 0) {
|
|
newLeft = 0;
|
|
scrollWidth = 1;
|
|
}
|
|
|
|
break;
|
|
|
|
case SB_PAGERIGHT:
|
|
if (newLeft + (pData->itemWidth << 1) <= pData->itemMaxWidth) {
|
|
newLeft += pData->itemWidth;
|
|
scrollWidth = 1;
|
|
}
|
|
else {
|
|
newLeft = pData->itemMaxWidth - pData->itemWidth;
|
|
scrollWidth = 1;
|
|
}
|
|
|
|
break;
|
|
|
|
case SB_THUMBTRACK:
|
|
newLeft = MIN((int)lParam, (pData->itemMaxWidth - pData->itemWidth));
|
|
scrollWidth = (pData->itemLeft - newLeft);
|
|
|
|
break;
|
|
}
|
|
|
|
if (scrollWidth) {
|
|
pData->itemLeft = newLeft;
|
|
lstSetScrollInfo (hwnd, pData, TRUE);
|
|
InvalidateRect (hwnd, NULL, TRUE);
|
|
return 0;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case LB_SETITEMDISABLE:
|
|
{
|
|
PLISTBOXITEM item;
|
|
int index = (int)wParam;
|
|
pData = (PLISTBOXDATA)pCtrl->dwAddData2;
|
|
|
|
if (pData->itemCount <= 0 || index < 0 || index > pData->itemCount)
|
|
return LB_ERR;
|
|
|
|
item = lstGetItem (pData, index);
|
|
if (lParam)
|
|
item->dwFlags |= LBIF_DISABLE;
|
|
else
|
|
item->dwFlags &=~LBIF_DISABLE;
|
|
|
|
return lstInvalidateUnderItem (hwnd, pData, index);
|
|
}
|
|
|
|
case LB_GETITEMDISABLE:
|
|
{
|
|
PLISTBOXITEM item;
|
|
int index = (int)wParam;
|
|
pData = (PLISTBOXDATA)pCtrl->dwAddData2;
|
|
|
|
if (pData->itemCount <= 0 || index < 0 || index > pData->itemCount)
|
|
return LB_ERR;
|
|
item = lstGetItem (pData, index);
|
|
return item->dwFlags&LBIF_DISABLE;
|
|
}
|
|
break;
|
|
|
|
case LB_SETITEMBOLD:
|
|
{
|
|
PLISTBOXITEM item;
|
|
int index = (int) wParam;
|
|
|
|
pData = (PLISTBOXDATA)pCtrl->dwAddData2;
|
|
|
|
if(pData->lst_font == INV_LOGFONT)
|
|
return LB_ERR;
|
|
|
|
if (pData->itemCount <= 0 || index < 0 || index > pData->itemCount)
|
|
return LB_ERR;
|
|
|
|
item = lstGetItem (pData, index);
|
|
|
|
if (lParam)
|
|
item->dwFlags |= LBIF_BOLDSTYLE;
|
|
else
|
|
item->dwFlags &=~LBIF_BOLDSTYLE;
|
|
|
|
return lstInvalidateUnderItem (hwnd, pData, index);
|
|
}
|
|
|
|
case LB_MULTIADDITEM:
|
|
{
|
|
char* string = NULL;
|
|
PLISTBOXITEMINFO plbii = NULL;
|
|
char** stringarray = NULL;
|
|
|
|
PLISTBOXITEM newItem;
|
|
int itemWidth;
|
|
int start, pos = -1;
|
|
int i;
|
|
|
|
pData = (PLISTBOXDATA)pCtrl->dwAddData2;
|
|
start = pData->itemCount;
|
|
|
|
if (dwStyle & LBS_CHECKBOX || dwStyle & LBS_USEICON) {
|
|
plbii = (PLISTBOXITEMINFO)lParam;
|
|
if (!plbii)
|
|
return LB_ERR;
|
|
}
|
|
else {
|
|
stringarray = (char* *)lParam;
|
|
if (stringarray == NULL)
|
|
return LB_ERR;
|
|
}
|
|
|
|
for (i = 0; i < (int)wParam; i++)
|
|
{
|
|
if (dwStyle & LBS_CHECKBOX || dwStyle & LBS_USEICON)
|
|
string = plbii[i].string;
|
|
else
|
|
string = stringarray[i];
|
|
|
|
if(string == NULL || string[0] == '\0')
|
|
break;
|
|
|
|
newItem = lstAllocItem (pData);
|
|
if (!newItem) {
|
|
if (dwStyle & LBS_NOTIFY)
|
|
NotifyParent (hwnd, pCtrl->id, LBN_ERRSPACE);
|
|
return LB_ERRSPACE;
|
|
}
|
|
#if _USE_FIXSTR
|
|
len = strlen (string);
|
|
newItem->key = FixStrAlloc (len);
|
|
if (!newItem->key) {
|
|
lstFreeItem (pData, newItem);
|
|
return LB_ERRSPACE;
|
|
}
|
|
if (len > 0)
|
|
strcpy (newItem->key, string);
|
|
#else
|
|
newItem->key = strdup (string);
|
|
if (!newItem->key) {
|
|
lstFreeItem (pData, newItem);
|
|
return LB_ERRSPACE;
|
|
}
|
|
#endif
|
|
newItem->dwFlags = LBIF_NORMAL;
|
|
|
|
if (dwStyle & LBS_CHECKBOX || dwStyle & LBS_USEICON) {
|
|
if (plbii[i].cmFlag & CMFLAG_CHECKED)
|
|
newItem->dwFlags |= LBIF_CHECKED;
|
|
else if (plbii[i].cmFlag & CMFLAG_PARTCHECKED)
|
|
newItem->dwFlags |= LBIF_PARTCHECKED;
|
|
|
|
if (plbii[i].cmFlag & IMGFLAG_BITMAP)
|
|
newItem->dwFlags |= LBIF_USEBITMAP;
|
|
|
|
if (plbii[i].cmFlag & LBIS_SIGNIFICANT)
|
|
newItem->dwFlags |= LBIF_SIGNIFICANT;
|
|
|
|
if (dwStyle & LBS_USEICON)
|
|
newItem->dwImage = (DWORD)plbii[i].hIcon;
|
|
else
|
|
newItem->dwImage = 0L;
|
|
}
|
|
newItem->dwAddData = 0L;
|
|
pos = lstAddNewItem (dwStyle, pData, newItem, -1);
|
|
|
|
itemWidth = lstGetItemWidth (hwnd, newItem, pData->itemHeight);
|
|
if (pData->itemMaxWidth < itemWidth)
|
|
pData->itemMaxWidth = itemWidth;
|
|
}
|
|
|
|
lstInvalidateUnderMultiItem (hwnd, pData, start, pos);
|
|
lstSetScrollInfo (hwnd, pData, TRUE);
|
|
return pos;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return DefaultControlProc (hwnd, message, wParam, lParam);
|
|
}
|
|
|
|
#endif /* _MGCTRL_LISTBOX */
|
|
|
|
|