wine/controls/listbox.c
Alexandre Julliard e2991ea7bd Release 950727
Sat Jul 22 22:39:09 IDT 1995 Michael Veksler <e1678223@tochnapc2.technion.ac.il>

	* [ipc/*]
	New directory. This directory contains the new inter-wine
 	communications support. It enables DDE protocols between two wine
 	instances.  Currently it is limited to DDE, but can be enhanced to
 	support OLE between 2 different wine instances.  This is very
 	important for libwine.a DDE/OLE support.

	* [tools/ipcl]
    	A script to delete garbage IPC handles (shared memory, semaphores
 	and message queues).  The current inter-wine communication is not
 	perfect, and sometimes leaves garbage behind.

	* [if1632/relay.c] [include/atom.h] [include/global.h]
 	[loader/selector.c] [loader/task.c] [loader/module.c]
 	[loader/signal.c] [memory/global.c] [misc/atom.c]
 	[windows/class.c] [windows/message.c] [windows/win.c]
	[Imakefile]
    	Hooks for inter-wine DDE support, current Global.*Atom functions
 	renamed to Local.*Atom since Global.*Atom are used for Inter-Wine
 	DDE communication. (The first call to these functions sets up the
 	IPC structures - which otherwise cause unneeded overhead.

Mon Jul 17 19:55:21 1995  Alexandre Julliard  <julliard@sunsite.unc.edu>

	* [controls/menu.c]
	Don't crash if a NULL string is passed to menu functions.

	* [memory/selector.c]
	We now use a bit in ldt_flags_copy to indicate free LDT entries.
	Fixed a bug in SELECTOR_ReallocBlock that could cause it to
	overwrite valid LDT entries when growing a block.

	* [miscemu/instr.c]
	Emulate int xx instruction by storing the interrupt vector in
	CS:IP and returning directly. This allows a program to install an
	interrupt vector.

	* [windows/win.c]
	Added function WIN_GetTopParent to get the top-level parent of a
	window.

Sun Jul  16 18:17:17 1995  Gregory Trubetskoy <grisha@mira.com>

        * [loader/resource.c]
        Added LoadIconHandler. It doesn't do anything yet, but now you
        can use borland help files with winhelp.exe.

Sun Jul 16 11:58:45 1995 Anand Kumria <akumria@ozemail.com.au>

	* [misc/main.c]
	Fixed to return 386 Enhanced mode correctly. Also return the same
 	type of CPU, for both Enhanced and Standard mode, namely a 386.

Sun Jul 16 00:02:04 1995    Martin von Loewis <loewis@informatik.hu-berlin.de>

	* [Configure] [include/options.h] [include/wineopts.h]
	  [misc/main.c][misc/spy.c]
	  Removed support of spy file. Redirected spy messages to stddeb.
	  Removed -spy option. Added -debugmsg +spy option.

	* [debugger/dbg.y][debugger/debug.l]
	Enabled segmented addresses (seg:offs) for break and x commands.

	* [if1632/gdi.spec] [objects/region.c] [windows/graphics.c]
	  [include/region.h]
	FrameRgn, REGION_FrameRgn: New functions

	* [if1632/kernel.spec]
	IsWinOldApTask: Return false

	* [if1632/mouse.spec]
	CplApplet: Removed

	* [if1632/user.spec] [windows/win.c]
	ShowOwnedPopups: New function

	* [if1632/winsock.spec] [misc/winsocket.c]
	inet_addr, select: New prototypes in relay code
	Fixed memory layout for netdb functions (getXbyY).
	WINSOCK_ioctlsocket: Translated FIONREAD, FIONBIO, and FIOASYNC

	* [objects/clipping.c]
	RectVisible: Fixed call to LPToDP

	* [rc/winerc.c]
	main: Removed extra argument to getopt for Linux.

Tue Jul 11 00:14:41 1995   Bernd Schmidt <crux@pool.informatik.rwth-aachen.de>

        * [controls/listbox.c]
	Yet another fix for ListBoxDirectory().
	
	* [loader/module.c] [if1632/kernel.spec]
	Make GetModuleHandle() accept instance handles as parameter.

        * [if1632/relay.c] [loader/task.c]
	Put a magic cookie at the bottom of the 32 bit stack, and check on
	each return from a 32 bit function whether it's still there. Complain
	if it's not.

        * [if1632/user.spec]
	Wrong entry for CloseDriver().

	* [misc/dos_fs.c] [loader/task.c] [include/dos_fs.h] [misc/file.c]
	[miscemu/int21.c]
	Large parts of dos_fs.c simplified. Changed it to use one
	current drive/directory per task, which is set to the module path on
	task creation.
	Prevent CorelPaint from closing stdin.
	open() with O_CREAT set must be passed three parameters.
	DOS FindFirst()/FindNext() could crash when FA_LABEL was set. Fixed,
	it's in DOS_readdir() now.

	* [misc/profile.c]
	Some badly written software (Lotus Freelance Graphics) passes a bogus
	size parameter that caused Wine to write off the end of a segment.
	Fixed. (It's probably too paranoid now.)
	
	* [multimedia/mmsystem.c] [multimedia/time.c] [multimedia/joystick.c]
	[multimedia/Imakefile] [if1632/winprocs.spec]
	16 bit entry point for MMSysTimeCallback.
	Split off time.c and joystick.c from mmsystem.c.
	
	* [objects/dib.c]
	GetDIBits(): call XGetImage() via CallTo32_LargeStack.

        * [windows/cursor.c]
	DestroyCursor(): do nothing for builtin cursors.
	
	* [windows/mdi.c]
	Half of WM_MDISETMENU implemented.
	
	* [windows/win.c]
	EnumWindows() and EnumTaskWindows() never enumerated any windows.
	Fixed.

	* [windows/*.c]
	Fixed GetParent() to return correct values for owned windows.

	* [windows/message.c]
	Don't try to activate disabled top-level windows.

        * [windows/nonclient.c]
	Work around a bug in gcc-2.7.0.
	
	* [tools/build.c] [include/stackframe.h] [memory/global.c] 
	[loader/task.c] [memory/selector.c]
	Some Visual Basic programs (and possibly others, too) expect ES to be 
	preserved by a call to an API function, so we have to save it.
	In GlobalFree() and FreeSelector(), we must clear CURRENT_STACK16->es 
	to prevent segfaults if ES contained the selector to be freed.

Sun Jul  9 20:21:20 1995  Jon Tombs  <jon@gtex02.us.es>

	* [*/*]
	Added missing prototypes to header files and relevant includes
	to reduce compile time warnings.

Sun Jul  9 18:32:56 1995  Michael Patra  <micky@marie.physik.tu-berlin.de>

	* [configure.in] [include/config.h] [*/Makefile.in]
	New configuration scheme based on autoconf.

Sat Jul  8 14:12:45 1995  Morten Welinder  <terra+@cs.cmu.edu>

	* [miscemu/ioports.c]
	Revamp to have only one in- and one out- variant, both really
 	implemented.

	* [miscemu/instr.c]
	INSTR_EmulateInstruction: Use new ioport interface.  Implement
 	string io.  Correct instruction pointer for 32-bit code.

	* [include/miscemu.h]
	Update port function prototypes.

	* [include/registers.h]
	Defined FS and GS.

