1
0
Fork 0
mirror of synced 2025-03-07 03:53:26 +01:00
wine/controls/listbox.c
Alexandre Julliard fb9a919f8a Release 940301
Tue Mar  1 11:30:21 1994  Bob Amstadt  (bob@pooh)

	* [Configure] [*/Imakefile]
	Created configure script to handle different types of Wine builds.

	* [Configure] [tools/build.c] [if1632/Imakefile] [Wine.tmpl]
	Added ability to compile Wine on systems with 14-char filename limit.

	* [if1632/relay.c] [include/options.h] [misc/main.c]
	Added -relaydbg option to command line if DEBUG_RELAY is defined.

	* [loader/selector.c]
	Fixed bug in GetEntryDLLName() that caused Wine to seg fault.

	* [memory/heap.c]
	Fixed LocalInit() to work correctly.

	* [misc/user.c]
	Added code to call loaded DLLs' initialization routines.

Tue Mar  1 01:01:17 MET 1994  julliard@di.epfl.ch (Alexandre Julliard)

	* [windows/dce.c]
	Added clipping of child windows by their parent's client area.

	* [windows/nonclient.c]
	Bug fix in NC_DoNCPaint().

	* [windows/painting.c]
	Bug fix in RedrawWindow().

Feb 27, 94 martin2@trgcorp.solucorp.qc.ca (Martin Ayotte)

	* [mem/atom.c]
	Bug fix again in ATOM_DeleteAtom() : 
		change LocalFree() by USER_HEAP_FREE().
	(Previous patch done Feb 13th had been lost)

	* [controls/scroll.c]
	Move bitmaps loading in AllocScrollBar() instead of in WM_CREATE.

	* [windows/class.c] (sorry Alex ...)
	There was no bug there "in RegisterClass() : 
                WNDCLASS->lpszClassName was reset to NULL."
                              ^^^^^

	* [misc/clipboard.c]	--- New File ---
	New function EnumClipboardFormats().
	New function OpenClipboard().
	New function CloseClipboard().
	New function EmptyClipboard().
	New function GetClipboardOwner().
	New function GetClipboardViewer().
	New function CountClipboardFormats().
	New function IsClipboardFormatAvailable().
	New function OpenClipboard().
	New function GetClipboardData().
	New function SetClipboardViewer().
	New function EnumClipboardFormats().
	New function RegisterClipboardFormat().
	New function ChangeClipboardChain().
	New function SetClipboardData().
	New function GetOpenClipboardWindow().
	New function GetPriorityClipboardFormat().
	New function GetClipboardFormatName().

Tue Mar  1 20:15:45 1994  Erik Bos <erik@trashcan.hacktic.nl>

	* [misc/comm.c]
	bugfix in OpenComm().

Tue Feb 22 18:04:02 1994  Jeffrey Hsu <hsu@freefall.cdrom.com>

	* [include/winsock.h]
	The sockproto struct is already defined in <sys/socket.h>

	* [misc/winsock.c]
	Need to include <netinet/in.h> for struct in-addr.
	Use sys_errlist[] instead of strerror[].

	*[toolkit/heap.c]
	ANSI C specifies that the malloc functions are defined in stdlib.h,
	  so we don't need to include malloc.h.

	*[loader/ldtlib.c]
	Print informative error message about probable cause of i386_set_ldt()
	  failure and then exit.

	*[Imakefile]
	For systems that don't use gmake by default, set the MAKE variable
	  to gmake and propagate it on recursive makes.
	Take out -li386 for FreeBSD systems and define __FreeBSD__ so Wine
	  can be built with the FreeBSD 1.0.2 compiler.

Tue Feb 22 02:52:19 EST 1994    jrichard@cs.uml.edu (John Richardson)

        * [objects/bitblt.c]
        Added in three functions to do stretching and compression
        for WHITEONBLACK, BLACKONWHITE, and color copies.

Tue Feb 22 15:01:31 EST 1994    jrichard@cs.uml.edu (John Richardson)

        * [windows/graphics.c]
        Added FloodFill and FloodFill_rec.  FloodFill_rec is pretty
        inefficent, but should suffice for now.

        * [include/windows.h]
        Changed the x,y paramaters for the FloodFill prototype 
        from ints to shorts

Tue Feb 22 00:58:28 MET 1994  julliard@di.epfl.ch (Alexandre Julliard)

	* [windows/widgets.c]
	Added desktop window class.

	* [windows/painting.c]
	Bug fix in RedrawWindow().
	Implemented ExcludeUpdateRgn().

	* [windows/win.c] [windows/winpos.c]
	Implemented desktop window.

	* [controls/desktop.c]
	Preliminary desktop window procedure.

Feb 20, 94 martin2@trgcorp.solucorp.qc.ca (Martin Ayotte)

	* [controls/menu.c]
	New function LoadMenuIndirect().
	New function GetMenuCheckMarkDimensions().

	* [if1632/user.spec]
	Entry for DefDlgProc().

	* [windows/class.c]
	Fix bug in RegisterClass() : 
		WNDCLASS->lpszMenuName was reset to NULL.

	* [windows/win.c]
	In CreateWindowEx(), if hMenu == 0 then use 
		wndclass->lpszMenuName to load Menu from resource;

Mon Feb 21 22:38:28 1994 Erik Bos (erik@trashcan.hacktic.nl)

	* [loader/library.c] [loader/wine.c]
	Fixed runing DLL's as main executable problem.

	* [misc/dos_fs.c]
	Added wildcard support in DOS_readdir().

	* [misc/winsocket.c]
	Added proper error handling of BSD winsocket functions.

	* [miscemu/int21.c]
	KERNEL_DOS3Call renamed to DOS3Call and modified to use do_int21().

	* [main/main.c]
	Added functions for GetVersion, GetWinFlags and GetTimerResolution
	for libwine.a, SystemParametersInfo() partly implemented.

