1
0
Fork 0
mirror of synced 2025-03-07 03:53:26 +01:00
wine/controls/combo.c
Alexandre Julliard 2787be8766 Release 950522
Sun May 21 12:30:30 1995  Alexandre Julliard  (julliard@sunsite.unc.edu)

	* [debugger/hash.c] [debugger/info.c]
	Added support for symbolic segmented addresses. Add symbols for all
	built-in API entry points.

	* [if1632/relay.c] [include/dlls.h]
	Removed dll_table structure, as we now use the built-in module
	structures.

	* [if1632/relay.c] [loader/main.c]
	Removed winestat option, as it was no longer very meaningful.

	* [include/stackframe.h]
	New macro MAKE_SEGPTR that creates a segmented pointer to a local
	variable on the 32-bit stack.

	* [loader/module.c]
	Added support for multiple instances of an application.
	Implemented LoadModule() and FreeModule().

	* [loader/ne_image.c] [loader/task.c]
	Moved initialisation of built-in DLLs to InitTask().

	* [memory/global.c]
	Implemented discardable blocks.

	* [misc/file.c]
	Search path of current executable in OpenFile().
	Fixed bug with searching in Windows path.

	* [misc/lstr.c]
	Hard-coded translation tables for Ansi<->Oem.

	* [misc/user.c]
	Moved some global initializations to InitApp(), because they need
	a task context to be performed.

	* [objects/dc.c]
	Handle R2_BLACK and R2_WHITE specially so that they work correctly
	with palette displays.

	* [tools/build.c]
	Suppressed generation of the C file for DLL specs, because it's no
	longer needed. Output all the assembly code directly to stdout.
	Some changes to integrate Win32 support from Martin von	Loewis. 

	* [windows/msgbox.c]
	Moved message box code from misc/ to windows/.

Mon May 15 23:40:04 1995  Martin Ayotte (wine@trgcorp.mksinfo.qc.ca)

	* [misc/audio.c] [misc/mcicda.c] [misc/mcianim.c] [misc/midi.c]
	  [misc/mmaux.c] [misc/mmsystem.c]
	Modify code & use pointers conversion macros.
	Make cdaudio & wave devices work again (only using some applets).

	* [misc/profile.c]
	Change getc() to fgetc() where needed.

Mon May 15 22:10:56 1995  Martin von Loewis  <loewis@informatik.hu-berlin.de>

	* [if1632/Imakefile]
	added entries for the new files gdi32.spec, kernel32.spec,
	user32.spec, shell32.spec and winprocs32.spec.

	* [if1632/commdlg.spec][if1632/kernel.spec][if1632/shell.spec]
	  [if1632/storage.spec][if1632/system.spec][if1632/user.spec]
	ChooseFont, RESERVED5, InternalExtractIcon: Marked as stubs
	ExtractAssociatedIcon, DoEnvironmentSubst, DumpIcon:
		stub implementations provided 
	marked storage.dll,storege.sys functions as stubs

	* [include/pe_image.h]
	Added structures WIN32_builtin and  WIN32_function

	* [include/peexe.h]
	PE_Import_Directory: renamed reserved fields to 
		TimeDate, Forwarder, Thunk_List

	* [include/winerror.h]
	New file.

	* [loader/main.c]
	called RELAY32_Init

	* [loader/pe_image.c]
	xmmap: map BSS anonymous
	dump_imports: renamed to fixup_imports, do the fixup of imported
	              symbols
	PE_LoadImage: pass raw data size to xmmap

	* [loader/resource.c]
	DumpIcon: new function

	* [misc/kernel32.c]
	New file.

	* [misc/main.c]
	make stdout and stderr unbuffered

	* [misc/shell.c]
	DoEnvironmentSubst: new function

	* [objects/font.c]
	FONT_MatchFont: try oblique if there is no italic

	* [rc/Imakefile][rc/parser.l]
	yywrap: new function
	Don't link with libfl.a on Linux

	* [tools/build.c]
	Added keywords stdcall, subsystem, base
	GenerateForWin32: new function
	BuildSpecFiles: call GenerateForWin32 if subsystem is win32

Mon May 15 10:38:14 1995   Bernd Schmidt <crux@pool.informatik.rwth-aachen.de>
        
        * [controls/listbox.c] [controls/combo.c] [windows/defwnd.c]
	Minor fixes.
	
	* [misc/message.c] [misc/main.c] [rc/sysres*.rc] [include/texts.h]
	Rewrote message box handling.
	
	* [windows/dialog.c]
	Dialogs should be invisible until after WM_INITDIALOG is seent.
	Don't switch to invisible dialog items on a TAB keypress.
	
	* [windows/mdi.c]
	Send WM_NCPAINT message in MDIRestoreChild().
	
	* [windows/painting.c]
	Fixed typo (&& -> &).
	
	* [windows/message.c] [if1632/user.spec]
	Implemented PostAppMessage().
	
	* [windows/event.c]
	SetCapture(0) should act like ReleaseCapture().

Tue May  9 11:55:52 1995     Eddie C. Dost             (ecd@dressler.de)

	* [Imakefile]
	Changed CDEBUGFLAGS for systems running __ELF__ (temporarily)
	Added ASFLAGS to exported variables.

	* [debugger/readline/Imakefile]
	Moved defines for libreadline from DEFINES to EXTRA_DEFINES

	* [memory/local.c] [miscemu/int21.c]
	Added some more debugging outputs.