Sat Jul  8 13:38:54 1995  Hans de Graaff  <graaff@twi72.twi.tudelft.nl>

	* [misc/dos_fs.c]
	ChopOffSlash(): A path consisting off a single slash is left
 	intact, and multiple slashes are all removed.
1995-07-29 13:09:43 +00:00

1782 lines
46 KiB
C

/*
* Listbox controls
*
* Copyright Martin Ayotte, 1993
* Copyright Constantine Sapuntzakis, 1995
*
*/
/*
* TODO:
* - check if multi-column listboxes work
* - implement more messages and styles
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.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"
#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
/* FIXME: shouldn't each listbox have its own heap? */
#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)
#define LIST_HEAP_SEG_ADDR(lphl,handle) USER_HEAP_SEG_ADDR(handle)
#endif
#define LIST_HEAP_SIZE 0x10000
static void ListBoxInitialize(LPHEADLIST lphl)
{
lphl->lpFirst = NULL;
lphl->ItemsCount = 0;
lphl->ItemsVisible = 0;
lphl->FirstVisible = 0;
lphl->ColumnsVisible = 1;
lphl->ItemsPerColumn = 0;
lphl->ItemFocused = -1;
lphl->PrevFocused = -1;
}
void CreateListBoxStruct(HWND hwnd, WORD CtlType, LONG styles, HWND parent)
{
LPHEADLIST lphl;
lphl = (LPHEADLIST)malloc(sizeof(HEADLIST));
SetWindowLong(hwnd, 0, (LONG)lphl);
if (lphl == NULL) {
fprintf(stderr,"malloc failed in CreateListBoxStruct()\n");
exit(1); /* Things won't get better */
}
ListBoxInitialize(lphl);
lphl->DrawCtlType = CtlType;
lphl->CtlID = GetWindowWord(hwnd,GWW_ID);
lphl->bRedrawFlag = TRUE;
lphl->iNumStops = 0;
lphl->TabStops = NULL;
lphl->hFont = GetStockObject(SYSTEM_FONT);
lphl->hParent = parent;
lphl->StdItemHeight = 15; /* FIXME: should get the font height */
lphl->dwStyle = styles;
lphl->OwnerDrawn = styles & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE);
lphl->HasStrings = (styles & LBS_HASSTRINGS) || !lphl->OwnerDrawn;
if (lphl->OwnerDrawn) {
LISTSTRUCT dummyls;
lphl->hDrawItemStruct = USER_HEAP_ALLOC(sizeof(DRAWITEMSTRUCT));
lphl->needMeasure = TRUE;
dummyls.mis.CtlType = lphl->DrawCtlType;
dummyls.mis.CtlID = lphl->CtlID;
dummyls.mis.itemID = -1;
dummyls.mis.itemWidth = 0; /* ignored */
dummyls.mis.itemData = 0;
ListBoxAskMeasure(lphl,&dummyls);
} 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
}
void DestroyListBoxStruct(LPHEADLIST lphl)
{
if (lphl->hDrawItemStruct)
USER_HEAP_FREE(lphl->hDrawItemStruct);
/* XXX need to free lphl->Heap */
free(lphl);
}
static LPHEADLIST ListBoxGetStorageHeader(HWND hwnd)
{
return (LPHEADLIST)GetWindowLong(hwnd,0);
}
/* Send notification "code" as part of a WM_COMMAND-message if hwnd
has the LBS_NOTIFY style */
void ListBoxSendNotification(LPHEADLIST lphl, HWND hwnd, WORD code)
{
if (lphl->dwStyle & LBS_NOTIFY)
SendMessage(lphl->hParent, WM_COMMAND,
lphl->CtlID, MAKELONG(hwnd, code));
}
/* get the maximum value of lphl->FirstVisible */
int ListMaxFirstVisible(LPHEADLIST lphl)
{
int m = lphl->ItemsCount-lphl->ItemsVisible;
return (m < 0) ? 0 : m;
}
void ListBoxUpdateWindow(HWND hwnd, LPHEADLIST lphl, BOOL repaint)
{
SetScrollRange(hwnd, SB_VERT, 0, ListMaxFirstVisible(lphl), TRUE);
if (lphl->ItemsPerColumn != 0) {
SetScrollRange(hwnd, SB_HORZ, 1, lphl->ItemsVisible /
lphl->ItemsPerColumn + 1, TRUE);
}
if (repaint && lphl->bRedrawFlag) {
InvalidateRect(hwnd, NULL, TRUE);
}
}
/* Returns: 0 if nothing needs to be changed */
/* 1 if FirstVisible changed */
int ListBoxScrollToFocus(LPHEADLIST lphl)
{
short end;
if (lphl->ItemsCount == 0) return 0;
if (lphl->ItemFocused == -1) return 0;
end = lphl->FirstVisible + lphl->ItemsVisible - 1;
if (lphl->ItemFocused < lphl->FirstVisible ) {
lphl->FirstVisible = lphl->ItemFocused;
return 1;
} else {
if (lphl->ItemFocused > end) {
WORD maxFirstVisible = ListMaxFirstVisible(lphl);
lphl->FirstVisible = lphl->ItemFocused;
if (lphl->FirstVisible > maxFirstVisible) {
lphl->FirstVisible = maxFirstVisible;
}
return 1;
}
}
return 0;
}
LPLISTSTRUCT ListBoxGetItem(LPHEADLIST lphl, UINT uIndex)
{
LPLISTSTRUCT lpls;
UINT Count = 0;
if (uIndex >= lphl->ItemsCount) return NULL;
lpls = lphl->lpFirst;
while (Count++ < uIndex) lpls = lpls->lpNext;
return lpls;
}
void ListBoxDrawItem (HWND hwnd, LPHEADLIST lphl, HDC hdc, LPLISTSTRUCT lpls,
RECT *rect, WORD itemAction, WORD itemState)
{
if (lphl->OwnerDrawn) {
DRAWITEMSTRUCT *dis = USER_HEAP_LIN_ADDR(lphl->hDrawItemStruct);
dis->CtlID = lpls->mis.CtlID;
dis->CtlType = lpls->mis.CtlType;
dis->itemID = lpls->mis.itemID;
dis->hDC = hdc;
dis->hwndItem = hwnd;
dis->itemData = lpls->mis.itemData;
dis->itemAction = itemAction;
dis->itemState = itemState;
dis->rcItem = *rect;
SendMessage(lphl->hParent, WM_DRAWITEM,
0, (LPARAM)USER_HEAP_SEG_ADDR(lphl->hDrawItemStruct));
} else {
if (itemAction == ODA_DRAWENTIRE || itemAction == ODA_SELECT) {
int OldBkMode;
DWORD dwOldTextColor = 0;
OldBkMode = SetBkMode(hdc, TRANSPARENT);
if (itemState != 0) {
dwOldTextColor = SetTextColor(hdc, 0x00FFFFFFL);
FillRect(hdc, rect, GetStockObject(BLACK_BRUSH));
}
if (lphl->dwStyle & LBS_USETABSTOPS) {
TabbedTextOut(hdc, rect->left + 5, rect->top + 2,
(char *)lpls->itemText, strlen((char *)lpls->itemText),
lphl->iNumStops, lphl->TabStops, 0);
} else {
TextOut(hdc, rect->left + 5, rect->top + 2,
(char *)lpls->itemText, strlen((char *)lpls->itemText));
}
if (itemState != 0) {
SetTextColor(hdc, dwOldTextColor);
}
SetBkMode(hdc, OldBkMode);
} else DrawFocusRect(hdc, rect);
}
return;
}
int ListBoxFindMouse(LPHEADLIST lphl, int X, int Y)
{
LPLISTSTRUCT lpls = lphl->lpFirst;
int i, j;
POINT point;
point.x = X; point.y = Y;
if (lphl->ItemsCount == 0) return LB_ERR;
for(i = 0; i < lphl->FirstVisible; i++) {
if (lpls == NULL) return LB_ERR;
lpls = lpls->lpNext;
}
for(j = 0; j < lphl->ItemsVisible; i++, j++) {
if (lpls == NULL) return LB_ERR;
if (PtInRect(&lpls->itemRect,point)) {
return i;
}
lpls = lpls->lpNext;
}
dprintf_listbox(stddeb,"ListBoxFindMouse: not found\n");
return LB_ERR;
}
void ListBoxAskMeasure(LPHEADLIST lphl, LPLISTSTRUCT lpls)
{
HANDLE hTemp = USER_HEAP_ALLOC( sizeof(MEASUREITEMSTRUCT) );
MEASUREITEMSTRUCT *lpmeasure = (MEASUREITEMSTRUCT *) USER_HEAP_LIN_ADDR(hTemp);
if (lpmeasure == NULL) {
fprintf(stderr,"ListBoxAskMeasure() out of memory !\n");
return;
}
*lpmeasure = lpls->mis;
lpmeasure->itemHeight = lphl->StdItemHeight;
SendMessage(lphl->hParent, WM_MEASUREITEM, 0, USER_HEAP_SEG_ADDR(hTemp));
if (lphl->dwStyle & LBS_OWNERDRAWFIXED) {
lphl->StdItemHeight = lpmeasure->itemHeight;
lphl->needMeasure = FALSE;
}
USER_HEAP_FREE(hTemp);
}
LPLISTSTRUCT ListBoxCreateItem(LPHEADLIST lphl, int id)
{
LPLISTSTRUCT lplsnew = (LPLISTSTRUCT)malloc(sizeof(LISTSTRUCT));
if (lplsnew == NULL) return NULL;
lplsnew->itemState = 0;
lplsnew->mis.CtlType = lphl->DrawCtlType;
lplsnew->mis.CtlID = lphl->CtlID;
lplsnew->mis.itemID = id;
lplsnew->mis.itemHeight = lphl->StdItemHeight;
lplsnew->mis.itemWidth = 0; /* ignored */
lplsnew->mis.itemData = 0;
SetRect(&lplsnew->itemRect, 0, 0, 0, 0);
return lplsnew;
}
int ListBoxInsertString(LPHEADLIST lphl, UINT uIndex, LPSTR newstr)
{
LPLISTSTRUCT *lppls, lplsnew, lpls;
HANDLE hStr;
LPSTR str;
UINT Count;
dprintf_listbox(stddeb,"ListBoxInsertString(%d, %p);\n", uIndex, newstr);
if (uIndex == (UINT)-1)
uIndex = lphl->ItemsCount;
lppls = &lphl->lpFirst;
for(Count = 0; Count < uIndex; Count++) {
if (*lppls == NULL) return LB_ERR;
lppls = (LPLISTSTRUCT *) &(*lppls)->lpNext;
}
lplsnew = ListBoxCreateItem(lphl, Count);
if (lplsnew == NULL) {
printf("ListBoxInsertString() out of memory !\n");
return LB_ERRSPACE;
}
lplsnew->lpNext = *lppls;
*lppls = lplsnew;
lphl->ItemsCount++;
hStr = 0;
if (lphl->HasStrings) {
dprintf_listbox(stddeb," string: %s\n", newstr);
hStr = LIST_HEAP_ALLOC(lphl, LMEM_MOVEABLE, strlen(newstr) + 1);
str = (LPSTR)LIST_HEAP_ADDR(lphl, hStr);
if (str == NULL) return LB_ERRSPACE;
strcpy(str, newstr);
lplsnew->itemText = str;
/* I'm not so sure about the next one */
lplsnew->mis.itemData = 0;
} else {
lplsnew->itemText = NULL;
lplsnew->mis.itemData = (DWORD)newstr;
}
lplsnew->mis.itemID = uIndex;
lplsnew->hData = hStr;
/* adjust the itemID field of the following entries */
for(lpls = lplsnew->lpNext; lpls != NULL; lpls = lpls->lpNext) {
lpls->mis.itemID++;
}
if (lphl->needMeasure) {
ListBoxAskMeasure(lphl, lplsnew);
}
dprintf_listbox(stddeb,"ListBoxInsertString // count=%d\n", lphl->ItemsCount);
return uIndex;
}
int ListBoxAddString(LPHEADLIST lphl, LPSTR newstr)
{
UINT pos = (UINT) -1;
if (lphl->HasStrings && (lphl->dwStyle & LBS_SORT)) {
LPLISTSTRUCT lpls = lphl->lpFirst;
for (pos = 0; lpls != NULL; lpls = lpls->lpNext, pos++)
if (strcmp(lpls->itemText, newstr) >= 0)
break;
}
return ListBoxInsertString(lphl, pos, newstr);
}
int ListBoxGetText(LPHEADLIST lphl, UINT uIndex, LPSTR OutStr)
{
LPLISTSTRUCT lpls;
if (!OutStr) {
dprintf_listbox(stddeb, "ListBoxGetText // OutStr==NULL\n");
return 0;
}
lpls = ListBoxGetItem (lphl, uIndex);
if (lpls == NULL) return LB_ERR;
if (!lphl->HasStrings) {
*((long *)OutStr) = lpls->mis.itemData;
return 4;
}
strcpy(OutStr, lpls->itemText);
return strlen(OutStr);
}
DWORD ListBoxGetItemData(LPHEADLIST lphl, UINT uIndex)
{
LPLISTSTRUCT lpls;
lpls = ListBoxGetItem (lphl, uIndex);
if (lpls == NULL) return LB_ERR;
return lpls->mis.itemData;
}
int ListBoxSetItemData(LPHEADLIST lphl, UINT uIndex, DWORD ItemData)
{
LPLISTSTRUCT lpls = ListBoxGetItem(lphl, uIndex);
if (lpls == NULL) return LB_ERR;
lpls->mis.itemData = ItemData;
return 1;
}
int ListBoxDeleteString(LPHEADLIST lphl, UINT uIndex)
{
LPLISTSTRUCT lpls, lpls2;
UINT Count;
if (uIndex >= lphl->ItemsCount) return LB_ERR;
lpls = lphl->lpFirst;
if (lpls == NULL) return LB_ERR;
if (uIndex == 0)
lphl->lpFirst = lpls->lpNext;
else {
LPLISTSTRUCT lpls2 = NULL;
for(Count = 0; Count < uIndex; Count++) {
if (lpls->lpNext == NULL) return LB_ERR;
lpls2 = lpls;
lpls = (LPLISTSTRUCT)lpls->lpNext;
}
lpls2->lpNext = lpls->lpNext;
}
/* adjust the itemID field of the following entries */
for(lpls2 = lpls->lpNext; lpls2 != NULL; lpls2 = lpls2->lpNext) {
lpls2->mis.itemID--;
}
lphl->ItemsCount--;
if (lpls->hData != 0) LIST_HEAP_FREE(lphl, lpls->hData);
free(lpls);
return lphl->ItemsCount;
}
int ListBoxFindString(LPHEADLIST lphl, UINT nFirst, SEGPTR MatchStr)
{
LPLISTSTRUCT lpls;
UINT Count;
UINT First = nFirst + 1;
LPSTR lpMatchStr = (LPSTR)MatchStr;
if (First > lphl->ItemsCount) return LB_ERR;
if (lphl->HasStrings) lpMatchStr = PTR_SEG_TO_LIN(MatchStr);
lpls = ListBoxGetItem(lphl, First);
Count = 0;
while(lpls != NULL) {
if (lphl->HasStrings) {
if (strstr(lpls->itemText, lpMatchStr) == lpls->itemText) return Count;
} else if (lphl->dwStyle & LBS_SORT) {
/* XXX Do a compare item */
}
else
if (lpls->mis.itemData == (DWORD)lpMatchStr) return Count;
lpls = lpls->lpNext;
Count++;
}
/* Start over at top */
Count = 0;
lpls = lphl->lpFirst;
while (Count < First) {
if (lphl->HasStrings) {
if (strstr(lpls->itemText, lpMatchStr) == lpls->itemText) return Count;
} else if (lphl->dwStyle & LBS_SORT) {
/* XXX Do a compare item */
} else {
if (lpls->mis.itemData == (DWORD)lpMatchStr) return Count;
}
lpls = lpls->lpNext;
Count++;
}
return LB_ERR;
}
int ListBoxResetContent(LPHEADLIST lphl)
{
LPLISTSTRUCT lpls;
int i;
if (lphl->ItemsCount == 0) return 0;
dprintf_listbox(stddeb, "ListBoxResetContent // ItemCount = %d\n",
lphl->ItemsCount);
for(i = 0; i < lphl->ItemsCount; i++) {
lpls = lphl->lpFirst;
if (lpls == NULL) return LB_ERR;
lphl->lpFirst = lpls->lpNext;
if (lpls->hData != 0) LIST_HEAP_FREE(lphl, lpls->hData);
free(lpls);
}
ListBoxInitialize(lphl);
return TRUE;
}
int ListBoxSetCurSel(LPHEADLIST lphl, WORD wIndex)
{
LPLISTSTRUCT lpls;
if (lphl->dwStyle & LBS_MULTIPLESEL) return 0;
if (lphl->ItemFocused != -1) {
lpls = ListBoxGetItem(lphl, lphl->ItemFocused);
if (lpls == 0) return LB_ERR;
lpls->itemState = 0;
}
if (wIndex != (UINT)-1) {
lphl->ItemFocused = wIndex;
lpls = ListBoxGetItem(lphl, wIndex);
if (lpls == 0) return LB_ERR;
lpls->itemState = ODS_SELECTED | ODS_FOCUS;
return 0;
}
return LB_ERR;
}
int ListBoxSetSel(LPHEADLIST lphl, WORD wIndex, WORD state)
{
LPLISTSTRUCT lpls;
if (!(lphl->dwStyle & LBS_MULTIPLESEL)) return 0;
if (wIndex == (UINT)-1) {
for (lpls = lphl->lpFirst; lpls != NULL; lpls = lpls->lpNext) {
lpls->itemState = state;
}
return 0;
}
if (wIndex >= lphl->ItemsCount) return LB_ERR;
lpls = ListBoxGetItem(lphl, wIndex);
lpls->itemState = state;
return 0;
}
int ListBoxGetSel(LPHEADLIST lphl, WORD wIndex)
{
LPLISTSTRUCT lpls = ListBoxGetItem(lphl, wIndex);
if (lpls == NULL) return LB_ERR;
return lpls->itemState;
}
int ListBoxDirectory(LPHEADLIST lphl, UINT attrib, LPSTR filespec)
{
struct dosdirent *dp, *dp_old;
char temp[256];
int drive;
LPSTR tstr;
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;
}
strcpy(temp,filespec);
tstr = strrchr(temp, '\\');
if (tstr != NULL) {
*(tstr+1) = 0;
filespec += tstr - temp + 1;
if (!DOS_ChangeDir( drive, temp )) return 0;
}
DOS_SetDefaultDrive( drive );
dprintf_listbox(stddeb,"Changing directory to %c:%s, filemask is %s\n",
drive+'A', temp, filespec);
}
if ((dp = (struct dosdirent *)DOS_opendir(filespec)) ==NULL) return 0;
dp_old = dp;
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, ".") != 0) {
sprintf(temp, "[%s]", dp->filename);
if (ListBoxAddString(lphl, temp) == LB_ERR) break;
}
}
else {
if (attrib & DDL_EXCLUSIVE) {
if (attrib & (DDL_READWRITE | DDL_READONLY | DDL_HIDDEN | DDL_SYSTEM)) {
if (ListBoxAddString(lphl, dp->filename) == LB_ERR) break;
}
} else {
if (ListBoxAddString(lphl, dp->filename) == LB_ERR) break;
}
}
}
DOS_closedir(dp_old);
if (attrib & DDL_DRIVES) {
int x;
for (x = 0; x != MAX_DOS_DRIVES ; x++) {
if (DOS_ValidDrive(x)) {
sprintf(temp, "[-%c-]", 'a'+x);
if (ListBoxInsertString(lphl, (UINT)-1, temp) == LB_ERR) break;
}
}
}
return 1;
}
int ListBoxGetItemRect(LPHEADLIST lphl, WORD wIndex, LPRECT lprect)
{
LPLISTSTRUCT lpls = ListBoxGetItem(lphl,wIndex);
if (lpls == NULL) return LB_ERR;
*lprect = lpls->itemRect;
return 0;
}
int ListBoxSetItemHeight(LPHEADLIST lphl, WORD wIndex, long height)
{
LPLISTSTRUCT lpls;
if (!(lphl->dwStyle & LBS_OWNERDRAWVARIABLE)) {
lphl->StdItemHeight = (short)height;
return 0;
}
lpls = ListBoxGetItem(lphl, wIndex);
if (lpls == NULL) return LB_ERR;
lpls->mis.itemHeight = height;
return 0;
}
int ListBoxFindNextMatch(LPHEADLIST lphl, WORD wChar)
{
LPLISTSTRUCT lpls;
UINT count,first;
if ((char)wChar < ' ') return LB_ERR;
if (!lphl->HasStrings) return LB_ERR;
lpls = lphl->lpFirst;
for (count = 0; lpls != NULL; lpls = lpls->lpNext, count++) {
if (tolower(*lpls->itemText) == tolower((char)wChar)) break;
}
if (lpls == NULL) return LB_ERR;
first = count;
for(; lpls != NULL; lpls = lpls->lpNext, count++) {
if (*lpls->itemText != (char)wChar)
break;
if (count > lphl->ItemFocused)
return count;
}
return first;
}
/***********************************************************************
* LBCreate
*/
static LONG LBCreate(HWND hwnd, WORD wParam, LONG lParam)
{
LPHEADLIST lphl;
RECT rect;
CreateListBoxStruct(hwnd, ODT_LISTBOX, GetWindowLong(hwnd,GWL_STYLE), GetParent(hwnd));
lphl = ListBoxGetStorageHeader(hwnd);
dprintf_listbox(stddeb,"ListBox WM_CREATE %p !\n", lphl);
GetClientRect(hwnd,&rect);
lphl->ColumnsWidth = rect.right - rect.left;
SetScrollRange(hwnd, SB_VERT, 0, ListMaxFirstVisible(lphl), TRUE);
SetScrollRange(hwnd, SB_HORZ, 1, 1, TRUE);
return 0;
}
/***********************************************************************
* LBDestroy
*/
static LONG LBDestroy(HWND hwnd, WORD wParam, LONG lParam)
{
LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
ListBoxResetContent(lphl);
DestroyListBoxStruct(lphl);
dprintf_listbox(stddeb,"ListBox WM_DESTROY %p !\n", lphl);
return 0;
}
/***********************************************************************
* LBVScroll
*/
static LONG LBVScroll(HWND hwnd, WORD wParam, LONG lParam)
{
LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
int y;
dprintf_listbox(stddeb,"ListBox WM_VSCROLL w=%04X l=%08lX !\n",
wParam, lParam);
y = lphl->FirstVisible;
switch(wParam) {
case SB_LINEUP:
if (lphl->FirstVisible > 0)
lphl->FirstVisible--;
break;
case SB_LINEDOWN:
lphl->FirstVisible++;
break;
case SB_PAGEUP:
if (lphl->FirstVisible > lphl->ItemsVisible) {
lphl->FirstVisible -= lphl->ItemsVisible;
} else {
lphl->FirstVisible = 0;
}
break;
case SB_PAGEDOWN:
lphl->FirstVisible += lphl->ItemsVisible;
break;
case SB_THUMBTRACK:
lphl->FirstVisible = LOWORD(lParam);
break;
}
if (lphl->FirstVisible > ListMaxFirstVisible(lphl))
lphl->FirstVisible = ListMaxFirstVisible(lphl);
if (y != lphl->FirstVisible) {
SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
InvalidateRect(hwnd, NULL, TRUE);
}
return 0;
}
/***********************************************************************
* LBHScroll
*/
static LONG LBHScroll(HWND hwnd, WORD wParam, LONG lParam)
{
LPHEADLIST lphl;
int y;
dprintf_listbox(stddeb,"ListBox WM_HSCROLL w=%04X l=%08lX !\n",
wParam, lParam);
lphl = ListBoxGetStorageHeader(hwnd);
y = lphl->FirstVisible;
switch(wParam) {
case SB_LINEUP:
if (lphl->FirstVisible > lphl->ItemsPerColumn) {
lphl->FirstVisible -= lphl->ItemsPerColumn;
} else {
lphl->FirstVisible = 0;
}
break;
case SB_LINEDOWN:
lphl->FirstVisible += lphl->ItemsPerColumn;
break;
case SB_PAGEUP:
if (lphl->ItemsPerColumn != 0) {
int lbsub = lphl->ItemsVisible / lphl->ItemsPerColumn * lphl->ItemsPerColumn;
if (lphl->FirstVisible > lbsub) {
lphl->FirstVisible -= lbsub;
} else {
lphl->FirstVisible = 0;
}
}
break;
case SB_PAGEDOWN:
if (lphl->ItemsPerColumn != 0)
lphl->FirstVisible += lphl->ItemsVisible /
lphl->ItemsPerColumn * lphl->ItemsPerColumn;
break;
case SB_THUMBTRACK:
lphl->FirstVisible = lphl->ItemsPerColumn * LOWORD(lParam);
break;
}
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);
}
}
return 0;
}
/***********************************************************************
* LBLButtonDown
*/
static LONG LBLButtonDown(HWND hwnd, WORD wParam, LONG lParam)
{
LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
WORD wRet;
int y;
RECT rectsel;
SetFocus(hwnd);
SetCapture(hwnd);
lphl->PrevFocused = lphl->ItemFocused;
y = ListBoxFindMouse(lphl, LOWORD(lParam), HIWORD(lParam));
if (y == -1)
return 0;
if (lphl->dwStyle & LBS_MULTIPLESEL) {
lphl->ItemFocused = y;
wRet = ListBoxGetSel(lphl, y);
ListBoxSetSel(lphl, y, !wRet);
} else {
ListBoxSetCurSel(lphl, y);
}
if (lphl->dwStyle & LBS_MULTIPLESEL)
ListBoxSendNotification(lphl, hwnd, LBN_SELCHANGE);
ListBoxGetItemRect(lphl, y, &rectsel);
InvalidateRect(hwnd, NULL, TRUE);
return 0;
}
/***********************************************************************
* LBLButtonUp
*/
static LONG LBLButtonUp(HWND hwnd, WORD wParam, LONG lParam)
{
LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
if (GetCapture() == hwnd) ReleaseCapture();
if (lphl->PrevFocused != lphl->ItemFocused)
ListBoxSendNotification(lphl, hwnd, LBN_SELCHANGE);
return 0;
}
/***********************************************************************
* LBRButtonUp
*/
static LONG LBRButtonUp(HWND hwnd, WORD wParam, LONG lParam)
{
LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
SendMessage(lphl->hParent, WM_COMMAND, GetWindowWord(hwnd,GWW_ID),
MAKELONG(hwnd, LBN_DBLCLK));
return 0;
}
/***********************************************************************
* LBMouseMove
*/
static LONG LBMouseMove(HWND hwnd, WORD wParam, LONG lParam)
{
LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
int y;
WORD wRet;
RECT rect, rectsel; /* XXX Broken */
dprintf_listbox(stddeb,"LBMouseMove %d %d\n",SLOWORD(lParam),SHIWORD(lParam));
if ((wParam & MK_LBUTTON) != 0) {
y = SHIWORD(lParam);
if (y < 0) {
if (lphl->FirstVisible > 0) {
lphl->FirstVisible--;
SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
InvalidateRect(hwnd, NULL, TRUE);
return 0;
}
}
GetClientRect(hwnd, &rect);
if (y >= rect.bottom) {
if (lphl->FirstVisible < ListMaxFirstVisible(lphl)) {
lphl->FirstVisible++;
SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
InvalidateRect(hwnd, NULL, TRUE);
return 0;
}
}
if ((y > 0) && (y < (rect.bottom - 4))) {
if ((y < rectsel.top) || (y > rectsel.bottom)) {
wRet = ListBoxFindMouse(lphl, LOWORD(lParam), HIWORD(lParam));
if (wRet == lphl->ItemFocused) {
return 0;
}
if (lphl->dwStyle & LBS_MULTIPLESEL) {
lphl->ItemFocused = wRet;
ListBoxSendNotification(lphl, hwnd, LBN_SELCHANGE);
} else {
ListBoxSetCurSel(lphl, wRet);
}
ListBoxGetItemRect(lphl, wRet, &rectsel);
InvalidateRect(hwnd, NULL, TRUE);
}
}
}
return 0;
}
/***********************************************************************
* LBKeyDown
*/
static LONG LBKeyDown(HWND hwnd, WORD wParam, LONG lParam)
{
LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
WORD newFocused = lphl->ItemFocused;
if (wParam == VK_SPACE) {
if (lphl->dwStyle & LBS_MULTIPLESEL) {
WORD wRet = ListBoxGetSel(lphl, lphl->ItemFocused);
ListBoxSetSel(lphl, lphl->ItemFocused, !wRet);
}
return 0;
}
switch(wParam) {
case VK_HOME:
newFocused = 0;
break;
case VK_END:
newFocused = lphl->ItemsCount - 1;
break;
case VK_LEFT:
if (lphl->dwStyle & LBS_MULTICOLUMN) {
if (newFocused >= lphl->ItemsPerColumn) {
newFocused -= lphl->ItemsPerColumn;
} else {
newFocused = 0;
}
}
break;
case VK_UP:
if (newFocused > 0) newFocused--;
break;
case VK_RIGHT:
if (lphl->dwStyle & LBS_MULTICOLUMN) {
newFocused += lphl->ItemsPerColumn;
}
break;
case VK_DOWN:
newFocused++;
break;
case VK_PRIOR:
if (newFocused > lphl->ItemsVisible) {
newFocused -= lphl->ItemsVisible;
} else {
newFocused = 0;
}
break;
case VK_NEXT:
newFocused += lphl->ItemsVisible;
break;
default:
return 0;
}
if (newFocused >= lphl->ItemsCount)
newFocused = lphl->ItemsCount - 1;
if (!(lphl->dwStyle & LBS_MULTIPLESEL)) {
ListBoxSetCurSel(lphl, newFocused);
ListBoxSendNotification(lphl, hwnd, LBN_SELCHANGE);
}
lphl->ItemFocused = newFocused;
ListBoxScrollToFocus(lphl);
SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
InvalidateRect(hwnd, NULL, TRUE);
return 0;
}
/***********************************************************************
* LBChar
*/
static LONG LBChar(HWND hwnd, WORD wParam, LONG lParam)
{
LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
WORD newFocused;
newFocused = ListBoxFindNextMatch(lphl, wParam);
if (newFocused == (WORD)LB_ERR) return 0;
if (newFocused >= lphl->ItemsCount)
newFocused = lphl->ItemsCount - 1;
if (!(lphl->dwStyle & LBS_MULTIPLESEL)) {
ListBoxSetCurSel(lphl, newFocused);
ListBoxSendNotification(lphl, hwnd, LBN_SELCHANGE);
}
lphl->ItemFocused = newFocused;
ListBoxScrollToFocus(lphl);
SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
InvalidateRect(hwnd, NULL, TRUE);
return 0;
}
/***********************************************************************
* LBSetRedraw
*/
static LONG LBSetRedraw(HWND hwnd, WORD wParam, LONG lParam)
{
LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
dprintf_listbox(stddeb,"ListBox WM_SETREDRAW hWnd=%04X w=%04X !\n", hwnd, wParam);
lphl->bRedrawFlag = wParam;
return 0;
}
/***********************************************************************
* LBSetFont
*/
static LONG LBSetFont(HWND hwnd, WORD wParam, LONG lParam)
{
LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
if (wParam == 0)
lphl->hFont = GetStockObject(SYSTEM_FONT);
else
lphl->hFont = wParam;
return 0;
}
/***********************************************************************
* LBPaint
*/
static LONG LBPaint(HWND hwnd, WORD wParam, LONG lParam)
{
LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
LPLISTSTRUCT lpls;
PAINTSTRUCT ps;
HBRUSH hBrush;
HFONT hOldFont;
HDC hdc;
RECT rect;
int i, top, height, maxwidth, ipc;
top = 0;
hdc = BeginPaint( hwnd, &ps );
if (!IsWindowVisible(hwnd) || !lphl->bRedrawFlag) {
EndPaint(hwnd, &ps);
return 0;
}
hOldFont = SelectObject(hdc, lphl->hFont);
hBrush = SendMessage(lphl->hParent, WM_CTLCOLOR, hdc,
MAKELONG(hwnd, CTLCOLOR_LISTBOX));
if (hBrush == 0) hBrush = GetStockObject(WHITE_BRUSH);
GetClientRect(hwnd, &rect);
FillRect(hdc, &rect, hBrush);
maxwidth = rect.right;
if (lphl->dwStyle & LBS_MULTICOLUMN) {
rect.right = lphl->ColumnsWidth;
}
lpls = lphl->lpFirst;
lphl->ItemsVisible = 0;
lphl->ItemsPerColumn = ipc = 0;
for(i = 0; i < lphl->ItemsCount; i++) {
if (lpls == NULL) break;
if (i >= lphl->FirstVisible) {
height = lpls->mis.itemHeight;
if (top > rect.bottom) {
if (lphl->dwStyle & 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->itemRect.top = top;
lpls->itemRect.bottom = top + height;
lpls->itemRect.left = rect.left;
lpls->itemRect.right = rect.right;
dprintf_listbox(stddeb,"drawing item: %d %d %d %d %d\n",rect.left,top,rect.right,top+height,lpls->itemState);
if (lphl->OwnerDrawn) {
ListBoxDrawItem (hwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_DRAWENTIRE, 0);
if (lpls->itemState)
ListBoxDrawItem (hwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_SELECT, ODS_SELECTED);
} else {
ListBoxDrawItem (hwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_DRAWENTIRE,
lpls->itemState);
}
if ((lphl->ItemFocused == i) && GetFocus() == hwnd)
ListBoxDrawItem (hwnd,lphl, hdc, lpls, &lpls->itemRect, ODA_FOCUS, ODS_FOCUS);
top += height;
lphl->ItemsVisible++;
ipc++;
}
lpls = lpls->lpNext;
}
SelectObject(hdc,hOldFont);
EndPaint( hwnd, &ps );
return 0;
}
/***********************************************************************
* LBSetFocus
*/
static LONG LBSetFocus(HWND hwnd, WORD wParam, LONG lParam)
{
dprintf_listbox(stddeb,"ListBox WM_SETFOCUS !\n");
return 0;
}
/***********************************************************************
* LBKillFocus
*/
static LONG LBKillFocus(HWND hwnd, WORD wParam, LONG lParam)
{
dprintf_listbox(stddeb,"ListBox WM_KILLFOCUS !\n");
InvalidateRect(hwnd, NULL, TRUE);
return 0;
}
/***********************************************************************
* LBResetContent
*/
static LONG LBResetContent(HWND hwnd, WORD wParam, LONG lParam)
{
LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
dprintf_listbox(stddeb,"ListBox LB_RESETCONTENT !\n");
ListBoxResetContent(lphl);
ListBoxUpdateWindow(hwnd, lphl, TRUE);
return 0;
}
/***********************************************************************
* LBDir
*/
static LONG LBDir(HWND hwnd, WORD wParam, LONG lParam)
{
WORD wRet;
LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
dprintf_listbox(stddeb,"ListBox LB_DIR !\n");
wRet = ListBoxDirectory(lphl, wParam, (LPSTR)PTR_SEG_TO_LIN(lParam));
ListBoxUpdateWindow(hwnd, lphl, TRUE);
return wRet;
}
/***********************************************************************
* LBAddString
*/
static LONG LBAddString(HWND hwnd, WORD wParam, LONG lParam)
{
WORD wRet;
LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
if (lphl->HasStrings)
wRet = ListBoxAddString(lphl, (LPSTR)PTR_SEG_TO_LIN(lParam));
else
wRet = ListBoxAddString(lphl, (LPSTR)lParam);
ListBoxUpdateWindow(hwnd,lphl,TRUE);
return wRet;
}
/***********************************************************************
* LBGetText
*/
static LONG LBGetText(HWND hwnd, WORD wParam, LONG lParam)
{
LONG wRet;
LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
dprintf_listbox(stddeb, "LB_GETTEXT wParam=%d\n",wParam);
wRet = ListBoxGetText(lphl, wParam, (LPSTR)PTR_SEG_TO_LIN(lParam));
return wRet;
}
/***********************************************************************
* LBInsertString
*/
static LONG LBInsertString(HWND hwnd, WORD wParam, LONG lParam)
{
WORD wRet;
LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
if (lphl->HasStrings)
wRet = ListBoxInsertString(lphl, wParam, (LPSTR)PTR_SEG_TO_LIN(lParam));
else
wRet = ListBoxInsertString(lphl, wParam, (LPSTR)lParam);
ListBoxUpdateWindow(hwnd,lphl,TRUE);
return wRet;
}
/***********************************************************************
* LBDeleteString
*/
static LONG LBDeleteString(HWND hwnd, WORD wParam, LONG lParam)
{
LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
LONG lRet = ListBoxDeleteString(lphl,wParam);
ListBoxUpdateWindow(hwnd,lphl,TRUE);
return lRet;
}
/***********************************************************************
* LBFindString
*/
static LONG LBFindString(HWND hwnd, WORD wParam, LONG lParam)
{
LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
return ListBoxFindString(lphl, wParam, lParam);
}
/***********************************************************************
* LBGetCaretIndex
*/
static LONG LBGetCaretIndex(HWND hwnd, WORD wParam, LONG lParam)
{
LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
return lphl->ItemFocused;
}
/***********************************************************************
* LBGetCount
*/
static LONG LBGetCount(HWND hwnd, WORD wParam, LONG lParam)
{
LPHEADLIST lphl;
lphl = ListBoxGetStorageHeader(hwnd);
return lphl->ItemsCount;
}
/***********************************************************************
* LBGetCurSel
*/
static LONG LBGetCurSel(HWND hwnd, WORD wParam, LONG lParam)
{
LPHEADLIST lphl;
lphl = ListBoxGetStorageHeader(hwnd);
dprintf_listbox(stddeb,"ListBox LB_GETCURSEL %u !\n",
lphl->ItemFocused);
return lphl->ItemFocused;
}
/***********************************************************************
* LBGetHorizontalExtent
*/
static LONG LBGetHorizontalExtent(HWND hwnd, WORD wParam, LONG lParam)
{
return 0;
}
/***********************************************************************
* LBGetItemHeight
*/
static LONG LBGetItemHeight(HWND hwnd, WORD wParam, LONG lParam)
{
LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
LPLISTSTRUCT lpls = ListBoxGetItem (lphl, wParam);
if (lpls == NULL) return LB_ERR;
return lpls->mis.itemHeight;
}
/***********************************************************************
* LBGetItemRect
*/
static LONG LBGetItemRect(HWND hwnd, WORD wParam, LONG lParam)
{
LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
return ListBoxGetItemRect(lphl, wParam, PTR_SEG_TO_LIN(lParam));
}
/***********************************************************************
* LBGetSel
*/
static LONG LBGetSel(HWND hwnd, WORD wParam, LONG lParam)
{
LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
return ListBoxGetSel(lphl, wParam);
}
/***********************************************************************
* LBGetSelCount
*/
static LONG LBGetSelCount(HWND hwnd, WORD wParam, LONG lParam)
{
LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
LPLISTSTRUCT lpls;
int cnt = 0;
if (!(lphl->dwStyle & LBS_MULTIPLESEL)) return LB_ERR;
lpls = lphl->lpFirst;
while (lpls != NULL) {
if (lpls->itemState > 0) cnt++;
lpls = lpls->lpNext;
}
return cnt;
}
/***********************************************************************
* LBGetSelItems
*/
static LONG LBGetSelItems(HWND hwnd, WORD wParam, LONG lParam)
{
LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
LPLISTSTRUCT lpls;
int cnt, idx;
int *lpItems = PTR_SEG_TO_LIN(lParam);
if (!(lphl->dwStyle & LBS_MULTIPLESEL)) return LB_ERR;
if (wParam == 0) return 0;
lpls = lphl->lpFirst;
cnt = 0; idx = 0;
while (lpls != NULL) {
if (lpls->itemState > 0) lpItems[cnt++] = idx;
if (cnt == wParam) break;
idx++;
lpls = lpls->lpNext;
}
return cnt;
}
/***********************************************************************
* LBGetTextLen
*/
static LONG LBGetTextLen(HWND hwnd, WORD wParam, LONG lParam)
{
LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
LPLISTSTRUCT lpls = ListBoxGetItem(lphl,wParam);
if (lpls == NULL || !lphl->HasStrings) return LB_ERR;
return strlen(lpls->itemText);
}
/***********************************************************************
* LBGetDlgCode
*/
static LONG LBGetDlgCode(HWND hwnd, WORD wParam, LONG lParam)
{
return DLGC_WANTARROWS | DLGC_WANTCHARS;
}
/***********************************************************************
* LBGetTopIndex
*/
static LONG LBGetTopIndex(HWND hwnd, WORD wParam, LONG lParam)
{
LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
return lphl->FirstVisible;
}
/***********************************************************************
* LBSelectString
*/
static LONG LBSelectString(HWND hwnd, WORD wParam, LONG lParam)
{
LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
WORD wRet;
wRet = ListBoxFindString(lphl, wParam, lParam);
/* XXX add functionality here */
return 0;
}
/***********************************************************************
* LBSelItemRange
*/
static LONG LBSelItemRange(HWND hwnd, WORD wParam, LONG lParam)
{
LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
LPLISTSTRUCT lpls;
WORD cnt;
WORD first = LOWORD(lParam);
WORD last = HIWORD(lParam);
BOOL select = wParam;
if (!(lphl->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->itemState = select ? ODS_SELECTED : 0;
if (cnt > last)
break;
lpls = lpls->lpNext;
}
return 0;
}
/***********************************************************************
* LBSetCaretIndex
*/
static LONG LBSetCaretIndex(HWND hwnd, WORD wParam, LONG lParam)
{
LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
if (!(lphl->dwStyle & LBS_MULTIPLESEL)) return 0;
if (wParam >= lphl->ItemsCount) return LB_ERR;
lphl->ItemFocused = wParam;
ListBoxScrollToFocus (lphl);
SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
InvalidateRect(hwnd, NULL, TRUE);
return 0;
}
/***********************************************************************
* LBSetColumnWidth
*/
static LONG LBSetColumnWidth(HWND hwnd, WORD wParam, LONG lParam)
{
LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
lphl->ColumnsWidth = wParam;
InvalidateRect(hwnd,NULL,TRUE);
return 0;
}
/***********************************************************************
* LBSetHorizontalExtent
*/
static LONG LBSetHorizontalExtent(HWND hwnd, WORD wParam, LONG lParam)
{
return 0;
}
/***********************************************************************
* LBGetItemData
*/
static LONG LBGetItemData(HWND hwnd, WORD wParam, LONG lParam)
{
LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
dprintf_listbox(stddeb, "LB_GETITEMDATA wParam=%x\n", wParam);
return ListBoxGetItemData(lphl, wParam);
}
/***********************************************************************
* LBSetItemData
*/
static LONG LBSetItemData(HWND hwnd, WORD wParam, LONG lParam)
{
LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
dprintf_listbox(stddeb, "LB_SETITEMDATA wParam=%x lParam=%lx\n", wParam, lParam);
return ListBoxSetItemData(lphl, wParam, lParam);
}
/***********************************************************************
* LBSetTabStops
*/
static LONG LBSetTabStops(HWND hwnd, 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
*/
static LONG LBSetCurSel(HWND hwnd, WORD wParam, LONG lParam)
{
LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
WORD wRet;
dprintf_listbox(stddeb,"ListBox LB_SETCURSEL wParam=%x !\n",
wParam);
wRet = ListBoxSetCurSel(lphl, wParam);
SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
InvalidateRect(hwnd, NULL, TRUE);
return wRet;
}
/***********************************************************************
* LBSetSel
*/
static LONG LBSetSel(HWND hwnd, WORD wParam, LONG lParam)
{
LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
WORD wRet;
dprintf_listbox(stddeb,"ListBox LB_SETSEL wParam=%x lParam=%lX !\n", wParam, lParam);
wRet = ListBoxSetSel(lphl, LOWORD(lParam), wParam);
InvalidateRect(hwnd, NULL, TRUE);
return wRet;
}
/***********************************************************************
* LBSetTopIndex
*/
static LONG LBSetTopIndex(HWND hwnd, WORD wParam, LONG lParam)
{
LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
dprintf_listbox(stddeb,"ListBox LB_SETTOPINDEX wParam=%x !\n",
wParam);
lphl->FirstVisible = wParam;
SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
InvalidateRect(hwnd, NULL, TRUE);
return 0;
}
/***********************************************************************
* LBSetItemHeight
*/
static LONG LBSetItemHeight(HWND hwnd, WORD wParam, LONG lParam)
{
LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
WORD wRet;
dprintf_listbox(stddeb,"ListBox LB_SETITEMHEIGHT wParam=%x lParam=%lX !\n", wParam, lParam);
wRet = ListBoxSetItemHeight(lphl, wParam, lParam);
InvalidateRect(hwnd,NULL,TRUE);
return wRet;
}
/***********************************************************************
* ListBoxWndProc
*/
LONG ListBoxWndProc(HWND hwnd, WORD message, WORD wParam, LONG lParam)
{
switch (message) {
case WM_CREATE: return LBCreate(hwnd, wParam, lParam);
case WM_DESTROY: return LBDestroy(hwnd, wParam, lParam);
case WM_GETDLGCODE: return LBGetDlgCode(hwnd, wParam, lParam);
case WM_VSCROLL: return LBVScroll(hwnd, wParam, lParam);
case WM_HSCROLL: return LBHScroll(hwnd, wParam, lParam);
case WM_LBUTTONDOWN: return LBLButtonDown(hwnd, wParam, lParam);
case WM_LBUTTONUP: return LBLButtonUp(hwnd, wParam, lParam);
case WM_RBUTTONUP: return LBRButtonUp(hwnd, wParam, lParam);
case WM_LBUTTONDBLCLK: return LBRButtonUp(hwnd, wParam, lParam);
case WM_MOUSEMOVE: return LBMouseMove(hwnd, wParam, lParam);
case WM_KEYDOWN: return LBKeyDown(hwnd, wParam, lParam);
case WM_CHAR: return LBChar(hwnd, wParam, lParam);
case WM_SETFONT: return LBSetFont(hwnd, wParam, lParam);
case WM_SETREDRAW: return LBSetRedraw(hwnd, wParam, lParam);
case WM_PAINT: return LBPaint(hwnd, wParam, lParam);
case WM_SETFOCUS: return LBSetFocus(hwnd, wParam, lParam);
case WM_KILLFOCUS: return LBKillFocus(hwnd, wParam, lParam);
case LB_RESETCONTENT: return LBResetContent(hwnd, wParam, lParam);
case LB_DIR: return LBDir(hwnd, wParam, lParam);
case LB_ADDSTRING: return LBAddString(hwnd, wParam, lParam);
case LB_INSERTSTRING: return LBInsertString(hwnd, wParam, lParam);
case LB_DELETESTRING: return LBDeleteString(hwnd, wParam, lParam);
case LB_FINDSTRING: return LBFindString(hwnd, wParam, lParam);
case LB_GETCARETINDEX: return LBGetCaretIndex(hwnd, wParam, lParam);
case LB_GETCOUNT: return LBGetCount(hwnd, wParam, lParam);
case LB_GETCURSEL: return LBGetCurSel(hwnd, wParam, lParam);
case LB_GETHORIZONTALEXTENT: return LBGetHorizontalExtent(hwnd, wParam, lParam);
case LB_GETITEMDATA: return LBGetItemData(hwnd, wParam, lParam);
case LB_GETITEMHEIGHT: return LBGetItemHeight(hwnd, wParam, lParam);
case LB_GETITEMRECT: return LBGetItemRect(hwnd, wParam, lParam);
case LB_GETSEL: return LBGetSel(hwnd, wParam, lParam);
case LB_GETSELCOUNT: return LBGetSelCount(hwnd, wParam, lParam);
case LB_GETSELITEMS: return LBGetSelItems(hwnd, wParam, lParam);
case LB_GETTEXT: return LBGetText(hwnd, wParam, lParam);
case LB_GETTEXTLEN: return LBGetTextLen(hwnd, wParam, lParam);
case LB_GETTOPINDEX: return LBGetTopIndex(hwnd, wParam, lParam);
case LB_SELECTSTRING: return LBSelectString(hwnd, wParam, lParam);
case LB_SELITEMRANGE: return LBSelItemRange(hwnd, wParam, lParam);
case LB_SETCARETINDEX: return LBSetCaretIndex(hwnd, wParam, lParam);
case LB_SETCOLUMNWIDTH: return LBSetColumnWidth(hwnd, wParam, lParam);
case LB_SETHORIZONTALEXTENT: return LBSetHorizontalExtent(hwnd, wParam, lParam);
case LB_SETITEMDATA: return LBSetItemData(hwnd, wParam, lParam);
case LB_SETTABSTOPS: return LBSetTabStops(hwnd, wParam, lParam);
case LB_SETCURSEL: return LBSetCurSel(hwnd, wParam, lParam);
case LB_SETSEL: return LBSetSel(hwnd, wParam, lParam);
case LB_SETTOPINDEX: return LBSetTopIndex(hwnd, wParam, lParam);
case LB_SETITEMHEIGHT: return LBSetItemHeight(hwnd, wParam, lParam);
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
/************************************************************************
* 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(lphl, lphl->ItemFocused, s);
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) {
LPHEADLIST lphl;
hWnd = GetDlgItem(hDlg, nIDLBox);
lphl = ListBoxGetStorageHeader(hWnd);
ListBoxResetContent(lphl);
ret = ListBoxDirectory(lphl, wType, lpPathSpec);
ListBoxUpdateWindow(hWnd, lphl, TRUE);
} 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;
}