Tue Feb 22 19:00:02 1994  Miguel de Icaza  (miguel@xochitl.nuclecu.unam.mx)

	* [toolkit/winmain.c]
	Added _WinMain function. Setups the library (calls USER_InitApp).

	* [toolkit/sup.c]
	Added load_mz_header, load_ne_header, load_type_info and
	load_name_info functions.

	* [toolkit/heap.c] 
	Code cleanup. 

	* [misc/user.c]
	Moved from loader/misc.c. I hope to put back all the loader
	functions in the ~loader subdirectory in the future. CUrrently is
	needed since it has USER_InitApp.

	* [misc/resource.c]
	Since WineLib will probably need DLLs (currently it needs
	Sysres.dll). WineLib will be using much code of the loader again.
	So I removed some ifdefs that were used by WineLib.

	Added load_typeinfo and load_nameinfo (and the corresponding
	functions in [toolkit/sup.c]

	Added integer convertion functions in the needed places.

	Added very ugly patch (includes wine.c). In the next release I
	plan to move back all the loader routines to ~/loader. In the
	meantime I needed this patch. It doesn't affect any of the
	emulator code (its ifdefed for WineLib).

	* [misc/main.c]
	Cleaned up call to WinMain (now uses [toolkit/winmain.c]
	Ifdefed argument number checking when compiling the library.

	* [loader/wine.c]
	Modified to use load_(mz|ne)_header instead of doing a direct
	read.  When compiling the emulator it still uses the direct read
	for performance. 

	* [include/wine.h]
	Prototypes for loading routines.

	* [include/class.h]
	Added WINE_PACKED macro instead of __attribute__ ((packed))

	* [include/arch.h]
	Macros for converting integers (Little endian to big-endian).
	Needed in the Sun to allow loading of DLL files.

Mon Feb 14 23:48:09 MET 1994  julliard@di.epfl.ch (Alexandre Julliard)

	* [windows/clipping.c]
	Moved everything into windows/painting.c and removed this file.

	* [windows/message.c]
	Removed calls to memmove() in MSG_RemoveMsg().

	* [windows/nonclient.c]
	Added WM_GETMINMAXINFO support for window resizing.

	* [windows/painting.c]
	Implemented RedrawWindow().

	* [windows/scroll.c]
	Bug fix in ScrollWindowEx().

	* [windows/win.c]
	Moved UpdateWindow() to windows/painting.c.

Fri Feb 11 12:41:28 1994  Erik Bos (erik@trashcan.hacktic.nl)
	
	* [loader/wine.c] [misc/dos_fs.c]
	getenv() eq NULL bugfixes.

	* [misc/comm.c]
	cfmakeraw changed for SunOS.

Feb 13, 94 martin2@trgcorp.solucorp.qc.ca (Martin Ayotte)

	* [mem/atom.c]
	Bug fix in ATOM_DeleteAtom() : 
		change LocalFree() by USER_HEAP_FREE().

	* [misc/message.c]
	New function FatalAppExit().

	* [objects/font.c]
	New empty stub SetMapperFlags().

	* [controls/menu.c]
	Better CheckMark & other bitmaps placement.

	* [windows/graphics.c]
	New function RoundRect() : calc.exe now working...

Tue Feb 15 14:29:37 1994  John Richardson

        * [objects/bitblt.c]
        Fixed StretchBlt so it works quicker and faster.  It still doesn't
        use the StretchMode bits for bitmap compression, but that will
        come soon.

Mon Feb 14 13:21:04 1994  Miguel de Icaza  (miguel@roxanne.nuclecu.unam.mx)

	* [include/windows.h,dialog.h,gdi.h]
	Changed __atribute__ ((packed)) for WINE_PACKED. 
	When compiling the library this is defined as nothing. This gets
	rid with all the problems compiling under SunOS. Also 

	* [windows/utility.c]
	Added DebugPrintString.

	* [toolkit/sup.c]
	Added hSysRes = 1 definition to resolve externals.
	Added CallLineDDAProc function (toolkit version).
	Added toy, and hi ineficient memmove until code in message.c get
	rewritten.

	* [objects/gdiobj.c]
	Ifdefed linux/emulator-dependent code to allow compilation of
	WineLib.

	* [misc/winsocket.c]
	Added ifdef to allow compilation under SunOS.

	* [misc/resource.c]
	When compiling the library, the resource file is expected to be in
	a file called $argv[0].Res. Also the information of the resource
	is expected to be at offset 0 of the .Res file.

	* [misc/main.c]
	Call WinMain with arguments if compiling WineLib.
	Call shutdown functions (Comm_DeInit, DOS_DeInitFS).
	Call sync_profiles to preserve changes to .INI files.

	* [misc/comm.c,dos_fs.c]
	removed call to atexit(Comm_DeInit)
	removed call to atexit(DOS_DeInitFS)
	Shutdown functions are now called from the return of WinMain

	* removed memorylib subdirectory

	* moved memory/atom.c    to misc/atom.c
	  moved memorylib/heap.c to toolkit/heap.c

	* [loader/wine.c]
	Moved DebugPrintString to windows/utility.c

	* [include/winsock.h]
	Define SO_DONTLINGER only if it has not been previously defined.

	* [include/windows.h]
	added definition for DLGPROC.
	added definition for LMEM_WINE_ALIGN and other LMEM_* constants.
	When compiling WineLib WNDPROC is defined with all the parameters
	to avoid compilation problems.

	* [include/user.h]
	When compiling WineLib USER_HEAP_(ALLOC|REALLOC|ADDR|FREE) the
	calls are translated to the library allocation routines.

	* [include/gdi.h,user.h]
	When compiling WineLib GDI_HEAP_(ALLOC|ADDR|FREE) the calls are
	translated to the library allocation routines.

	* [include/atom.h]
	Defined LocalAlign. When compiling the emulator it's translated as
	a call to LocalAlloc (the original code), when compiling WineLib
	as a call to LocalAlloc with a WINE-flag called LMEM_WINE_ALIGN
	(atom.c needs aligned data on a 4 byte boundary).

	* [misc/file.c]
	Renamed KERNEL_* functions and fixed prototypes.

	* [if1632/kernel.spec]
	Renamed KERNEL_* functions in order to be used by applications
	using Wine as a library (OpeFile, _lclose, _lread, _lcreate,
	_llseek, _lopen, _lwrite).

	* [Makefile]
	Create library instead of executable when building target
	libwine.a 

Tue Feb  8 13:52:11 1994  Miguel de Icaza  (miguel@roxanne)

	* [Makefiles]
	Use $(CC) instead of cc.
	Added libwine target.

	* [include/prototypes]
	#ifdefed section for WineLib

	* moved loader/cursor.c   to misc/cursor.c
	  moved loader/resource.c to misc/resource.c
	  moved misc/emulate.c    to miscemu/emulate.c
	  moved misc/int1a.c      to miscemu/int1a.c
	  moved misc/int21.c	  to miscemu/int21.c
	  moved	misc/kernel.c	  to miscemu/kernel.c
	  moved misc/user.c       to miscemu/user.c

	* [memorylib/heap.c]
	Heap management for WineLib

	* [misc/comm.c]
	Modified to allow compilation under SunOS (#include errno, SunOS
	doesn't have atexit ()).

	* [misc/dos_fs.c]
	Modified to allow compilation under SunOS (#include vfs.h)

	* [misc/file.c]
	Modified to allow compilation under SunOS (OPEN_MAX constant,
	#include unistd.h)

	* [objects/palette.c]
	Modified to allow compilation under SunOS (#include limits)

	* [toolkit/sup.c]
	WineLib version of CallWindowProc.

	* [windows/event.c]
	Typedef XPointer under X11R4 (OpenWindows).

	* [windows/win.c]
	When compiling WineLib, use direct callbacks instead of the
	windows supplied callbacks.

Mon Feb  7 22:37:34 MET 1994  julliard@di.epfl.ch (Alexandre Julliard)

	* [loader/cursor.c]
	New function CURSOR_SetWinCursor(), for internal use, to set
	the cursor of a specific window more reliably than with SetCursor().

	* [windows/nonclient.c]
	Better window management. Moving and resizing from the system
	menu should work now.
	Added scroll-bar mouse tracking.

	* [windows/win.c]
	Moved scroll-bar creation and destruction to defwnd.c.

Feb 5, 94 martin2@trgcorp.solucorp.qc.ca (Martin Ayotte)

	* [windows/nonclient.c]
	Call to StdDrawMenuBar() during NC's drawing.
	New NC_TrackMouseMenuBar() function which call 
		MenuButtonDown(), MenuButtonUp() & MenuMouseMove().

	* [controls/menu.c]
	New ChangeMenu() function.
	Remove permanently old Xt menu code.
	Make common functions MenuButtonDown(), MenuButtonUp()
		& MenuMouseMove() for both popups & menubar.
	
	* [controls/combo.c]
	Paint OBM_COMBO directly in combo client.

	* [controls/listbox.c]
	Fix bug in multicolumns calculations.

	* [controls/Makefile]
	Remove rules for old file 'caption.c'.

	* [misc/kernel.c]
	Remove empty stub GetModuleFileName().

	* [loader/library.c]
	New GetModuleHandle() function.
	New GetModuleUsage() function.
	New GetModuleFileName() function.

	* [loader/resource.c]
	Try to find the bug a missing menu loading ... Not found yet !

	* [windows/win.c]
	Remove old menubar creation.

Thu Feb  3 22:30:11 1994  Erik Bos (erik@trashcan.hacktic.nl)

	* [misc/winsocket.c]
	More functions added.

	* [if1632/winsock.spec] [misc/winsocket.c]
	Added John Brezak's winsock.dll stuff.
1994-03-01 19:48:04 +00:00

1199 lines
34 KiB
C

/*
* Interface code to listbox widgets
*
* Copyright Martin Ayotte, 1993
*
*/
/*
#define DEBUG_LISTBOX
*/
static char Copyright[] = "Copyright Martin Ayotte, 1993";
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include "windows.h"
#include "user.h"
#include "heap.h"
#include "win.h"
#include "wine.h"
#include "listbox.h"
#include "scroll.h"
#include "int21.h"
#include "prototypes.h"
#define GMEM_ZEROINIT 0x0040
LPHEADLIST ListBoxGetWindowAndStorage(HWND hwnd, WND **wndPtr);
LPHEADLIST ListBoxGetStorageHeader(HWND hwnd);
void StdDrawListBox(HWND hwnd);
void OwnerDrawListBox(HWND hwnd);
int ListBoxFindMouse(HWND hwnd, int X, int Y);
int CreateListBoxStruct(HWND hwnd);
int ListBoxAddString(HWND hwnd, LPSTR newstr);
int ListBoxInsertString(HWND hwnd, UINT uIndex, LPSTR newstr);
int ListBoxGetText(HWND hwnd, UINT uIndex, LPSTR OutStr);
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);
/***********************************************************************
* ListBoxWndProc
*/
LONG ListBoxWndProc( HWND hwnd, WORD message, WORD wParam, LONG lParam )
{
WND *wndPtr;
LPHEADLIST lphl;
WORD wRet;
RECT rect;
int y;
CREATESTRUCT *createStruct;
static RECT rectsel;
switch(message)
{
case WM_CREATE:
CreateListBoxStruct(hwnd);
lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
#ifdef DEBUG_LISTBOX
printf("ListBox WM_CREATE %lX !\n", lphl);
#endif
createStruct = (CREATESTRUCT *)lParam;
if (HIWORD(createStruct->lpCreateParams) != 0)
lphl->hWndLogicParent = (HWND)HIWORD(createStruct->lpCreateParams);
else
lphl->hWndLogicParent = GetParent(hwnd);
lphl->ColumnsWidth = wndPtr->rectClient.right - wndPtr->rectClient.left;
if (wndPtr->dwStyle & WS_VSCROLL) {
SetScrollRange(hwnd, SB_VERT, 1, lphl->ItemsCount, TRUE);
ShowScrollBar(hwnd, SB_VERT, FALSE);
}
if (wndPtr->dwStyle & WS_HSCROLL) {
SetScrollRange(hwnd, SB_HORZ, 1, 1, TRUE);
ShowScrollBar(hwnd, SB_HORZ, FALSE);
}
return 0;
case WM_DESTROY:
lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
if (lphl == 0) return 0;
ListBoxResetContent(hwnd);
free(lphl);
*((LPHEADLIST *)&wndPtr->wExtra[1]) = 0;
#ifdef DEBUG_LISTBOX
printf("ListBox WM_DESTROY %lX !\n", lphl);
#endif
return 0;
case WM_VSCROLL:
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 < lphl->ItemsCount)
lphl->FirstVisible++;
break;
case SB_PAGEUP:
if (lphl->FirstVisible > 1)
lphl->FirstVisible -= lphl->ItemsVisible;
break;
case SB_PAGEDOWN:
if (lphl->FirstVisible < lphl->ItemsCount)
lphl->FirstVisible += lphl->ItemsVisible;
break;
case SB_THUMBTRACK:
lphl->FirstVisible = LOWORD(lParam);
break;
}
if (lphl->FirstVisible < 1) lphl->FirstVisible = 1;
if (lphl->FirstVisible > lphl->ItemsCount)
lphl->FirstVisible = lphl->ItemsCount;
if (y != lphl->FirstVisible) {
SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
InvalidateRect(hwnd, NULL, TRUE);
UpdateWindow(hwnd);
}
return 0;
case WM_HSCROLL:
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 < lphl->ItemsCount)
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 < lphl->ItemsCount &&
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 > lphl->ItemsCount)
lphl->FirstVisible = lphl->ItemsCount;
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;
case WM_LBUTTONDOWN:
/*
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 ((wndPtr->dwStyle & LBS_MULTIPLESEL) == LBS_MULTIPLESEL) {
lphl->ItemFocused = y;
wRet = ListBoxGetSel(hwnd, y);
ListBoxSetSel(hwnd, y, !wRet);
}
else {
ListBoxSetCurSel(hwnd, y);
}
ListBoxGetItemRect(hwnd, y, &rectsel);
InvalidateRect(hwnd, NULL, TRUE);
UpdateWindow(hwnd);
return 0;
case WM_LBUTTONUP:
ReleaseCapture();
lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
if (lphl == NULL) return 0;
if (lphl->PrevFocused != lphl->ItemFocused)
SendMessage(lphl->hWndLogicParent, WM_COMMAND, wndPtr->wIDmenu,
MAKELONG(hwnd, LBN_SELCHANGE));
return 0;
case WM_RBUTTONUP:
case WM_LBUTTONDBLCLK:
lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
if (lphl == NULL) return 0;
SendMessage(lphl->hWndLogicParent, WM_COMMAND, wndPtr->wIDmenu,
MAKELONG(hwnd, LBN_DBLCLK));
printf("ListBox Send LBN_DBLCLK !\n");
return 0;
case WM_MOUSEMOVE:
if ((wParam & MK_LBUTTON) != 0) {
y = HIWORD(lParam);
if (y < 4) {
lphl = ListBoxGetStorageHeader(hwnd);
if (lphl->FirstVisible > 1) {
lphl->FirstVisible--;
if (wndPtr->dwStyle & WS_VSCROLL)
SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
InvalidateRect(hwnd, NULL, TRUE);
UpdateWindow(hwnd);
break;
}
}
GetClientRect(hwnd, &rect);
if (y > (rect.bottom - 4)) {
lphl = ListBoxGetStorageHeader(hwnd);
if (lphl->FirstVisible < lphl->ItemsCount) {
lphl->FirstVisible++;
if (wndPtr->dwStyle & WS_VSCROLL)
SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
InvalidateRect(hwnd, NULL, TRUE);
UpdateWindow(hwnd);
break;
}
}
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;
}
else {
ListBoxSetCurSel(hwnd, wRet);
}
ListBoxGetItemRect(hwnd, wRet, &rectsel);
InvalidateRect(hwnd, NULL, TRUE);
UpdateWindow(hwnd);
}
}
}
break;
case WM_KEYDOWN:
lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
if (lphl == NULL) return 0;
switch(wParam) {
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;
lphl->FirstVisible = lphl->ItemFocused / lphl->ItemsVisible *
lphl->ItemsVisible + 1;
if (lphl->FirstVisible < 1) lphl->FirstVisible = 1;
if ((wndPtr->dwStyle & LBS_MULTIPLESEL) != LBS_MULTIPLESEL) {
ListBoxSetCurSel(hwnd, lphl->ItemFocused);
}
if (wndPtr->dwStyle & WS_VSCROLL)
SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
InvalidateRect(hwnd, NULL, TRUE);
UpdateWindow(hwnd);
break;
case WM_PAINT:
wndPtr = WIN_FindWndPtr(hwnd);
if ((wndPtr->dwStyle & LBS_OWNERDRAWFIXED) == LBS_OWNERDRAWFIXED) {
OwnerDrawListBox(hwnd);
break;
}
if ((wndPtr->dwStyle & LBS_OWNERDRAWVARIABLE) == LBS_OWNERDRAWVARIABLE) {
OwnerDrawListBox(hwnd);
break;
}
StdDrawListBox(hwnd);
break;
case LB_RESETCONTENT:
printf("ListBox LB_RESETCONTENT !\n");
ListBoxResetContent(hwnd);
return 0;
case LB_DIR:
printf("ListBox LB_DIR !\n");
wRet = ListBoxDirectory(hwnd, wParam, (LPSTR)lParam);
InvalidateRect(hwnd, NULL, TRUE);
UpdateWindow(hwnd);
return wRet;
case LB_ADDSTRING:
wRet = ListBoxAddString(hwnd, (LPSTR)lParam);
return wRet;
case LB_GETTEXT:
wRet = ListBoxGetText(hwnd, wParam, (LPSTR)lParam);
#ifdef DEBUG_LISTBOX
printf("ListBox LB_GETTEXT #%u '%s' !\n", wParam, (LPSTR)lParam);
#endif
return wRet;
case LB_INSERTSTRING:
wRet = ListBoxInsertString(hwnd, wParam, (LPSTR)lParam);
return wRet;
case LB_DELETESTRING:
printf("ListBox LB_DELETESTRING #%u !\n", wParam);
wRet = ListBoxDeleteString(hwnd, wParam);
return wRet;
case LB_FINDSTRING:
wRet = ListBoxFindString(hwnd, wParam, (LPSTR)lParam);
return wRet;
case LB_GETCARETINDEX:
return wRet;
case LB_GETCOUNT:
lphl = ListBoxGetStorageHeader(hwnd);
return lphl->ItemsCount;
case LB_GETCURSEL:
lphl = ListBoxGetStorageHeader(hwnd);
printf("ListBox LB_GETCURSEL %u !\n", lphl->ItemFocused);
return lphl->ItemFocused;
case LB_GETHORIZONTALEXTENT:
return wRet;
case LB_GETITEMDATA:
return wRet;
case LB_GETITEMHEIGHT:
return wRet;
case LB_GETITEMRECT:
return wRet;
case LB_GETSEL:
wRet = ListBoxGetSel(hwnd, wParam);
return wRet;
case LB_GETSELCOUNT:
return wRet;
case LB_GETSELITEMS:
return wRet;
case LB_GETTEXTLEN:
return wRet;
case LB_GETTOPINDEX:
return wRet;
case LB_SELECTSTRING:
return wRet;
case LB_SELITEMRANGE:
return wRet;
case LB_SETCARETINDEX:
return wRet;
case LB_SETCOLUMNWIDTH:
lphl = ListBoxGetStorageHeader(hwnd);
lphl->ColumnsWidth = wParam;
break;
case LB_SETHORIZONTALEXTENT:
return wRet;
case LB_SETITEMDATA:
return wRet;
case LB_SETTABSTOPS:
return wRet;
case LB_SETCURSEL:
#ifdef DEBUG_LISTBOX
printf("ListBox LB_SETCURSEL wParam=%x !\n", wParam);
#endif
wRet = ListBoxSetCurSel(hwnd, wParam);
InvalidateRect(hwnd, NULL, TRUE);
UpdateWindow(hwnd);
return wRet;
case LB_SETSEL:
printf("ListBox LB_SETSEL wParam=%x lParam=%lX !\n", wParam, lParam);
wRet = ListBoxSetSel(hwnd, LOWORD(lParam), wParam);
InvalidateRect(hwnd, NULL, TRUE);
UpdateWindow(hwnd);
return wRet;
case LB_SETTOPINDEX:
printf("ListBox LB_SETTOPINDEX wParam=%x !\n", wParam);
lphl = ListBoxGetStorageHeader(hwnd);
lphl->FirstVisible = wParam;
if (wndPtr->dwStyle & WS_VSCROLL)
SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
InvalidateRect(hwnd, NULL, TRUE);
UpdateWindow(hwnd);
break;
case LB_SETITEMHEIGHT:
#ifdef DEBUG_LISTBOX
printf("ListBox LB_SETITEMHEIGHT wParam=%x lParam=%lX !\n", wParam, lParam);
#endif
wRet = ListBoxSetItemHeight(hwnd, wParam, lParam);
return wRet;
default:
return DefWindowProc( hwnd, message, wParam, lParam );
}
return 0;
}
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 StdDrawListBox(HWND hwnd)
{
WND *wndPtr;
LPHEADLIST lphl;
LPLISTSTRUCT lpls;
PAINTSTRUCT ps;
HBRUSH hBrush;
HWND hWndParent;
HDC hdc;
RECT rect;
UINT i, h, h2, maxwidth, ipc;
char C[128];
h = 0;
hdc = BeginPaint( hwnd, &ps );
if (!IsWindowVisible(hwnd)) {
EndPaint( hwnd, &ps );
return;
}
lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
if (lphl == NULL) goto EndOfPaint;
hBrush = SendMessage(lphl->hWndLogicParent, WM_CTLCOLOR, (WORD)hdc,
MAKELONG(hwnd, CTLCOLOR_LISTBOX));
if (hBrush == (HBRUSH)NULL) hBrush = GetStockObject(WHITE_BRUSH);
GetClientRect(hwnd, &rect);
/*
if (wndPtr->dwStyle & WS_VSCROLL) rect.right -= 16;
if (wndPtr->dwStyle & WS_HSCROLL) rect.bottom -= 16;
*/
FillRect(hdc, &rect, hBrush);
maxwidth = rect.right;
rect.right = lphl->ColumnsWidth;
if (lphl->ItemsCount == 0) goto EndOfPaint;
lpls = lphl->lpFirst;
if (lpls == NULL) goto EndOfPaint;
lphl->ItemsVisible = 0;
lphl->ItemsPerColumn = ipc = 0;
for(i = 1; i <= lphl->ItemsCount; i++) {
if (i >= lphl->FirstVisible) {
if (lpls == NULL) break;
if ((h + lpls->dis.rcItem.bottom - lpls->dis.rcItem.top) > rect.bottom) {
if ((wndPtr->dwStyle & LBS_MULTICOLUMN) == LBS_MULTICOLUMN) {
lphl->ItemsPerColumn = max(lphl->ItemsPerColumn, ipc);
ipc = 0;
h = 0;
rect.left += lphl->ColumnsWidth;
rect.right += lphl->ColumnsWidth;
if (rect.left > maxwidth) break;
}
else
break;
}
h2 = lpls->dis.rcItem.bottom - lpls->dis.rcItem.top;
lpls->dis.rcItem.top = h;
lpls->dis.rcItem.bottom = h + h2;
lpls->dis.rcItem.left = rect.left;
lpls->dis.rcItem.right = rect.right;
TextOut(hdc, rect.left + 5, h + 2, (char *)lpls->dis.itemData,
strlen((char *)lpls->dis.itemData));
if (lpls->dis.itemState != 0) {
InvertRect(hdc, &lpls->dis.rcItem);
}
if (lphl->ItemFocused == i - 1) {
DrawFocusRect(hdc, &lpls->dis.rcItem);
}
h += h2;
lphl->ItemsVisible++;
ipc++;
}
if (lpls->lpNext == NULL) goto EndOfPaint;
lpls = (LPLISTSTRUCT)lpls->lpNext;
}
EndOfPaint:
EndPaint( hwnd, &ps );
if ((lphl->ItemsCount > lphl->ItemsVisible) &
(wndPtr->dwStyle & WS_VSCROLL)) {
/*
InvalidateRect(wndPtr->hWndVScroll, NULL, TRUE);
UpdateWindow(wndPtr->hWndVScroll);
*/
}
}
void OwnerDrawListBox(HWND hwnd)
{
WND *wndPtr;
LPHEADLIST lphl;
LPLISTSTRUCT lpls;
PAINTSTRUCT ps;
HBRUSH hBrush;
HWND hWndParent;
HDC hdc;
RECT rect;
UINT i, h, h2, maxwidth;
char C[128];
h = 0;
hdc = BeginPaint(hwnd, &ps);
if (!IsWindowVisible(hwnd)) {
EndPaint( hwnd, &ps );
return;
}
lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
if (lphl == NULL) goto EndOfPaint;
hBrush = SendMessage(lphl->hWndLogicParent, WM_CTLCOLOR, (WORD)hdc,
MAKELONG(hwnd, CTLCOLOR_LISTBOX));
if (hBrush == (HBRUSH)NULL) hBrush = GetStockObject(WHITE_BRUSH);
GetClientRect(hwnd, &rect);
if (wndPtr->dwStyle & WS_VSCROLL) rect.right -= 16;
if (wndPtr->dwStyle & WS_HSCROLL) rect.bottom -= 16;
FillRect(hdc, &rect, hBrush);
maxwidth = rect.right;
rect.right = lphl->ColumnsWidth;
if (lphl->ItemsCount == 0) goto EndOfPaint;
lpls = lphl->lpFirst;
if (lpls == NULL) goto EndOfPaint;
lphl->ItemsVisible = 0;
for (i = 1; i <= lphl->ItemsCount; i++) {
if (i >= lphl->FirstVisible) {
lpls->dis.hDC = hdc;
lpls->dis.itemID = i - 1;
h2 = lpls->dis.rcItem.bottom - lpls->dis.rcItem.top;
lpls->dis.rcItem.top = h;
lpls->dis.rcItem.bottom = h + h2;
lpls->dis.rcItem.left = rect.left;
lpls->dis.rcItem.right = rect.right;
lpls->dis.itemAction = ODA_DRAWENTIRE;
if (lpls->dis.itemState != 0) {
lpls->dis.itemAction |= ODA_SELECT;
}
if (lphl->ItemFocused == i - 1) {
lpls->dis.itemAction |= ODA_FOCUS;
}
#ifdef DEBUT_LISTBOX
printf("LBOX WM_DRAWITEM #%d left=%d top=%d right=%d bottom=%d !\n",
i, lpls->dis.rcItem.left, lpls->dis.rcItem.top,
lpls->dis.rcItem.right, lpls->dis.rcItem.bottom);
printf("LBOX WM_DRAWITEM Parent=%X &dis=%lX CtlID=%u !\n",
hWndParent, (LONG)&lpls->dis, lpls->dis.CtlID);
printf("LBOX WM_DRAWITEM '%s' !\n", lpls->dis.itemData);
#endif
SendMessage(lphl->hWndLogicParent, WM_DRAWITEM, i, (LPARAM)&lpls->dis);
if (lpls->dis.itemState != 0) {
InvertRect(hdc, &lpls->dis.rcItem);
}
h += h2;
lphl->ItemsVisible++;
if (h > rect.bottom) goto EndOfPaint;
}
if (lpls->lpNext == NULL) goto EndOfPaint;
lpls = (LPLISTSTRUCT)lpls->lpNext;
}
EndOfPaint:
EndPaint( hwnd, &ps );
if ((lphl->ItemsCount > lphl->ItemsVisible) &
(wndPtr->dwStyle & WS_VSCROLL)) {
/*
InvalidateRect(wndPtr->hWndVScroll, NULL, TRUE);
UpdateWindow(wndPtr->hWndVScroll);
*/
}
}
int ListBoxFindMouse(HWND hwnd, int X, int Y)
{
WND *wndPtr;
LPHEADLIST lphl;
LPLISTSTRUCT lpls;
RECT rect;
UINT i, h, h2, w, w2;
char C[128];
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);
if (wndPtr->dwStyle & WS_VSCROLL) rect.right -= 16;
if (wndPtr->dwStyle & WS_HSCROLL) rect.bottom -= 16;
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);
}
int CreateListBoxStruct(HWND hwnd)
{
WND *wndPtr;
LPHEADLIST lphl;
wndPtr = WIN_FindWndPtr(hwnd);
lphl = (LPHEADLIST)malloc(sizeof(HEADLIST));
lphl->lpFirst = NULL;
*((LPHEADLIST *)&wndPtr->wExtra[1]) = lphl; /* HEAD of List */
lphl->ItemsCount = 0;
lphl->ItemsVisible = 0;
lphl->FirstVisible = 1;
lphl->StdItemHeight = 15;
lphl->DrawCtlType = ODT_LISTBOX;
return TRUE;
}
int ListBoxAddString(HWND hwnd, LPSTR newstr)
{
WND *wndPtr;
LPHEADLIST lphl;
LPLISTSTRUCT lpls, lplsnew;
HANDLE hTemp;
LPSTR str;
lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
if (lphl == NULL) return LB_ERR;
hTemp = USER_HEAP_ALLOC(GMEM_MOVEABLE, sizeof(LISTSTRUCT));
lplsnew = (LPLISTSTRUCT) USER_HEAP_ADDR(hTemp);
lpls = lphl->lpFirst;
if (lpls != NULL) {
while(lpls->lpNext != NULL) {
lpls = (LPLISTSTRUCT)lpls->lpNext;
}
lpls->lpNext = lplsnew;
}
else
lphl->lpFirst = lplsnew;
lphl->ItemsCount++;
#ifdef DEBUG_LISTBOX
printf("Items Count = %u\n", lphl->ItemsCount);
#endif
hTemp = 0;
if ((wndPtr->dwStyle & LBS_HASSTRINGS) != LBS_HASSTRINGS) {
if (((wndPtr->dwStyle & LBS_OWNERDRAWFIXED) != LBS_OWNERDRAWFIXED) &&
((wndPtr->dwStyle & LBS_OWNERDRAWVARIABLE) != LBS_OWNERDRAWVARIABLE)) {
hTemp = USER_HEAP_ALLOC(GMEM_MOVEABLE, strlen(newstr) + 1);
str = (LPSTR)USER_HEAP_ADDR(hTemp);
if (str == NULL) return LB_ERRSPACE;
strcpy(str, newstr);
newstr = str;
}
}
ListBoxDefaultItem(hwnd, wndPtr, lphl, lplsnew);
lplsnew->hMem = hTemp;
lplsnew->lpNext = NULL;
lplsnew->dis.itemID = lphl->ItemsCount;
lplsnew->dis.itemData = (DWORD)newstr;
lplsnew->hData = hTemp;
if (wndPtr->dwStyle & WS_VSCROLL)
SetScrollRange(hwnd, SB_VERT, 1, lphl->ItemsCount,
(lphl->FirstVisible != 1));
if ((wndPtr->dwStyle & WS_HSCROLL) && lphl->ItemsPerColumn != 0)
SetScrollRange(hwnd, SB_HORZ, 1, lphl->ItemsVisible /
lphl->ItemsPerColumn + 1, (lphl->FirstVisible != 1));
if (lphl->FirstVisible >= (lphl->ItemsCount - lphl->ItemsVisible)) {
InvalidateRect(hwnd, NULL, TRUE);
UpdateWindow(hwnd);
}
if ((lphl->ItemsCount - lphl->FirstVisible) == lphl->ItemsVisible) {
if (wndPtr->dwStyle & WS_VSCROLL)
ShowScrollBar(hwnd, SB_VERT, TRUE);
if (wndPtr->dwStyle & WS_HSCROLL)
ShowScrollBar(hwnd, SB_HORZ, TRUE);
}
return lphl->ItemsCount;
}
int ListBoxInsertString(HWND hwnd, UINT uIndex, LPSTR newstr)
{
WND *wndPtr;
LPHEADLIST lphl;
LPLISTSTRUCT lpls, lplsnew;
HANDLE hTemp;
LPSTR str;
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 > lphl->ItemsCount) return LB_ERR;
for(Count = 1; Count < uIndex; Count++) {
if (lpls->lpNext == NULL) return LB_ERR;
lpls = (LPLISTSTRUCT)lpls->lpNext;
}
hTemp = USER_HEAP_ALLOC(GMEM_MOVEABLE, sizeof(LISTSTRUCT));
lplsnew = (LPLISTSTRUCT) USER_HEAP_ADDR(hTemp);
ListBoxDefaultItem(hwnd, wndPtr, lphl, lplsnew);
lplsnew->hMem = hTemp;
lpls->lpNext = lplsnew;
lphl->ItemsCount++;
hTemp = 0;
if ((wndPtr->dwStyle & LBS_HASSTRINGS) != LBS_HASSTRINGS) {
if (((wndPtr->dwStyle & LBS_OWNERDRAWFIXED) != LBS_OWNERDRAWFIXED) &&
((wndPtr->dwStyle & LBS_OWNERDRAWVARIABLE) != LBS_OWNERDRAWVARIABLE)) {
hTemp = USER_HEAP_ALLOC(GMEM_MOVEABLE, strlen(newstr) + 1);
str = (LPSTR)USER_HEAP_ADDR(hTemp);
if (str == NULL) return LB_ERRSPACE;
strcpy(str, newstr);
newstr = str;
}
}
lplsnew->lpNext = NULL;
lplsnew->dis.itemID = lphl->ItemsCount;
lplsnew->dis.itemData = (DWORD)newstr;
lplsnew->hData = hTemp;
if (wndPtr->dwStyle & WS_VSCROLL)
SetScrollRange(hwnd, SB_VERT, 1, lphl->ItemsCount,
(lphl->FirstVisible != 1));
if ((wndPtr->dwStyle & WS_HSCROLL) && lphl->ItemsPerColumn != 0)
SetScrollRange(hwnd, SB_HORZ, 1, lphl->ItemsVisible /
lphl->ItemsPerColumn + 1, (lphl->FirstVisible != 1));
if (((lphl->ItemsCount - lphl->FirstVisible) == lphl->ItemsVisible) &&
(lphl->ItemsVisible != 0)) {
if (wndPtr->dwStyle & WS_VSCROLL)
ShowScrollBar(hwnd, SB_VERT, TRUE);
if (wndPtr->dwStyle & WS_HSCROLL)
ShowScrollBar(hwnd, SB_HORZ, TRUE);
}
if ((lphl->FirstVisible <= uIndex) &&
((lphl->FirstVisible + lphl->ItemsVisible) >= uIndex)) {
InvalidateRect(hwnd, NULL, TRUE);
UpdateWindow(hwnd);
}
return lphl->ItemsCount;
}
int ListBoxGetText(HWND hwnd, UINT uIndex, LPSTR OutStr)
{
WND *wndPtr;
LPHEADLIST lphl;
LPLISTSTRUCT lpls;
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 > lphl->ItemsCount) return LB_ERR;
for(Count = 0; Count < uIndex; Count++) {
if (lpls->lpNext == NULL) return LB_ERR;
lpls = (LPLISTSTRUCT)lpls->lpNext;
}
if (((wndPtr->dwStyle & LBS_OWNERDRAWFIXED) == LBS_OWNERDRAWFIXED) ||
((wndPtr->dwStyle & LBS_OWNERDRAWVARIABLE) == LBS_OWNERDRAWVARIABLE)) {
if ((wndPtr->dwStyle & LBS_HASSTRINGS) != LBS_HASSTRINGS) {
*((long *)OutStr) = lpls->dis.itemData;
return 4;
}
}
strcpy(OutStr, (char *)lpls->dis.itemData);
return strlen(OutStr);
}
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 > lphl->ItemsCount) return LB_ERR;
for(Count = 1; 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) USER_HEAP_FREE(lpls->hData);
if (lpls->hMem != 0) USER_HEAP_FREE(lpls->hMem);
if (wndPtr->dwStyle & WS_VSCROLL)
SetScrollRange(hwnd, SB_VERT, 1, lphl->ItemsCount, TRUE);
if ((wndPtr->dwStyle & WS_HSCROLL) && lphl->ItemsPerColumn != 0)
SetScrollRange(hwnd, SB_HORZ, 1, lphl->ItemsVisible /
lphl->ItemsPerColumn + 1, TRUE);
if (lphl->ItemsCount < lphl->ItemsVisible) {
if (wndPtr->dwStyle & WS_VSCROLL)
ShowScrollBar(hwnd, SB_VERT, FALSE);
if (wndPtr->dwStyle & WS_HSCROLL)
ShowScrollBar(hwnd, SB_HORZ, FALSE);
}
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)
{
LPHEADLIST lphl;
LPLISTSTRUCT lpls;
UINT Count;
lphl = ListBoxGetStorageHeader(hwnd);
if (lphl == NULL) return LB_ERR;
if (nFirst > lphl->ItemsCount) return LB_ERR;
lpls = lphl->lpFirst;
if (lpls == NULL) return LB_ERR;
Count = 0;
while(lpls != NULL) {
if (strcmp((char *)lpls->dis.itemData, MatchStr) == 0) return Count;
lpls = (LPLISTSTRUCT)lpls->lpNext;
Count++;
}
return LB_ERR;
}
int ListBoxResetContent(HWND hwnd)
{
WND *wndPtr;
LPHEADLIST lphl;
LPLISTSTRUCT lpls, lpls2;
UINT i;
lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
if (lphl == NULL) return LB_ERR;
lpls = lphl->lpFirst;
if (lpls == NULL) return LB_ERR;
for(i = 0; i <= lphl->ItemsCount; i++) {
lpls2 = lpls;
lpls = (LPLISTSTRUCT)lpls->lpNext;
if (i != 0) {
#ifdef DEBUG_LISTBOX
printf("ResetContent #%u\n", i);
#endif
if (lpls2->hData != 0) USER_HEAP_FREE(lpls->hData);
if (lpls2->hMem != 0) USER_HEAP_FREE(lpls->hMem);
}
if (lpls == NULL) break;
}
lphl->lpFirst = NULL;
lphl->FirstVisible = 1;
lphl->ItemsCount = 0;
lphl->ItemFocused = 0;
lphl->PrevFocused = 0;
if ((wndPtr->dwStyle && LBS_NOTIFY) != 0)
SendMessage(wndPtr->hwndParent, WM_COMMAND,
wndPtr->wIDmenu, MAKELONG(hwnd, LBN_SELCHANGE));
if (wndPtr->dwStyle & WS_VSCROLL)
SetScrollRange(hwnd, SB_VERT, 1, lphl->ItemsCount, TRUE);
if ((wndPtr->dwStyle & WS_HSCROLL) && lphl->ItemsPerColumn != 0)
SetScrollRange(hwnd, SB_HORZ, 1, lphl->ItemsVisible /
lphl->ItemsPerColumn + 1, TRUE);
if (wndPtr->dwStyle & WS_VSCROLL)
ShowScrollBar(hwnd, SB_VERT, FALSE);
if (wndPtr->dwStyle & WS_HSCROLL)
ShowScrollBar(hwnd, SB_HORZ, FALSE);
InvalidateRect(hwnd, NULL, TRUE);
UpdateWindow(hwnd);
return TRUE;
}
int ListBoxSetCurSel(HWND hwnd, WORD wIndex)
{
WND *wndPtr;
LPHEADLIST lphl;
LPLISTSTRUCT lpls, lpls2;
UINT i;
lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
if (lphl == NULL) return LB_ERR;
lphl->ItemFocused = LB_ERR;
if (wIndex >= lphl->ItemsCount) return LB_ERR;
lpls = lphl->lpFirst;
if (lpls == NULL) return LB_ERR;
for(i = 0; i < lphl->ItemsCount; i++) {
lpls2 = lpls;
lpls = (LPLISTSTRUCT)lpls->lpNext;
if (i == wIndex)
lpls2->dis.itemState = 1;
else
if (lpls2->dis.itemState != 0)
lpls2->dis.itemState = 0;
if (lpls == NULL) break;
}
lphl->ItemFocused = wIndex;
if ((wndPtr->dwStyle && LBS_NOTIFY) != 0)
SendMessage(wndPtr->hwndParent, WM_COMMAND,
wndPtr->wIDmenu, MAKELONG(hwnd, LBN_SELCHANGE));
return LB_ERR;
}
int ListBoxSetSel(HWND hwnd, WORD wIndex, WORD state)
{
LPHEADLIST lphl;
LPLISTSTRUCT lpls, lpls2;
UINT i;
lphl = ListBoxGetStorageHeader(hwnd);
if (lphl == NULL) return LB_ERR;
if (wIndex >= lphl->ItemsCount) return LB_ERR;
lpls = lphl->lpFirst;
if (lpls == NULL) return LB_ERR;
for(i = 0; i < lphl->ItemsCount; i++) {
lpls2 = lpls;
lpls = (LPLISTSTRUCT)lpls->lpNext;
if ((i == wIndex) || (wIndex == (WORD)-1)) {
lpls2->dis.itemState = state;
break;
}
if (lpls == NULL) break;
}
return LB_ERR;
}
int ListBoxGetSel(HWND hwnd, WORD wIndex)
{
LPHEADLIST lphl;
LPLISTSTRUCT lpls, lpls2;
UINT i;
lphl = ListBoxGetStorageHeader(hwnd);
if (lphl == NULL) return LB_ERR;
if (wIndex >= lphl->ItemsCount) return LB_ERR;
lpls = lphl->lpFirst;
if (lpls == NULL) return LB_ERR;
for(i = 0; i < lphl->ItemsCount; i++) {
lpls2 = lpls;
lpls = (LPLISTSTRUCT)lpls->lpNext;
if (i == wIndex) {
return lpls2->dis.itemState;
}
if (lpls == NULL) break;
}
return LB_ERR;
}
int ListBoxDirectory(HWND hwnd, UINT attrib, LPSTR filespec)
{
struct dosdirent *dp;
struct stat st;
int x, wRet;
char temp[256];
fprintf(stderr,"ListBoxDirectory: %s, %4x\n",filespec,attrib);
if ((dp = (struct dosdirent *)DOS_opendir(filespec)) ==NULL)
return 0;
while (1)
{
dp = (struct dosdirent *)DOS_readdir(dp);
if (!dp->inuse)
break;
if (dp->attribute & 0x08)
{
if (attrib & DDL_DIRECTORY) {
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);
if (attrib & DDL_DRIVES)
{
for (x=0;x!=MAX_DOS_DRIVES;x++)
{
if (DOS_ValidDrive(x))
{
sprintf(temp, "[-%c-]", 'A'+x);
if ( (wRet = ListBoxAddString(hwnd, temp)) == LB_ERR)
break;
}
}
}
return wRet;
}
int ListBoxGetItemRect(HWND hwnd, WORD wIndex, LPRECT lprect)
{
LPHEADLIST lphl;
LPLISTSTRUCT lpls, lpls2;
UINT i;
lphl = ListBoxGetStorageHeader(hwnd);
if (lphl == NULL) return LB_ERR;
if (wIndex > lphl->ItemsCount) return LB_ERR;
lpls = lphl->lpFirst;
if (lpls == NULL) return LB_ERR;
for(i = 0; i < lphl->ItemsCount; i++) {
lpls2 = lpls;
lpls = (LPLISTSTRUCT)lpls->lpNext;
if (i == wIndex) {
*(lprect) = lpls2->dis.rcItem;
break;
}
if (lpls == NULL) break;
}
return LB_ERR;
}
int ListBoxSetItemHeight(HWND hwnd, WORD wIndex, long height)
{
LPHEADLIST lphl;
LPLISTSTRUCT lpls, lpls2;
UINT i;
lphl = ListBoxGetStorageHeader(hwnd);
if (lphl == NULL) return LB_ERR;
if (wIndex > lphl->ItemsCount) return LB_ERR;
lpls = lphl->lpFirst;
if (lpls == NULL) return LB_ERR;
for(i = 0; i < lphl->ItemsCount; i++) {
lpls2 = lpls;
lpls = (LPLISTSTRUCT)lpls->lpNext;
if (i == wIndex) {
lpls2->dis.rcItem.bottom = lpls2->dis.rcItem.top + (short)height;
InvalidateRect(hwnd, NULL, TRUE);
UpdateWindow(hwnd);
break;
}
if (lpls == NULL) break;
}
return LB_ERR;
}
int ListBoxDefaultItem(HWND hwnd, WND *wndPtr,
LPHEADLIST lphl, LPLISTSTRUCT lpls)
{
RECT rect;
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;
}
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 (((wndPtr->dwStyle & LBS_OWNERDRAWFIXED) == LBS_OWNERDRAWFIXED) ||
((wndPtr->dwStyle & LBS_OWNERDRAWVARIABLE) == LBS_OWNERDRAWVARIABLE)) {
if ((wndPtr->dwStyle & LBS_HASSTRINGS) != LBS_HASSTRINGS) {
return LB_ERR;
}
}
Count = 0;
while(lpls != NULL) {
if (Count > lphl->ItemFocused) {
if (*((char *)lpls->dis.itemData) == (char)wChar) {
lphl->FirstVisible = Count - lphl->ItemsVisible / 2;
if (lphl->FirstVisible < 1) lphl->FirstVisible = 1;
if ((wndPtr->dwStyle & LBS_MULTIPLESEL) == LBS_MULTIPLESEL) {
lphl->ItemFocused = Count;
}
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 (*((char *)lpls->dis.itemData) == (char)wChar) {
if (Count == lphl->ItemFocused) return LB_ERR;
lphl->FirstVisible = Count - lphl->ItemsVisible / 2;
if (lphl->FirstVisible < 1) lphl->FirstVisible = 1;
if ((wndPtr->dwStyle & LBS_MULTIPLESEL) == LBS_MULTIPLESEL) {
lphl->ItemFocused = Count;
}
else {
ListBoxSetCurSel(hwnd, Count);
}
SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
InvalidateRect(hwnd, NULL, TRUE);
UpdateWindow(hwnd);
return Count;
}
lpls = (LPLISTSTRUCT)lpls->lpNext;
Count++;
}
return LB_ERR;
}