Mon May  8 00:55:27 MET DST 1995	  Dag Asheim (dash@ifi.uio.no)

	* [misc/message.c]
	Fixed a "FIXME" concerning norwegian translation.

Sun May  7 23:25:23 1995   Bernd Schmidt <crux@pool.informatik.rwth-aachen.de>
        
	* [*/*]
        Removed warnings in a couple of files and deleted some obsolete code.

        * [controls/listbox.c]
        Cleanup, speed improvements & lots of bug fixes.

        * [controls/combo.c]
	Mostly rewritten. This is still very buggy, but not quite as bad as 
	before.

        * [include/commdlg.h] [misc/commdlg.c]
        Removed the need for sysres.dll. Small bug fixes.
	
        * [objects/oembitmap.c] [include/bitmaps/<many>] [include/windows.h]
          [loader/library.c] [loader/main.c] [rc/sysres*.rc]
        Removed sysres.dll and replaced the remaining bitmaps/icons with
        XPM equivalents.

        * [misc/message.c] [windows/nonclient.c] [misc/main.c]
          [if1632/winprocs.spec]
        "About Wine..." now brings up a standard ShellAbout() window with
        the Wine icon and the list of contributors.
	
	* [misc/shell.c]
	Fixed ShellAbout()/AboutDialogProc() to show the right icon.

	* [windows/event.c]
	Small hack for non-alphanumeric keys: Dont't send the ascii value in
	the WM_KEYDOWN message, but some unused code instead. Should be done
	properly by sending different codes for each key. The edit control
	used to get a VK_DELETE message each time the user typed '.'.

	* [windows/class.c]
	Removed a check for CS_GLOBALCLASS in CLASS_FindClassByName().
	This used to be no problem, but breaks Resource Workshop in 950403.
	
	* [objects/dib.c]
	New diagnostic for a bug I've been encountering. If it shows up,
	please report it.

Sun May  7 23:11:18 EDT 1995  William Magro (wmagro@tc.cornell.edu)

	* [objects/color.c]
	Handle situation when 'dc' exists, but palette mapping
	does not.  (Fixes kidpix2 demo.)

Sun May  7 03:32:00 1995  Charles M. Hannum  (mycroft@mit.edu)

	* [loader/ldt.c]
	LDT_Print: Only show the number of entries that the kernel
	returned. Make this work for NetBSD.

Fri May  5 02:53:26 1995  Charles M. Hannum  (mycroft@mit.edu)

	* [debugger/dbg.y] [include/wine.h] [loader/signal.c]
	Modify cs and ds selector values for NetBSD-current.

	* [debugger/debug.l]
	$sp, $esp: Use RN_ESP_AT_SIGNAL rather than RN_ESP.

	* [debugger/regpos.h]
	Modify sigcontext format for NetBSD-current.
	SC_ESP: Use RN_ESP_AT_SIGNAL rather than RN_ESP.

	* [include/ldt.h]
	SELECTOR_TO_ENTRY: Explicitly clear the top half of the selector
	value, since only 16 bits of it may have been saved.

	* [misc/winsocket.c]
	Set structure packing with `#pragma pack' to accomodate
	other/older compilers.

Tue May  2 18:15:01 1995 Paal Beyer (beyer@idt.unit.no)
	
	* [misc/commdlg.c]
	Fixed path-names so when changing directory the listboxes
	changes too.
	
	* [debugger/dbg.y debugger/debug.l wine.ini]
	Added SymbolTableFile to wine.ini so symbols can be read
	without standing in the directory containing wine.sym.
	Added the possibility to specify full name of wine.sym from
	the debugger prompt.
1995-05-22 18:23:01 +00:00

1083 lines
31 KiB
C

/*
* Combo controls
*
* Copyright 1993 Martin Ayotte
* Copyright 1995 Bernd Schmidt
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "windows.h"
#include "sysmetrics.h"
#include "combo.h"
#include "user.h"
#include "win.h"
#include "stddebug.h"
/* #define DEBUG_COMBO */
#include "debug.h"
#include "graphics.h"
#include "listbox.h"
#include "dos_fs.h"
/*
* Note: Combos are probably implemented in a different way by Windows.
* Using a message spy for Windows, you can see some undocumented
* messages being passed between ComboBox and ComboLBox.
* I hope no programs rely on the implementation of combos.
*/
static LONG CBNCCreate( HWND hwnd, WORD message, WORD wParam, LONG lParam );
static LONG CBCreate( HWND hwnd, WORD message, WORD wParam, LONG lParam );
static LONG CBGetDlgCode( HWND hwnd, WORD message, WORD wParam, LONG lParam );
static LONG CBDestroy( HWND hwnd, WORD message, WORD wParam, LONG lParam );
static LONG CBPaint( HWND hwnd, WORD message, WORD wParam, LONG lParam );
static LONG CBKeyDown( HWND hwnd, WORD message, WORD wParam, LONG lParam );
static LONG CBChar( HWND hwnd, WORD message, WORD wParam, LONG lParam );
static LONG CBSetFont( HWND hwnd, WORD message, WORD wParam, LONG lParam );
static LONG CBSetRedraw( HWND hwnd, WORD message, WORD wParam, LONG lParam );
static LONG CBLButtonDown( HWND hwnd, WORD message, WORD wParam, LONG lParam );
static LONG CBSetFocus( HWND hwnd, WORD message, WORD wParam, LONG lParam );
static LONG CBKillFocus( HWND hwnd, WORD message, WORD wParam, LONG lParam );
static LONG CBResetContent( HWND hwnd, WORD message, WORD wParam, LONG lParam );
static LONG CBDir( HWND hwnd, WORD message, WORD wParam, LONG lParam );
static LONG CBAddString( HWND hwnd, WORD message, WORD wParam, LONG lParam );
static LONG CBGetLBText( HWND hwnd, WORD message, WORD wParam, LONG lParam );
static LONG CBInsertString( HWND hwnd, WORD message, WORD wParam, LONG lParam );
static LONG CBDeleteString( HWND hwnd, WORD message, WORD wParam, LONG lParam );
static LONG CBFindString( HWND hwnd, WORD message, WORD wParam, LONG lParam );
static LONG CBGetCount( HWND hwnd, WORD message, WORD wParam, LONG lParam );
static LONG CBGetCurSel( HWND hwnd, WORD message, WORD wParam, LONG lParam );
static LONG CBGetItemData( HWND hwnd, WORD message, WORD wParam, LONG lParam );
static LONG CBGetItemHeight( HWND hwnd, WORD message, WORD wParam, LONG lParam );
static LONG CBGetLBTextLen( HWND hwnd, WORD message, WORD wParam, LONG lParam );
static LONG CBSelectString( HWND hwnd, WORD message, WORD wParam, LONG lParam );
static LONG CBSetItemData( HWND hwnd, WORD message, WORD wParam, LONG lParam );
static LONG CBSetCurSel( HWND hwnd, WORD message, WORD wParam, LONG lParam );
static LONG CBSetItemHeight( HWND hwnd, WORD message, WORD wParam, LONG lParam );
static LONG CBShowDropDown( HWND hwnd, WORD message, WORD wParam, LONG lParam );
static LONG CBLCreate( HWND hwnd, WORD message, WORD wParam, LONG lParam );
static LONG CBLGetDlgCode( HWND hwnd, WORD message, WORD wParam, LONG lParam );
static LONG CBLKeyDown( HWND hwnd, WORD message, WORD wParam, LONG lParam );
static LONG CBLChar( HWND hwnd, WORD message, WORD wParam, LONG lParam );
static LONG CBLPaint( HWND hwnd, WORD message, WORD wParam, LONG lParam );
static LONG CBLKillFocus( HWND hwnd, WORD message, WORD wParam, LONG lParam );
static LONG CBLActivate( HWND hwnd, WORD message, WORD wParam, LONG lParam );
static LONG CBLLButtonDown( HWND hwnd, WORD message, WORD wParam, LONG lParam );
static LONG CBLLButtonUp( HWND hwnd, WORD message, WORD wParam, LONG lParam );
static LONG CBLMouseMove( HWND hwnd, WORD message, WORD wParam, LONG lParam );
static LONG CBLVScroll( HWND hwnd, WORD message, WORD wParam, LONG lParam );
typedef struct {
WORD message;
LONG (*handler)(HWND, WORD, WPARAM, LPARAM);
} msg_tbl;
static msg_tbl combo_tbl[] = {
{WM_NCCREATE, CBNCCreate},
{WM_CREATE, CBCreate},
{WM_DESTROY, CBDestroy},
{WM_GETDLGCODE, CBGetDlgCode},
{WM_KEYDOWN, CBKeyDown},
{WM_CHAR, CBChar},
{WM_SETFONT, CBSetFont},
{WM_SETREDRAW, CBSetRedraw},
{WM_PAINT, CBPaint},
{WM_LBUTTONDOWN, CBLButtonDown},
{WM_SETFOCUS, CBSetFocus},
{WM_KILLFOCUS, CBKillFocus},
{CB_RESETCONTENT, CBResetContent},
{CB_DIR, CBDir},
{CB_ADDSTRING, CBAddString},
{CB_INSERTSTRING, CBInsertString},
{CB_DELETESTRING, CBDeleteString},
{CB_FINDSTRING, CBFindString},
{CB_GETCOUNT, CBGetCount},
{CB_GETCURSEL, CBGetCurSel},
{CB_GETITEMDATA, CBGetItemData},
{CB_GETITEMHEIGHT, CBGetItemHeight},
{CB_GETLBTEXT, CBGetLBText},
{CB_GETLBTEXTLEN, CBGetLBTextLen},
{CB_SELECTSTRING, CBSelectString},
{CB_SETITEMDATA, CBSetItemData},
{CB_SETCURSEL, CBSetCurSel},
{CB_SETITEMHEIGHT, CBSetItemHeight},
{CB_SHOWDROPDOWN, CBShowDropDown}
};
static msg_tbl clbox_tbl[] = {
{WM_CREATE, CBLCreate},
{WM_GETDLGCODE, CBLGetDlgCode},
{WM_KEYDOWN, CBLKeyDown},
{WM_CHAR, CBLChar},
{WM_PAINT, CBLPaint},
{WM_KILLFOCUS, CBLKillFocus},
{WM_ACTIVATE, CBLActivate},
{WM_LBUTTONDOWN, CBLLButtonDown},
{WM_LBUTTONUP, CBLLButtonUp},
{WM_MOUSEMOVE, CBLMouseMove},
{WM_VSCROLL, CBLVScroll}
};
static HBITMAP hComboBit = 0;
static WORD CBitHeight, CBitWidth;
static int COMBO_Init()
{
BITMAP bm;
dprintf_combo(stddeb, "COMBO_Init\n");
hComboBit = LoadBitmap(0, MAKEINTRESOURCE(OBM_COMBO));
GetObject(hComboBit, sizeof(BITMAP), (LPSTR)&bm);
CBitHeight = bm.bmHeight;
CBitWidth = bm.bmWidth;
return 0;
}
LPHEADCOMBO ComboGetStorageHeader(HWND hwnd)
{
return (LPHEADCOMBO)GetWindowLong(hwnd,4);
}
LPHEADLIST ComboGetListHeader(HWND hwnd)
{
return (LPHEADLIST)GetWindowLong(hwnd,0);
}
int CreateComboStruct(HWND hwnd, LONG style)
{
LPHEADCOMBO lphc;
lphc = (LPHEADCOMBO)malloc(sizeof(HEADCOMBO));
SetWindowLong(hwnd,4,(LONG)lphc);
lphc->hWndEdit = 0;
lphc->hWndLBox = 0;
lphc->dwState = 0;
lphc->LastSel = -1;
lphc->dwStyle = style;
lphc->DropDownVisible = FALSE;
return TRUE;
}
void ComboUpdateWindow(HWND hwnd, LPHEADLIST lphl, LPHEADCOMBO lphc, BOOL repaint)
{
SetScrollRange(lphc->hWndLBox, SB_VERT, 0, ListMaxFirstVisible(lphl), TRUE);
if (repaint && lphl->bRedrawFlag) {
InvalidateRect(hwnd, NULL, TRUE);
}
}
/***********************************************************************
* CBNCCreate
*/
static LONG CBNCCreate(HWND hwnd, WORD message, WORD wParam, LONG lParam)
{
CREATESTRUCT *createStruct;
if (!hComboBit) COMBO_Init();
createStruct = (CREATESTRUCT *)PTR_SEG_TO_LIN(lParam);
createStruct->style &= ~(WS_VSCROLL | WS_HSCROLL);
SetWindowLong(hwnd, GWL_STYLE, createStruct->style);
dprintf_combo(stddeb,"ComboBox WM_NCCREATE!\n");
return DefWindowProc(hwnd, message, wParam, lParam);
}
/***********************************************************************
* CBCreate
*/
static LONG CBCreate(HWND hwnd, WORD message, WORD wParam, LONG lParam)
{
LPHEADLIST lphl;
LPHEADCOMBO lphc;
LONG style = 0;
LONG cstyle = GetWindowLong(hwnd,GWL_STYLE);
RECT rect,lboxrect;
/* translate combo into listbox styles */
if (cstyle & CBS_OWNERDRAWFIXED) style |= LBS_OWNERDRAWFIXED;
if (cstyle & CBS_OWNERDRAWVARIABLE) style |= LBS_OWNERDRAWVARIABLE;
if (cstyle & CBS_SORT) style |= LBS_SORT;
if (cstyle & CBS_HASSTRINGS) style |= LBS_HASSTRINGS;
style |= LBS_NOTIFY;
CreateListBoxStruct(hwnd, ODT_COMBOBOX, style, GetParent(hwnd));
CreateComboStruct(hwnd,cstyle);
lphl = ComboGetListHeader(hwnd);
lphc = ComboGetStorageHeader(hwnd);
GetClientRect(hwnd,&rect);
GetWindowRect(hwnd,&lboxrect);
/* FIXME: combos with edit controls are broken. */
switch(cstyle & 3) {
case CBS_SIMPLE: /* edit control, list always visible */
dprintf_combo(stddeb,"CBS_SIMPLE\n");
SetRectEmpty(&lphc->RectButton);
lphc->LBoxTop = lphl->StdItemHeight;
lphc->hWndEdit = CreateWindow("EDIT", "",
WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE | SS_LEFT,
0, 0, rect.right, lphl->StdItemHeight,
hwnd, 1, GetWindowWord(hwnd,GWW_HINSTANCE), 0L);
break;
case CBS_DROPDOWN: /* edit control, dropdown listbox */
dprintf_combo(stddeb,"CBS_DROPDOWN\n");
lphc->RectButton = rect;
lphc->RectButton.left = lphc->RectButton.right - 6 - CBitWidth;
lphc->RectButton.bottom = lphc->RectButton.top + lphl->StdItemHeight;
lphc->LBoxTop = lphl->StdItemHeight;
SetWindowPos(hwnd, 0, 0, 0, rect.right - rect.left + 2*SYSMETRICS_CXBORDER,
lphl->StdItemHeight + 2*SYSMETRICS_CYBORDER,
SWP_NOMOVE | SWP_NOZORDER);
lphc->hWndEdit = CreateWindow("EDIT", "",
WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE | SS_LEFT,
0, 0, lphc->RectButton.left, lphl->StdItemHeight,
hwnd, 1, GetWindowWord(hwnd,GWW_HINSTANCE), 0L);
break;
case CBS_DROPDOWNLIST: /* static control, downdown listbox */
dprintf_combo(stddeb,"CBS_DROPDOWNLIST\n");
lphc->RectButton = rect;
lphc->RectButton.left = lphc->RectButton.right - 6 - CBitWidth;
lphc->RectButton.bottom = lphc->RectButton.top + lphl->StdItemHeight;
lphc->LBoxTop = lphl->StdItemHeight;
SetWindowPos(hwnd, 0, 0, 0, rect.right - rect.left + 2*SYSMETRICS_CXBORDER,
lphl->StdItemHeight + 2*SYSMETRICS_CYBORDER,
SWP_NOMOVE | SWP_NOZORDER);
break;
}
lboxrect.top += lphc->LBoxTop;
/* FIXME: WinSight says these should be CHILD windows with the TOPMOST flag
* set. Wine doesn't support TOPMOST, and simply setting the WS_CHILD
* flag doesn't work. */
lphc->hWndLBox = CreateWindow("COMBOLBOX", "",
WS_POPUP | WS_BORDER | WS_VSCROLL,
lboxrect.left, lboxrect.top,
lboxrect.right - lboxrect.left,
lboxrect.bottom - lboxrect.top,
0, 0, GetWindowWord(hwnd,GWW_HINSTANCE),
(SEGPTR)MAKELONG(hwnd, hwnd));
ShowWindow(lphc->hWndLBox, SW_HIDE);
dprintf_combo(stddeb,"Combo Creation LBox=%X!\n", lphc->hWndLBox);
return 0;
}
/***********************************************************************
* CBDestroy
*/
static LONG CBDestroy(HWND hwnd, WORD message, WORD wParam, LONG lParam)
{
LPHEADLIST lphl = ComboGetListHeader(hwnd);
ListBoxResetContent(lphl);
DestroyListBoxStruct(lphl);
dprintf_combo(stddeb,"Combo WM_DESTROY %p !\n", lphl);
return 0;
}
/***********************************************************************
* CBPaint
*/
static LONG CBPaint(HWND hwnd, WORD message, WORD wParam, LONG lParam)
{
LPHEADLIST lphl = ComboGetListHeader(hwnd);
LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
LPLISTSTRUCT lpls;
PAINTSTRUCT ps;
HBRUSH hBrush;
HFONT hOldFont;
HDC hdc;
RECT rect;
int height;
hdc = BeginPaint(hwnd, &ps);
if (hComboBit != 0) {
GRAPH_DrawReliefRect(hdc, &lphc->RectButton, 2, 2, FALSE);
GRAPH_DrawBitmap(hdc, hComboBit,
lphc->RectButton.left + 3,lphc->RectButton.top + 2,
0, 0, CBitWidth, CBitHeight );
}
if (!IsWindowVisible(hwnd) || !lphl->bRedrawFlag
|| (lphc->dwStyle & 3) != CBS_DROPDOWNLIST)
{
/* we don't want to draw an entry when there is an edit control */
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);
rect.right -= (lphc->RectButton.right - lphc->RectButton.left);
FillRect(hdc, &rect, hBrush);
lpls = ListBoxGetItem(lphl,lphl->ItemFocused);
if (lpls != NULL) {
height = lpls->mis.itemHeight;
rect.bottom = rect.top + height;
if (OWNER_DRAWN(lphl)) {
ListBoxDrawItem (hwnd, lphl, hdc, lpls, &rect, ODA_DRAWENTIRE, 0);
} else {
ListBoxDrawItem (hwnd, lphl, hdc, lpls, &rect, ODA_DRAWENTIRE, 0);
}
if (GetFocus() == hwnd)
ListBoxDrawItem (hwnd,lphl, hdc, lpls, &rect, ODA_FOCUS, ODS_FOCUS);
}
SelectObject(hdc,hOldFont);
EndPaint(hwnd, &ps);
return 0;
}
/***********************************************************************
* CBGetDlgCode
*/
static LONG CBGetDlgCode(HWND hwnd, WORD message, WORD wParam, LONG lParam)
{
return DLGC_WANTARROWS | DLGC_WANTCHARS;
}
/***********************************************************************
* CBLButtonDown
*/
static LONG CBLButtonDown(HWND hwnd, WORD message, WORD wParam, LONG lParam)
{
LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
SendMessage(hwnd,CB_SHOWDROPDOWN,!lphc->DropDownVisible,0);
return 0;
}
/***********************************************************************
* CBKeyDown
*/
static LONG CBKeyDown(HWND hwnd, WORD message, WORD wParam, LONG lParam)
{
LPHEADLIST lphl = ComboGetListHeader(hwnd);
WORD newFocused = lphl->ItemFocused;
switch(wParam) {
case VK_HOME:
newFocused = 0;
break;
case VK_END:
newFocused = lphl->ItemsCount - 1;
break;
case VK_UP:
if (newFocused > 0) newFocused--;
break;
case VK_DOWN:
newFocused++;
break;
default:
return 0;
}
if (newFocused >= lphl->ItemsCount)
newFocused = lphl->ItemsCount - 1;
ListBoxSetCurSel(lphl, newFocused);
ListBoxSendNotification(lphl, hwnd, CBN_SELCHANGE);
lphl->ItemFocused = newFocused;
ListBoxScrollToFocus(lphl);
/* SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);*/
InvalidateRect(hwnd, NULL, TRUE);
return 0;
}
/***********************************************************************
* CBChar
*/
static LONG CBChar(HWND hwnd, WORD message, WORD wParam, LONG lParam)
{
LPHEADLIST lphl = ComboGetListHeader(hwnd);
WORD newFocused;
newFocused = ListBoxFindNextMatch(lphl, wParam);
if (newFocused == (WORD)LB_ERR) return 0;
if (newFocused >= lphl->ItemsCount)
newFocused = lphl->ItemsCount - 1;
ListBoxSetCurSel(lphl, newFocused);
ListBoxSendNotification(lphl, hwnd, CBN_SELCHANGE);
lphl->ItemFocused = newFocused;
ListBoxScrollToFocus(lphl);
/* SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);*/
InvalidateRect(hwnd, NULL, TRUE);
return 0;
}
/***********************************************************************
* CBKillFocus
*/
static LONG CBKillFocus(HWND hwnd, WORD message, WORD wParam, LONG lParam)
{
return 0;
}
/***********************************************************************
* CBSetFocus
*/
static LONG CBSetFocus(HWND hwnd, WORD message, WORD wParam, LONG lParam)
{
return 0;
}
/***********************************************************************
* CBResetContent
*/
static LONG CBResetContent(HWND hwnd, WORD message, WORD wParam, LONG lParam)
{
LPHEADLIST lphl = ComboGetListHeader(hwnd);
LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
ListBoxResetContent(lphl);
ComboUpdateWindow(hwnd, lphl, lphc, TRUE);
return 0;
}
/***********************************************************************
* CBDir
*/
static LONG CBDir(HWND hwnd, WORD message, WORD wParam, LONG lParam)
{
WORD wRet;
LPHEADLIST lphl = ComboGetListHeader(hwnd);
LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
wRet = ListBoxDirectory(lphl, wParam, (LPSTR)PTR_SEG_TO_LIN(lParam));
ComboUpdateWindow(hwnd, lphl, lphc, TRUE);
return wRet;
}
/***********************************************************************
* CBInsertString
*/
static LONG CBInsertString(HWND hwnd, WORD message, WORD wParam, LONG lParam)
{
WORD wRet;
LPHEADLIST lphl = ComboGetListHeader(hwnd);
LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
if (HasStrings(lphl))
wRet = ListBoxInsertString(lphl, wParam, (LPSTR)PTR_SEG_TO_LIN(lParam));
else
wRet = ListBoxInsertString(lphl, wParam, (LPSTR)lParam);
ComboUpdateWindow(hwnd, lphl, lphc, TRUE);
return wRet;
}
/***********************************************************************
* CBAddString
*/
static LONG CBAddString(HWND hwnd, WORD message, WORD wParam, LONG lParam)
{
WORD wRet;
LPHEADLIST lphl = ComboGetListHeader(hwnd);
LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
if (HasStrings(lphl))
wRet = ListBoxAddString(lphl, (LPSTR)PTR_SEG_TO_LIN(lParam));
else
wRet = ListBoxAddString(lphl, (LPSTR)lParam);
ComboUpdateWindow(hwnd, lphl, lphc, TRUE);
return wRet;
}
/***********************************************************************
* CBDeleteString
*/
static LONG CBDeleteString(HWND hwnd, WORD message, WORD wParam, LONG lParam)
{
LPHEADLIST lphl = ComboGetListHeader(hwnd);
LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
LONG lRet = ListBoxDeleteString(lphl,wParam);
ComboUpdateWindow(hwnd, lphl, lphc, TRUE);
return lRet;
}
/***********************************************************************
* CBSelectString
*/
static LONG CBSelectString(HWND hwnd, WORD message, WORD wParam, LONG lParam)
{
LPHEADLIST lphl = ComboGetListHeader(hwnd);
WORD wRet;
wRet = ListBoxFindString(lphl, wParam, lParam);
/* XXX add functionality here */
return 0;
}
/***********************************************************************
* CBFindString
*/
static LONG CBFindString(HWND hwnd, WORD message, WORD wParam, LONG lParam)
{
LPHEADLIST lphl = ComboGetListHeader(hwnd);
return ListBoxFindString(lphl, wParam, lParam);
}
/***********************************************************************
* CBGetCount
*/
static LONG CBGetCount(HWND hwnd, WORD message, WORD wParam, LONG lParam)
{
LPHEADLIST lphl = ComboGetListHeader(hwnd);
return lphl->ItemsCount;
}
/***********************************************************************
* CBSetCurSel
*/
static LONG CBSetCurSel(HWND hwnd, WORD message, WORD wParam, LONG lParam)
{
LPHEADLIST lphl = ComboGetListHeader(hwnd);
WORD wRet;
wRet = ListBoxSetCurSel(lphl, wParam);
/* SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);*/
InvalidateRect(hwnd, NULL, TRUE);
return wRet;
}
/***********************************************************************
* CBGetCurSel
*/
static LONG CBGetCurSel(HWND hwnd, WORD message, WORD wParam, LONG lParam)
{
LPHEADLIST lphl = ComboGetListHeader(hwnd);
return lphl->ItemFocused;
}
/***********************************************************************
* CBGetItemHeight
*/
static LONG CBGetItemHeight(HWND hwnd, WORD message, WORD wParam, LONG lParam)
{
LPHEADLIST lphl = ComboGetListHeader(hwnd);
LPLISTSTRUCT lpls = ListBoxGetItem (lphl, wParam);
if (lpls == NULL) return LB_ERR;
return lpls->mis.itemHeight;
}
/***********************************************************************
* CBSetItemHeight
*/
static LONG CBSetItemHeight(HWND hwnd, WORD message, WORD wParam, LONG lParam)
{
LPHEADLIST lphl = ComboGetListHeader(hwnd);
return ListBoxSetItemHeight(lphl, wParam, lParam);
}
/***********************************************************************
* CBSetRedraw
*/
static LONG CBSetRedraw(HWND hwnd, WORD message, WORD wParam, LONG lParam)
{
LPHEADLIST lphl = ComboGetListHeader(hwnd);
lphl->bRedrawFlag = wParam;
return 0;
}
/***********************************************************************
* CBSetFont
*/
static LONG CBSetFont(HWND hwnd, WORD message, WORD wParam, LONG lParam)
{
LPHEADLIST lphl = ComboGetListHeader(hwnd);
if (wParam == 0)
lphl->hFont = GetStockObject(SYSTEM_FONT);
else
lphl->hFont = wParam;
return 0;
}
/***********************************************************************
* CBGetLBTextLen
*/
static LONG CBGetLBTextLen(HWND hwnd, WORD message, WORD wParam, LONG lParam)
{
LPHEADLIST lphl = ComboGetListHeader(hwnd);
LPLISTSTRUCT lpls = ListBoxGetItem(lphl,wParam);
if (lpls == NULL || !HasStrings(lphl)) return LB_ERR;
return strlen(lpls->itemText);
}
/***********************************************************************
* CBGetLBText
*/
static LONG CBGetLBText(HWND hwnd, WORD message, WORD wParam, LONG lParam)
{
LPHEADLIST lphl = ComboGetListHeader(hwnd);
return ListBoxGetText(lphl, wParam, (LPSTR)PTR_SEG_TO_LIN(lParam));
}
/***********************************************************************
* CBGetItemData
*/
static LONG CBGetItemData(HWND hwnd, WORD message, WORD wParam, LONG lParam)
{
LPHEADLIST lphl = ComboGetListHeader(hwnd);
return ListBoxGetItemData(lphl, wParam);
}
/***********************************************************************
* CBSetItemData
*/
static LONG CBSetItemData(HWND hwnd, WORD message, WORD wParam, LONG lParam)
{
LPHEADLIST lphl = ComboGetListHeader(hwnd);
return ListBoxSetItemData(lphl, wParam, lParam);
}
/***********************************************************************
* CBShowDropDown
*/
static LONG CBShowDropDown(HWND hwnd, WORD message, WORD wParam, LONG lParam)
{
LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
RECT rect;
if (lphc->dwStyle & 3 == CBS_SIMPLE) return LB_ERR;
wParam = !!wParam;
if (wParam != lphc->DropDownVisible) {
lphc->DropDownVisible = wParam;
GetWindowRect(hwnd,&rect);
SetWindowPos(lphc->hWndLBox, 0, rect.left, rect.top+lphc->LBoxTop, 0, 0,
SWP_NOSIZE | (wParam ? SWP_SHOWWINDOW : SWP_HIDEWINDOW));
if (!wParam) SetFocus(hwnd);
}
return 0;
}
/***********************************************************************
* ComboWndProc
*/
LONG ComboBoxWndProc(HWND hwnd, WORD message, WORD wParam, LONG lParam)
{
int idx = 0;
int table_size = sizeof (combo_tbl) / sizeof (msg_tbl);
while (idx < table_size) {
if (message == combo_tbl[idx].message) {
return (*(combo_tbl[idx].handler))(hwnd, message, wParam, lParam);
}
idx++;
}
return DefWindowProc (hwnd, message, wParam, lParam);
}
/*--------------------------------------------------------------------*/
/* ComboLBox code starts here */
HWND CLBoxGetCombo(HWND hwnd)
{
return GetWindowWord(hwnd,0);
}
LPHEADLIST CLBoxGetListHeader(HWND hwnd)
{
return ComboGetListHeader(CLBoxGetCombo(hwnd));
}
/***********************************************************************
* CBLCreate
*/
static LONG CBLCreate( HWND hwnd, WORD message, WORD wParam, LONG lParam )
{
CREATESTRUCT *createStruct = (CREATESTRUCT *)PTR_SEG_TO_LIN(lParam);
SetWindowWord(hwnd,0,LOWORD(createStruct->lpCreateParams));
return 0;
}
/***********************************************************************
* CBLGetDlgCode
*/
static LONG CBLGetDlgCode( HWND hwnd, WORD message, WORD wParam, LONG lParam )
{
return DLGC_WANTARROWS | DLGC_WANTCHARS;
}
/***********************************************************************
* CBLKeyDown
*/
static LONG CBLKeyDown( HWND hwnd, WORD message, WORD wParam, LONG lParam )
{
LPHEADLIST lphl = CLBoxGetListHeader(hwnd);
WORD newFocused = lphl->ItemFocused;
switch(wParam) {
case VK_HOME:
newFocused = 0;
break;
case VK_END:
newFocused = lphl->ItemsCount - 1;
break;
case VK_UP:
if (newFocused > 0) newFocused--;
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;
ListBoxSetCurSel(lphl, newFocused);
ListBoxSendNotification(lphl, hwnd, CBN_SELCHANGE);
lphl->ItemFocused = newFocused;
ListBoxScrollToFocus(lphl);
SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
InvalidateRect(hwnd, NULL, TRUE);
return 0;
}
/***********************************************************************
* CBLChar
*/
static LONG CBLChar( HWND hwnd, WORD message, WORD wParam, LONG lParam )
{
return 0;
}
/***********************************************************************
* CBLPaint
*/
static LONG CBLPaint( HWND hwnd, WORD message, WORD wParam, LONG lParam )
{
LPHEADLIST lphl = CLBoxGetListHeader(hwnd);
LPLISTSTRUCT lpls;
PAINTSTRUCT ps;
HBRUSH hBrush;
HFONT hOldFont;
HDC hdc;
RECT rect;
int i, top, height;
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);
lpls = lphl->lpFirst;
lphl->ItemsVisible = 0;
for(i = 0; i < lphl->ItemsCount; i++) {
if (lpls == NULL) break;
if (i >= lphl->FirstVisible) {
height = lpls->mis.itemHeight;
if (top > rect.bottom) 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 (OWNER_DRAWN(lphl)) {
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++;
}
lpls = lpls->lpNext;
}
SelectObject(hdc,hOldFont);
EndPaint( hwnd, &ps );
return 0;
}
/***********************************************************************
* CBLKillFocus
*/
static LONG CBLKillFocus( HWND hwnd, WORD message, WORD wParam, LONG lParam )
{
/* SendMessage(CLBoxGetCombo(hwnd),CB_SHOWDROPDOWN,0,0);*/
return 0;
}
/***********************************************************************
* CBLActivate
*/
static LONG CBLActivate( HWND hwnd, WORD message, WORD wParam, LONG lParam )
{
if (wParam == WA_INACTIVE)
SendMessage(CLBoxGetCombo(hwnd),CB_SHOWDROPDOWN,0,0);
return 0;
}
/***********************************************************************
* CBLLButtonDown
*/
static LONG CBLLButtonDown( HWND hwnd, WORD message, WORD wParam, LONG lParam )
{
LPHEADLIST lphl = CLBoxGetListHeader(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;
ListBoxSetCurSel(lphl, y);
ListBoxGetItemRect(lphl, y, &rectsel);
InvalidateRect(hwnd, NULL, TRUE);
return 0;
}
/***********************************************************************
* CBLLButtonUp
*/
static LONG CBLLButtonUp( HWND hwnd, WORD message, WORD wParam, LONG lParam )
{
LPHEADLIST lphl = CLBoxGetListHeader(hwnd);
if (GetCapture() == hwnd) ReleaseCapture();
if (lphl->PrevFocused != lphl->ItemFocused) {
SendMessage(CLBoxGetCombo(hwnd),CB_SETCURSEL,lphl->ItemFocused,0);
ListBoxSendNotification(lphl, CLBoxGetCombo(hwnd), CBN_SELCHANGE);
}
SendMessage(CLBoxGetCombo(hwnd),CB_SHOWDROPDOWN,0,0);
return 0;
}
/***********************************************************************
* CBLMouseMove
*/
static LONG CBLMouseMove( HWND hwnd, WORD message, WORD wParam, LONG lParam )
{
LPHEADLIST lphl = CLBoxGetListHeader(hwnd);
int y;
WORD wRet;
RECT rect, rectsel; /* XXX Broken */
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;
ListBoxSetCurSel(lphl, wRet);
ListBoxGetItemRect(lphl, wRet, &rectsel);
InvalidateRect(hwnd, NULL, TRUE);
}
}
}
return 0;
}
/***********************************************************************
* CBLVScroll
*/
static LONG CBLVScroll( HWND hwnd, WORD message, WORD wParam, LONG lParam )
{
LPHEADLIST lphl = CLBoxGetListHeader(hwnd);
int y;
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;
}
/***********************************************************************
* ComboLBoxWndProc
*/
LONG ComboLBoxWndProc(HWND hwnd, WORD message, WORD wParam, LONG lParam)
{
int idx = 0;
int table_size = sizeof (clbox_tbl) / sizeof (msg_tbl);
while (idx < table_size) {
if (message == clbox_tbl[idx].message) {
return (*(clbox_tbl[idx].handler))(hwnd, message, wParam, lParam);
}
idx++;
}
return DefWindowProc (hwnd, message, wParam, lParam);
}
/************************************************************************
* DlgDirSelectComboBox [USER.194]
*/
BOOL DlgDirSelectComboBox(HWND hDlg, LPSTR lpStr, int nIDLBox)
{
fprintf(stdnimp,"DlgDirSelectComboBox(%04X, '%s', %d) \n",
hDlg, lpStr, nIDLBox);
return TRUE;
}
/************************************************************************
* DlgDirListComboBox [USER.195]
*/
int DlgDirListComboBox(HWND hDlg, SEGPTR PathSpec,
int nIDLBox, int nIDStat, WORD wType)
{
HWND hWnd;
int ret;
LPSTR lpPathSpec = PTR_SEG_TO_LIN(PathSpec);
dprintf_combo(stddeb,"DlgDirListComboBox(%04X, '%s', %d, %d, %04X) \n",
hDlg, lpPathSpec, nIDLBox, nIDStat, wType);
if (nIDLBox) {
LPHEADLIST lphl;
LPHEADCOMBO lphc;
hWnd = GetDlgItem(hDlg, nIDLBox);
lphl = ComboGetListHeader(hWnd);
lphc = ComboGetStorageHeader(hWnd);
ListBoxResetContent(lphl);
ret = ListBoxDirectory(lphl, wType, lpPathSpec);
ComboUpdateWindow(hWnd, lphl, lphc, 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;
}