blob: 58d204c762b1f7b1ecd9b27889a5061d965cc74d [file] [log] [blame]
/*
* Interface code to listbox widgets
*
* Copyright Martin Ayotte, 1993
* Copyright Constantine Sapuntzakis, 1995
*
static char Copyright[] = "Copyright Martin Ayotte, 1993";
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "windows.h"
#include "user.h"
#include "win.h"
#include "msdos.h"
#include "listbox.h"
#include "dos_fs.h"
#include "stddebug.h"
#include "debug.h"
#define GMEM_ZEROINIT 0x0040
LPLISTSTRUCT ListBoxGetItem (HWND hwnd, UINT uIndex);
int ListBoxScrolltoFocus(HWND hwnd);
LPHEADLIST ListBoxGetWindowAndStorage(HWND hwnd, WND **wndPtr);
LPHEADLIST ListBoxGetStorageHeader(HWND hwnd);
void RepaintListBox(HWND hwnd);
int ListBoxFindMouse(HWND hwnd, int X, int Y);
int CreateListBoxStruct(HWND hwnd);
void ListBoxAskMeasure(WND *wndPtr, LPHEADLIST lphl, LPLISTSTRUCT lpls);
int ListBoxAddString(HWND hwnd, LPSTR newstr);
int ListBoxInsertString(HWND hwnd, UINT uIndex, LPSTR newstr);
int ListBoxGetText(HWND hwnd, UINT uIndex, LPSTR OutStr, BOOL bItemData);
int ListBoxSetItemData(HWND hwnd, UINT uIndex, DWORD ItemData);
int ListBoxDeleteString(HWND hwnd, UINT uIndex);
int ListBoxFindString(HWND hwnd, UINT nFirst, LPSTR MatchStr);
int ListBoxResetContent(HWND hwnd);
int ListBoxSetCurSel(HWND hwnd, WORD wIndex);
int ListBoxSetSel(HWND hwnd, WORD wIndex, WORD state);
int ListBoxGetSel(HWND hwnd, WORD wIndex);
int ListBoxDirectory(HWND hwnd, UINT attrib, LPSTR filespec);
int ListBoxGetItemRect(HWND hwnd, WORD wIndex, LPRECT rect);
int ListBoxSetItemHeight(HWND hwnd, WORD wIndex, long height);
int ListBoxDefaultItem(HWND hwnd, WND *wndPtr,
LPHEADLIST lphl, LPLISTSTRUCT lpls);
int ListBoxFindNextMatch(HWND hwnd, WORD wChar);
int ListMaxFirstVisible(LPHEADLIST lphl);
void ListBoxSendNotification(HWND hwnd, WORD code);
#define OWNER_DRAWN(wndPtr) \
((wndPtr->dwStyle & LBS_OWNERDRAWFIXED) || \
(wndPtr->dwStyle & LBS_OWNERDRAWVARIABLE))
#define HasStrings(wndPtr) ( \
(! OWNER_DRAWN (wndPtr)) || \
(wndPtr->dwStyle & LBS_HASSTRINGS))
#if 0
#define LIST_HEAP_ALLOC(lphl,f,size) ((int)HEAP_Alloc(&lphl->Heap,f,size) & 0xffff)
#define LIST_HEAP_FREE(lphl,handle) (HEAP_Free(&lphl->Heap,LIST_HEAP_ADDR(lphl,handle)))
#define LIST_HEAP_ADDR(lphl,handle) \
((void *)((handle) ? ((handle) | ((int)lphl->Heap & 0xffff0000)) : 0))
#else
#define LIST_HEAP_ALLOC(lphl,f,size) USER_HEAP_ALLOC(size)
#define LIST_HEAP_FREE(lphl,handle) USER_HEAP_FREE(handle)
#define LIST_HEAP_ADDR(lphl,handle) USER_HEAP_LIN_ADDR(handle)
#endif
#define LIST_HEAP_SIZE 0x10000
/* Design notes go here */
LONG LBCreate( HWND hwnd, WORD message, WORD wParam, LONG lParam );
LONG LBGetDlgCode( HWND hwnd, WORD message, WORD wParam, LONG lParam );
LONG LBDestroy( HWND hwnd, WORD message, WORD wParam, LONG lParam );
LONG LBVScroll( HWND hwnd, WORD message, WORD wParam, LONG lParam );
LONG LBHScroll( HWND hwnd, WORD message, WORD wParam, LONG lParam );
LONG LBLButtonDown( HWND hwnd, WORD message, WORD wParam, LONG lParam );
LONG LBLButtonUp( HWND hwnd, WORD message, WORD wParam, LONG lParam );
LONG LBRButtonUp( HWND hwnd, WORD message, WORD wParam, LONG lParam );
LONG LBMouseMove( HWND hwnd, WORD message, WORD wParam, LONG lParam );
LONG LBKeyDown( HWND hwnd, WORD message, WORD wParam, LONG lParam );
LONG LBSetFont( HWND hwnd, WORD message, WORD wParam, LONG lParam );
LONG LBSetRedraw( HWND hwnd, WORD message, WORD wParam, LONG lParam );
LONG LBPaint( HWND hwnd, WORD message, WORD wParam, LONG lParam );
LONG LBSetFocus( HWND hwnd, WORD message, WORD wParam, LONG lParam );
LONG LBKillFocus( HWND hwnd, WORD message, WORD wParam, LONG lParam );
LONG LBResetContent( HWND hwnd, WORD message, WORD wParam, LONG lParam );
LONG LBDir( HWND hwnd, WORD message, WORD wParam, LONG lParam );
LONG LBAddString( HWND hwnd, WORD message, WORD wParam, LONG lParam );
LONG LBGetText( HWND hwnd, WORD message, WORD wParam, LONG lParam );
LONG LBInsertString( HWND hwnd, WORD message, WORD wParam, LONG lParam );
LONG LBDeleteString( HWND hwnd, WORD message, WORD wParam, LONG lParam );
LONG LBFindString( HWND hwnd, WORD message, WORD wParam, LONG lParam );
LONG LBGetCaretIndex( HWND hwnd, WORD message, WORD wParam, LONG lParam );
LONG LBGetCount( HWND hwnd, WORD message, WORD wParam, LONG lParam );
LONG LBGetCurSel( HWND hwnd, WORD message, WORD wParam, LONG lParam );
LONG LBGetHorizontalExtent(HWND hwnd, WORD message, WORD wParam, LONG lParam );
LONG LBGetItemData( HWND hwnd, WORD message, WORD wParam, LONG lParam );
LONG LBGetItemHeight( HWND hwnd, WORD message, WORD wParam, LONG lParam );
LONG LBGetItemRect( HWND hwnd, WORD message, WORD wParam, LONG lParam );
LONG LBGetSel( HWND hwnd, WORD message, WORD wParam, LONG lParam );
LONG LBGetSelCount( HWND hwnd, WORD message, WORD wParam, LONG lParam );
LONG LBGetSelItems( HWND hwnd, WORD message, WORD wParam, LONG lParam );
LONG LBGetTextLen( HWND hwnd, WORD message, WORD wParam, LONG lParam );
LONG LBGetTopIndex( HWND hwnd, WORD message, WORD wParam, LONG lParam );
LONG LBSelectString( HWND hwnd, WORD message, WORD wParam, LONG lParam );
LONG LBSelItemRange( HWND hwnd, WORD message, WORD wParam, LONG lParam );
LONG LBSetCaretIndex( HWND hwnd, WORD message, WORD wParam, LONG lParam );
LONG LBSetColumnWidth( HWND hwnd, WORD message, WORD wParam, LONG lParam );
LONG LBSetHorizontalExtent(HWND hwnd, WORD message, WORD wParam, LONG lParam );
LONG LBSetItemData( HWND hwnd, WORD message, WORD wParam, LONG lParam );
LONG LBSetTabStops( HWND hwnd, WORD message, WORD wParam, LONG lParam );
LONG LBSetCurSel( HWND hwnd, WORD message, WORD wParam, LONG lParam );
LONG LBSetSel( HWND hwnd, WORD message, WORD wParam, LONG lParam );
LONG LBSetTopIndex( HWND hwnd, WORD message, WORD wParam, LONG lParam );
LONG LBSetItemHeight( HWND hwnd, WORD message, WORD wParam, LONG lParam );
typedef struct {
WORD message;
LONG (*handler)(HWND, WORD, WPARAM, LPARAM);
} msg_tbl;
static msg_tbl methods[] = {
{WM_CREATE, LBCreate},
{WM_DESTROY, LBDestroy},
{WM_GETDLGCODE, LBGetDlgCode},
{WM_VSCROLL, LBVScroll},
{WM_HSCROLL, LBHScroll},
{WM_LBUTTONDOWN, LBLButtonDown},
{WM_LBUTTONUP, LBLButtonUp},
{WM_RBUTTONUP, LBRButtonUp},
{WM_LBUTTONDBLCLK, LBRButtonUp},
{WM_MOUSEMOVE, LBMouseMove},
{WM_KEYDOWN, LBKeyDown},
{WM_SETFONT, LBSetFont},
{WM_SETREDRAW, LBSetRedraw},
{WM_PAINT, LBPaint},
{WM_SETFOCUS, LBSetFocus},
{WM_KILLFOCUS, LBKillFocus},
{LB_RESETCONTENT, LBResetContent},
{LB_DIR, LBDir},
{LB_ADDSTRING, LBAddString},
{LB_INSERTSTRING, LBInsertString},
{LB_DELETESTRING, LBDeleteString},
{LB_FINDSTRING, LBFindString},
{LB_GETCARETINDEX, LBGetCaretIndex},
{LB_GETCOUNT, LBGetCount},
{LB_GETCURSEL, LBGetCurSel},
{LB_GETHORIZONTALEXTENT, LBGetHorizontalExtent},
{LB_GETITEMDATA, LBGetItemData},
{LB_GETITEMHEIGHT, LBGetItemHeight},
{LB_GETITEMRECT, LBGetItemRect},
{LB_GETSEL, LBGetSel},
{LB_GETSELCOUNT, LBGetSelCount},
{LB_GETSELITEMS, LBGetSelItems},
{LB_GETTEXT, LBGetText},
{LB_GETTEXTLEN, LBGetTextLen},
{LB_GETTOPINDEX, LBGetTopIndex},
{LB_SELECTSTRING, LBSelectString},
{LB_SELITEMRANGE, LBSelItemRange},
{LB_SETCARETINDEX, LBSetCaretIndex},
{LB_SETCOLUMNWIDTH, LBSetColumnWidth},
{LB_SETHORIZONTALEXTENT, LBSetHorizontalExtent},
{LB_SETITEMDATA, LBSetItemData},
{LB_SETTABSTOPS, LBSetTabStops},
{LB_SETCURSEL, LBSetCurSel},
{LB_SETSEL, LBSetSel},
{LB_SETTOPINDEX, LBSetTopIndex},
{LB_SETITEMHEIGHT, LBSetItemHeight}
};
/***********************************************************************
* LBCreate
*/
LONG LBCreate( HWND hwnd, WORD message, WORD wParam, LONG lParam )
{
LPHEADLIST lphl;
CREATESTRUCT *createStruct;
WND *wndPtr;
CreateListBoxStruct(hwnd);
lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
dprintf_listbox(stddeb,"ListBox WM_CREATE %p !\n", lphl);
if (lphl == NULL) return 0;
createStruct = (CREATESTRUCT *)PTR_SEG_TO_LIN(lParam);
if (HIWORD(createStruct->lpCreateParams) != 0)
lphl->hWndLogicParent = (HWND)HIWORD(createStruct->lpCreateParams);
else
lphl->hWndLogicParent = GetParent(hwnd);
lphl->hFont = GetStockObject(SYSTEM_FONT);
lphl->ColumnsWidth = wndPtr->rectClient.right - wndPtr->rectClient.left;
SetScrollRange(hwnd, SB_VERT, 1, ListMaxFirstVisible(lphl), TRUE);
SetScrollRange(hwnd, SB_HORZ, 1, 1, TRUE);
return 0;
}
int CreateListBoxStruct(HWND hwnd)
{
WND *wndPtr;
LPHEADLIST lphl;
wndPtr = WIN_FindWndPtr(hwnd);
lphl = (LPHEADLIST)malloc(sizeof(HEADLIST));
*((LPHEADLIST *)&wndPtr->wExtra[1]) = lphl;
lphl->lpFirst = NULL;
lphl->ItemsCount = 0;
lphl->ItemsVisible = 0;
lphl->FirstVisible = 1;
lphl->ColumnsVisible = 1;
lphl->ItemsPerColumn = 0;
lphl->StdItemHeight = 15;
lphl->ItemFocused = -1;
lphl->PrevFocused = -1;
lphl->DrawCtlType = ODT_LISTBOX;
lphl->bRedrawFlag = TRUE;
lphl->iNumStops = 0;
lphl->TabStops = NULL;
if (OWNER_DRAWN(wndPtr))
lphl->hDrawItemStruct = USER_HEAP_ALLOC(sizeof(DRAWITEMSTRUCT));
else
lphl->hDrawItemStruct = 0;
#if 0
HeapHandle = GlobalAlloc(GMEM_FIXED, LIST_HEAP_SIZE);
HeapBase = GlobalLock(HeapHandle);
HEAP_Init(&lphl->Heap, HeapBase, LIST_HEAP_SIZE);
#endif
return TRUE;
}
/***********************************************************************
* LBDestroy
*/
LONG LBDestroy( HWND hwnd, WORD message, WORD wParam, LONG lParam )
{
LPHEADLIST lphl;
WND *wndPtr;
lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
if (lphl == NULL) return 0;
ListBoxResetContent(hwnd);
if (lphl->hDrawItemStruct)
USER_HEAP_FREE(lphl->hDrawItemStruct);
/* XXX need to free lphl->Heap */
free(lphl);
*((LPHEADLIST *)&wndPtr->wExtra[1]) = 0;
dprintf_listbox(stddeb,"ListBox WM_DESTROY %p !\n", lphl);
return 0;
}
/* get the maximum value of lphl->FirstVisible */
int ListMaxFirstVisible(LPHEADLIST lphl)
{
int m = lphl->ItemsCount-lphl->ItemsVisible+1;
return (m < 1) ? 1 : m;
}
/***********************************************************************
* LBVScroll
*/
LONG LBVScroll( HWND hwnd, WORD message, WORD wParam, LONG lParam )
{
LPHEADLIST lphl;
int y;
dprintf_listbox(stddeb,"ListBox WM_VSCROLL w=%04X l=%08lX !\n",
wParam, lParam);
lphl = ListBoxGetStorageHeader(hwnd);
if (lphl == NULL) return 0;
y = lphl->FirstVisible;
switch(wParam) {
case SB_LINEUP:
if (lphl->FirstVisible > 1)
lphl->FirstVisible--;
break;
case SB_LINEDOWN:
if (lphl->FirstVisible < ListMaxFirstVisible(lphl))
lphl->FirstVisible++;
break;
case SB_PAGEUP:
if (lphl->FirstVisible > 1)
lphl->FirstVisible -= lphl->ItemsVisible;
break;
case SB_PAGEDOWN:
if (lphl->FirstVisible < ListMaxFirstVisible(lphl))
lphl->FirstVisible += lphl->ItemsVisible;
break;
case SB_THUMBTRACK:
lphl->FirstVisible = LOWORD(lParam);
break;
}
if (lphl->FirstVisible < 1) lphl->FirstVisible = 1;
if (lphl->FirstVisible > ListMaxFirstVisible(lphl))
lphl->FirstVisible = ListMaxFirstVisible(lphl);
if (y != lphl->FirstVisible) {
SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
InvalidateRect(hwnd, NULL, TRUE);
UpdateWindow(hwnd);
}
return 0;
}
/***********************************************************************
* LBHScroll
*/
LONG LBHScroll( HWND hwnd, WORD message, WORD wParam, LONG lParam )
{
LPHEADLIST lphl;
int y;
dprintf_listbox(stddeb,"ListBox WM_HSCROLL w=%04X l=%08lX !\n",
wParam, lParam);
lphl = ListBoxGetStorageHeader(hwnd);
if (lphl == NULL) return 0;
y = lphl->FirstVisible;
switch(wParam) {
case SB_LINEUP:
if (lphl->FirstVisible > 1)
lphl->FirstVisible -= lphl->ItemsPerColumn;
break;
case SB_LINEDOWN:
if (lphl->FirstVisible < ListMaxFirstVisible(lphl))
lphl->FirstVisible += lphl->ItemsPerColumn;
break;
case SB_PAGEUP:
if (lphl->FirstVisible > 1 && lphl->ItemsPerColumn != 0)
lphl->FirstVisible -= lphl->ItemsVisible /
lphl->ItemsPerColumn * lphl->ItemsPerColumn;
break;
case SB_PAGEDOWN:
if (lphl->FirstVisible < ListMaxFirstVisible(lphl) &&
lphl->ItemsPerColumn != 0)
lphl->FirstVisible += lphl->ItemsVisible /
lphl->ItemsPerColumn * lphl->ItemsPerColumn;
break;
case SB_THUMBTRACK:
lphl->FirstVisible = lphl->ItemsPerColumn *
(LOWORD(lParam) - 1) + 1;
break;
}
if (lphl->FirstVisible < 1) lphl->FirstVisible = 1;
if (lphl->FirstVisible > ListMaxFirstVisible(lphl))
lphl->FirstVisible = ListMaxFirstVisible(lphl);
if (lphl->ItemsPerColumn != 0) {
lphl->FirstVisible = lphl->FirstVisible /
lphl->ItemsPerColumn * lphl->ItemsPerColumn + 1;
if (y != lphl->FirstVisible) {
SetScrollPos(hwnd, SB_HORZ, lphl->FirstVisible /
lphl->ItemsPerColumn + 1, TRUE);
InvalidateRect(hwnd, NULL, TRUE);
UpdateWindow(hwnd);
}
}
return 0;
}
/***********************************************************************
* LBLButtonDown
*/
LONG LBLButtonDown( HWND hwnd, WORD message, WORD wParam, LONG lParam )
{
LPHEADLIST lphl;
WND *wndPtr;
WORD wRet;
int y;
RECT rectsel;
SetFocus(hwnd);
SetCapture(hwnd);
lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
if (lphl == NULL) return 0;
lphl->PrevFocused = lphl->ItemFocused;
y = ListBoxFindMouse(hwnd, LOWORD(lParam), HIWORD(lParam));
if (y==-1)
return 0;
if (wndPtr->dwStyle & LBS_MULTIPLESEL) {
lphl->ItemFocused = y;
wRet = ListBoxGetSel(hwnd, y);
ListBoxSetSel(hwnd, y, !wRet);
}
else
ListBoxSetCurSel(hwnd, y);
if (wndPtr->dwStyle & LBS_MULTIPLESEL)
ListBoxSendNotification( hwnd, LBN_SELCHANGE );
ListBoxGetItemRect(hwnd, y, &rectsel);
InvalidateRect(hwnd, NULL, TRUE);
UpdateWindow(hwnd);
return 0;
}
/***********************************************************************
* LBLButtonUp
*/
LONG LBLButtonUp( HWND hwnd, WORD message, WORD wParam, LONG lParam )
{
LPHEADLIST lphl;
WND *wndPtr;
ReleaseCapture();
lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
if (lphl == NULL) return 0;
if (lphl->PrevFocused != lphl->ItemFocused)
ListBoxSendNotification( hwnd, LBN_SELCHANGE );
return 0;
}
/***********************************************************************
* LBRButtonUp
*/
LONG LBRButtonUp( HWND hwnd, WORD message, WORD wParam, LONG lParam )
{
LPHEADLIST lphl;
WND *wndPtr;
lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
if (lphl == NULL) return 0;
SendMessage(lphl->hWndLogicParent, WM_COMMAND, wndPtr->wIDmenu,
MAKELONG(hwnd, LBN_DBLCLK));
return 0;
}
/***********************************************************************
* LBMouseMove
*/
LONG LBMouseMove( HWND hwnd, WORD message, WORD wParam, LONG lParam )
{
LPHEADLIST lphl;
WND *wndPtr;
int y;
WORD wRet;
RECT rect, rectsel; /* XXX Broken */
lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
if (lphl == NULL) return 0;
if ((wParam & MK_LBUTTON) != 0) {
y = HIWORD(lParam);
if (y < 4) {
if (lphl->FirstVisible > 1) {
lphl->FirstVisible--;
SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
InvalidateRect(hwnd, NULL, TRUE);
UpdateWindow(hwnd);
return 0;
}
}
GetClientRect(hwnd, &rect);
if (y > (rect.bottom - 4)) {
if (lphl->FirstVisible < ListMaxFirstVisible(lphl)) {
lphl->FirstVisible++;
SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
InvalidateRect(hwnd, NULL, TRUE);
UpdateWindow(hwnd);
return 0;
}
}
if ((y > 0) && (y < (rect.bottom - 4))) {
if ((y < rectsel.top) || (y > rectsel.bottom)) {
wRet = ListBoxFindMouse(hwnd, LOWORD(lParam), HIWORD(lParam));
if ((wndPtr->dwStyle & LBS_MULTIPLESEL) == LBS_MULTIPLESEL) {
lphl->ItemFocused = wRet;
ListBoxSendNotification(hwnd, LBN_SELCHANGE);
}
else
ListBoxSetCurSel(hwnd, wRet);
ListBoxGetItemRect(hwnd, wRet, &rectsel);
InvalidateRect(hwnd, NULL, TRUE);
UpdateWindow(hwnd);
}
}
}
return 0;
}
/***********************************************************************
* LBKeyDown
*/
LONG LBKeyDown( HWND hwnd, WORD message, WORD wParam, LONG lParam )
{
LPHEADLIST lphl;
WND *wndPtr;
HWND hWndCtl;
WORD wRet;
lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
if (lphl == NULL) return 0;
switch(wParam) {
case VK_TAB:
hWndCtl = GetNextDlgTabItem(lphl->hWndLogicParent,
hwnd, !(GetKeyState(VK_SHIFT) < 0));
SetFocus(hWndCtl);
if(debugging_listbox){
if ((GetKeyState(VK_SHIFT) < 0))
dprintf_listbox(stddeb,"ListBox PreviousDlgTabItem %04X !\n", hWndCtl);
else
dprintf_listbox(stddeb,"ListBox NextDlgTabItem %04X !\n", hWndCtl);
}
break;
case VK_HOME:
lphl->ItemFocused = 0;
break;
case VK_END:
lphl->ItemFocused = lphl->ItemsCount - 1;
break;
case VK_LEFT:
if ((wndPtr->dwStyle & LBS_MULTICOLUMN) == LBS_MULTICOLUMN) {
lphl->ItemFocused -= lphl->ItemsPerColumn;
}
break;
case VK_UP:
lphl->ItemFocused--;
break;
case VK_RIGHT:
if ((wndPtr->dwStyle & LBS_MULTICOLUMN) == LBS_MULTICOLUMN) {
lphl->ItemFocused += lphl->ItemsPerColumn;
}
break;
case VK_DOWN:
lphl->ItemFocused++;
break;
case VK_PRIOR:
lphl->ItemFocused -= lphl->ItemsVisible;
break;
case VK_NEXT:
lphl->ItemFocused += lphl->ItemsVisible;
break;
case VK_SPACE:
wRet = ListBoxGetSel(hwnd, lphl->ItemFocused);
ListBoxSetSel(hwnd, lphl->ItemFocused, !wRet);
break;
default:
ListBoxFindNextMatch(hwnd, wParam);
return 0;
}
if (lphl->ItemFocused < 0) lphl->ItemFocused = 0;
if (lphl->ItemFocused >= lphl->ItemsCount)
lphl->ItemFocused = lphl->ItemsCount - 1;
if (lphl->ItemsVisible != 0)
lphl->FirstVisible = lphl->ItemFocused / lphl->ItemsVisible *
lphl->ItemsVisible + 1;
if (lphl->FirstVisible < 1) lphl->FirstVisible = 1;
if (lphl->FirstVisible > ListMaxFirstVisible(lphl))
lphl->FirstVisible = ListMaxFirstVisible(lphl);
if ((wndPtr->dwStyle & LBS_MULTIPLESEL) != LBS_MULTIPLESEL) {
ListBoxSetCurSel(hwnd, lphl->ItemFocused);
ListBoxSendNotification(hwnd, LBN_SELCHANGE);
}
SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
InvalidateRect(hwnd, NULL, TRUE);
UpdateWindow(hwnd);
return 0;
}
/***********************************************************************
* LBSetRedraw
*/
LONG LBSetRedraw( HWND hwnd, WORD message, WORD wParam, LONG lParam )
{
LPHEADLIST lphl;
WND *wndPtr;
dprintf_listbox(stddeb,"ListBox WM_SETREDRAW hWnd=%04X w=%04X !\n", hwnd, wParam);
lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
if (lphl == NULL) return 0;
lphl->bRedrawFlag = wParam;
return 0;
}
/***********************************************************************
* LBSetFont
*/
LONG LBSetFont( HWND hwnd, WORD message, WORD wParam, LONG lParam )
{
LPHEADLIST lphl;
WND *wndPtr;
lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
if (lphl == NULL) return 0;
if (wParam == 0)
lphl->hFont = GetStockObject(SYSTEM_FONT);
else
lphl->hFont = wParam;
return 0;
}
/***********************************************************************
* LBPaint
*/
LONG LBPaint( HWND hwnd, WORD message, WORD wParam, LONG lParam )
{
RepaintListBox(hwnd);
return 0;
}
/***********************************************************************
* LBSetFocus
*/
LONG LBSetFocus( HWND hwnd, WORD message, WORD wParam, LONG lParam )
{
LPHEADLIST lphl;
WND *wndPtr;
dprintf_listbox(stddeb,"ListBox WM_SETFOCUS !\n");
lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
return 0;
}
/***********************************************************************
* LBKillFocus
*/
LONG LBKillFocus( HWND hwnd, WORD message, WORD wParam, LONG lParam )
{
dprintf_listbox(stddeb,"ListBox WM_KILLFOCUS !\n");
InvalidateRect(hwnd, NULL, TRUE);
UpdateWindow(hwnd);
return 0;
}
/***********************************************************************
* LBResetContent
*/
LONG LBResetContent( HWND hwnd, WORD message, WORD wParam, LONG lParam )
{
dprintf_listbox(stddeb,"ListBox LB_RESETCONTENT !\n");
ListBoxResetContent(hwnd);
return 0;
}
/***********************************************************************
* LBDir
*/
LONG LBDir( HWND hwnd, WORD message, WORD wParam, LONG lParam )
{
WORD wRet;
dprintf_listbox(stddeb,"ListBox LB_DIR !\n");
wRet = ListBoxDirectory(hwnd, wParam,
(LPSTR)PTR_SEG_TO_LIN(lParam));
InvalidateRect(hwnd, NULL, TRUE);
UpdateWindow(hwnd);
return wRet;
}
/***********************************************************************
* LBAddString
*/
LONG LBAddString( HWND hwnd, WORD message, WORD wParam, LONG lParam )
{
WORD wRet;
WND *wndPtr;
wndPtr = WIN_FindWndPtr(hwnd);
if (HasStrings(wndPtr))
wRet = ListBoxAddString(hwnd, (LPSTR)PTR_SEG_TO_LIN(lParam));
else
wRet = ListBoxAddString(hwnd, (LPSTR)lParam);
return wRet;
}
/***********************************************************************
* LBGetText
*/
LONG LBGetText( HWND hwnd, WORD message, WORD wParam, LONG lParam )
{
LONG wRet;
dprintf_listbox(stddeb, "LB_GETTEXT wParam=%d\n",wParam);
wRet = ListBoxGetText(hwnd, wParam,
(LPSTR)PTR_SEG_TO_LIN(lParam), FALSE);
return wRet;
}
/***********************************************************************
* LBInsertString
*/
LONG LBInsertString( HWND hwnd, WORD message, WORD wParam, LONG lParam )
{
WORD wRet;
WND *wndPtr;
wndPtr = WIN_FindWndPtr(hwnd);
if (HasStrings(wndPtr))
wRet = ListBoxInsertString(hwnd, wParam, (LPSTR)PTR_SEG_TO_LIN(lParam));
else
wRet = ListBoxInsertString(hwnd, wParam, (LPSTR)lParam);
return wRet;
}
/***********************************************************************
* LBDeleteString
*/
LONG LBDeleteString( HWND hwnd, WORD message, WORD wParam, LONG lParam )
{
return ListBoxDeleteString(hwnd, wParam);
}
/***********************************************************************
* LBFindString
*/
LONG LBFindString( HWND hwnd, WORD message, WORD wParam, LONG lParam )
{
return ListBoxFindString(hwnd, wParam,
(LPSTR)PTR_SEG_TO_LIN(lParam));
}
/***********************************************************************
* LBGetCaretIndex
*/
LONG LBGetCaretIndex( HWND hwnd, WORD message, WORD wParam, LONG lParam )
{
LPHEADLIST lphl;
lphl = ListBoxGetStorageHeader(hwnd);
if (lphl == NULL) return LB_ERR;
return lphl->ItemFocused;
}
/***********************************************************************
* LBGetCount
*/
LONG LBGetCount( HWND hwnd, WORD message, WORD wParam, LONG lParam )
{
LPHEADLIST lphl;
lphl = ListBoxGetStorageHeader(hwnd);
return lphl->ItemsCount;
}
/***********************************************************************
* LBGetCurSel
*/
LONG LBGetCurSel( HWND hwnd, WORD message, WORD wParam, LONG lParam )
{
LPHEADLIST lphl;
lphl = ListBoxGetStorageHeader(hwnd);
dprintf_listbox(stddeb,"ListBox LB_GETCURSEL %u !\n",
lphl->ItemFocused);
return lphl->ItemFocused;
}
/***********************************************************************
* LBGetHorizontalExtent
*/
LONG LBGetHorizontalExtent( HWND hwnd, WORD message, WORD wParam, LONG lParam )
{
return 0;
}
/***********************************************************************
* LBGetItemData
*/
LONG LBGetItemData( HWND hwnd, WORD message, WORD wParam, LONG lParam )
{
dprintf_listbox(stddeb, "LB_GETITEMDATA wParam=%x\n", wParam);
return ListBoxGetText(hwnd, wParam,
(LPSTR)PTR_SEG_TO_LIN(lParam), TRUE);
}
/***********************************************************************
* LBGetItemHeight
*/
LONG LBGetItemHeight( HWND hwnd, WORD message, WORD wParam, LONG lParam )
{
RECT rect;
ListBoxGetItemRect(hwnd, wParam, &rect);
return (rect.bottom - rect.top);
}
/***********************************************************************
* LBGetItemRect
*/
LONG LBGetItemRect( HWND hwnd, WORD message, WORD wParam, LONG lParam )
{
return ListBoxGetItemRect (hwnd, wParam, PTR_SEG_TO_LIN(lParam));
}
/***********************************************************************
* LBGetSel
*/
LONG LBGetSel( HWND hwnd, WORD message, WORD wParam, LONG lParam )
{
return ListBoxGetSel (hwnd, wParam);
}
/***********************************************************************
* LBGetSelCount
*/
LONG LBGetSelCount( HWND hwnd, WORD message, WORD wParam, LONG lParam )
{
LPHEADLIST lphl;
LPLISTSTRUCT lpls;
int cnt = 0;
WND *wndPtr;
lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
if (lphl == NULL) return LB_ERR;
if (!(wndPtr->dwStyle & LBS_MULTIPLESEL)) return LB_ERR;
lpls = lphl->lpFirst;
while (lpls != NULL) {
if (lpls->dis.itemState > 0) cnt++;
lpls = lpls->lpNext;
}
return cnt;
}
/***********************************************************************
* LBGetSelItems
*/
LONG LBGetSelItems( HWND hwnd, WORD message, WORD wParam, LONG lParam )
{
LPHEADLIST lphl;
LPLISTSTRUCT lpls;
int cnt, idx;
WND *wndPtr;
int *lpItems = PTR_SEG_TO_LIN(lParam);
lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
if (lphl == NULL) return LB_ERR;
if (!(wndPtr->dwStyle & LBS_MULTIPLESEL)) return LB_ERR;
if (wParam == 0) return 0;
lpls = lphl->lpFirst;
cnt = 0; idx = 0;
while (lpls != NULL) {
if (lpls->dis.itemState > 0) lpItems[cnt++] = idx;
if (cnt == wParam) break;
idx++;
lpls = lpls->lpNext;
}
return cnt;
}
/***********************************************************************
* LBGetTextLen
*/
LONG LBGetTextLen( HWND hwnd, WORD message, WORD wParam, LONG lParam )
{
LPHEADLIST lphl;
LPLISTSTRUCT lpls;
WND *wndPtr;
int cnt = 0;
lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
if (lphl == NULL) return LB_ERR;
if (!HasStrings(wndPtr)) return LB_ERR;
if (wParam >= lphl->ItemsCount) return LB_ERR;
lpls = lphl->lpFirst;
while (cnt++ < wParam) lpls = lpls->lpNext;
return strlen(lpls->itemText);
}
/***********************************************************************
* LBGetDlgCode
*/
LONG LBGetDlgCode( HWND hwnd, WORD message, WORD wParam, LONG lParam )
{
return DLGC_WANTALLKEYS;
}
/***********************************************************************
* LBGetTopIndex
*/
LONG LBGetTopIndex( HWND hwnd, WORD message, WORD wParam, LONG lParam )
{
LPHEADLIST lphl;
lphl = ListBoxGetStorageHeader(hwnd);
if (lphl == NULL) return LB_ERR;
return (lphl->FirstVisible - 1);
}
/***********************************************************************
* LBSelectString
*/
LONG LBSelectString( HWND hwnd, WORD message, WORD wParam, LONG lParam )
{
WND *wndPtr;
WORD wRet;
wndPtr = WIN_FindWndPtr(hwnd);
wRet = ListBoxFindString(hwnd, wParam,
(LPSTR)PTR_SEG_TO_LIN(lParam));
/* XXX add functionality here */
return 0;
}
/***********************************************************************
* LBSelItemRange
*/
LONG LBSelItemRange( HWND hwnd, WORD message, WORD wParam, LONG lParam )
{
LPHEADLIST lphl;
LPLISTSTRUCT lpls;
WND *wndPtr;
WORD cnt;
WORD first = LOWORD(lParam);
WORD last = HIWORD(lParam);
BOOL select = wParam;
lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
if (lphl == NULL) return LB_ERR;
if (!(wndPtr->dwStyle & LBS_MULTIPLESEL)) return LB_ERR;
if (first >= lphl->ItemsCount ||
last >= lphl->ItemsCount) return LB_ERR;
lpls = lphl->lpFirst;
cnt = 0;
while (lpls != NULL) {
if (cnt++ >= first)
lpls->dis.itemState = select ? ODS_SELECTED : 0;
if (cnt > last)
break;
lpls = lpls->lpNext;
}
return 0;
}
/***********************************************************************
* LBSetCaretIndex
*/
LONG LBSetCaretIndex( HWND hwnd, WORD message, WORD wParam, LONG lParam )
{
LPHEADLIST lphl;
WND *wndPtr;
lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
if (lphl == NULL) return LB_ERR;
if (!(wndPtr->dwStyle & LBS_MULTIPLESEL)) return 0;
if (wParam >= lphl->ItemsCount) return LB_ERR;
lphl->ItemFocused = wParam;
ListBoxScrolltoFocus (hwnd);
SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
InvalidateRect(hwnd, NULL, TRUE);
UpdateWindow(hwnd);
return 0;
}
/***********************************************************************
* LBSetColumnWidth
*/
LONG LBSetColumnWidth( HWND hwnd, WORD message, WORD wParam, LONG lParam )
{
LPHEADLIST lphl;
lphl = ListBoxGetStorageHeader(hwnd);
if (lphl == NULL) return LB_ERR;
lphl->ColumnsWidth = wParam;
return 0;
}
/***********************************************************************
* LBSetHorizontalExtent
*/
LONG LBSetHorizontalExtent( HWND hwnd, WORD message, WORD wParam, LONG lParam )
{
return 0;
}
/***********************************************************************
* LBSetItemData
*/
LONG LBSetItemData( HWND hwnd, WORD message, WORD wParam, LONG lParam )
{
dprintf_listbox(stddeb, "LB_SETITEMDATA wParam=%x lParam=%lx\n", wParam, lParam);
return ListBoxSetItemData(hwnd, wParam, lParam);
}
/***********************************************************************
* LBSetTabStops
*/
LONG LBSetTabStops( HWND hwnd, WORD message, WORD wParam, LONG lParam )
{
LPHEADLIST lphl;
lphl = ListBoxGetStorageHeader(hwnd);
if (lphl->TabStops != NULL) {
lphl->iNumStops = 0;
free (lphl->TabStops);
}
lphl->TabStops = malloc (wParam * sizeof (short));
if (lphl->TabStops) {
lphl->iNumStops = wParam;
memcpy (lphl->TabStops, PTR_SEG_TO_LIN(lParam), wParam * sizeof (short));
return TRUE;
}
return FALSE;
}
/***********************************************************************
* LBSetCurSel
*/
LONG LBSetCurSel( HWND hwnd, WORD message, WORD wParam, LONG lParam )
{
LPHEADLIST lphl;
WORD wRet;
lphl = ListBoxGetStorageHeader(hwnd);
if (lphl == NULL) return LB_ERR;
dprintf_listbox(stddeb,"ListBox LB_SETCURSEL wParam=%x !\n",
wParam);
wRet = ListBoxSetCurSel(hwnd, wParam);
SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
InvalidateRect(hwnd, NULL, TRUE);
UpdateWindow(hwnd);
return wRet;
}
/***********************************************************************
* LBSetSel
*/
LONG LBSetSel( HWND hwnd, WORD message, WORD wParam, LONG lParam )
{
WORD wRet;
dprintf_listbox(stddeb,"ListBox LB_SETSEL wParam=%x lParam=%lX !\n", wParam, lParam);
wRet = ListBoxSetSel(hwnd, LOWORD(lParam), wParam);
InvalidateRect(hwnd, NULL, TRUE);
UpdateWindow(hwnd);
return wRet;
}
/***********************************************************************
* LBSetTopIndex
*/
LONG LBSetTopIndex( HWND hwnd, WORD message, WORD wParam, LONG lParam )
{
LPHEADLIST lphl;
dprintf_listbox(stddeb,"ListBox LB_SETTOPINDEX wParam=%x !\n",
wParam);
lphl = ListBoxGetStorageHeader(hwnd);
lphl->FirstVisible = wParam;
SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
InvalidateRect(hwnd, NULL, TRUE);
UpdateWindow(hwnd);
return 0;
}
/***********************************************************************
* LBSetItemHeight
*/
LONG LBSetItemHeight( HWND hwnd, WORD message, WORD wParam, LONG lParam)
{
WORD wRet;
dprintf_listbox(stddeb,"ListBox LB_SETITEMHEIGHT wParam=%x lParam=%lX !\n", wParam, lParam);
wRet = ListBoxSetItemHeight(hwnd, wParam, lParam);
return wRet;
}
/***********************************************************************
* ListBoxWndProc
*/
LONG ListBoxWndProc( HWND hwnd, WORD message, WORD wParam, LONG lParam )
{
int idx = 0;
int table_size = sizeof (methods) / sizeof (msg_tbl);
while (idx < table_size) {
if (message == methods[idx].message) {
return (*(methods[idx].handler))(hwnd, message, wParam, lParam);
}
idx++;
}
return DefWindowProc (hwnd, message, wParam, lParam);
}
LPLISTSTRUCT ListBoxGetItem(HWND hwnd, UINT uIndex)
{
LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
LPLISTSTRUCT lpls;
UINT Count = 0;
if (uIndex >= lphl->ItemsCount) return NULL;
lpls = lphl->lpFirst;
while (Count++ < uIndex) lpls = lpls->lpNext;
return lpls;
}
LPHEADLIST ListBoxGetWindowAndStorage(HWND hwnd, WND **wndPtr)
{
WND *Ptr;
LPHEADLIST lphl;
*(wndPtr) = Ptr = WIN_FindWndPtr(hwnd);
lphl = *((LPHEADLIST *)&Ptr->wExtra[1]);
return lphl;
}
LPHEADLIST ListBoxGetStorageHeader(HWND hwnd)
{
WND *wndPtr;
LPHEADLIST lphl;
wndPtr = WIN_FindWndPtr(hwnd);
lphl = *((LPHEADLIST *)&wndPtr->wExtra[1]);
return lphl;
}
void ListBoxDrawItem (HWND hwnd, HDC hdc, LPLISTSTRUCT lpls,
WORD itemAction, WORD itemState)
{
LPHEADLIST lphl;
WND *wndPtr;
lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
if (OWNER_DRAWN(wndPtr)) {
DRAWITEMSTRUCT *dis = USER_HEAP_LIN_ADDR(lphl->hDrawItemStruct);
memcpy (dis, &lpls->dis, sizeof(DRAWITEMSTRUCT));
dis->CtlType = ODT_LISTBOX;
dis->hDC = hdc;
if ((!dis->CtlID) && lphl->hWndLogicParent) {
WND *ParentWndPtr;
ParentWndPtr = WIN_FindWndPtr(lphl->hWndLogicParent);
dis->CtlID = ParentWndPtr->wIDmenu;
}
if (HasStrings(wndPtr)) dis->itemData = (DWORD)lpls->itemText;
dis->itemAction = itemAction;
dis->itemState = itemState;
SendMessage(lphl->hWndLogicParent, WM_DRAWITEM,
0, (LPARAM)USER_HEAP_SEG_ADDR(lphl->hDrawItemStruct));
}
else {
if (itemAction == ODA_DRAWENTIRE ||
itemAction == ODA_SELECT) {
int OldBkMode;
DWORD dwOldTextColor;
OldBkMode = SetBkMode(hdc, TRANSPARENT);
if (itemState != 0) {
dwOldTextColor = SetTextColor(hdc, 0x00FFFFFFL);
FillRect(hdc, &lpls->dis.rcItem, GetStockObject(BLACK_BRUSH));
}
if (wndPtr->dwStyle & LBS_USETABSTOPS)
TabbedTextOut(hdc, lpls->dis.rcItem.left + 5,
lpls->dis.rcItem.top + 2,
(char *)lpls->itemText,
strlen((char *)lpls->itemText), lphl->iNumStops,
lphl->TabStops, 0);
else
TextOut(hdc, lpls->dis.rcItem.left + 5, lpls->dis.rcItem.top + 2,
(char *)lpls->itemText, strlen((char *)lpls->itemText));
if (itemState != 0) {
SetTextColor(hdc, dwOldTextColor);
}
SetBkMode(hdc, OldBkMode);
} else DrawFocusRect(hdc, &lpls->dis.rcItem);
}
return;
}
void RepaintListBox(HWND hwnd)
{
WND *wndPtr;
LPHEADLIST lphl;
LPLISTSTRUCT lpls;
PAINTSTRUCT ps;
HBRUSH hBrush;
HDC hdc;
RECT rect;
int i, top, height, maxwidth, ipc;
top = 0;
hdc = BeginPaint( hwnd, &ps );
if (!IsWindowVisible(hwnd)) {
EndPaint( hwnd, &ps );
return;
}
lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
if (lphl == NULL) goto EndOfPaint;
if (!lphl->bRedrawFlag) goto EndOfPaint;
SelectObject(hdc, lphl->hFont);
hBrush = SendMessage(lphl->hWndLogicParent, WM_CTLCOLOR, (WORD)hdc,
MAKELONG(hwnd, CTLCOLOR_LISTBOX));
if (hBrush == (HBRUSH)NULL) hBrush = GetStockObject(WHITE_BRUSH);
GetClientRect(hwnd, &rect);
FillRect(hdc, &rect, hBrush);
maxwidth = rect.right;
rect.right = lphl->ColumnsWidth;
if (lphl->ItemsCount == 0) goto EndOfPaint;
lpls = lphl->lpFirst;
lphl->ItemsVisible = 0;
lphl->ItemsPerColumn = ipc = 0;
for(i = 0; i < lphl->ItemsCount; i++) {
if (lpls == NULL) goto EndOfPaint;
if (i >= lphl->FirstVisible - 1) {
height = lpls->dis.rcItem.bottom - lpls->dis.rcItem.top;
if (top > rect.bottom) {
if ((wndPtr->dwStyle & LBS_MULTICOLUMN) == LBS_MULTICOLUMN) {
lphl->ItemsPerColumn = max(lphl->ItemsPerColumn, ipc);
ipc = 0;
top = 0;
rect.left += lphl->ColumnsWidth;
rect.right += lphl->ColumnsWidth;
if (rect.left > maxwidth) break;
}
else
break;
}
lpls->dis.rcItem.top = top;
lpls->dis.rcItem.bottom = top + height;
lpls->dis.rcItem.left = rect.left;
lpls->dis.rcItem.right = rect.right;
if (OWNER_DRAWN(wndPtr)) {
ListBoxDrawItem (hwnd, hdc, lpls, ODA_DRAWENTIRE, 0);
if (lpls->dis.itemState)
ListBoxDrawItem (hwnd, hdc, lpls, ODA_SELECT, ODS_SELECTED);
}
else
ListBoxDrawItem (hwnd, hdc, lpls, ODA_DRAWENTIRE, lpls->dis.itemState);
if ((lphl->ItemFocused == i) && GetFocus() == hwnd)
ListBoxDrawItem (hwnd, hdc, lpls, ODA_FOCUS, ODS_FOCUS);
top += height;
lphl->ItemsVisible++;
ipc++;
}
lpls = lpls->lpNext;
}
EndOfPaint:
EndPaint( hwnd, &ps );
}
int ListBoxFindMouse(HWND hwnd, int X, int Y)
{
WND *wndPtr;
LPHEADLIST lphl;
LPLISTSTRUCT lpls;
RECT rect;
int i, h, h2, w, w2;
lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
if (lphl == NULL) return LB_ERR;
if (lphl->ItemsCount == 0) return LB_ERR;
lpls = lphl->lpFirst;
if (lpls == NULL) return LB_ERR;
GetClientRect(hwnd, &rect);
h = w2 = 0;
w = lphl->ColumnsWidth;
for(i = 1; i <= lphl->ItemsCount; i++) {
if (i >= lphl->FirstVisible) {
h2 = h;
h += lpls->dis.rcItem.bottom - lpls->dis.rcItem.top;
if ((Y > h2) && (Y < h) &&
(X > w2) && (X < w)) return(i - 1);
if (h > rect.bottom) {
if ((wndPtr->dwStyle & LBS_MULTICOLUMN) != LBS_MULTICOLUMN) return LB_ERR;
h = 0;
w2 = w;
w += lphl->ColumnsWidth;
if (w2 > rect.right) return LB_ERR;
}
}
if (lpls->lpNext == NULL) return LB_ERR;
lpls = (LPLISTSTRUCT)lpls->lpNext;
}
return(LB_ERR);
}
void ListBoxAskMeasure(WND *wndPtr, LPHEADLIST lphl, LPLISTSTRUCT lpls)
{
MEASUREITEMSTRUCT *lpmeasure;
HANDLE hTemp = USER_HEAP_ALLOC( sizeof(MEASUREITEMSTRUCT) );
lpmeasure = (MEASUREITEMSTRUCT *) USER_HEAP_LIN_ADDR(hTemp);
if (lpmeasure == NULL) {
fprintf(stderr,"ListBoxAskMeasure() // Bad allocation of Measure struct !\n");
return;
}
lpmeasure->CtlType = ODT_LISTBOX;
lpmeasure->CtlID = wndPtr->wIDmenu;
lpmeasure->itemID = lpls->dis.itemID;
lpmeasure->itemWidth = wndPtr->rectWindow.right - wndPtr->rectWindow.left;
lpmeasure->itemHeight = 0;
if (HasStrings(wndPtr))
lpmeasure->itemData = (DWORD)lpls->itemText;
else
lpmeasure->itemData = lpls->dis.itemData;
SendMessage(lphl->hWndLogicParent, WM_MEASUREITEM,
0, USER_HEAP_SEG_ADDR(hTemp));
if (wndPtr->dwStyle & LBS_OWNERDRAWFIXED) {
lphl->StdItemHeight = lpmeasure->itemHeight;
}
lpls->dis.rcItem.right = lpls->dis.rcItem.left + lpmeasure->itemWidth;
lpls->dis.rcItem.bottom = lpls->dis.rcItem.top + lpmeasure->itemHeight;
USER_HEAP_FREE(hTemp);
}
int ListBoxAddString(HWND hwnd, LPSTR newstr)
{
LPHEADLIST lphl;
UINT pos = (UINT) -1;
WND *wndPtr;
lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
if (lphl == NULL) return LB_ERR;
if (HasStrings(wndPtr) && (wndPtr->dwStyle & LBS_SORT)) {
LPLISTSTRUCT lpls = lphl->lpFirst;
for (pos = 0; lpls; lpls = lpls->lpNext, pos++)
if (strcmp(lpls->itemText, newstr) >= 0)
break;
}
return ListBoxInsertString(hwnd, pos, newstr);
}
int ListBoxInsertString(HWND hwnd, UINT uIndex, LPSTR newstr)
{
WND *wndPtr;
LPHEADLIST lphl;
LPLISTSTRUCT *lppls, lplsnew;
HANDLE hItem;
HANDLE hStr;
LPSTR str;
UINT Count;
dprintf_listbox(stddeb,"ListBoxInsertString(%04X, %d, %p);\n",
hwnd, uIndex, newstr);
lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
if (lphl == NULL) return LB_ERR;
if (uIndex == (UINT)-1)
uIndex = lphl->ItemsCount;
if (uIndex > lphl->ItemsCount) return LB_ERR;
lppls = (LPLISTSTRUCT *) &lphl->lpFirst;
for(Count = 0; Count < uIndex; Count++) {
if (*lppls == NULL) return LB_ERR;
lppls = (LPLISTSTRUCT *) &(*lppls)->lpNext;
}
hItem = LIST_HEAP_ALLOC(lphl, GMEM_MOVEABLE, sizeof(LISTSTRUCT));
lplsnew = (LPLISTSTRUCT) LIST_HEAP_ADDR(lphl, hItem);
if (lplsnew == NULL) {
printf("ListBoxInsertString() // Bad allocation of new item !\n");
return LB_ERRSPACE;
}
ListBoxDefaultItem(hwnd, wndPtr, lphl, lplsnew);
lplsnew->hMem = hItem;
lplsnew->lpNext = *lppls;
*lppls = lplsnew;
lphl->ItemsCount++;
hStr = 0;
if (HasStrings(wndPtr)) {
hStr = LIST_HEAP_ALLOC(lphl, GMEM_MOVEABLE, strlen(newstr) + 1);
str = (LPSTR)LIST_HEAP_ADDR(lphl, hStr);
if (str == NULL) return LB_ERRSPACE;
strcpy(str, newstr);
newstr = str;
lplsnew->itemText = str;
dprintf_listbox(stddeb,"ListBoxInsertString // LBS_HASSTRINGS after strcpy '%s'\n", str);
}
else {
lplsnew->itemText = NULL;
lplsnew->dis.itemData = (DWORD)newstr;
}
lplsnew->dis.itemID = lphl->ItemsCount;
lplsnew->hData = hStr;
if ((wndPtr->dwStyle & LBS_OWNERDRAWFIXED) && (lphl->ItemsCount == 1)) {
ListBoxAskMeasure(wndPtr, lphl, lplsnew);
}
if (wndPtr->dwStyle & LBS_OWNERDRAWVARIABLE)
ListBoxAskMeasure(wndPtr, lphl, lplsnew);
SetScrollRange(hwnd, SB_VERT, 1, ListMaxFirstVisible(lphl),
(lphl->FirstVisible != 1 && lphl->bRedrawFlag));
if (lphl->ItemsPerColumn != 0)
SetScrollRange(hwnd, SB_HORZ, 1, lphl->ItemsVisible /
lphl->ItemsPerColumn + 1,
(lphl->FirstVisible != 1 && lphl->bRedrawFlag));
if ((lphl->FirstVisible <= uIndex) &&
((lphl->FirstVisible + lphl->ItemsVisible) >= uIndex)) {
InvalidateRect(hwnd, NULL, TRUE);
UpdateWindow(hwnd);
}
dprintf_listbox(stddeb,"ListBoxInsertString // count=%d\n", lphl->ItemsCount);
return uIndex;
}
int ListBoxGetText(HWND hwnd, UINT uIndex, LPSTR OutStr, BOOL bItemData)
{
WND *wndPtr;
LPLISTSTRUCT lpls;
wndPtr = WIN_FindWndPtr(hwnd);
if (!OutStr && !bItemData) {
dprintf_listbox(stddeb, "ListBoxGetText // OutStr==NULL\n");
return 0;
}
if (!bItemData) *OutStr=0;
if ((lpls = ListBoxGetItem (hwnd, uIndex)) == NULL)
return 0;
if (bItemData)
return lpls->dis.itemData;
if (!HasStrings(wndPtr)) {
*((long *)OutStr) = lpls->dis.itemData;
return 4;
}
strcpy(OutStr, lpls->itemText);
return strlen(OutStr);
}
int ListBoxSetItemData(HWND hwnd, UINT uIndex, DWORD ItemData)
{
LPLISTSTRUCT lpls;
if ((lpls = ListBoxGetItem(hwnd, uIndex)) == NULL)
return 0;
lpls->dis.itemData = ItemData;
return 1;
}
int ListBoxDeleteString(HWND hwnd, UINT uIndex)
{
WND *wndPtr;
LPHEADLIST lphl;
LPLISTSTRUCT lpls, lpls2;
UINT Count;
lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
if (lphl == NULL) return LB_ERR;
if (uIndex >= lphl->ItemsCount) return LB_ERR;
lpls = lphl->lpFirst;
if (lpls == NULL) return LB_ERR;
if( uIndex == 0 )
lphl->lpFirst = lpls->lpNext;
else {
for(Count = 0; Count < uIndex; Count++) {
if (lpls->lpNext == NULL) return LB_ERR;
lpls2 = lpls;
lpls = (LPLISTSTRUCT)lpls->lpNext;
}
lpls2->lpNext = (LPLISTSTRUCT)lpls->lpNext;
}
lphl->ItemsCount--;
if (lpls->hData != 0) LIST_HEAP_FREE(lphl, lpls->hData);
if (lpls->hMem != 0) LIST_HEAP_FREE(lphl, lpls->hMem);
SetScrollRange(hwnd, SB_VERT, 1, ListMaxFirstVisible(lphl), TRUE);
if (lphl->ItemsPerColumn != 0)
SetScrollRange(hwnd, SB_HORZ, 1, lphl->ItemsVisible /
lphl->ItemsPerColumn + 1, TRUE);
if ((lphl->FirstVisible <= uIndex) &&
((lphl->FirstVisible + lphl->ItemsVisible) >= uIndex)) {
InvalidateRect(hwnd, NULL, TRUE);
UpdateWindow(hwnd);
}
return lphl->ItemsCount;
}
int ListBoxFindString(HWND hwnd, UINT nFirst, LPSTR MatchStr)
{
WND *wndPtr;
LPHEADLIST lphl;
LPLISTSTRUCT lpls;
UINT Count;
UINT First = nFirst + 1;
lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
if (lphl == NULL) return LB_ERR;
if (First > lphl->ItemsCount) return LB_ERR;
lpls = ListBoxGetItem(hwnd, First);
Count = 0;
while(lpls != NULL) {
if (HasStrings(wndPtr)) {
if (strstr(lpls->itemText, MatchStr) == lpls->itemText) return Count;
} else if (wndPtr->dwStyle & LBS_SORT) {
/* XXX Do a compare item */
}
else
if (lpls->dis.itemData == (DWORD)MatchStr) return Count;
lpls = lpls->lpNext;
Count++;
}
/* Start over at top */
Count = 0;
lpls = lphl->lpFirst;
while (Count < First) {
if (HasStrings(wndPtr)) {
if (strstr(lpls->itemText, MatchStr) == lpls->itemText) return Count;
} else if (wndPtr->dwStyle & LBS_SORT) {
/* XXX Do a compare item */
}
else
if (lpls->dis.itemData == (DWORD)MatchStr) return Count;
lpls = lpls->lpNext;
Count++;
}
return LB_ERR;
}
int ListBoxResetContent(HWND hwnd)
{
WND *wndPtr;
LPHEADLIST lphl;
LPLISTSTRUCT lpls;
UINT i;
lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
if (lphl == NULL) return LB_ERR;
if (lphl->ItemsCount == 0) return 0;
lpls = lphl->lpFirst;
dprintf_listbox(stddeb, "ListBoxResetContent // ItemCount = %d\n",
lphl->ItemsCount);
for(i = 0; i < lphl->ItemsCount; i++) {
LPLISTSTRUCT lpls2;
if (lpls == NULL) return LB_ERR;
lpls2 = lpls->lpNext;
if (i != 0) {
dprintf_listbox(stddeb,"ResetContent #%u\n", i);
if (lpls->hData != 0 && lpls->hData != lpls->hMem)
LIST_HEAP_FREE(lphl, lpls->hData);
if (lpls->hMem != 0) LIST_HEAP_FREE(lphl, lpls->hMem);
}
lpls = lpls2;
}
lphl->lpFirst = NULL;
lphl->FirstVisible = 1;
lphl->ItemsCount = 0;
lphl->ItemFocused = -1;
lphl->PrevFocused = -1;
SetScrollRange(hwnd, SB_VERT, 1, ListMaxFirstVisible(lphl), TRUE);
if (lphl->ItemsPerColumn != 0)
SetScrollRange(hwnd, SB_HORZ, 1, lphl->ItemsVisible /
lphl->ItemsPerColumn + 1, TRUE);
InvalidateRect(hwnd, NULL, TRUE);
UpdateWindow(hwnd);
return TRUE;
}
int ListBoxSetCurSel(HWND hwnd, WORD wIndex)
{
WND *wndPtr;
LPHEADLIST lphl;
LPLISTSTRUCT lpls;
lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
if (lphl == NULL) return LB_ERR;
if (wndPtr->dwStyle & LBS_MULTIPLESEL) return 0;
if (lphl->ItemFocused != -1) {
lpls = ListBoxGetItem(hwnd, lphl->ItemFocused);
lpls->dis.itemState = 0;
}
if (wIndex != (UINT)-1) {
lphl->ItemFocused = wIndex;
lpls = ListBoxGetItem(hwnd, wIndex);
lpls->dis.itemState = ODS_SELECTED | ODS_FOCUS;
return 0;
}
return LB_ERR;
}
int ListBoxSetSel(HWND hwnd, WORD wIndex, WORD state)
{
LPHEADLIST lphl;
LPLISTSTRUCT lpls;
WND *wndPtr;
lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
if (lphl == NULL) return LB_ERR;
if (!(wndPtr->dwStyle & LBS_MULTIPLESEL)) return 0;
if (wIndex == (UINT)-1) {
lpls = lphl->lpFirst;
while (lpls != NULL) {
lpls->dis.itemState = state;
lpls = lpls->lpNext;
}
return 0;
}
if (wIndex >= lphl->ItemsCount) return LB_ERR;
lpls = ListBoxGetItem(hwnd, wIndex);
lpls->dis.itemState = state;
return 0;
}
int ListBoxGetSel(HWND hwnd, WORD wIndex)
{
LPLISTSTRUCT lpls;
if ((lpls = ListBoxGetItem(hwnd, wIndex)) == NULL) return LB_ERR;
return lpls->dis.itemState;
}
int ListBoxDirectory(HWND hwnd, UINT attrib, LPSTR filespec)
{
struct dosdirent *dp, *dp_old;
int x, wRet = LB_OKAY;
BOOL OldFlag;
char temp[256];
LPHEADLIST lphl;
int drive;
dprintf_listbox(stddeb,"ListBoxDirectory: %s, %4x\n",filespec,attrib);
if( strchr( filespec, '\\' ) || strchr( filespec, ':' ) ) {
drive = DOS_GetDefaultDrive();
if( filespec[1] == ':' ) {
drive = toupper(filespec[0]) - 'A';
filespec += 2;
}
if( !strchr( filespec, '\\' ) )
DOS_SetDefaultDrive( drive );
else {
int i;
strcpy( temp, filespec );
for( i=0; i<strlen(temp); i++ )
if( temp[i] == '\\' ) {
temp[i] = 0;
filespec += ( i+1 );
break;
}
DOS_ChangeDir( drive, temp );
DOS_SetDefaultDrive( drive );
}
dprintf_listbox(stddeb,"Changing directory to %c:%s, filemask is %s\n",
drive+'A', temp, filespec );
}
lphl = ListBoxGetStorageHeader(hwnd);
if (lphl == NULL) return LB_ERR;
if ((dp = (struct dosdirent *)DOS_opendir(filespec)) ==NULL) return 0;
dp_old = dp;
OldFlag = lphl->bRedrawFlag;
lphl->bRedrawFlag = FALSE;
while ((dp = (struct dosdirent *)DOS_readdir(dp))) {
if (!dp->inuse) break;
dprintf_listbox( stddeb, "ListBoxDirectory %p '%s' !\n", dp->filename,
dp->filename);
if (dp->attribute & FA_DIREC) {
if (attrib & DDL_DIRECTORY &&
strcmp(dp->filename, ".")) {
sprintf(temp, "[%s]", dp->filename);
if ( (wRet = ListBoxAddString(hwnd, temp)) == LB_ERR) break;
}
}
else {
if (attrib & DDL_EXCLUSIVE) {
if (attrib & (DDL_READWRITE | DDL_READONLY | DDL_HIDDEN |
DDL_SYSTEM) )
if ( (wRet = ListBoxAddString(hwnd, dp->filename))
== LB_ERR) break;
}
else {
if ( (wRet = ListBoxAddString(hwnd, dp->filename))
== LB_ERR) break;
}
}
}
DOS_closedir(dp_old);
if (attrib & DDL_DRIVES) {
for (x=0;x!=MAX_DOS_DRIVES;x++) {
if (DOS_ValidDrive(x)) {
sprintf(temp, "[-%c-]", 'a'+x);
if((wRet = ListBoxInsertString(hwnd, (UINT)-1, temp)) == LB_ERR) break;
}
}
}
lphl->bRedrawFlag = OldFlag;
if (OldFlag) {
InvalidateRect(hwnd, NULL, TRUE);
UpdateWindow(hwnd);
}
dprintf_listbox(stddeb,"End of ListBoxDirectory !\n");
return 1; /* FIXME: Should be 0 if "filespec" is invalid */
}
int ListBoxGetItemRect(HWND hwnd, WORD wIndex, LPRECT lprect)
{
LPLISTSTRUCT lpls;
if ((lpls = ListBoxGetItem(hwnd, wIndex)) == NULL) return LB_ERR;
*(lprect) = lpls->dis.rcItem;
return 0;
}
int ListBoxSetItemHeight(HWND hwnd, WORD wIndex, long height)
{
LPHEADLIST lphl;
WND *wndPtr;
LPLISTSTRUCT lpls;
lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
if (lphl == NULL) return LB_ERR;
if (!(wndPtr->dwStyle & LBS_OWNERDRAWVARIABLE)) {
lphl->StdItemHeight = (short)height;
InvalidateRect(hwnd, NULL, TRUE);
UpdateWindow(hwnd);
return 0;
}
if ((lpls = ListBoxGetItem(hwnd, wIndex)) == NULL) return LB_ERR;
lpls->dis.rcItem.bottom = lpls->dis.rcItem.top + (short)height;
InvalidateRect(hwnd, NULL, TRUE);
UpdateWindow(hwnd);
return 0;
}
int ListBoxDefaultItem(HWND hwnd, WND *wndPtr,
LPHEADLIST lphl, LPLISTSTRUCT lpls)
{
RECT rect;
if (wndPtr == NULL || lphl == NULL || lpls == NULL) {
fprintf(stderr,"ListBoxDefaultItem() // Bad Pointers !\n");
return FALSE;
}
GetClientRect(hwnd, &rect);
SetRect(&lpls->dis.rcItem, 0, 0, rect.right, lphl->StdItemHeight);
lpls->dis.CtlType = lphl->DrawCtlType;
lpls->dis.CtlID = wndPtr->wIDmenu;
lpls->dis.itemID = 0;
lpls->dis.itemAction = 0;
lpls->dis.itemState = 0;
lpls->dis.hwndItem = hwnd;
lpls->dis.hDC = 0;
lpls->dis.itemData = 0;
return TRUE;
}
int ListBoxFindNextMatch(HWND hwnd, WORD wChar)
{
WND *wndPtr;
LPHEADLIST lphl;
LPLISTSTRUCT lpls;
UINT Count;
lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
if (lphl == NULL) return LB_ERR;
lpls = lphl->lpFirst;
if (lpls == NULL) return LB_ERR;
if (wChar < ' ') return LB_ERR;
if (!HasStrings(wndPtr)) return LB_ERR;
Count = 0;
while(lpls != NULL) {
if (Count > lphl->ItemFocused) {
if (*(lpls->itemText) == (char)wChar) {
if ((wndPtr->dwStyle & LBS_MULTIPLESEL) == LBS_MULTIPLESEL) {
lphl->ItemFocused = Count;
ListBoxScrolltoFocus(hwnd);
}
else {
ListBoxSetCurSel(hwnd, Count);
}
SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
InvalidateRect(hwnd, NULL, TRUE);
UpdateWindow(hwnd);
return Count;
}
}
lpls = (LPLISTSTRUCT)lpls->lpNext;
Count++;
}
Count = 0;
lpls = lphl->lpFirst;
while(lpls != NULL) {
if (*(lpls->itemText) == (char)wChar) {
if (Count == lphl->ItemFocused) return LB_ERR;
if ((wndPtr->dwStyle & LBS_MULTIPLESEL) == LBS_MULTIPLESEL) {
lphl->ItemFocused = Count;
ListBoxScrolltoFocus(hwnd);
}
else {
ListBoxSetCurSel(hwnd, Count);
}
SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
InvalidateRect(hwnd, NULL, TRUE);
UpdateWindow(hwnd);
return Count;
}
lpls = lpls->lpNext;
Count++;
}
return LB_ERR;
}
/************************************************************************
* DlgDirSelect [USER.99]
*/
BOOL DlgDirSelect(HWND hDlg, LPSTR lpStr, int nIDLBox)
{
HWND hwnd;
LPHEADLIST lphl;
char s[130];
dprintf_listbox( stddeb, "DlgDirSelect(%04X, '%s', %d) \n", hDlg, lpStr,
nIDLBox );
hwnd = GetDlgItem(hDlg, nIDLBox);
lphl = ListBoxGetStorageHeader(hwnd);
if( lphl->ItemFocused == -1 ) {
dprintf_listbox( stddeb, "Nothing selected!\n" );
return FALSE;
}
ListBoxGetText(hwnd, lphl->ItemFocused, (LPSTR)s, FALSE);
dprintf_listbox( stddeb, "Selection is %s\n", s );
if( s[0] == '[' ) {
if( s[1] == '-' ) {
strncpy( lpStr, s+2, strlen(s)-4 ); /* device name */
lpStr[ strlen(s)-4 ] = 0;
strcat( lpStr, ":" );
}
else {
strncpy( lpStr, s+1, strlen(s)-2 ); /* directory name */
lpStr[ strlen(s)-2 ] = 0;
strcat( lpStr, "\\" );
}
dprintf_listbox( stddeb, "Returning %s\n", lpStr );
return TRUE;
}
else {
strcpy( lpStr, s ); /* file name */
dprintf_listbox( stddeb, "Returning %s\n", lpStr );
return FALSE;
}
}
/************************************************************************
* DlgDirList [USER.100]
*/
int DlgDirList(HWND hDlg, LPSTR lpPathSpec,
int nIDLBox, int nIDStat, WORD wType)
{
HWND hWnd;
int ret;
dprintf_listbox(stddeb,"DlgDirList(%04X, '%s', %d, %d, %04X) \n",
hDlg, lpPathSpec, nIDLBox, nIDStat, wType);
if (nIDLBox)
hWnd = GetDlgItem(hDlg, nIDLBox);
else
hWnd = 0;
if (hWnd)
ListBoxResetContent(hWnd);
if (hWnd)
ret=ListBoxDirectory(hWnd, wType, lpPathSpec);
else
ret=0;
if (nIDStat)
{
int drive;
HANDLE hTemp;
char *temp;
drive = DOS_GetDefaultDrive();
hTemp = USER_HEAP_ALLOC( 256 );
temp = (char *) USER_HEAP_LIN_ADDR( hTemp );
strcpy( temp+3, DOS_GetCurrentDir(drive) );
if( temp[3] == '\\' ) {
temp[1] = 'A'+drive;
temp[2] = ':';
SendDlgItemMessage( hDlg, nIDStat, WM_SETTEXT, 0,
USER_HEAP_SEG_ADDR(hTemp) + 1 );
}
else {
temp[0] = 'A'+drive;
temp[1] = ':';
temp[2] = '\\';
SendDlgItemMessage( hDlg, nIDStat, WM_SETTEXT, 0,
USER_HEAP_SEG_ADDR(hTemp) );
}
USER_HEAP_FREE( hTemp );
}
return ret;
}
/* Returns: 0 if nothing needs to be changed */
/* 1 if FirstVisible changed */
int ListBoxScrolltoFocus(HWND hwnd)
{
WND *wndPtr;
LPHEADLIST lphl;
short end;
lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
if (lphl->ItemsCount == 0) return 0;
if (lphl->ItemFocused == -1) return 0;
end = lphl->FirstVisible + lphl->ItemsVisible - 2;
if (lphl->ItemFocused < lphl->FirstVisible - 1) {
lphl->FirstVisible = lphl->ItemFocused + 1;
}
else if (lphl->ItemFocused > end) {
UINT maxFirstVisible = ListMaxFirstVisible(lphl);
lphl->FirstVisible = lphl->ItemFocused;
if (lphl->FirstVisible > maxFirstVisible) {
lphl->FirstVisible = maxFirstVisible;
}
} else return 0;
return 1;
}
/* Send notification "code" as part of a WM_COMMAND-message if hwnd
has the LBS_NOTIFY style */
void ListBoxSendNotification(HWND hwnd, WORD code)
{
WND *wndPtr;
LPHEADLIST lphl;
lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
if (wndPtr && (wndPtr->dwStyle & LBS_NOTIFY))
SendMessage(lphl->hWndLogicParent, WM_COMMAND,
wndPtr->wIDmenu, MAKELONG(hwnd, code));
}