From 007128eb662c577083bc766bedc71356d6d0c4c9 Mon Sep 17 00:00:00 2001 From: Boudewijn Dekker Date: Fri, 20 Aug 1999 09:37:25 +0000 Subject: [PATCH] Small additions, not yet finished svn path=/trunk/; revision=618 --- reactos/lib/user32/controls/button.c | 598 +++ reactos/lib/user32/controls/combo.c | 1570 +++++++ reactos/lib/user32/controls/edit.c | 3745 +++++++++++++++++ reactos/lib/user32/controls/icontitle.c | 242 ++ reactos/lib/user32/controls/listbox.c | 2557 +++++++++++ .../lib/user32/{windows => controls}/menu.c | 87 +- reactos/lib/user32/controls/scroll.c | 1445 +++++++ reactos/lib/user32/controls/static.c | 509 +++ reactos/lib/user32/controls/widgets.c | 112 + reactos/lib/user32/graphics/fill.c | 31 + reactos/lib/user32/graphics/icon.c | 115 +- reactos/lib/user32/graphics/syscol.c | 6 +- reactos/lib/user32/graphics/text.c | 47 +- reactos/lib/user32/internal/defwnd.c | 25 +- reactos/lib/user32/internal/dialog.c | 1333 +++--- reactos/lib/user32/internal/heapdup.c | 12 + reactos/lib/user32/internal/menu.c | 16 +- reactos/lib/user32/internal/msg.c | 127 +- reactos/lib/user32/internal/nc.c | 68 +- reactos/lib/user32/internal/paint.c | 61 +- reactos/lib/user32/internal/scroll.c | 30 + reactos/lib/user32/internal/uitools.c | 8 +- reactos/lib/user32/internal/win.c | 131 +- reactos/lib/user32/makefile.main | 23 +- reactos/lib/user32/misc/bitmap.c | 3 + reactos/lib/user32/misc/main.c | 43 +- reactos/lib/user32/resources/sysres.c | 2 + reactos/lib/user32/user32.rc | 26 +- reactos/lib/user32/windows/class.c | 33 +- reactos/lib/user32/windows/defdlg.c | 374 ++ reactos/lib/user32/windows/dialog.c | 875 +--- reactos/lib/user32/windows/hook.c | 15 +- reactos/lib/user32/windows/msg.c | 90 +- reactos/lib/user32/windows/msgbox.c | 304 +- reactos/lib/user32/windows/scroll.c | 312 ++ reactos/lib/user32/windows/win.c | 91 +- reactos/lib/user32/windows/winpos.c | 266 +- 37 files changed, 13556 insertions(+), 1776 deletions(-) create mode 100644 reactos/lib/user32/controls/button.c create mode 100644 reactos/lib/user32/controls/combo.c create mode 100644 reactos/lib/user32/controls/edit.c create mode 100644 reactos/lib/user32/controls/icontitle.c create mode 100644 reactos/lib/user32/controls/listbox.c rename reactos/lib/user32/{windows => controls}/menu.c (94%) create mode 100644 reactos/lib/user32/controls/scroll.c create mode 100644 reactos/lib/user32/controls/static.c create mode 100644 reactos/lib/user32/controls/widgets.c create mode 100644 reactos/lib/user32/windows/defdlg.c create mode 100644 reactos/lib/user32/windows/scroll.c diff --git a/reactos/lib/user32/controls/button.c b/reactos/lib/user32/controls/button.c new file mode 100644 index 00000000000..fe8ed5b2880 --- /dev/null +++ b/reactos/lib/user32/controls/button.c @@ -0,0 +1,598 @@ +/* File: button.c -- Button type widgets + * + * Copyright (C) 1993 Johannes Ruscheinski + * Copyright (C) 1993 David Metcalfe + * Copyright (C) 1994 Alexandre Julliard + */ +#include +#include +#include +#include +#include +#include +#include + + +static void PB_Paint( WND *wndPtr, HDC hDC, WORD action ); +static void PB_PaintGrayOnGray(HDC hDC,HFONT hFont,RECT *rc,char *text); +static void CB_Paint( WND *wndPtr, HDC hDC, WORD action ); +static void GB_Paint( WND *wndPtr, HDC hDC, WORD action ); +static void UB_Paint( WND *wndPtr, HDC hDC, WORD action ); +static void OB_Paint( WND *wndPtr, HDC hDC, WORD action ); +static void BUTTON_CheckAutoRadioButton( WND *wndPtr ); + +#define MAX_BTN_TYPE 12 + +static const WORD maxCheckState[MAX_BTN_TYPE] = +{ + BUTTON_UNCHECKED, /* BS_PUSHBUTTON */ + BUTTON_UNCHECKED, /* BS_DEFPUSHBUTTON */ + BUTTON_CHECKED, /* BS_CHECKBOX */ + BUTTON_CHECKED, /* BS_AUTOCHECKBOX */ + BUTTON_CHECKED, /* BS_RADIOBUTTON */ + BUTTON_3STATE, /* BS_3STATE */ + BUTTON_3STATE, /* BS_AUTO3STATE */ + BUTTON_UNCHECKED, /* BS_GROUPBOX */ + BUTTON_UNCHECKED, /* BS_USERBUTTON */ + BUTTON_CHECKED, /* BS_AUTORADIOBUTTON */ + BUTTON_UNCHECKED, /* Not defined */ + BUTTON_UNCHECKED /* BS_OWNERDRAW */ +}; + +typedef void (*pfPaint)( WND *wndPtr, HDC hdc, WORD action ); + +static const pfPaint btnPaintFunc[MAX_BTN_TYPE] = +{ + PB_Paint, /* BS_PUSHBUTTON */ + PB_Paint, /* BS_DEFPUSHBUTTON */ + CB_Paint, /* BS_CHECKBOX */ + CB_Paint, /* BS_AUTOCHECKBOX */ + CB_Paint, /* BS_RADIOBUTTON */ + CB_Paint, /* BS_3STATE */ + CB_Paint, /* BS_AUTO3STATE */ + GB_Paint, /* BS_GROUPBOX */ + UB_Paint, /* BS_USERBUTTON */ + CB_Paint, /* BS_AUTORADIOBUTTON */ + NULL, /* Not defined */ + OB_Paint /* BS_OWNERDRAW */ +}; + +#define PAINT_BUTTON(wndPtr,style,action) \ + if (btnPaintFunc[style]) { \ + HDC hdc = GetDC( (wndPtr)->hwndSelf ); \ + (btnPaintFunc[style])(wndPtr,hdc,action); \ + ReleaseDC( (wndPtr)->hwndSelf, hdc ); } + +#define BUTTON_SEND_CTLCOLOR(wndPtr,hdc) \ + SendMessageA( GetParent((wndPtr)->hwndSelf), WM_CTLCOLORBTN, \ + (WPARAM)(hdc), (LPARAM)(wndPtr)->hwndSelf ) + +static HBITMAP hbitmapCheckBoxes = 0; +static WORD checkBoxWidth = 0, checkBoxHeight = 0; + + +/*********************************************************************** + * ButtonWndProc + */ +LRESULT WINAPI ButtonWndProc( HWND hWnd, UINT uMsg, + WPARAM wParam, LPARAM lParam ) +{ + RECT rect; + POINT pt = { LOWORD(lParam), HIWORD(lParam) }; + WND *wndPtr = WIN_FindWndPtr(hWnd); + BUTTONINFO *infoPtr = (BUTTONINFO *)wndPtr->wExtra; + LONG style = wndPtr->dwStyle & 0x0f; + + switch (uMsg) + { + case WM_GETDLGCODE: + switch(style) + { + case BS_PUSHBUTTON: return DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON; + case BS_DEFPUSHBUTTON: return DLGC_BUTTON | DLGC_DEFPUSHBUTTON; + case BS_RADIOBUTTON: + case BS_AUTORADIOBUTTON: return DLGC_BUTTON | DLGC_RADIOBUTTON; + default: return DLGC_BUTTON; + } + + case WM_ENABLE: + PAINT_BUTTON( wndPtr, style, ODA_DRAWENTIRE ); + break; + + case WM_CREATE: + if (!hbitmapCheckBoxes) + { + BITMAP bmp; + hbitmapCheckBoxes = LoadBitmapA(0, MAKEINTRESOURCEA(OBM_CHECKBOXES)); + GetObjectA( hbitmapCheckBoxes, sizeof(bmp), &bmp ); + checkBoxWidth = bmp.bmWidth / 4; + checkBoxHeight = bmp.bmHeight / 3; + } + if (style < 0L || style >= MAX_BTN_TYPE) return -1; /* abort */ + infoPtr->state = BUTTON_UNCHECKED; + infoPtr->hFont = 0; + return 0; + + case WM_ERASEBKGND: + return 1; + + case WM_PAINT: + if (btnPaintFunc[style]) + { + PAINTSTRUCT ps; + HDC hdc = wParam ? (HDC)wParam : BeginPaint( hWnd, &ps ); + SetBkMode( hdc, OPAQUE ); + (btnPaintFunc[style])( wndPtr, hdc, ODA_DRAWENTIRE ); + if( !wParam ) EndPaint( hWnd, &ps ); + } + break; + + case WM_LBUTTONDOWN: + case WM_LBUTTONDBLCLK: + SendMessageA( hWnd, BM_SETSTATE, TRUE, 0 ); + SetFocus( hWnd ); + SetCapture( hWnd ); + break; + + case WM_LBUTTONUP: + ReleaseCapture(); + if (!(infoPtr->state & BUTTON_HIGHLIGHTED)) break; + SendMessageA( hWnd, BM_SETSTATE, FALSE, 0 ); + GetClientRect( hWnd, &rect ); + if (PtInRect( &rect, pt )) + { + switch(style) + { + case BS_AUTOCHECKBOX: + SendMessageA( hWnd, BM_SETCHECK, + !(infoPtr->state & BUTTON_CHECKED), 0 ); + break; + case BS_AUTORADIOBUTTON: + SendMessageA( hWnd, BM_SETCHECK, TRUE, 0 ); + break; + case BS_AUTO3STATE: + SendMessageA( hWnd, BM_SETCHECK, + (infoPtr->state & BUTTON_3STATE) ? 0 : + ((infoPtr->state & 3) + 1), 0 ); + break; + } + SendMessageA( GetParent(hWnd), WM_COMMAND, + MAKEWPARAM( wndPtr->wIDmenu, BN_CLICKED ), (LPARAM)hWnd); + } + break; + + case WM_MOUSEMOVE: + if (GetCapture() == hWnd) + { + GetClientRect( hWnd, &rect ); + SendMessageA( hWnd, BM_SETSTATE, PtInRect(&rect, pt), 0 ); + } + break; + + case WM_NCHITTEST: + if(style == BS_GROUPBOX) return HTTRANSPARENT; + return DefWindowProcA( hWnd, uMsg, wParam, lParam ); + + case WM_SETTEXT: + DEFWND_SetTextA( wndPtr, (LPCSTR)lParam ); + if( wndPtr->dwStyle & WS_VISIBLE ) + PAINT_BUTTON( wndPtr, style, ODA_DRAWENTIRE ); + return 0; + + case WM_SETFONT: + infoPtr->hFont = (HFONT)wParam; + if (lParam && (wndPtr->dwStyle & WS_VISIBLE)) + PAINT_BUTTON( wndPtr, style, ODA_DRAWENTIRE ); + break; + + case WM_GETFONT: + return (LRESULT)infoPtr->hFont; + + case WM_SETFOCUS: + infoPtr->state |= BUTTON_HASFOCUS; + if (style == BS_AUTORADIOBUTTON) + { + SendMessageA( hWnd, BM_SETCHECK, 1, 0 ); + } + PAINT_BUTTON( wndPtr, style, ODA_FOCUS ); + break; + + case WM_KILLFOCUS: + infoPtr->state &= ~BUTTON_HASFOCUS; + PAINT_BUTTON( wndPtr, style, ODA_FOCUS ); + InvalidateRect( hWnd, NULL, TRUE ); + break; + + case WM_SYSCOLORCHANGE: + InvalidateRect( hWnd, NULL, FALSE ); + break; + + case BM_SETSTYLE: + if ((wParam & 0x0f) >= MAX_BTN_TYPE) break; + wndPtr->dwStyle = (wndPtr->dwStyle & 0xfffffff0) + | (wParam & 0x0000000f); + style = wndPtr->dwStyle & 0x0000000f; + PAINT_BUTTON( wndPtr, style, ODA_DRAWENTIRE ); + break; + + case BM_GETCHECK: + return infoPtr->state & 3; + + case BM_SETCHECK: + if (wParam > maxCheckState[style]) wParam = maxCheckState[style]; + if ((infoPtr->state & 3) != wParam) + { + if ((style == BS_RADIOBUTTON) || (style == BS_AUTORADIOBUTTON)) + { + if (wParam) + wndPtr->dwStyle |= WS_TABSTOP; + else + wndPtr->dwStyle &= ~WS_TABSTOP; + } + infoPtr->state = (infoPtr->state & ~3) | wParam; + PAINT_BUTTON( wndPtr, style, ODA_SELECT ); + } + if ((style == BS_AUTORADIOBUTTON) && (wParam == BUTTON_CHECKED)) + BUTTON_CheckAutoRadioButton( wndPtr ); + break; + + case BM_GETSTATE: + return infoPtr->state; + + case BM_SETSTATE: + if (wParam) + { + if (infoPtr->state & BUTTON_HIGHLIGHTED) break; + infoPtr->state |= BUTTON_HIGHLIGHTED; + } + else + { + if (!(infoPtr->state & BUTTON_HIGHLIGHTED)) break; + infoPtr->state &= ~BUTTON_HIGHLIGHTED; + } + PAINT_BUTTON( wndPtr, style, ODA_SELECT ); + break; + + default: + return DefWindowProcA(hWnd, uMsg, wParam, lParam); + } + return 0; +} + + +/********************************************************************** + * Push Button Functions + */ + +static void PB_Paint( WND *wndPtr, HDC hDC, WORD action ) +{ + RECT rc; + HPEN hOldPen; + HBRUSH hOldBrush; + BUTTONINFO *infoPtr = (BUTTONINFO *)wndPtr->wExtra; + + GetClientRect( wndPtr->hwndSelf, &rc ); + + /* Send WM_CTLCOLOR to allow changing the font (the colors are fixed) */ + if (infoPtr->hFont) SelectObject( hDC, infoPtr->hFont ); + BUTTON_SEND_CTLCOLOR( wndPtr, hDC ); + hOldPen = (HPEN)SelectObject(hDC, GetSysColorPen(COLOR_WINDOWFRAME)); + hOldBrush =(HBRUSH)SelectObject(hDC,GetSysColorBrush(COLOR_BTNFACE)); + SetBkMode(hDC, TRANSPARENT); + Rectangle(hDC, rc.left, rc.top, rc.right, rc.bottom); + if (action == ODA_DRAWENTIRE) + { + SetPixel( hDC, rc.left, rc.top, GetSysColor(COLOR_WINDOW) ); + SetPixel( hDC, rc.left, rc.bottom-1, GetSysColor(COLOR_WINDOW) ); + SetPixel( hDC, rc.right-1, rc.top, GetSysColor(COLOR_WINDOW) ); + SetPixel( hDC, rc.right-1, rc.bottom-1, GetSysColor(COLOR_WINDOW)); + } + InflateRect( &rc, -1, -1 ); + + if ((wndPtr->dwStyle & 0x000f) == BS_DEFPUSHBUTTON) + { + Rectangle(hDC, rc.left, rc.top, rc.right, rc.bottom); + InflateRect( &rc, -1, -1 ); + } + + if (infoPtr->state & BUTTON_HIGHLIGHTED) + { + /* draw button shadow: */ + SelectObject(hDC, GetSysColorBrush(COLOR_BTNSHADOW)); + PatBlt(hDC, rc.left, rc.top, 1, rc.bottom-rc.top, PATCOPY ); + PatBlt(hDC, rc.left, rc.top, rc.right-rc.left, 1, PATCOPY ); + rc.left += 2; /* To position the text down and right */ + rc.top += 2; + } else { + rc.right++, rc.bottom++; + DrawEdge( hDC, &rc, EDGE_RAISED, BF_RECT ); + rc.right--, rc.bottom--; + } + + /* draw button label, if any: */ +// && wndPtr->text[0] + if (wndPtr->text ) + { + LOGBRUSH lb; + GetObject( GetSysColorBrush(COLOR_BTNFACE), sizeof(lb), &lb ); + if (wndPtr->dwStyle & WS_DISABLED && + GetSysColor(COLOR_GRAYTEXT)==lb.lbColor) + /* don't write gray text on gray bkg */ + PB_PaintGrayOnGray(hDC,infoPtr->hFont,&rc,wndPtr->text); + else + { + SetTextColor( hDC, (wndPtr->dwStyle & WS_DISABLED) ? + GetSysColor(COLOR_GRAYTEXT) : + GetSysColor(COLOR_BTNTEXT) ); + DrawTextA( hDC, wndPtr->text, -1, &rc, + DT_SINGLELINE | DT_CENTER | DT_VCENTER ); + /* do we have the focus? */ + if (infoPtr->state & BUTTON_HASFOCUS) + { + RECT r = { 0, 0, 0, 0 }; + INT xdelta, ydelta; + + DrawTextA( hDC, wndPtr->text, -1, &r, + DT_SINGLELINE | DT_CALCRECT ); + xdelta = ((rc.right - rc.left) - (r.right - r.left) - 1) / 2; + ydelta = ((rc.bottom - rc.top) - (r.bottom - r.top) - 1) / 2; + if (xdelta < 0) xdelta = 0; + if (ydelta < 0) ydelta = 0; + InflateRect( &rc, -xdelta, -ydelta ); + DrawFocusRect( hDC, &rc ); + } + } + } + + SelectObject( hDC, hOldPen ); + SelectObject( hDC, hOldBrush ); +} + + +/********************************************************************** + * Push Button sub function [internal] + * using a raster brush to avoid gray text on gray background + */ + +void PB_PaintGrayOnGray(HDC hDC,HFONT hFont,RECT *rc,char *text) +{ + static const int Pattern[] = {0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55}; + HBITMAP hbm = CreateBitmap( 8, 8, 1, 1, Pattern ); + HDC hdcMem = CreateCompatibleDC(hDC); + HBITMAP hbmMem; + HBRUSH hBr; + RECT rect,rc2; + + rect=*rc; + DrawTextA( hDC, text, -1, &rect, DT_SINGLELINE | DT_CALCRECT); + rc2=rect; + rect.left=(rc->right-rect.right)/2; /* for centering text bitmap */ + rect.top=(rc->bottom-rect.bottom)/2; + hbmMem = CreateCompatibleBitmap( hDC,rect.right,rect.bottom ); + SelectObject( hdcMem, hbmMem); + hBr = SelectObject( hdcMem, CreatePatternBrush(hbm) ); + DeleteObject( hbm ); + PatBlt( hdcMem,0,0,rect.right,rect.bottom,WHITENESS); + if (hFont) SelectObject( hdcMem, hFont); + DrawTextA( hdcMem, text, -1, &rc2, DT_SINGLELINE); + PatBlt( hdcMem,0,0,rect.right,rect.bottom,0xFA0089); + DeleteObject( SelectObject( hdcMem,hBr) ); + BitBlt(hDC,rect.left,rect.top,rect.right,rect.bottom,hdcMem,0,0,0x990000); + DeleteDC( hdcMem); + DeleteObject( hbmMem ); +} + + +/********************************************************************** + * Check Box & Radio Button Functions + */ + +static void CB_Paint( WND *wndPtr, HDC hDC, WORD action ) +{ + RECT rbox, rtext, client; + HBRUSH hBrush; + int textlen, delta; + BUTTONINFO *infoPtr = (BUTTONINFO *)wndPtr->wExtra; + + textlen = 0; + GetClientRect(wndPtr->hwndSelf, &client); + rbox = rtext = client; + + if (infoPtr->hFont) SelectObject( hDC, infoPtr->hFont ); + + /* Something is still not right, checkboxes (and edit controls) + * in wsping have white backgrounds instead of dark grey. + * BUTTON_SEND_CTLCOLOR() is even worse since it returns 0 in this + * particular case and the background is not painted at all. + */ + + hBrush = GetControlBrush( wndPtr->hwndSelf, hDC, CTLCOLOR_BTN ); + + if (wndPtr->dwStyle & BS_LEFTTEXT) + { + /* magic +4 is what CTL3D expects */ + + rtext.right -= checkBoxWidth + 4; + rbox.left = rbox.right - checkBoxWidth; + } + else + { + rtext.left += checkBoxWidth + 4; + rbox.right = checkBoxWidth; + } + + /* Draw the check-box bitmap */ + + + if (wndPtr->text) { + textlen = lstrlenA( wndPtr->text ); + } + if (action == ODA_DRAWENTIRE || action == ODA_SELECT) + { + HDC hMemDC = CreateCompatibleDC( hDC ); + int x = 0, y = 0; + delta = (rbox.bottom - rbox.top - checkBoxHeight) >> 1; + + if (action == ODA_SELECT) FillRect( hDC, &rbox, hBrush ); + else FillRect( hDC, &client, hBrush ); + + if (infoPtr->state & BUTTON_HIGHLIGHTED) x += 2 * checkBoxWidth; + if (infoPtr->state & (BUTTON_CHECKED | BUTTON_3STATE)) x += checkBoxWidth; + if (((wndPtr->dwStyle & 0x0f) == BS_RADIOBUTTON) || + ((wndPtr->dwStyle & 0x0f) == BS_AUTORADIOBUTTON)) y += checkBoxHeight; + else if (infoPtr->state & BUTTON_3STATE) y += 2 * checkBoxHeight; + + SelectObject( hMemDC, hbitmapCheckBoxes ); + BitBlt( hDC, rbox.left, rbox.top + delta, checkBoxWidth, + checkBoxHeight, hMemDC, x, y, SRCCOPY ); + DeleteDC( hMemDC ); + + if( textlen && action != ODA_SELECT ) + { + if (wndPtr->dwStyle & WS_DISABLED) + SetTextColor( hDC, GetSysColor(COLOR_GRAYTEXT) ); + DrawTextA( hDC, wndPtr->text, textlen, &rtext, + DT_SINGLELINE | DT_VCENTER ); + textlen = 0; /* skip DrawText() below */ + } + } + + if ((action == ODA_FOCUS) || + ((action == ODA_DRAWENTIRE) && (infoPtr->state & BUTTON_HASFOCUS))) + { + /* again, this is what CTL3D expects */ + + SetRectEmpty(&rbox); + if( textlen ) + DrawTextA( hDC, wndPtr->text, textlen, &rbox, + DT_SINGLELINE | DT_CALCRECT ); + textlen = rbox.bottom - rbox.top; + delta = ((rtext.bottom - rtext.top) - textlen)/2; + rbox.bottom = (rbox.top = rtext.top + delta - 1) + textlen + 2; + textlen = rbox.right - rbox.left; + rbox.right = (rbox.left += --rtext.left) + textlen + 2; + IntersectRect(&rbox, &rbox, &rtext); + DrawFocusRect( hDC, &rbox ); + } +} + + +/********************************************************************** + * BUTTON_CheckAutoRadioButton + * + * wndPtr is checked, uncheck every other auto radio button in group + */ +static void BUTTON_CheckAutoRadioButton( WND *wndPtr ) +{ + HWND parent, sibling, start; + WND *sibPtr; + if (!(wndPtr->dwStyle & WS_CHILD)) return; + parent = wndPtr->parent->hwndSelf; + /* assure that starting control is not disabled or invisible */ + start = sibling = GetNextDlgGroupItem( parent, wndPtr->hwndSelf, TRUE ); + do + { + + if (!sibling) break; + sibPtr = WIN_FindWndPtr(sibling); + if (!sibPtr) break; + if ((wndPtr->hwndSelf != sibling) && + ((sibPtr->dwStyle & 0x0f) == BS_AUTORADIOBUTTON)) + SendMessageA( sibling, BM_SETCHECK, BUTTON_UNCHECKED, 0 ); + sibling = GetNextDlgGroupItem( parent, sibling, FALSE ); + } while (sibling != start); +} + + +/********************************************************************** + * Group Box Functions + */ + +static void GB_Paint( WND *wndPtr, HDC hDC, WORD action ) +{ + RECT rc, rcFrame; + BUTTONINFO *infoPtr = (BUTTONINFO *)wndPtr->wExtra; + + if (action != ODA_DRAWENTIRE) return; + + BUTTON_SEND_CTLCOLOR( wndPtr, hDC ); + + GetClientRect( wndPtr->hwndSelf, &rc); + if (TWEAK_WineLook == WIN31_LOOK) { + HPEN hPrevPen = SelectObject( hDC, + GetSysColorPen(COLOR_WINDOWFRAME)); + HBRUSH hPrevBrush = SelectObject( hDC, + GetStockObject(NULL_BRUSH) ); + + Rectangle( hDC, rc.left, rc.top + 2, rc.right - 1, rc.bottom - 1 ); + SelectObject( hDC, hPrevBrush ); + SelectObject( hDC, hPrevPen ); + } else { + TEXTMETRIC tm; + rcFrame = rc; + + if (infoPtr->hFont) + SelectObject (hDC, infoPtr->hFont); + GetTextMetricsA (hDC, &tm); + rcFrame.top += (tm.tmHeight / 2) - 1; + DrawEdge (hDC, &rcFrame, EDGE_ETCHED, BF_RECT); + } + + if (wndPtr->text) + { + if (infoPtr->hFont) SelectObject( hDC, infoPtr->hFont ); + if (wndPtr->dwStyle & WS_DISABLED) + SetTextColor( hDC, GetSysColor(COLOR_GRAYTEXT) ); + rc.left += 10; + DrawTextA( hDC, wndPtr->text, -1, &rc, DT_SINGLELINE | DT_NOCLIP ); + } +} + + +/********************************************************************** + * User Button Functions + */ + +static void UB_Paint( WND *wndPtr, HDC hDC, WORD action ) +{ + RECT rc; + HBRUSH hBrush; + BUTTONINFO *infoPtr = (BUTTONINFO *)wndPtr->wExtra; + + if (action == ODA_SELECT) return; + + GetClientRect( wndPtr->hwndSelf, &rc); + + if (infoPtr->hFont) SelectObject( hDC, infoPtr->hFont ); + hBrush = GetControlBrush( wndPtr->hwndSelf, hDC, CTLCOLOR_BTN ); + + FillRect( hDC, &rc, hBrush ); + if ((action == ODA_FOCUS) || + ((action == ODA_DRAWENTIRE) && (infoPtr->state & BUTTON_HASFOCUS))) + DrawFocusRect( hDC, &rc ); +} + + +/********************************************************************** + * Ownerdrawn Button Functions + */ + +static void OB_Paint( WND *wndPtr, HDC hDC, WORD action ) +{ + BUTTONINFO *infoPtr = (BUTTONINFO *)wndPtr->wExtra; + DRAWITEMSTRUCT dis; + + dis.CtlType = ODT_BUTTON; + dis.CtlID = wndPtr->wIDmenu; + dis.itemID = 0; + dis.itemAction = action; + dis.itemState = ((infoPtr->state & BUTTON_HASFOCUS) ? ODS_FOCUS : 0) | + ((infoPtr->state & BUTTON_HIGHLIGHTED) ? ODS_SELECTED : 0) | + ((wndPtr->dwStyle & WS_DISABLED) ? ODS_DISABLED : 0); + dis.hwndItem = wndPtr->hwndSelf; + dis.hDC = hDC; + dis.itemData = 0; + GetClientRect( wndPtr->hwndSelf, &dis.rcItem ); + SendMessageA( GetParent(wndPtr->hwndSelf), WM_DRAWITEM, + wndPtr->wIDmenu, (LPARAM)&dis ); +} diff --git a/reactos/lib/user32/controls/combo.c b/reactos/lib/user32/controls/combo.c new file mode 100644 index 00000000000..4b5bb207eac --- /dev/null +++ b/reactos/lib/user32/controls/combo.c @@ -0,0 +1,1570 @@ +/* + * Combo controls + * + * Copyright 1997 Alex Korobka + * + * FIXME: roll up in Netscape 3.01. + */ + +#include + +#include +#include +#include + +#include +#include +#include + + /* bits in the dwKeyData */ +#define KEYDATA_ALT 0x2000 +#define KEYDATA_PREVSTATE 0x4000 + +/* + * Additional combo box definitions + */ + +#define CB_GETPTR( wnd ) (*(LPHEADCOMBO*)((wnd)->wExtra)) +#define CB_NOTIFY( lphc, code ) \ + (SendMessageA( (lphc)->owner, WM_COMMAND, \ + MAKEWPARAM((lphc)->self->wIDmenu, (code)), (LPARAM)(lphc)->self->hwndSelf)) +#define CB_GETEDITTEXTLENGTH( lphc ) \ + (SendMessageA( (lphc)->hWndEdit, WM_GETTEXTLENGTH, 0, 0 )) + +static HBITMAP hComboBmp = 0; +static UINT CBitHeight, CBitWidth; +static UINT CBitOffset = 8; + +/*********************************************************************** + * COMBO_Init + * + * Load combo button bitmap. + */ +WINBOOL COMBO_Init(void) +{ + HDC hDC; + + if( hComboBmp ) return TRUE; + if( (hDC = CreateCompatibleDC(0)) ) + { + WINBOOL bRet = FALSE; + if( (hComboBmp = LoadBitmap(0, MAKEINTRESOURCE(OBM_COMBO))) ) + { + BITMAP bm; + HBITMAP hPrevB; + RECT r; + + GetObjectA( hComboBmp, sizeof(bm), &bm ); + CBitHeight = bm.bmHeight; + CBitWidth = bm.bmWidth; + + DPRINT( "combo bitmap [%i,%i]\n", CBitWidth, CBitHeight ); + + hPrevB = SelectObject( hDC, hComboBmp); + SetRect( &r, 0, 0, CBitWidth, CBitHeight ); + InvertRect( hDC, &r ); + SelectObject( hDC, hPrevB ); + bRet = TRUE; + } + DeleteDC( hDC ); + return bRet; + } + return FALSE; +} + +/*********************************************************************** + * COMBO_NCCreate + */ +static LRESULT COMBO_NCCreate(WND* wnd, LPARAM lParam) +{ + LPHEADCOMBO lphc; + + if ( wnd && COMBO_Init() && + (lphc = HeapAlloc(GetProcessHeap(), 0, sizeof(HEADCOMBO))) ) + { + LPCREATESTRUCTA lpcs = (CREATESTRUCTA*)lParam; + + memset( lphc, 0, sizeof(HEADCOMBO) ); + *(LPHEADCOMBO*)wnd->wExtra = lphc; + + /* some braindead apps do try to use scrollbar/border flags */ + + lphc->dwStyle = (lpcs->style & ~(WS_BORDER | WS_HSCROLL | WS_VSCROLL)); + wnd->dwStyle &= ~(WS_BORDER | WS_HSCROLL | WS_VSCROLL); + + if( !(lpcs->style & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE)) ) + lphc->dwStyle |= CBS_HASSTRINGS; + if( !(wnd->dwExStyle & WS_EX_NOPARENTNOTIFY) ) + lphc->wState |= CBF_NOTIFY; + + DPRINT( "[0x%08x], style = %08x\n", + (UINT)lphc, lphc->dwStyle ); + + return (LRESULT)(UINT)wnd->hwndSelf; + } + return (LRESULT)FALSE; +} + +/*********************************************************************** + * COMBO_NCDestroy + */ +static LRESULT COMBO_NCDestroy( LPHEADCOMBO lphc ) +{ + + if( lphc ) + { + WND* wnd = lphc->self; + + DPRINT("[%04x]: freeing storage\n", CB_HWND(lphc)); + + if( (CB_GETTYPE(lphc) != CBS_SIMPLE) && lphc->hWndLBox ) + DestroyWindow( lphc->hWndLBox ); + + HeapFree( GetProcessHeap(), 0, lphc ); + wnd->wExtra[0] = 0; + } + return 0; +} + +/*********************************************************************** + * CBGetDefaultTextHeight + */ +static void CBGetDefaultTextHeight( LPHEADCOMBO lphc, LPSIZE lpSize ) +{ + if( lphc->editHeight ) /* explicitly set height */ + lpSize->cy = lphc->editHeight; + else + { + HDC hDC = GetDC( lphc->self->hwndSelf ); + HFONT hPrevFont = 0; + + if( lphc->hFont ) hPrevFont = SelectObject( hDC, lphc->hFont ); + + GetTextExtentPointA( hDC, "0", 1, lpSize); + + lpSize->cy += lpSize->cy / 4 + 4 * SYSMETRICS_CYBORDER; + + if( hPrevFont ) SelectObject( hDC, hPrevFont ); + ReleaseDC( lphc->self->hwndSelf, hDC ); + } + lpSize->cx = lphc->RectCombo.right - lphc->RectCombo.left; +} + + +/*********************************************************************** + * CBCalcPlacement + * + * Set up component coordinates given valid lphc->RectCombo. + */ +static void CBCalcPlacement( LPHEADCOMBO lphc, LPRECT lprEdit, + LPRECT lprButton, LPRECT lprLB ) +{ + RECT rect = lphc->RectCombo; + SIZE size; + + /* get combo height and width */ + + if( CB_OWNERDRAWN(lphc) ) + { + UINT u = lphc->RectEdit.bottom - lphc->RectEdit.top; + + if( lphc->wState & CBF_MEASUREITEM ) /* first initialization */ + { + MEASUREITEMSTRUCT mi; + + /* calculate defaults before sending WM_MEASUREITEM */ + + CBGetDefaultTextHeight( lphc, &size ); + + lphc->wState &= ~CBF_MEASUREITEM; + + mi.CtlType = ODT_COMBOBOX; + mi.CtlID = lphc->self->wIDmenu; + mi.itemID = -1; + mi.itemWidth = size.cx; + mi.itemHeight = size.cy - 6; /* ownerdrawn cb is taller */ + mi.itemData = 0; + SendMessageA(lphc->owner, WM_MEASUREITEM, + (WPARAM)mi.CtlID, (LPARAM)&mi); + u = 6 + (UINT)mi.itemHeight; + } + else + size.cx = rect.right - rect.left; + size.cy = u; + } + else + CBGetDefaultTextHeight( lphc, &size ); + + /* calculate text and button placement */ + + lprEdit->left = lprEdit->top = lprButton->top = 0; + if( CB_GETTYPE(lphc) == CBS_SIMPLE ) /* no button */ + lprButton->left = lprButton->right = lprButton->bottom = 0; + else + { + INT i = size.cx - CBitWidth - 10; /* seems ok */ + + lprButton->right = size.cx; + lprButton->left = (INT)i; + lprButton->bottom = lprButton->top + size.cy; + + if( i < 0 ) size.cx = 0; + else size.cx = i; + } + + if( CB_GETTYPE(lphc) == CBS_DROPDOWN ) + { + size.cx -= CBitOffset; + if( size.cx < 0 ) size.cx = 0; + } + + lprEdit->right = size.cx; lprEdit->bottom = size.cy; + + /* listbox placement */ + + lprLB->left = ( CB_GETTYPE(lphc) == CBS_DROPDOWNLIST ) ? 0 : CBitOffset; + lprLB->top = lprEdit->bottom - SYSMETRICS_CYBORDER; + lprLB->right = rect.right - rect.left; + lprLB->bottom = rect.bottom - rect.top; + + if( lphc->droppedWidth > (lprLB->right - lprLB->left) ) + lprLB->right = lprLB->left + lphc->droppedWidth; + + DPRINT("[%04x]: (%i,%i-%i,%i) placement\n", + CB_HWND(lphc), lphc->RectCombo.left, lphc->RectCombo.top, + lphc->RectCombo.right, lphc->RectCombo.bottom); + + DPRINT("\ttext\t= (%i,%i-%i,%i)\n", + lprEdit->left, lprEdit->top, lprEdit->right, lprEdit->bottom); + + DPRINT("\tbutton\t= (%i,%i-%i,%i)\n", + lprButton->left, lprButton->top, lprButton->right, lprButton->bottom); + + DPRINT("\tlbox\t= (%i,%i-%i,%i)\n", + lprLB->left, lprLB->top, lprLB->right, lprLB->bottom ); +} + +/*********************************************************************** + * CBGetDroppedControlRect + */ +static void CBGetDroppedControlRect( LPHEADCOMBO lphc, LPRECT lpRect) +{ + lpRect->left = lphc->RectCombo.left + + (lphc->wState & CBF_EDIT) ? CBitOffset : 0; + lpRect->top = lphc->RectCombo.top + lphc->RectEdit.bottom - + SYSMETRICS_CYBORDER; + lpRect->right = lphc->RectCombo.right; + lpRect->bottom = lphc->RectCombo.bottom - SYSMETRICS_CYBORDER; +} + +/*********************************************************************** + * COMBO_Create + */ +LRESULT COMBO_Create( LPHEADCOMBO lphc, WND* wnd, LPARAM lParam) +{ + static char clbName[] = "ComboLBox"; + static char editName[] = "Edit"; + + LPCREATESTRUCT lpcs = (CREATESTRUCT*)lParam; + + if( !CB_GETTYPE(lphc) ) lphc->dwStyle |= CBS_SIMPLE; + else if( CB_GETTYPE(lphc) != CBS_DROPDOWNLIST ) lphc->wState |= CBF_EDIT; + + lphc->self = wnd; + lphc->owner = lpcs->hwndParent; + + /* M$ IE 3.01 actually creates (and rapidly destroys) an ownerless combobox */ + + if( lphc->owner || !(lpcs->style & WS_VISIBLE) ) + { + UINT lbeStyle; + RECT editRect, btnRect, lbRect; + + GetWindowRect( wnd->hwndSelf, &lphc->RectCombo ); + + lphc->wState |= CBF_MEASUREITEM; + CBCalcPlacement( lphc, &editRect, &btnRect, &lbRect ); + lphc->RectButton = btnRect; + lphc->droppedWidth = lphc->editHeight = 0; + + /* create listbox popup */ + + lbeStyle = (LBS_NOTIFY | WS_BORDER | WS_CLIPSIBLINGS) | + (lpcs->style & (WS_VSCROLL | CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE)); + + if( lphc->dwStyle & CBS_SORT ) + lbeStyle |= LBS_SORT; + if( lphc->dwStyle & CBS_HASSTRINGS ) + lbeStyle |= LBS_HASSTRINGS; + if( lphc->dwStyle & CBS_NOINTEGRALHEIGHT ) + lbeStyle |= LBS_NOINTEGRALHEIGHT; + if( lphc->dwStyle & CBS_DISABLENOSCROLL ) + lbeStyle |= LBS_DISABLENOSCROLL; + + if( CB_GETTYPE(lphc) == CBS_SIMPLE ) /* child listbox */ + lbeStyle |= WS_CHILD | WS_VISIBLE; + else /* popup listbox */ + { + lbeStyle |= WS_POPUP; + OffsetRect( &lbRect, lphc->RectCombo.left, lphc->RectCombo.top ); + } + + /* Dropdown ComboLBox is not a child window and we cannot pass + * ID_CB_LISTBOX directly because it will be treated as a menu handle. + */ + + lphc->hWndLBox = CreateWindowExA( 0, clbName, NULL, lbeStyle, + lbRect.left + SYSMETRICS_CXBORDER, + lbRect.top + SYSMETRICS_CYBORDER, + lbRect.right - lbRect.left - 2 * SYSMETRICS_CXBORDER, + lbRect.bottom - lbRect.top - 2 * SYSMETRICS_CYBORDER, + lphc->self->hwndSelf, + (lphc->dwStyle & CBS_DROPDOWN)? (HMENU)0 : (HMENU)ID_CB_LISTBOX, + lphc->self->hInstance, (LPVOID)lphc ); + if( lphc->hWndLBox ) + { + WINBOOL bEdit = TRUE; + lbeStyle = WS_CHILD | WS_VISIBLE | WS_BORDER | ES_NOHIDESEL | ES_LEFT; + if( lphc->wState & CBF_EDIT ) + { + if( lphc->dwStyle & CBS_OEMCONVERT ) + lbeStyle |= ES_OEMCONVERT; + if( lphc->dwStyle & CBS_AUTOHSCROLL ) + lbeStyle |= ES_AUTOHSCROLL; + if( lphc->dwStyle & CBS_LOWERCASE ) + lbeStyle |= ES_LOWERCASE; + else if( lphc->dwStyle & CBS_UPPERCASE ) + lbeStyle |= ES_UPPERCASE; + lphc->hWndEdit = CreateWindowExA( 0, editName, NULL, lbeStyle, + editRect.left, editRect.top, editRect.right - editRect.left, + editRect.bottom - editRect.top, lphc->self->hwndSelf, + (HMENU)ID_CB_EDIT, lphc->self->hInstance, NULL ); + if( !lphc->hWndEdit ) bEdit = FALSE; + } + + if( bEdit ) + { + lphc->RectEdit = editRect; + if( CB_GETTYPE(lphc) != CBS_SIMPLE ) + { + lphc->wState |= CBF_NORESIZE; + SetWindowPos( wnd->hwndSelf, 0, 0, 0, + lphc->RectCombo.right - lphc->RectCombo.left, + lphc->RectEdit.bottom - lphc->RectEdit.top, + SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE ); + lphc->wState &= ~CBF_NORESIZE; + } + DPRINT("init done\n"); + return (LRESULT)wnd->hwndSelf; + } + DPRINT("edit control failure.\n"); + } else DPRINT("listbox failure.\n"); + } else DPRINT("no owner for visible combo.\n"); + + /* CreateWindow() will send WM_NCDESTROY to cleanup */ + + return -1; +} + +/*********************************************************************** + * CBPaintButton + * + * Paint combo button (normal, pressed, and disabled states). + */ +static void CBPaintButton(LPHEADCOMBO lphc, HDC hdc) +{ + RECT r; + UINT x, y; + WINBOOL bWINBOOL; + HDC hMemDC; + HBRUSH hPrevBrush; + COLORREF oldTextColor, oldBkColor; + + if( lphc->wState & CBF_NOREDRAW ) return; + + hPrevBrush = SelectObject(hdc, GetSysColorBrush(COLOR_BTNFACE)); + r = lphc->RectButton; + + Rectangle(hdc, r.left, r.top, r.right, r.bottom ); + if( (bWINBOOL = lphc->wState & CBF_BUTTONDOWN) ) + { + DrawEdge( hdc, &r, EDGE_SUNKEN, BF_RECT ); + OffsetRect( &r, 1, 1 ); + } else { + r.top++, r.left++; + DrawEdge( hdc, &r, EDGE_RAISED, BF_RECT ); + r.top--, r.left--; + } + + InflateRect( &r, -1, -1 ); + + x = (r.left + r.right - CBitWidth) >> 1; + y = (r.top + r.bottom - CBitHeight) >> 1; + + InflateRect( &r, -3, -3 ); + + hMemDC = CreateCompatibleDC( hdc ); + SelectObject( hMemDC, hComboBmp ); + oldTextColor = SetTextColor( hdc, GetSysColor(COLOR_BTNFACE) ); + oldBkColor = SetBkColor( hdc, CB_DISABLED(lphc) ? RGB(128,128,128) : + RGB(0,0,0) ); + BitBlt( hdc, x, y, 8, 8, hMemDC, 0, 0, SRCCOPY ); + SetBkColor( hdc, oldBkColor ); + SetTextColor( hdc, oldTextColor ); + DeleteDC( hMemDC ); + SelectObject( hdc, hPrevBrush ); +} + +/*********************************************************************** + * CBPaintText + * + * Paint CBS_DROPDOWNLIST text field / update edit control contents. + */ +static void CBPaintText(LPHEADCOMBO lphc, HDC hdc) +{ + INT id, size = 0; + LPSTR pText = NULL; + + if( lphc->wState & CBF_NOREDRAW ) return; + + /* follow Windows combobox that sends a bunch of text + * inquiries to its listbox while processing WM_PAINT. */ + + if( (id = SendMessageA(lphc->hWndLBox, LB_GETCURSEL, 0, 0) ) != LB_ERR ) + { + size = SendMessageA( lphc->hWndLBox, LB_GETTEXTLEN, id, 0); + if( (pText = HeapAlloc( GetProcessHeap(), 0, size + 1)) ) + { + SendMessageA( lphc->hWndLBox, LB_GETTEXT, (WPARAM)id, (LPARAM)pText ); + pText[size] = '\0'; /* just in case */ + } else return; + } + + if( lphc->wState & CBF_EDIT ) + { + if( CB_HASSTRINGS(lphc) ) SetWindowTextA( lphc->hWndEdit, pText ? pText : "" ); + if( lphc->wState & CBF_FOCUSED ) + SendMessageA( lphc->hWndEdit, EM_SETSEL, 0, (LPARAM)(-1)); + } + else /* paint text field ourselves */ + { + HBRUSH hPrevBrush = 0; + HDC hDC = hdc; + + if( !hDC ) + { + if ((hDC = GetDC(lphc->self->hwndSelf))) + { + HBRUSH hBrush = (HBRUSH)SendMessageA( lphc->owner, + WM_CTLCOLORLISTBOX, + (WPARAM)hDC, (LPARAM)lphc->self->hwndSelf ); + hPrevBrush = SelectObject( hDC, + (hBrush) ? hBrush : GetStockObject(WHITE_BRUSH) ); + } + } + if( hDC ) + { + RECT rect; + UINT itemState; + HFONT hPrevFont = (lphc->hFont) ? SelectObject(hDC, lphc->hFont) : 0; + + PatBlt( hDC, (rect.left = lphc->RectEdit.left + SYSMETRICS_CXBORDER), + (rect.top = lphc->RectEdit.top + SYSMETRICS_CYBORDER), + (rect.right = lphc->RectEdit.right - SYSMETRICS_CXBORDER), + (rect.bottom = lphc->RectEdit.bottom - SYSMETRICS_CYBORDER) - 1, PATCOPY ); + InflateRect( &rect, -1, -1 ); + + if( lphc->wState & CBF_FOCUSED && + !(lphc->wState & CBF_DROPPED) ) + { + /* highlight */ + + FillRect( hDC, &rect, GetSysColorBrush(COLOR_HIGHLIGHT) ); + SetBkColor( hDC, GetSysColor( COLOR_HIGHLIGHT ) ); + SetTextColor( hDC, GetSysColor( COLOR_HIGHLIGHTTEXT ) ); + itemState = ODS_SELECTED | ODS_FOCUS; + } else itemState = 0; + + if( CB_OWNERDRAWN(lphc) ) + { + DRAWITEMSTRUCT dis; + + if( lphc->self->dwStyle & WS_DISABLED ) itemState |= ODS_DISABLED; + + dis.CtlType = ODT_COMBOBOX; + dis.CtlID = lphc->self->wIDmenu; + dis.hwndItem = lphc->self->hwndSelf; + dis.itemAction = ODA_DRAWENTIRE; + dis.itemID = id; + dis.itemState = itemState; + dis.hDC = hDC; + dis.rcItem = rect; + dis.itemData = SendMessageA( lphc->hWndLBox, LB_GETITEMDATA, + (WPARAM)id, 0 ); + SendMessageA( lphc->owner, WM_DRAWITEM, + lphc->self->wIDmenu, (LPARAM)&dis ); + } + else + { + ExtTextOutA( hDC, rect.left + 1, rect.top + 1, + ETO_OPAQUE | ETO_CLIPPED, &rect, + pText ? pText : "" , size, NULL ); + if(lphc->wState & CBF_FOCUSED && !(lphc->wState & CBF_DROPPED)) + DrawFocusRect( hDC, &rect ); + } + + if( hPrevFont ) SelectObject(hDC, hPrevFont ); + if( !hdc ) + { + if( hPrevBrush ) SelectObject( hDC, hPrevBrush ); + ReleaseDC( lphc->self->hwndSelf, hDC ); + } + } + } + if (pText) + HeapFree( GetProcessHeap(), 0, pText ); +} + +/*********************************************************************** + * COMBO_Paint + */ +static LRESULT COMBO_Paint(LPHEADCOMBO lphc, HDC hParamDC) +{ + PAINTSTRUCT ps; + HDC hDC; + + hDC = (hParamDC) ? hParamDC + : BeginPaint( lphc->self->hwndSelf, &ps); + if( hDC && !(lphc->wState & CBF_NOREDRAW) ) + { + HBRUSH hPrevBrush, hBkgBrush; + + hBkgBrush = (HBRUSH)SendMessageA( lphc->owner, WM_CTLCOLORLISTBOX, + (WPARAM)hDC, (LPARAM)lphc->self->hwndSelf ); + if( !hBkgBrush ) hBkgBrush = GetStockObject(WHITE_BRUSH); + + hPrevBrush = SelectObject( hDC, hBkgBrush ); + if( !IsRectEmpty(&lphc->RectButton) ) + { + /* paint everything to the right of the text field */ + + PatBlt( hDC, lphc->RectEdit.right, lphc->RectEdit.top, + lphc->RectButton.right - lphc->RectEdit.right, + lphc->RectEdit.bottom - lphc->RectEdit.top, PATCOPY ); + CBPaintButton( lphc, hDC ); + } + + if( !(lphc->wState & CBF_EDIT) ) + { + /* paint text field */ + + HPEN hPrevPen = SelectObject( hDC, GetSysColorPen( + COLOR_WINDOWFRAME) ); + + Rectangle( hDC, lphc->RectEdit.left, lphc->RectEdit.top, + lphc->RectEdit.right, lphc->RectButton.bottom ); + SelectObject( hDC, hPrevPen ); + CBPaintText( lphc, hDC ); + } + if( hPrevBrush ) SelectObject( hDC, hPrevBrush ); + } + if( !hParamDC ) EndPaint(lphc->self->hwndSelf, &ps); + return 0; +} + +/*********************************************************************** + * CBUpdateLBox + * + * Select listbox entry according to the contents of the edit control. + */ +static INT CBUpdateLBox( LPHEADCOMBO lphc ) +{ + INT length, idx, ret; + LPSTR pText = NULL; + + idx = ret = LB_ERR; + length = CB_GETEDITTEXTLENGTH( lphc ); + + if( length > 0 ) + pText = (LPSTR) HeapAlloc( GetProcessHeap(), 0, length + 1); + + DPRINT("\t edit text length %i\n", length ); + + if( pText ) + { + if( length ) GetWindowTextA( lphc->hWndEdit, pText, length + 1); + else pText[0] = '\0'; + idx = SendMessageA( lphc->hWndLBox, LB_FINDSTRING, + (WPARAM)(-1), (LPARAM)pText ); + if( idx == LB_ERR ) idx = 0; /* select first item */ + else ret = idx; + HeapFree( GetProcessHeap(), 0, pText ); + } + + /* select entry */ + + SendMessageA( lphc->hWndLBox, LB_SETCURSEL, (WPARAM)idx, 0 ); + + if( idx >= 0 ) + { + SendMessageA( lphc->hWndLBox, LB_SETTOPINDEX, (WPARAM)idx, 0 ); + /* probably superfluous but Windows sends this too */ + SendMessageA( lphc->hWndLBox, LB_SETCARETINDEX, (WPARAM)idx, 0 ); + } + return ret; +} + +/*********************************************************************** + * CBUpdateEdit + * + * Copy a listbox entry to the edit control. + */ +static void CBUpdateEdit( LPHEADCOMBO lphc , INT index ) +{ + INT length; + LPSTR pText = NULL; + + DPRINT("\t %i\n", index ); + + if( index == -1 ) + { + length = CB_GETEDITTEXTLENGTH( lphc ); + if( length ) + { + if( (pText = (LPSTR) HeapAlloc( GetProcessHeap(), 0, length + 1)) ) + { + GetWindowTextA( lphc->hWndEdit, pText, length + 1 ); + index = SendMessageA( lphc->hWndLBox, LB_FINDSTRING, + (WPARAM)(-1), (LPARAM)pText ); + HeapFree( GetProcessHeap(), 0, pText ); + } + } + } + + if( index >= 0 ) /* got an entry */ + { + length = SendMessageA( lphc->hWndLBox, LB_GETTEXTLEN, (WPARAM)index, 0); + if( length ) + { + if( (pText = (LPSTR) HeapAlloc( GetProcessHeap(), 0, length + 1)) ) + { + SendMessageA( lphc->hWndLBox, LB_GETTEXT, + (WPARAM)index, (LPARAM)pText ); + SendMessageA( lphc->hWndEdit, WM_SETTEXT, 0, (LPARAM)pText ); + SendMessageA( lphc->hWndEdit, EM_SETSEL, 0, (LPARAM)(-1) ); + HeapFree( GetProcessHeap(), 0, pText ); + } + } + } +} + +/*********************************************************************** + * CBDropDown + * + * Show listbox popup. + */ +static void CBDropDown( LPHEADCOMBO lphc ) +{ + INT index; + RECT rect; + LPRECT pRect = NULL; + + DPRINT("[%04x]: drop down\n", CB_HWND(lphc)); + + CB_NOTIFY( lphc, CBN_DROPDOWN ); + + /* set selection */ + + lphc->wState |= CBF_DROPPED; + if( CB_GETTYPE(lphc) == CBS_DROPDOWN ) + { + index = CBUpdateLBox( lphc ); + if( !(lphc->wState & CBF_CAPTURE) ) CBUpdateEdit( lphc, index ); + } + else + { + index = SendMessageA( lphc->hWndLBox, LB_GETCURSEL, 0, 0 ); + if( index == LB_ERR ) index = 0; + SendMessageA( lphc->hWndLBox, LB_SETTOPINDEX, (WPARAM)index, 0 ); + SendMessageA( lphc->hWndLBox, LB_CARETON, 0, 0 ); + pRect = &lphc->RectEdit; + } + + /* now set popup position */ + + GetWindowRect( lphc->self->hwndSelf, &rect ); + + rect.top += lphc->RectEdit.bottom - lphc->RectEdit.top - SYSMETRICS_CYBORDER; + rect.bottom = rect.top + lphc->RectCombo.bottom - + lphc->RectCombo.top - SYSMETRICS_CYBORDER; + rect.right = rect.left + lphc->RectCombo.right - lphc->RectCombo.left; + rect.left += ( CB_GETTYPE(lphc) == CBS_DROPDOWNLIST ) ? 0 : CBitOffset; + + SetWindowPos( lphc->hWndLBox, HWND_TOP, rect.left, rect.top, + rect.right - rect.left, rect.bottom - rect.top, + SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOREDRAW); + + if( !(lphc->wState & CBF_NOREDRAW) ) + if( pRect ) + RedrawWindow( lphc->self->hwndSelf, pRect, 0, RDW_INVALIDATE | + RDW_ERASE | RDW_UPDATENOW | RDW_NOCHILDREN ); + ShowWindow( lphc->hWndLBox, SW_SHOWNA ); +} + +/*********************************************************************** + * CBRollUp + * + * Hide listbox popup. + */ +static void CBRollUp( LPHEADCOMBO lphc, WINBOOL ok, WINBOOL bButton ) +{ + HWND hWnd = lphc->self->hwndSelf; + + CB_NOTIFY( lphc, (ok) ? CBN_SELENDOK : CBN_SELENDCANCEL ); + + if( IsWindow( hWnd ) && CB_GETTYPE(lphc) != CBS_SIMPLE ) + { + + DPRINT("[%04x]: roll up [%i]\n", CB_HWND(lphc), (INT)ok ); + + /* always send WM_LBUTTONUP? */ + SendMessageA( lphc->hWndLBox, WM_LBUTTONUP, 0, (LPARAM)(-1) ); + + if( lphc->wState & CBF_DROPPED ) + { + RECT rect; + + lphc->wState &= ~CBF_DROPPED; + ShowWindow( lphc->hWndLBox, SW_HIDE ); + + if( CB_GETTYPE(lphc) == CBS_DROPDOWN ) + { + INT index = SendMessageA( lphc->hWndLBox, LB_GETCURSEL, 0, 0 ); + CBUpdateEdit( lphc, index ); + rect = lphc->RectButton; + } + else + { + if( bButton ) + UnionRect( &rect, &lphc->RectButton, + &lphc->RectEdit ); + else + rect = lphc->RectEdit; + bButton = TRUE; + } + + if( bButton && !(lphc->wState & CBF_NOREDRAW) ) + RedrawWindow( hWnd, &rect, 0, RDW_INVALIDATE | + RDW_ERASE | RDW_UPDATENOW | RDW_NOCHILDREN ); + CB_NOTIFY( lphc, CBN_CLOSEUP ); + } + } +} + +/*********************************************************************** + * COMBO_FlipListbox + * + * Used by the ComboLBox to show/hide itself in response to VK_F4, etc... + */ +WINBOOL COMBO_FlipListbox( LPHEADCOMBO lphc, WINBOOL bRedrawButton ) +{ + if( lphc->wState & CBF_DROPPED ) + { + CBRollUp( lphc, TRUE, bRedrawButton ); + return FALSE; + } + + CBDropDown( lphc ); + return TRUE; +} + +/*********************************************************************** + * COMBO_GetLBWindow + * + * Edit control helper. + */ +HWND COMBO_GetLBWindow( WND* pWnd ) +{ + LPHEADCOMBO lphc = CB_GETPTR(pWnd); + if( lphc ) return lphc->hWndLBox; + return 0; +} + + +/*********************************************************************** + * CBRepaintButton + */ +static void CBRepaintButton( LPHEADCOMBO lphc ) +{ + HDC hDC = GetDC( lphc->self->hwndSelf ); + + if( hDC ) + { + CBPaintButton( lphc, hDC ); + ReleaseDC( lphc->self->hwndSelf, hDC ); + } +} + +/*********************************************************************** + * COMBO_SetFocus + */ +static void COMBO_SetFocus( LPHEADCOMBO lphc ) +{ + if( !(lphc->wState & CBF_FOCUSED) ) + { + if( CB_GETTYPE(lphc) == CBS_DROPDOWNLIST ) + SendMessageA( lphc->hWndLBox, LB_CARETON, 0, 0 ); + + if( lphc->wState & CBF_EDIT ) + SendMessageA( lphc->hWndEdit, EM_SETSEL, 0, (LPARAM)(-1) ); + lphc->wState |= CBF_FOCUSED; + if( !(lphc->wState & CBF_EDIT) ) CBPaintText( lphc, 0 ); + + CB_NOTIFY( lphc, CBN_SETFOCUS ); + } +} + +/*********************************************************************** + * COMBO_KillFocus + */ +static void COMBO_KillFocus( LPHEADCOMBO lphc ) +{ + HWND hWnd = lphc->self->hwndSelf; + + if( lphc->wState & CBF_FOCUSED ) + { + SendMessageA( hWnd, WM_LBUTTONUP, 0, (LPARAM)(-1) ); + + CBRollUp( lphc, FALSE, TRUE ); + if( IsWindow( hWnd ) ) + { + if( CB_GETTYPE(lphc) == CBS_DROPDOWNLIST ) + SendMessageA( lphc->hWndLBox, LB_CARETOFF, 0, 0 ); + + lphc->wState &= ~CBF_FOCUSED; + + /* redraw text */ + if( lphc->wState & CBF_EDIT ) + SendMessageA( lphc->hWndEdit, EM_SETSEL, (WPARAM)(-1), 0 ); + else CBPaintText( lphc, 0 ); + + CB_NOTIFY( lphc, CBN_KILLFOCUS ); + } + } +} + +/*********************************************************************** + * COMBO_Command + */ +static LRESULT COMBO_Command( LPHEADCOMBO lphc, WPARAM wParam, HWND hWnd ) +{ + if( lphc->wState & CBF_EDIT && lphc->hWndEdit == hWnd ) + { + /* ">> 8" makes gcc generate jump-table instead of cmp ladder */ + + switch( HIWORD(wParam) >> 8 ) + { + case (EN_SETFOCUS >> 8): + + DPRINT("[%04x]: edit [%04x] got focus\n", + CB_HWND(lphc), lphc->hWndEdit ); + + if( !(lphc->wState & CBF_FOCUSED) ) COMBO_SetFocus( lphc ); + break; + + case (EN_KILLFOCUS >> 8): + + DPRINT("[%04x]: edit [%04x] lost focus\n", + CB_HWND(lphc), lphc->hWndEdit ); + + /* NOTE: it seems that Windows' edit control sends an + * undocumented message WM_USER + 0x1B instead of this + * notification (only when it happens to be a part of + * the combo). ?? - AK. + */ + + COMBO_KillFocus( lphc ); + break; + + + case (EN_CHANGE >> 8): + CB_NOTIFY( lphc, CBN_EDITCHANGE ); + CBUpdateLBox( lphc ); + break; + + case (EN_UPDATE >> 8): + CB_NOTIFY( lphc, CBN_EDITUPDATE ); + break; + + case (EN_ERRSPACE >> 8): + CB_NOTIFY( lphc, CBN_ERRSPACE ); + } + } + else if( lphc->hWndLBox == hWnd ) + { + switch( HIWORD(wParam) ) + { + case LBN_ERRSPACE: + CB_NOTIFY( lphc, CBN_ERRSPACE ); + break; + + case LBN_DBLCLK: + CB_NOTIFY( lphc, CBN_DBLCLK ); + break; + + case LBN_SELCHANGE: + case LBN_SELCANCEL: + + DPRINT("[%04x]: lbox selection change [%04x]\n", + CB_HWND(lphc), lphc->wState ); + + /* do not roll up if selection is being tracked + * by arrowkeys in the dropdown listbox */ + + if( (lphc->wState & CBF_DROPPED) && !(lphc->wState & CBF_NOROLLUP) ) + CBRollUp( lphc, (HIWORD(wParam) == LBN_SELCHANGE), TRUE ); + else lphc->wState &= ~CBF_NOROLLUP; + + CB_NOTIFY( lphc, CBN_SELCHANGE ); + CBPaintText( lphc, 0 ); + /* fall through */ + + case LBN_SETFOCUS: + case LBN_KILLFOCUS: + /* nothing to do here since ComboLBox always resets the focus to its + * combo/edit counterpart */ + break; + } + } + return 0; +} + +/*********************************************************************** + * COMBO_ItemOp + * + * Fixup an ownerdrawn item operation and pass it up to the combobox owner. + */ +static LRESULT COMBO_ItemOp( LPHEADCOMBO lphc, UINT msg, + WPARAM wParam, LPARAM lParam ) +{ + HWND hWnd = lphc->self->hwndSelf; + + DPRINT("[%04x]: ownerdraw op %04x\n", CB_HWND(lphc), msg ); + +#define lpIS ((LPDELETEITEMSTRUCT)lParam) + + /* two first items are the same in all 4 structs */ + lpIS->CtlType = ODT_COMBOBOX; + lpIS->CtlID = lphc->self->wIDmenu; + + switch( msg ) /* patch window handle */ + { + case WM_DELETEITEM: + lpIS->hwndItem = hWnd; +#undef lpIS + break; + case WM_DRAWITEM: +#define lpIS ((LPDRAWITEMSTRUCT)lParam) + lpIS->hwndItem = hWnd; +#undef lpIS + break; + case WM_COMPAREITEM: +#define lpIS ((LPCOMPAREITEMSTRUCT)lParam) + lpIS->hwndItem = hWnd; +#undef lpIS + break; + } + + return SendMessageA( lphc->owner, msg, lphc->self->wIDmenu, lParam ); +} + +/*********************************************************************** + * COMBO_GetText + */ +static LRESULT COMBO_GetText( LPHEADCOMBO lphc, UINT N, LPSTR lpText) +{ + if( lphc->wState & CBF_EDIT ) + return SendMessageA( lphc->hWndEdit, WM_GETTEXT, + (WPARAM)N, (LPARAM)lpText ); + + /* get it from the listbox */ + + if( lphc->hWndLBox ) + { + INT idx = SendMessageA( lphc->hWndLBox, LB_GETCURSEL, 0, 0 ); + if( idx != LB_ERR ) + { + LPSTR lpBuffer; + INT length = SendMessageA( lphc->hWndLBox, LB_GETTEXTLEN, + (WPARAM)idx, 0 ); + + /* 'length' is without the terminating character */ + if( length >= N ) + lpBuffer = (LPSTR) HeapAlloc( GetProcessHeap(), 0, length + 1 ); + else + lpBuffer = lpText; + + if( lpBuffer ) + { + INT n = SendMessageA( lphc->hWndLBox, LB_GETTEXT, + (WPARAM)idx, (LPARAM)lpBuffer ); + + /* truncate if buffer is too short */ + + if( length >= N ) + { + if (N && lpText) { + if( n != LB_ERR ) memcpy( lpText, lpBuffer, (N>n) ? n+1 : N-1 ); + lpText[N - 1] = '\0'; + } + HeapFree( GetProcessHeap(), 0, lpBuffer ); + } + return (LRESULT)n; + } + } + } + return 0; +} + + +/*********************************************************************** + * CBResetPos + * + * This function sets window positions according to the updated + * component placement struct. + */ +static void CBResetPos( LPHEADCOMBO lphc, LPRECT lbRect, WINBOOL bRedraw ) +{ + WINBOOL bDrop = (CB_GETTYPE(lphc) != CBS_SIMPLE); + + /* NOTE: logs sometimes have WM_LBUTTONUP before a cascade of + * sizing messages */ + + if( lphc->wState & CBF_EDIT ) + SetWindowPos( lphc->hWndEdit, 0, lphc->RectEdit.left, lphc->RectEdit.top, + lphc->RectEdit.right - lphc->RectEdit.left, + lphc->RectEdit.bottom - lphc->RectEdit.top, + SWP_NOZORDER | SWP_NOACTIVATE | ((bDrop) ? SWP_NOREDRAW : 0) ); + + if( bDrop ) + OffsetRect( lbRect, lphc->RectCombo.left, lphc->RectCombo.top ); + + lbRect->right -= lbRect->left; /* convert to width */ + lbRect->bottom -= lbRect->top; + SetWindowPos( lphc->hWndLBox, 0, lbRect->left, lbRect->top, + lbRect->right, lbRect->bottom, + SWP_NOACTIVATE | SWP_NOZORDER | ((bDrop) ? SWP_NOREDRAW : 0) ); + + if( bDrop ) + { + if( lphc->wState & CBF_DROPPED ) + { + lphc->wState &= ~CBF_DROPPED; + ShowWindow( lphc->hWndLBox, SW_HIDE ); + } + + lphc->wState |= CBF_NORESIZE; + SetWindowPos( lphc->self->hwndSelf, 0, 0, 0, + lphc->RectCombo.right - lphc->RectCombo.left, + lphc->RectEdit.bottom - lphc->RectEdit.top, + SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW ); + lphc->wState &= ~CBF_NORESIZE; + + if( bRedraw && !(lphc->wState & CBF_NOREDRAW) ) + RedrawWindow( lphc->self->hwndSelf, NULL, 0, + RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW ); + } +} + + +/*********************************************************************** + * COMBO_Size + */ +static void COMBO_Size( LPHEADCOMBO lphc ) +{ + RECT rect; + INT w, h; + + GetWindowRect( lphc->self->hwndSelf, &rect ); + w = rect.right - rect.left; h = rect.bottom - rect.top; + + DPRINT("w = %i, h = %i\n", w, h ); + + /* CreateWindow() may send a bogus WM_SIZE, ignore it */ + + if( w == (lphc->RectCombo.right - lphc->RectCombo.left) ) + { + if( (CB_GETTYPE(lphc) == CBS_SIMPLE) && + (h == (lphc->RectCombo.bottom - lphc->RectCombo.top)) ) + return; + else if( (lphc->dwStyle & CBS_DROPDOWN) && + (h == (lphc->RectEdit.bottom - lphc->RectEdit.top)) ) + return; + } + lphc->RectCombo = rect; + CBCalcPlacement( lphc, &lphc->RectEdit, &lphc->RectButton, &rect ); + CBResetPos( lphc, &rect, TRUE ); +} + + +/*********************************************************************** + * COMBO_Font + */ +static void COMBO_Font( LPHEADCOMBO lphc, HFONT hFont, WINBOOL bRedraw ) +{ + RECT rect; + + lphc->hFont = hFont; + + if( lphc->wState & CBF_EDIT ) + SendMessageA( lphc->hWndEdit, WM_SETFONT, (WPARAM)hFont, bRedraw ); + SendMessageA( lphc->hWndLBox, WM_SETFONT, (WPARAM)hFont, bRedraw ); + + GetWindowRect( lphc->self->hwndSelf, &rect ); + OffsetRect( &lphc->RectCombo, rect.left - lphc->RectCombo.left, + rect.top - lphc->RectCombo.top ); + CBCalcPlacement( lphc, &lphc->RectEdit, + &lphc->RectButton, &rect ); + CBResetPos( lphc, &rect, bRedraw ); +} + + +/*********************************************************************** + * COMBO_SetItemHeight + */ +static LRESULT COMBO_SetItemHeight( LPHEADCOMBO lphc, INT index, INT height ) +{ + LRESULT lRet = CB_ERR; + + if( index == -1 ) /* set text field height */ + { + if( height < 768 ) + { + RECT rect; + + lphc->editHeight = height; + GetWindowRect( lphc->self->hwndSelf, &rect ); + OffsetRect( &lphc->RectCombo, rect.left - lphc->RectCombo.left, + rect.top - lphc->RectCombo.top ); + CBCalcPlacement( lphc, &lphc->RectEdit, + &lphc->RectButton, &rect ); + CBResetPos( lphc, &rect, TRUE ); + lRet = height; + } + } + else if ( CB_OWNERDRAWN(lphc) ) /* set listbox item height */ + lRet = SendMessageA( lphc->hWndLBox, LB_SETITEMHEIGHT, + (WPARAM)index, (LPARAM)height ); + return lRet; +} + +/*********************************************************************** + * COMBO_SelectString + */ +static LRESULT COMBO_SelectString( LPHEADCOMBO lphc, INT start, LPCSTR pText ) +{ + INT index = SendMessageA( lphc->hWndLBox, LB_SELECTSTRING, + (WPARAM)start, (LPARAM)pText ); + if( index >= 0 ) + { + if( lphc->wState & CBF_EDIT ) + CBUpdateEdit( lphc, index ); + else + CBPaintText( lphc, 0 ); + } + return (LRESULT)index; +} + +/*********************************************************************** + * COMBO_LButtonDown + */ +static void COMBO_LButtonDown( LPHEADCOMBO lphc, LPARAM lParam ) +{ + POINT pt = { LOWORD(lParam), HIWORD(lParam) }; + WINBOOL bButton = PtInRect(&lphc->RectButton, pt); + HWND hWnd = lphc->self->hwndSelf; + + if( (CB_GETTYPE(lphc) == CBS_DROPDOWNLIST) || + (bButton && (CB_GETTYPE(lphc) == CBS_DROPDOWN)) ) + { + lphc->wState |= CBF_BUTTONDOWN; + if( lphc->wState & CBF_DROPPED ) + { + /* got a click to cancel selection */ + + CBRollUp( lphc, TRUE, FALSE ); + if( !IsWindow( hWnd ) ) return; + + if( lphc->wState & CBF_CAPTURE ) + { + lphc->wState &= ~CBF_CAPTURE; + ReleaseCapture(); + } + lphc->wState &= ~CBF_BUTTONDOWN; + } + else + { + /* drop down the listbox and start tracking */ + + lphc->wState |= CBF_CAPTURE; + CBDropDown( lphc ); + SetCapture( hWnd ); + } + if( bButton ) CBRepaintButton( lphc ); + } +} + +/*********************************************************************** + * COMBO_LButtonUp + * + * Release capture and stop tracking if needed. + */ +static void COMBO_LButtonUp( LPHEADCOMBO lphc, LPARAM lParam ) +{ + if( lphc->wState & CBF_CAPTURE ) + { + lphc->wState &= ~CBF_CAPTURE; + if( CB_GETTYPE(lphc) == CBS_DROPDOWN ) + { + INT index = CBUpdateLBox( lphc ); + CBUpdateEdit( lphc, index ); + } + ReleaseCapture(); + } + + if( lphc->wState & CBF_BUTTONDOWN ) + { + lphc->wState &= ~CBF_BUTTONDOWN; + CBRepaintButton( lphc ); + } +} + +/*********************************************************************** + * COMBO_MouseMove + * + * Two things to do - track combo button and release capture when + * pointer goes into the listbox. + */ +static void COMBO_MouseMove( LPHEADCOMBO lphc, WPARAM wParam, LPARAM lParam ) +{ + POINT pt = { LOWORD(lParam), HIWORD(lParam) }; + RECT lbRect; + + if( lphc->wState & CBF_BUTTONDOWN ) + { + WINBOOL bButton = PtInRect(&lphc->RectButton, pt); + + if( !bButton ) + { + lphc->wState &= ~CBF_BUTTONDOWN; + CBRepaintButton( lphc ); + } + } + + GetClientRect( lphc->hWndLBox, &lbRect ); + MapWindowPoints( lphc->self->hwndSelf, lphc->hWndLBox, &pt, 1 ); + if( PtInRect(&lbRect, pt) ) + { + lphc->wState &= ~CBF_CAPTURE; + ReleaseCapture(); + if( CB_GETTYPE(lphc) == CBS_DROPDOWN ) CBUpdateLBox( lphc ); + + /* hand over pointer tracking */ + SendMessageA( lphc->hWndLBox, WM_LBUTTONDOWN, wParam, lParam ); + } +} + + +/*********************************************************************** + * ComboWndProc + * + * http://www.microsoft.com/msdn/sdk/platforms/doc/sdk/win/ctrl/src/combobox_15.htm + */ +LRESULT WINAPI ComboWndProc( HWND hwnd, UINT message, + WPARAM wParam, LPARAM lParam ) +{ + WND* pWnd = WIN_FindWndPtr(hwnd); + + if( pWnd ) + { + LPHEADCOMBO lphc = CB_GETPTR(pWnd); + + DPRINT( "[%04x]: msg %s wp %08x lp %08lx\n", + pWnd->hwndSelf, SPY_GetMsgName(message), wParam, lParam ); + + if( lphc || message == WM_NCCREATE ) + switch(message) + { + + /* System messages */ + + case WM_NCCREATE: + return COMBO_NCCreate(pWnd, lParam); + + case WM_NCDESTROY: + COMBO_NCDestroy(lphc); + break; + + case WM_CREATE: + return COMBO_Create(lphc, pWnd, lParam); + + case WM_PAINT: + /* wParam may contain a valid HDC! */ + return COMBO_Paint(lphc, wParam); + + case WM_ERASEBKGND: + return TRUE; + + case WM_GETDLGCODE: + return (LRESULT)(DLGC_WANTARROWS | DLGC_WANTCHARS); + + case WM_SIZE: + if( lphc->hWndLBox && + !(lphc->wState & CBF_NORESIZE) ) COMBO_Size( lphc ); + return TRUE; + + case WM_SETFONT: + COMBO_Font( lphc, (HFONT)wParam, (WINBOOL)lParam ); + return TRUE; + + case WM_GETFONT: + return (LRESULT)lphc->hFont; + + case WM_SETFOCUS: + if( lphc->wState & CBF_EDIT ) + SetFocus( lphc->hWndEdit ); + else + COMBO_SetFocus( lphc ); + return TRUE; + + case WM_KILLFOCUS: +#define hwndFocus ((HWND)wParam) + if( !hwndFocus || + (hwndFocus != lphc->hWndEdit && hwndFocus != lphc->hWndLBox )) + COMBO_KillFocus( lphc ); +#undef hwndFocus + return TRUE; + + case WM_COMMAND: + return COMBO_Command( lphc, wParam, (HWND)lParam ); + + case WM_GETTEXT: + return COMBO_GetText( lphc, (UINT)wParam, (LPSTR)lParam ); + + case WM_SETTEXT: + case WM_GETTEXTLENGTH: + case WM_CLEAR: + case WM_CUT: + case WM_PASTE: + case WM_COPY: + if( lphc->wState & CBF_EDIT ) + return SendMessageA( lphc->hWndEdit, message, wParam, lParam ); + return CB_ERR; + + case WM_DRAWITEM: + case WM_DELETEITEM: + case WM_COMPAREITEM: + case WM_MEASUREITEM: + return COMBO_ItemOp( lphc, message, wParam, lParam ); + + case WM_ENABLE: + if( lphc->wState & CBF_EDIT ) + EnableWindow( lphc->hWndEdit, (WINBOOL)wParam ); + EnableWindow( lphc->hWndLBox, (WINBOOL)wParam ); + return TRUE; + + case WM_SETREDRAW: + if( wParam ) + lphc->wState &= ~CBF_NOREDRAW; + else + lphc->wState |= CBF_NOREDRAW; + + if( lphc->wState & CBF_EDIT ) + SendMessageA( lphc->hWndEdit, message, wParam, lParam ); + SendMessageA( lphc->hWndLBox, message, wParam, lParam ); + return 0; + + case WM_SYSKEYDOWN: + if( KEYDATA_ALT & HIWORD(lParam) ) + if( wParam == VK_UP || wParam == VK_DOWN ) + COMBO_FlipListbox( lphc, TRUE ); + break; + + case WM_CHAR: + case WM_KEYDOWN: + if( lphc->wState & CBF_EDIT ) + return SendMessageA( lphc->hWndEdit, message, wParam, lParam ); + else + return SendMessageA( lphc->hWndLBox, message, wParam, lParam ); + + case WM_LBUTTONDOWN: + if( !(lphc->wState & CBF_FOCUSED) ) SetFocus( lphc->self->hwndSelf ); + if( lphc->wState & CBF_FOCUSED ) COMBO_LButtonDown( lphc, lParam ); + return TRUE; + + case WM_LBUTTONUP: + COMBO_LButtonUp( lphc, lParam ); + return TRUE; + + case WM_MOUSEMOVE: + if( lphc->wState & CBF_CAPTURE ) + COMBO_MouseMove( lphc, wParam, lParam ); + return TRUE; + + /* Combo messages */ + + case CB_ADDSTRING: + return SendMessageA( lphc->hWndLBox, LB_ADDSTRING, 0, lParam); + + case CB_INSERTSTRING: + return SendMessageA( lphc->hWndLBox, LB_INSERTSTRING, wParam, lParam); + + case CB_DELETESTRING: + return SendMessageA( lphc->hWndLBox, LB_DELETESTRING, wParam, 0); + + case CB_SELECTSTRING: + return COMBO_SelectString( lphc, (INT)wParam, (LPSTR)lParam ); + + case CB_FINDSTRING: + return SendMessageA( lphc->hWndLBox, LB_FINDSTRING, wParam, lParam); + + case CB_FINDSTRINGEXACT: + return SendMessageA( lphc->hWndLBox, LB_FINDSTRINGEXACT, + wParam, lParam ); + + case CB_SETITEMHEIGHT: + return COMBO_SetItemHeight( lphc, (INT)wParam, (INT)lParam); + + case CB_GETITEMHEIGHT: + if( (INT)wParam >= 0 ) /* listbox item */ + return SendMessageA( lphc->hWndLBox, LB_GETITEMHEIGHT, wParam, 0); + return (lphc->RectEdit.bottom - lphc->RectEdit.top); + + case CB_RESETCONTENT: + SendMessageA( lphc->hWndLBox, LB_RESETCONTENT, 0, 0 ); + CBPaintText( lphc, 0 ); + return TRUE; + + case CB_INITSTORAGE: + return SendMessageA( lphc->hWndLBox, LB_INITSTORAGE, wParam, lParam); + + case CB_GETHORIZONTALEXTENT: + return SendMessageA( lphc->hWndLBox, LB_GETHORIZONTALEXTENT, 0, 0); + + case CB_SETHORIZONTALEXTENT: + return SendMessageA( lphc->hWndLBox, LB_SETHORIZONTALEXTENT, wParam, 0); + + case CB_GETTOPINDEX: + return SendMessageA( lphc->hWndLBox, LB_GETTOPINDEX, 0, 0); + + case CB_GETLOCALE: + return SendMessageA( lphc->hWndLBox, LB_GETLOCALE, 0, 0); + + case CB_SETLOCALE: + return SendMessageA( lphc->hWndLBox, LB_SETLOCALE, wParam, 0); + + case CB_GETDROPPEDWIDTH: + if( lphc->droppedWidth ) + return lphc->droppedWidth; + return lphc->RectCombo.right - lphc->RectCombo.left - + (lphc->wState & CBF_EDIT) ? CBitOffset : 0; + + case CB_SETDROPPEDWIDTH: + if( (CB_GETTYPE(lphc) != CBS_SIMPLE) && + (INT)wParam < 768 ) lphc->droppedWidth = (INT)wParam; + return CB_ERR; + + case CB_GETDROPPEDCONTROLRECT: + if( lParam ) CBGetDroppedControlRect(lphc, (LPRECT)lParam ); + return CB_OKAY; + + case CB_GETDROPPEDSTATE: + return (lphc->wState & CBF_DROPPED) ? TRUE : FALSE; + + + case CB_DIR: + return COMBO_Directory( lphc, (UINT)wParam, + (LPSTR)lParam, (message == CB_DIR)); + case CB_SHOWDROPDOWN: + if( CB_GETTYPE(lphc) != CBS_SIMPLE ) + { + if( wParam ) + { + if( !(lphc->wState & CBF_DROPPED) ) + CBDropDown( lphc ); + } + else + if( lphc->wState & CBF_DROPPED ) + CBRollUp( lphc, FALSE, TRUE ); + } + return TRUE; + + case CB_GETCOUNT: + return SendMessageA( lphc->hWndLBox, LB_GETCOUNT, 0, 0); + + case CB_GETCURSEL: + return SendMessageA( lphc->hWndLBox, LB_GETCURSEL, 0, 0); + + case CB_SETCURSEL: + lParam = SendMessageA( lphc->hWndLBox, LB_SETCURSEL, wParam, 0); + if( lphc->wState & CBF_SELCHANGE ) + { + /* no LBN_SELCHANGE in this case, update manually */ + + CBPaintText( lphc, 0 ); + lphc->wState &= ~CBF_SELCHANGE; + } + return lParam; + + + case CB_GETLBTEXT: + return SendMessageA( lphc->hWndLBox, LB_GETTEXT, wParam, lParam); + + case CB_GETLBTEXTLEN: + return SendMessageA( lphc->hWndLBox, LB_GETTEXTLEN, wParam, 0); + + case CB_GETITEMDATA: + return SendMessageA( lphc->hWndLBox, LB_GETITEMDATA, wParam, 0); + + case CB_SETITEMDATA: + return SendMessageA( lphc->hWndLBox, LB_SETITEMDATA, wParam, lParam); + + case CB_GETEDITSEL: + if( lphc->wState & CBF_EDIT ) + { + INT a, b; + + return SendMessageA( lphc->hWndEdit, EM_GETSEL, + (wParam) ? wParam : (WPARAM)&a, + (lParam) ? lParam : (LPARAM)&b ); + } + return CB_ERR; + + + case CB_SETEDITSEL: + if( lphc->wState & CBF_EDIT ) + return SendMessageA( lphc->hWndEdit, EM_SETSEL, + (INT)(INT)LOWORD(lParam), (INT)(INT)HIWORD(lParam) ); + return CB_ERR; + + + case CB_SETEXTENDEDUI: + if( CB_GETTYPE(lphc) == CBS_SIMPLE ) return CB_ERR; + + if( wParam ) + lphc->wState |= CBF_EUI; + else lphc->wState &= ~CBF_EUI; + return CB_OKAY; + + + case CB_GETEXTENDEDUI: + return (lphc->wState & CBF_EUI) ? TRUE : FALSE; + + case (WM_USER + 0x1B): + DPRINT( "[%04x]: undocumented msg!\n", hwnd ); + } + return DefWindowProcA(hwnd, message, wParam, lParam); + } + return CB_ERR; +} + diff --git a/reactos/lib/user32/controls/edit.c b/reactos/lib/user32/controls/edit.c new file mode 100644 index 00000000000..459bbd21fa1 --- /dev/null +++ b/reactos/lib/user32/controls/edit.c @@ -0,0 +1,3745 @@ +/* + * Edit control + * + * Copyright David W. Metcalfe, 1994 + * Copyright William Magro, 1995, 1996 + * Copyright Frans van Dorsselaer, 1996, 1997 + * + */ + +/* + * please read EDIT.TODO (and update it when you change things) + */ + +#include +#include +#include +#include +#include +#include +#include + +#define MAX(x,y) x > y ? x : y +#define MIN(x,y) x < y ? x : y + +#define BUFLIMIT_MULTI 65534 /* maximum buffer size (not including '\0') + FIXME: BTW, new specs say 65535 (do you dare ???) */ +#define BUFLIMIT_SINGLE 766 /* maximum buffer size (not including '\0') */ +#define BUFSTART_MULTI 1024 /* starting size */ +#define BUFSTART_SINGLE 256 /* starting size */ +#define GROWLENGTH 64 /* buffers grow by this much */ +#define HSCROLL_FRACTION 3 /* scroll window by 1/3 width */ + +/* + * extra flags for EDITSTATE.flags field + */ +#define EF_MODIFIED 0x0001 /* text has been modified */ +#define EF_FOCUSED 0x0002 /* we have input focus */ +#define EF_UPDATE 0x0004 /* notify parent of changed state on next WM_PAINT */ +#define EF_VSCROLL_TRACK 0x0008 /* don't SetScrollPos() since we are tracking the thumb */ +#define EF_HSCROLL_TRACK 0x0010 /* don't SetScrollPos() since we are tracking the thumb */ +#define EF_VSCROLL_HACK 0x0020 /* we already have informed the user of the hacked handler */ +#define EF_HSCROLL_HACK 0x0040 /* we already have informed the user of the hacked handler */ +#define EF_AFTER_WRAP 0x0080 /* the caret is displayed after the last character of a + wrapped line, instead of in front of the next character */ +#define EF_USE_SOFTBRK 0x0100 /* Enable soft breaks in text. */ + +typedef enum +{ + END_0 = 0, /* line ends with terminating '\0' character */ + END_WRAP, /* line is wrapped */ + END_HARD, /* line ends with a hard return '\r\n' */ + END_SOFT /* line ends with a soft return '\r\r\n' */ +} LINE_END; + +typedef struct tagLINEDEF { + INT length; /* bruto length of a line in bytes */ + INT net_length; /* netto length of a line in visible characters */ + LINE_END ending; + INT width; /* width of the line in pixels */ + struct tagLINEDEF *next; +} LINEDEF; + +typedef INT (CALLBACK *EDITWORDBREAKPROCA)(LPSTR,INT,INT,INT); +typedef INT (CALLBACK *EDITWORDBREAKPROCW)(LPWSTR,INT,INT,INT); + +typedef struct +{ + HANDLE heap; /* our own heap */ + LPSTR text; /* the actual contents of the control */ + INT buffer_size; /* the size of the buffer */ + INT buffer_limit; /* the maximum size to which the buffer may grow */ + HFONT font; /* NULL means standard system font */ + INT x_offset; /* scroll offset for multi lines this is in pixels + for single lines it's in characters */ + INT line_height; /* height of a screen line in pixels */ + INT char_width; /* average character width in pixels */ + DWORD style; /* sane version of wnd->dwStyle */ + WORD flags; /* flags that are not in es->style or wnd->flags (EF_XXX) */ + INT undo_insert_count; /* number of characters inserted in sequence */ + INT undo_position; /* character index of the insertion and deletion */ + LPSTR undo_text; /* deleted text */ + INT undo_buffer_size; /* size of the deleted text buffer */ + INT selection_start; /* == selection_end if no selection */ + INT selection_end; /* == current caret position */ + CHAR password_char; /* == 0 if no password char, and for multi line controls */ + INT left_margin; /* in pixels */ + INT right_margin; /* in pixels */ + RECT format_rect; + INT region_posx; /* Position of cursor relative to region: */ + INT region_posy; /* -1: to left, 0: within, 1: to right */ + EDITWORDBREAKPROCA word_break_procA; + EDITWORDBREAKPROCW word_break_procW; + INT line_count; /* number of lines */ + INT y_offset; /* scroll offset in number of lines */ + /* + * only for multi line controls + */ + INT lock_count; /* amount of re-entries in the EditWndProc */ + INT tabs_count; + LPINT tabs; + INT text_width; /* width of the widest line in pixels */ + LINEDEF *first_line_def; /* linked list of (soft) linebreaks */ + HLOCAL hloc; /* for controls receiving EM_GETHANDLE */ +} EDITSTATE; + +#define SLOWORD(l) ((INT)(LONG)(l)) +#define SHIWORD(l) ((INT)((LONG)(l) >> 16)) + + +#define SWAP_INT(x,y) do { INT temp = (INT)(x); (x) = (INT)(y); (y) = temp; } while(0) +#define ORDER_INT(x,y) do { if ((INT)(y) < (INT)(x)) SWAP_INT((x),(y)); } while(0) + +#define SWAP_UINT(x,y) do { UINT temp = (UINT)(x); (x) = (UINT)(y); (y) = temp; } while(0) +#define ORDER_UINT(x,y) do { if ((UINT)(y) < (UINT)(x)) SWAP_UINT((x),(y)); } while(0) + +#define DPRINTF_EDIT_NOTIFY(hwnd, str) \ + ({DPRINT( "notification " str " sent to hwnd=%08x\n", \ + (UINT)(hwnd));}) + +#define EDIT_SEND_CTLCOLOR(wnd,hdc) \ + (SendMessageA((wnd)->parent->hwndSelf, WM_CTLCOLOREDIT, \ + (WPARAM)(hdc), (LPARAM)(wnd)->hwndSelf)) +#define EDIT_NOTIFY_PARENT(wnd, wNotifyCode, str) \ + (DPRINTF_EDIT_NOTIFY((wnd)->parent->hwndSelf, str), \ + SendMessageA((wnd)->parent->hwndSelf, WM_COMMAND, \ + MAKEWPARAM((wnd)->wIDmenu, wNotifyCode), \ + (LPARAM)(wnd)->hwndSelf)) + +#define DPRINTF_EDIT_MSG(str) \ + DPRINT( \ + " bit : " str ": hwnd=%08x, wParam=%08x, lParam=%08x\n", \ + (UINT)hwnd, (UINT)wParam, (UINT)lParam) + +/********************************************************************* + * + * Declarations + * + */ + +/* + * These functions have trivial implementations + * We still like to call them internally + * "static __inline__" makes them more like macro's + */ +static __inline__ BOOL EDIT_EM_CanUndo(WND *wnd, EDITSTATE *es); +static __inline__ void EDIT_EM_EmptyUndoBuffer(WND *wnd, EDITSTATE *es); +static __inline__ void EDIT_WM_Clear(WND *wnd, EDITSTATE *es); +static __inline__ void EDIT_WM_Cut(WND *wnd, EDITSTATE *es); +/* + * This is the only exported function + */ +LRESULT WINAPI EditWndProc( HWND hwnd, UINT msg, + WPARAM wParam, LPARAM lParam ); +/* + * Helper functions only valid for one type of control + */ +static void EDIT_BuildLineDefs_ML(WND *wnd, EDITSTATE *es); +static LPSTR EDIT_GetPasswordPointer_SL(WND *wnd, EDITSTATE *es); +static void EDIT_MoveDown_ML(WND *wnd, EDITSTATE *es, BOOL extend); +static void EDIT_MovePageDown_ML(WND *wnd, EDITSTATE *es, BOOL extend); +static void EDIT_MovePageUp_ML(WND *wnd, EDITSTATE *es, BOOL extend); +static void EDIT_MoveUp_ML(WND *wnd, EDITSTATE *es, BOOL extend); +/* + * Helper functions valid for both single line _and_ multi line controls + */ +static INT EDIT_CallWordBreakProc(WND *wnd, EDITSTATE *es, INT start, INT index, INT count, INT action); +static INT EDIT_CharFromPos(WND *wnd, EDITSTATE *es, INT x, INT y, LPBOOL after_wrap); +static void EDIT_ConfinePoint(WND *wnd, EDITSTATE *es, LPINT x, LPINT y); +static void EDIT_GetLineRect(WND *wnd, EDITSTATE *es, INT line, INT scol, INT ecol, LPRECT rc); +static void EDIT_InvalidateText(WND *wnd, EDITSTATE *es, INT start, INT end); +static void EDIT_LockBuffer(WND *wnd, EDITSTATE *es); +static BOOL EDIT_MakeFit(WND *wnd, EDITSTATE *es, INT size); +static BOOL EDIT_MakeUndoFit(WND *wnd, EDITSTATE *es, INT size); +static void EDIT_MoveBackward(WND *wnd, EDITSTATE *es, BOOL extend); +static void EDIT_MoveEnd(WND *wnd, EDITSTATE *es, BOOL extend); +static void EDIT_MoveForward(WND *wnd, EDITSTATE *es, BOOL extend); +static void EDIT_MoveHome(WND *wnd, EDITSTATE *es, BOOL extend); +static void EDIT_MoveWordBackward(WND *wnd, EDITSTATE *es, BOOL extend); +static void EDIT_MoveWordForward(WND *wnd, EDITSTATE *es, BOOL extend); +static void EDIT_PaintLine(WND *wnd, EDITSTATE *es, HDC hdc, INT line, BOOL rev); +static INT EDIT_PaintText(WND *wnd, EDITSTATE *es, HDC hdc, INT x, INT y, INT line, INT col, INT count, BOOL rev); +static void EDIT_SetCaretPos(WND *wnd, EDITSTATE *es, INT pos, BOOL after_wrap); +static void EDIT_SetRectNP(WND *wnd, EDITSTATE *es, LPRECT lprc); +static void EDIT_UnlockBuffer(WND *wnd, EDITSTATE *es, BOOL force); +static INT EDIT_WordBreakProc(LPSTR s, INT index, INT count, INT action); +/* + * EM_XXX message handlers + */ +static LRESULT EDIT_EM_CharFromPos(WND *wnd, EDITSTATE *es, INT x, INT y); +static BOOL EDIT_EM_FmtLines(WND *wnd, EDITSTATE *es, BOOL add_eol); +static HLOCAL EDIT_EM_GetHandle(WND *wnd, EDITSTATE *es); +static INT EDIT_EM_GetLine(WND *wnd, EDITSTATE *es, INT line, LPSTR lpch); +static LRESULT EDIT_EM_GetSel(WND *wnd, EDITSTATE *es, UINT *start, UINT *end); +static LRESULT EDIT_EM_GetThumb(WND *wnd, EDITSTATE *es); +static INT EDIT_EM_LineFromChar(WND *wnd, EDITSTATE *es, INT index); +static INT EDIT_EM_LineIndex(WND *wnd, EDITSTATE *es, INT line); +static INT EDIT_EM_LineLength(WND *wnd, EDITSTATE *es, INT index); +static BOOL EDIT_EM_LineScroll(WND *wnd, EDITSTATE *es, INT dx, INT dy); +static LRESULT EDIT_EM_PosFromChar(WND *wnd, EDITSTATE *es, INT index, BOOL after_wrap); +static void EDIT_EM_ReplaceSel(WND *wnd, EDITSTATE *es, BOOL can_undo, LPCSTR lpsz_replace); +static LRESULT EDIT_EM_Scroll(WND *wnd, EDITSTATE *es, INT action); +static void EDIT_EM_ScrollCaret(WND *wnd, EDITSTATE *es); +static void EDIT_EM_SetHandle(WND *wnd, EDITSTATE *es, HLOCAL hloc); +static void EDIT_EM_SetLimitText(WND *wnd, EDITSTATE *es, INT limit); +static void EDIT_EM_SetMargins(WND *wnd, EDITSTATE *es, INT action, INT left, INT right); +static void EDIT_EM_SetPasswordChar(WND *wnd, EDITSTATE *es, CHAR c); +static void EDIT_EM_SetSel(WND *wnd, EDITSTATE *es, UINT start, UINT end, BOOL after_wrap); +static BOOL EDIT_EM_SetTabStops(WND *wnd, EDITSTATE *es, INT count, LPINT tabs); +static void EDIT_EM_SetWordBreakProc(WND *wnd, EDITSTATE *es, EDITWORDBREAKPROCA wbp); +static BOOL EDIT_EM_Undo(WND *wnd, EDITSTATE *es); +/* + * WM_XXX message handlers + */ +static void EDIT_WM_Char(WND *wnd, EDITSTATE *es, CHAR c, DWORD key_data); +static void EDIT_WM_Command(WND *wnd, EDITSTATE *es, INT code, INT id, HWND conrtol); +static void EDIT_WM_ContextMenu(WND *wnd, EDITSTATE *es, HWND hwnd, INT x, INT y); +static void EDIT_WM_Copy(WND *wnd, EDITSTATE *es); +static LRESULT EDIT_WM_Create(WND *wnd, EDITSTATE *es, LPCREATESTRUCTA cs); +static void EDIT_WM_Destroy(WND *wnd, EDITSTATE *es); +static LRESULT EDIT_WM_EraseBkGnd(WND *wnd, EDITSTATE *es, HDC dc); +static INT EDIT_WM_GetText(WND *wnd, EDITSTATE *es, INT count, LPSTR text); +static LRESULT EDIT_WM_HScroll(WND *wnd, EDITSTATE *es, INT action, INT pos, HWND scroll_bar); +static LRESULT EDIT_WM_KeyDown(WND *wnd, EDITSTATE *es, INT key, DWORD key_data); +static LRESULT EDIT_WM_KillFocus(WND *wnd, EDITSTATE *es, HWND window_getting_focus); +static LRESULT EDIT_WM_LButtonDblClk(WND *wnd, EDITSTATE *es, DWORD keys, INT x, INT y); +static LRESULT EDIT_WM_LButtonDown(WND *wnd, EDITSTATE *es, DWORD keys, INT x, INT y); +static LRESULT EDIT_WM_LButtonUp(WND *wnd, EDITSTATE *es, DWORD keys, INT x, INT y); +static LRESULT EDIT_WM_MouseMove(WND *wnd, EDITSTATE *es, DWORD keys, INT x, INT y); +static LRESULT EDIT_WM_NCCreate(WND *wnd, LPCREATESTRUCTA cs); +static void EDIT_WM_Paint(WND *wnd, EDITSTATE *es); +static void EDIT_WM_Paste(WND *wnd, EDITSTATE *es); +static void EDIT_WM_SetFocus(WND *wnd, EDITSTATE *es, HWND window_losing_focus); +static void EDIT_WM_SetFont(WND *wnd, EDITSTATE *es, HFONT font, BOOL redraw); +static void EDIT_WM_SetText(WND *wnd, EDITSTATE *es, LPCSTR text); +static void EDIT_WM_Size(WND *wnd, EDITSTATE *es, UINT action, INT width, INT height); +static LRESULT EDIT_WM_SysKeyDown(WND *wnd, EDITSTATE *es, INT key, DWORD key_data); +static void EDIT_WM_Timer(WND *wnd, EDITSTATE *es, INT id, TIMERPROC timer_proc); +static LRESULT EDIT_WM_VScroll(WND *wnd, EDITSTATE *es, INT action, INT pos, HWND scroll_bar); + + +/********************************************************************* + * + * EM_CANUNDO + * + */ +static __inline__ BOOL EDIT_EM_CanUndo(WND *wnd, EDITSTATE *es) +{ + return (es->undo_insert_count || lstrlenA(es->undo_text)); +} + + +/********************************************************************* + * + * EM_EMPTYUNDOBUFFER + * + */ +static __inline__ void EDIT_EM_EmptyUndoBuffer(WND *wnd, EDITSTATE *es) +{ + es->undo_insert_count = 0; + *es->undo_text = '\0'; +} + + +/********************************************************************* + * + * WM_CLEAR + * + */ +static __inline__ void EDIT_WM_Clear(WND *wnd, EDITSTATE *es) +{ + EDIT_EM_ReplaceSel(wnd, es, TRUE, ""); +} + + +/********************************************************************* + * + * WM_CUT + * + */ +static __inline__ void EDIT_WM_Cut(WND *wnd, EDITSTATE *es) +{ + EDIT_WM_Copy(wnd, es); + EDIT_WM_Clear(wnd, es); +} + + +/********************************************************************* + * + * EditWndProc() + * + * The messages are in the order of the actual integer values + * (which can be found in include/windows.h) + * Whereever possible the 16 bit versions are converted to + * the bit ones, so that we can 'fall through' to the + * helper functions. These are mostly bit (with a few + * exceptions, clearly indicated by a '16' extension to their + * names). + * + */ +LRESULT WINAPI EditWndProc( HWND hwnd, UINT msg, + WPARAM wParam, LPARAM lParam ) +{ + WND *wnd = WIN_FindWndPtr(hwnd); + EDITSTATE *es = *(EDITSTATE **)((wnd)->wExtra); + LRESULT result = 0; + + switch (msg) { + case WM_DESTROY: + DPRINTF_EDIT_MSG("WM_DESTROY"); + EDIT_WM_Destroy(wnd, es); + return 0; + + case WM_NCCREATE: + DPRINTF_EDIT_MSG("WM_NCCREATE"); + return EDIT_WM_NCCreate(wnd, (LPCREATESTRUCTA)lParam); + } + + if (!es) + return DefWindowProcA(hwnd, msg, wParam, lParam); + + EDIT_LockBuffer(wnd, es); + switch (msg) { + case EM_GETSEL: + DPRINTF_EDIT_MSG("EM_GETSEL"); + result = EDIT_EM_GetSel(wnd, es, (UINT *)wParam, (UINT *)lParam); + break; + + + case EM_SETSEL: + DPRINTF_EDIT_MSG("EM_SETSEL"); + EDIT_EM_SetSel(wnd, es, wParam, lParam, FALSE); + result = 1; + break; + + + case EM_GETRECT: + DPRINTF_EDIT_MSG("EM_GETRECT"); + if (lParam) + CopyRect((LPRECT)lParam, &es->format_rect); + break; + + + case EM_SETRECT: + DPRINTF_EDIT_MSG("EM_SETRECT"); + if ((es->style & ES_MULTILINE) && lParam) { + EDIT_SetRectNP(wnd, es, (LPRECT)lParam); + InvalidateRect(wnd->hwndSelf, NULL, TRUE); + } + break; + + + case EM_SETRECTNP: + DPRINTF_EDIT_MSG("EM_SETRECTNP"); + if ((es->style & ES_MULTILINE) && lParam) + EDIT_SetRectNP(wnd, es, (LPRECT)lParam); + break; + + + case EM_SCROLL: + DPRINTF_EDIT_MSG("EM_SCROLL"); + result = EDIT_EM_Scroll(wnd, es, (INT)wParam); + break; + + + case EM_LINESCROLL: + DPRINTF_EDIT_MSG("EM_LINESCROLL"); + result = (LRESULT)EDIT_EM_LineScroll(wnd, es, (INT)wParam, (INT)lParam); + break; + + + case EM_SCROLLCARET: + DPRINTF_EDIT_MSG("EM_SCROLLCARET"); + EDIT_EM_ScrollCaret(wnd, es); + result = 1; + break; + + case EM_GETMODIFY: + DPRINTF_EDIT_MSG("EM_GETMODIFY"); + return ((es->flags & EF_MODIFIED) != 0); + break; + + case EM_SETMODIFY: + DPRINTF_EDIT_MSG("EM_SETMODIFY"); + if (wParam) + es->flags |= EF_MODIFIED; + else + es->flags &= ~EF_MODIFIED; + break; + + case EM_GETLINECOUNT: + DPRINTF_EDIT_MSG("EM_GETLINECOUNT"); + result = (es->style & ES_MULTILINE) ? es->line_count : 1; + break; + + case EM_LINEINDEX: + DPRINTF_EDIT_MSG("EM_LINEINDEX"); + result = (LRESULT)EDIT_EM_LineIndex(wnd, es, (INT)wParam); + break; + + case EM_SETHANDLE: + DPRINTF_EDIT_MSG("EM_SETHANDLE"); + EDIT_EM_SetHandle(wnd, es, (HLOCAL)wParam); + break; + + case EM_GETHANDLE: + DPRINTF_EDIT_MSG("EM_GETHANDLE"); + result = (LRESULT)EDIT_EM_GetHandle(wnd, es); + break; + + case EM_GETTHUMB: + DPRINTF_EDIT_MSG("EM_GETTHUMB"); + result = EDIT_EM_GetThumb(wnd, es); + break; + + /* messages 0x00bf and 0x00c0 missing from specs */ + + case 0x00bf: + DPRINTF_EDIT_MSG("undocumented 0x00bf, please report"); + result = DefWindowProcA(hwnd, msg, wParam, lParam); + break; + + case 0x00c0: + DPRINTF_EDIT_MSG("undocumented 0x00c0, please report"); + result = DefWindowProcA(hwnd, msg, wParam, lParam); + break; + + case EM_LINELENGTH: + DPRINTF_EDIT_MSG("EM_LINELENGTH"); + result = (LRESULT)EDIT_EM_LineLength(wnd, es, (INT)wParam); + break; + + + case EM_REPLACESEL: + DPRINTF_EDIT_MSG("EM_REPLACESEL"); + EDIT_EM_ReplaceSel(wnd, es, (BOOL)wParam, (LPCSTR)lParam); + result = 1; + break; + + /* message 0x00c3 missing from specs */ + + case 0x00c3: + DPRINTF_EDIT_MSG("undocumented 0x00c3, please report"); + result = DefWindowProcA(hwnd, msg, wParam, lParam); + break; + + case EM_GETLINE: + DPRINTF_EDIT_MSG("EM_GETLINE"); + result = (LRESULT)EDIT_EM_GetLine(wnd, es, (INT)wParam, (LPSTR)lParam); + break; + + case EM_SETLIMITTEXT: + DPRINTF_EDIT_MSG("EM_SETLIMITTEXT"); + EDIT_EM_SetLimitText(wnd, es, (INT)wParam); + break; + + case EM_CANUNDO: + DPRINTF_EDIT_MSG("EM_CANUNDO"); + result = (LRESULT)EDIT_EM_CanUndo(wnd, es); + break; + + case EM_UNDO: + /* fall through */ + case WM_UNDO: + DPRINTF_EDIT_MSG("EM_UNDO / WM_UNDO"); + result = (LRESULT)EDIT_EM_Undo(wnd, es); + break; + + case EM_FMTLINES: + DPRINTF_EDIT_MSG("EM_FMTLINES"); + result = (LRESULT)EDIT_EM_FmtLines(wnd, es, (BOOL)wParam); + break; + + case EM_LINEFROMCHAR: + DPRINTF_EDIT_MSG("EM_LINEFROMCHAR"); + result = (LRESULT)EDIT_EM_LineFromChar(wnd, es, (INT)wParam); + break; + + /* message 0x00ca missing from specs */ + + case 0x00ca: + DPRINTF_EDIT_MSG("undocumented 0x00ca, please report"); + result = DefWindowProcA(hwnd, msg, wParam, lParam); + break; + + case EM_SETTABSTOPS: + DPRINTF_EDIT_MSG("EM_SETTABSTOPS"); + result = (LRESULT)EDIT_EM_SetTabStops(wnd, es, (INT)wParam, (LPINT)lParam); + break; + + case EM_SETPASSWORDCHAR: + DPRINTF_EDIT_MSG("EM_SETPASSWORDCHAR"); + EDIT_EM_SetPasswordChar(wnd, es, (CHAR)wParam); + break; + + case EM_EMPTYUNDOBUFFER: + DPRINTF_EDIT_MSG("EM_EMPTYUNDOBUFFER"); + EDIT_EM_EmptyUndoBuffer(wnd, es); + break; + + case EM_GETFIRSTVISIBLELINE: + DPRINTF_EDIT_MSG("EM_GETFIRSTVISIBLELINE"); + result = (es->style & ES_MULTILINE) ? es->y_offset : es->x_offset; + break; + + case EM_SETREADONLY: + DPRINTF_EDIT_MSG("EM_SETREADONLY"); + if (wParam) { + wnd->dwStyle |= ES_READONLY; + es->style |= ES_READONLY; + } else { + wnd->dwStyle &= ~ES_READONLY; + es->style &= ~ES_READONLY; + } + return 1; + break; + + case EM_SETWORDBREAKPROC: + DPRINTF_EDIT_MSG("EM_SETWORDBREAKPROC"); + EDIT_EM_SetWordBreakProc(wnd, es, (EDITWORDBREAKPROCA)lParam); + break; + + case EM_GETWORDBREAKPROC: + DPRINTF_EDIT_MSG("EM_GETWORDBREAKPROC"); + result = (LRESULT)es->word_break_procA; + break; + + case EM_GETPASSWORDCHAR: + DPRINTF_EDIT_MSG("EM_GETPASSWORDCHAR"); + result = es->password_char; + break; + + /* The following EM_xxx are new to win95 and don't exist for 16 bit */ + + case EM_SETMARGINS: + DPRINTF_EDIT_MSG("EM_SETMARGINS"); + EDIT_EM_SetMargins(wnd, es, (INT)wParam, SLOWORD(lParam), SHIWORD(lParam)); + break; + + case EM_GETMARGINS: + DPRINTF_EDIT_MSG("EM_GETMARGINS"); + result = MAKELONG(es->left_margin, es->right_margin); + break; + + case EM_GETLIMITTEXT: + DPRINTF_EDIT_MSG("EM_GETLIMITTEXT"); + result = es->buffer_limit; + break; + + case EM_POSFROMCHAR: + DPRINTF_EDIT_MSG("EM_POSFROMCHAR"); + result = EDIT_EM_PosFromChar(wnd, es, (INT)wParam, FALSE); + break; + + case EM_CHARFROMPOS: + DPRINTF_EDIT_MSG("EM_CHARFROMPOS"); + result = EDIT_EM_CharFromPos(wnd, es, SLOWORD(lParam), SHIWORD(lParam)); + break; + + case WM_GETDLGCODE: + DPRINTF_EDIT_MSG("WM_GETDLGCODE"); + result = (es->style & ES_MULTILINE) ? + DLGC_WANTALLKEYS | DLGC_HASSETSEL | DLGC_WANTCHARS | DLGC_WANTARROWS : + DLGC_HASSETSEL | DLGC_WANTCHARS | DLGC_WANTARROWS; + break; + + case WM_CHAR: + DPRINTF_EDIT_MSG("WM_CHAR"); + EDIT_WM_Char(wnd, es, (CHAR)wParam, (DWORD)lParam); + break; + + case WM_CLEAR: + DPRINTF_EDIT_MSG("WM_CLEAR"); + EDIT_WM_Clear(wnd, es); + break; + + case WM_COMMAND: + DPRINTF_EDIT_MSG("WM_COMMAND"); + EDIT_WM_Command(wnd, es, HIWORD(wParam), LOWORD(wParam), (HWND)lParam); + break; + + case WM_CONTEXTMENU: + DPRINTF_EDIT_MSG("WM_CONTEXTMENU"); + EDIT_WM_ContextMenu(wnd, es, (HWND)wParam, SLOWORD(lParam), SHIWORD(lParam)); + break; + + case WM_COPY: + DPRINTF_EDIT_MSG("WM_COPY"); + EDIT_WM_Copy(wnd, es); + break; + + case WM_CREATE: + DPRINTF_EDIT_MSG("WM_CREATE"); + result = EDIT_WM_Create(wnd, es, (LPCREATESTRUCTA)lParam); + break; + + case WM_CUT: + DPRINTF_EDIT_MSG("WM_CUT"); + EDIT_WM_Cut(wnd, es); + break; + + case WM_ENABLE: + DPRINTF_EDIT_MSG("WM_ENABLE"); + InvalidateRect(hwnd, NULL, TRUE); + break; + + case WM_ERASEBKGND: + DPRINTF_EDIT_MSG("WM_ERASEBKGND"); + result = EDIT_WM_EraseBkGnd(wnd, es, (HDC)wParam); + break; + + case WM_GETFONT: + DPRINTF_EDIT_MSG("WM_GETFONT"); + result = (LRESULT)es->font; + break; + + case WM_GETTEXT: + DPRINTF_EDIT_MSG("WM_GETTEXT"); + result = (LRESULT)EDIT_WM_GetText(wnd, es, (INT)wParam, (LPSTR)lParam); + break; + + case WM_GETTEXTLENGTH: + DPRINTF_EDIT_MSG("WM_GETTEXTLENGTH"); + result = lstrlenA(es->text); + break; + + case WM_HSCROLL: + DPRINTF_EDIT_MSG("WM_HSCROLL"); + result = EDIT_WM_HScroll(wnd, es, LOWORD(wParam), SHIWORD(wParam), (HWND)lParam); + break; + + case WM_KEYDOWN: + DPRINTF_EDIT_MSG("WM_KEYDOWN"); + result = EDIT_WM_KeyDown(wnd, es, (INT)wParam, (DWORD)lParam); + break; + + case WM_KILLFOCUS: + DPRINTF_EDIT_MSG("WM_KILLFOCUS"); + result = EDIT_WM_KillFocus(wnd, es, (HWND)wParam); + break; + + case WM_LBUTTONDBLCLK: + DPRINTF_EDIT_MSG("WM_LBUTTONDBLCLK"); + result = EDIT_WM_LButtonDblClk(wnd, es, (DWORD)wParam, SLOWORD(lParam), SHIWORD(lParam)); + break; + + case WM_LBUTTONDOWN: + DPRINTF_EDIT_MSG("WM_LBUTTONDOWN"); + result = EDIT_WM_LButtonDown(wnd, es, (DWORD)wParam, SLOWORD(lParam), SHIWORD(lParam)); + break; + + case WM_LBUTTONUP: + DPRINTF_EDIT_MSG("WM_LBUTTONUP"); + result = EDIT_WM_LButtonUp(wnd, es, (DWORD)wParam, SLOWORD(lParam), SHIWORD(lParam)); + break; + + case WM_MOUSEACTIVATE: + /* + * FIXME: maybe DefWindowProc() screws up, but it seems that + * modalless dialog boxes need this. If we don't do this, the focus + * will _not_ be set by DefWindowProc() for edit controls in a + * modalless dialog box ??? + */ + DPRINTF_EDIT_MSG("WM_MOUSEACTIVATE"); + SetFocus(wnd->hwndSelf); + result = MA_ACTIVATE; + break; + + case WM_MOUSEMOVE: + /* + * DPRINTF_EDIT_MSG("WM_MOUSEMOVE"); + */ + result = EDIT_WM_MouseMove(wnd, es, (DWORD)wParam, SLOWORD(lParam), SHIWORD(lParam)); + break; + + case WM_PAINT: + DPRINTF_EDIT_MSG("WM_PAINT"); + EDIT_WM_Paint(wnd, es); + break; + + case WM_PASTE: + DPRINTF_EDIT_MSG("WM_PASTE"); + EDIT_WM_Paste(wnd, es); + break; + + case WM_SETFOCUS: + DPRINTF_EDIT_MSG("WM_SETFOCUS"); + EDIT_WM_SetFocus(wnd, es, (HWND)wParam); + break; + + case WM_SETFONT: + DPRINTF_EDIT_MSG("WM_SETFONT"); + EDIT_WM_SetFont(wnd, es, (HFONT)wParam, LOWORD(lParam) != 0); + break; + + case WM_SETTEXT: + DPRINTF_EDIT_MSG("WM_SETTEXT"); + EDIT_WM_SetText(wnd, es, (LPCSTR)lParam); + result = TRUE; + break; + + case WM_SIZE: + DPRINTF_EDIT_MSG("WM_SIZE"); + EDIT_WM_Size(wnd, es, (UINT)wParam, LOWORD(lParam), HIWORD(lParam)); + break; + + case WM_SYSKEYDOWN: + DPRINTF_EDIT_MSG("WM_SYSKEYDOWN"); + result = EDIT_WM_SysKeyDown(wnd, es, (INT)wParam, (DWORD)lParam); + break; + + case WM_TIMER: + DPRINTF_EDIT_MSG("WM_TIMER"); + EDIT_WM_Timer(wnd, es, (INT)wParam, (TIMERPROC)lParam); + break; + + case WM_VSCROLL: + DPRINTF_EDIT_MSG("WM_VSCROLL"); + result = EDIT_WM_VScroll(wnd, es, LOWORD(wParam), SHIWORD(wParam), (HWND)(lParam)); + break; + + default: + result = DefWindowProcA(hwnd, msg, wParam, lParam); + break; + } + EDIT_UnlockBuffer(wnd, es, FALSE); + return result; +} + + +/********************************************************************* + * + * EDIT_BuildLineDefs_ML + * + * Build linked list of text lines. + * Lines can end with '\0' (last line), a character (if it is wrapped), + * a soft return '\r\r\n' or a hard return '\r\n' + * + */ +static void EDIT_BuildLineDefs_ML(WND *wnd, EDITSTATE *es) +{ + HDC dc; + HFONT old_font = 0; + LPSTR start, cp; + INT fw; + LINEDEF *current_def; + LINEDEF **previous_next; + + current_def = es->first_line_def; + do { + LINEDEF *next_def = current_def->next; + HeapFree(es->heap, 0, current_def); + current_def = next_def; + } while (current_def); + es->line_count = 0; + es->text_width = 0; + + dc = GetDC(wnd->hwndSelf); + if (es->font) + old_font = SelectObject(dc, es->font); + + fw = es->format_rect.right - es->format_rect.left; + start = es->text; + previous_next = &es->first_line_def; + do { + current_def = HeapAlloc(es->heap, 0, sizeof(LINEDEF)); + current_def->next = NULL; + cp = start; + while (*cp) { + if ((*cp == '\r') && (*(cp + 1) == '\n')) + break; + cp++; + } + if (!(*cp)) { + current_def->ending = END_0; + current_def->net_length = lstrlenA(start); + } else if ((cp > start) && (*(cp - 1) == '\r')) { + current_def->ending = END_SOFT; + current_def->net_length = cp - start - 1; + } else { + current_def->ending = END_HARD; + current_def->net_length = cp - start; + } + current_def->width = (INT)LOWORD(GetTabbedTextExtentA(dc, + start, current_def->net_length, + es->tabs_count, es->tabs)); + /* FIXME: check here for lines that are too wide even in AUTOHSCROLL (> 767 ???) */ + if ((!(es->style & ES_AUTOHSCROLL)) && (current_def->width > fw)) { + INT next = 0; + INT prev; + do { + prev = next; + next = EDIT_CallWordBreakProc(wnd, es, start - es->text, + prev + 1, current_def->net_length, WB_RIGHT); + current_def->width = (INT)LOWORD(GetTabbedTextExtentA(dc, + start, next, es->tabs_count, es->tabs)); + } while (current_def->width <= fw); + if (!prev) { + next = 0; + do { + prev = next; + next++; + current_def->width = (INT)LOWORD(GetTabbedTextExtentA(dc, + start, next, es->tabs_count, es->tabs)); + } while (current_def->width <= fw); + if (!prev) + prev = 1; + } + current_def->net_length = prev; + current_def->ending = END_WRAP; + current_def->width = (INT)LOWORD(GetTabbedTextExtentA(dc, start, + current_def->net_length, es->tabs_count, es->tabs)); + } + switch (current_def->ending) { + case END_SOFT: + current_def->length = current_def->net_length + 3; + break; + case END_HARD: + current_def->length = current_def->net_length + 2; + break; + case END_WRAP: + case END_0: + current_def->length = current_def->net_length; + break; + } + es->text_width = MAX(es->text_width, current_def->width); + start += current_def->length; + *previous_next = current_def; + previous_next = ¤t_def->next; + es->line_count++; + } while (current_def->ending != END_0); + if (es->font) + SelectObject(dc, old_font); + ReleaseDC(wnd->hwndSelf, dc); +} + + +/********************************************************************* + * + * EDIT_CallWordBreakProc + * + * Call appropriate WordBreakProc (internal or external). + * + * Note: The "start" argument should always be an index refering + * to es->text. The actual wordbreak proc might be + * 16 bit, so we can't always pass any bit LPSTR. + * Hence we assume that es->text is the buffer that holds + * the string under examination (we can decide this for ourselves). + * + */ +static INT EDIT_CallWordBreakProc(WND *wnd, EDITSTATE *es, INT start, INT index, INT count, INT action) +{ + if (es->word_break_procA) + { + DPRINT("(wordbrk=%p,str='%s',idx=%d,cnt=%d,act=%d)\n", + es->word_break_procA, es->text + start, index, + count, action ); + return (INT)es->word_break_procA( es->text + start, index, + count, action ); + } + else + return EDIT_WordBreakProc(es->text + start, index, count, action); +} + + +/********************************************************************* + * + * EDIT_CharFromPos + * + * Beware: This is not the function called on EM_CHARFROMPOS + * The position _can_ be outside the formatting / client + * rectangle + * The return value is only the character index + * + */ +static INT EDIT_CharFromPos(WND *wnd, EDITSTATE *es, INT x, INT y, LPBOOL after_wrap) +{ + INT index; + HDC dc; + HFONT old_font = 0; + + if (es->style & ES_MULTILINE) { + INT line = (y - es->format_rect.top) / es->line_height + es->y_offset; + INT line_index = 0; + LINEDEF *line_def = es->first_line_def; + INT low, high; + while ((line > 0) && line_def->next) { + line_index += line_def->length; + line_def = line_def->next; + line--; + } + x += es->x_offset - es->format_rect.left; + if (x >= line_def->width) { + if (after_wrap) + *after_wrap = (line_def->ending == END_WRAP); + return line_index + line_def->net_length; + } + if (x <= 0) { + if (after_wrap) + *after_wrap = FALSE; + return line_index; + } + dc = GetDC(wnd->hwndSelf); + if (es->font) + old_font = SelectObject(dc, es->font); + low = line_index + 1; + high = line_index + line_def->net_length + 1; + while (low < high - 1) + { + INT mid = (low + high) / 2; + if (LOWORD(GetTabbedTextExtentA(dc, es->text + line_index,mid - line_index, es->tabs_count, es->tabs)) > x) high = mid; + else low = mid; + } + index = low; + + if (after_wrap) + *after_wrap = ((index == line_index + line_def->net_length) && + (line_def->ending == END_WRAP)); + } else { + LPSTR text; + SIZE size; + if (after_wrap) + *after_wrap = FALSE; + x -= es->format_rect.left; + if (!x) + return es->x_offset; + text = EDIT_GetPasswordPointer_SL(wnd, es); + dc = GetDC(wnd->hwndSelf); + if (es->font) + old_font = SelectObject(dc, es->font); + if (x < 0) + { + INT low = 0; + INT high = es->x_offset; + while (low < high - 1) + { + INT mid = (low + high) / 2; + GetTextExtentPointA( dc, text + mid, + es->x_offset - mid, &size ); + if (size.cx > -x) low = mid; + else high = mid; + } + index = low; + } + else + { + INT low = es->x_offset; + INT high = lstrlenA(es->text) + 1; + while (low < high - 1) + { + INT mid = (low + high) / 2; + GetTextExtentPointA( dc, text + es->x_offset, + mid - es->x_offset, &size ); + if (size.cx > x) high = mid; + else low = mid; + } + index = low; + } + if (es->style & ES_PASSWORD) + HeapFree(es->heap, 0 ,text); + } + if (es->font) + SelectObject(dc, old_font); + ReleaseDC(wnd->hwndSelf, dc); + return index; +} + + +/********************************************************************* + * + * EDIT_ConfinePoint + * + * adjusts the point to be within the formatting rectangle + * (so CharFromPos returns the nearest _visible_ character) + * + */ +static void EDIT_ConfinePoint(WND *wnd, EDITSTATE *es, LPINT x, LPINT y) +{ + *x = MIN(MAX(*x, es->format_rect.left), es->format_rect.right - 1); + *y = MIN(MAX(*y, es->format_rect.top), es->format_rect.bottom - 1); +} + + +/********************************************************************* + * + * EDIT_GetLineRect + * + * Calculates the bounding rectangle for a line from a starting + * column to an ending column. + * + */ +static void EDIT_GetLineRect(WND *wnd, EDITSTATE *es, INT line, INT scol, INT ecol, LPRECT rc) +{ + INT line_index = EDIT_EM_LineIndex(wnd, es, line); + + if (es->style & ES_MULTILINE) + rc->top = es->format_rect.top + (line - es->y_offset) * es->line_height; + else + rc->top = es->format_rect.top; + rc->bottom = rc->top + es->line_height; + rc->left = (scol == 0) ? es->format_rect.left : SLOWORD(EDIT_EM_PosFromChar(wnd, es, line_index + scol, TRUE)); + rc->right = (ecol == -1) ? es->format_rect.right : SLOWORD(EDIT_EM_PosFromChar(wnd, es, line_index + ecol, TRUE)); +} + + +/********************************************************************* + * + * EDIT_GetPasswordPointer_SL + * + * note: caller should free the (optionally) allocated buffer + * + */ +static LPSTR EDIT_GetPasswordPointer_SL(WND *wnd, EDITSTATE *es) +{ + if (es->style & ES_PASSWORD) { + INT len = lstrlenA(es->text); + LPSTR text = HeapAlloc(es->heap, 0, len + 1); + HEAP_memset(text, len, es->password_char); + text[len] = '\0'; + return text; + } else + return es->text; +} + + +/********************************************************************* + * + * EDIT_LockBuffer + * + * This acts as a LOCAL_Lock(), but it locks only once. This way + * you can call it whenever you like, without unlocking. + * + */ +static void EDIT_LockBuffer(WND *wnd, EDITSTATE *es) +{ + if (!es) { + DPRINT( "no EDITSTATE ... please report\n"); + return; + } + if (!(es->style & ES_MULTILINE)) + return; + if (!es->text) { + if (es->hloc) + es->text = LocalLock(es->hloc); + else { + DPRINT( "no buffer ... please report\n"); + return; + } + } + es->lock_count++; +} + + +/********************************************************************* + * + * EDIT_SL_InvalidateText + * + * Called from EDIT_InvalidateText(). + * Does the job for single-line controls only. + * + */ +static void EDIT_SL_InvalidateText(WND *wnd, EDITSTATE *es, INT start, INT end) +{ + RECT line_rect; + RECT rc; + + EDIT_GetLineRect(wnd, es, 0, start, end, &line_rect); + if (IntersectRect(&rc, &line_rect, &es->format_rect)) + InvalidateRect(wnd->hwndSelf, &rc, FALSE); +} + + +/********************************************************************* + * + * EDIT_ML_InvalidateText + * + * Called from EDIT_InvalidateText(). + * Does the job for multi-line controls only. + * + */ +static void EDIT_ML_InvalidateText(WND *wnd, EDITSTATE *es, INT start, INT end) +{ + INT vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height; + INT sl = EDIT_EM_LineFromChar(wnd, es, start); + INT el = EDIT_EM_LineFromChar(wnd, es, end); + INT sc; + INT ec; + RECT rc1; + RECT rcWnd; + RECT rcLine; + RECT rcUpdate; + INT l; + + if ((el < es->y_offset) || (sl > es->y_offset + vlc)) + return; + + sc = start - EDIT_EM_LineIndex(wnd, es, sl); + ec = end - EDIT_EM_LineIndex(wnd, es, el); + if (sl < es->y_offset) { + sl = es->y_offset; + sc = 0; + } + if (el > es->y_offset + vlc) { + el = es->y_offset + vlc; + ec = EDIT_EM_LineLength(wnd, es, EDIT_EM_LineIndex(wnd, es, el)); + } + GetClientRect(wnd->hwndSelf, &rc1); + IntersectRect(&rcWnd, &rc1, &es->format_rect); + if (sl == el) { + EDIT_GetLineRect(wnd, es, sl, sc, ec, &rcLine); + if (IntersectRect(&rcUpdate, &rcWnd, &rcLine)) + InvalidateRect(wnd->hwndSelf, &rcUpdate, FALSE); + } else { + EDIT_GetLineRect(wnd, es, sl, sc, + EDIT_EM_LineLength(wnd, es, + EDIT_EM_LineIndex(wnd, es, sl)), + &rcLine); + if (IntersectRect(&rcUpdate, &rcWnd, &rcLine)) + InvalidateRect(wnd->hwndSelf, &rcUpdate, FALSE); + for (l = sl + 1 ; l < el ; l++) { + EDIT_GetLineRect(wnd, es, l, 0, + EDIT_EM_LineLength(wnd, es, + EDIT_EM_LineIndex(wnd, es, l)), + &rcLine); + if (IntersectRect(&rcUpdate, &rcWnd, &rcLine)) + InvalidateRect(wnd->hwndSelf, &rcUpdate, FALSE); + } + EDIT_GetLineRect(wnd, es, el, 0, ec, &rcLine); + if (IntersectRect(&rcUpdate, &rcWnd, &rcLine)) + InvalidateRect(wnd->hwndSelf, &rcUpdate, FALSE); + } +} + + +/********************************************************************* + * + * EDIT_InvalidateText + * + * Invalidate the text from offset start upto, but not including, + * offset end. Useful for (re)painting the selection. + * Regions outside the linewidth are not invalidated. + * end == -1 means end == TextLength. + * start and end need not be ordered. + * + */ +static void EDIT_InvalidateText(WND *wnd, EDITSTATE *es, INT start, INT end) +{ + if (end == start) + return; + + if (end == -1) + end = lstrlenA(es->text); + + ORDER_INT(start, end); + + if (es->style & ES_MULTILINE) + EDIT_ML_InvalidateText(wnd, es, start, end); + else + EDIT_SL_InvalidateText(wnd, es, start, end); +} + + +/********************************************************************* + * + * EDIT_MakeFit + * + * Try to fit size + 1 bytes in the buffer. Constrain to limits. + * + */ +static BOOL EDIT_MakeFit(WND *wnd, EDITSTATE *es, INT size) +{ + HLOCAL hNew; + + if (size <= es->buffer_size) + return TRUE; + if (size > es->buffer_limit) { + EDIT_NOTIFY_PARENT(wnd, EN_MAXTEXT, "EN_MAXTEXT"); + return FALSE; + } + size = ((size / GROWLENGTH) + 1) * GROWLENGTH; + if (size > es->buffer_limit) + size = es->buffer_limit; + + DPRINT( "trying to ReAlloc to %d+1\n", size); + + EDIT_UnlockBuffer(wnd, es, TRUE); + if (es->text) { + if ((es->text = HeapReAlloc(es->heap, 0, es->text, size + 1))) + es->buffer_size = MIN(HeapSize(es->heap, 0, es->text) - 1, es->buffer_limit); + else + es->buffer_size = 0; + } else if (es->hloc) { + if ((hNew = LocalReAlloc(es->hloc, size + 1, 0))) { + DPRINT( "Old bit handle %08x, new handle %08x\n", es->hloc, hNew); + es->hloc = hNew; + es->buffer_size = MIN(LocalSize(es->hloc) - 1, es->buffer_limit); + } + } + if (es->buffer_size < size) { + EDIT_LockBuffer(wnd, es); + DPRINT( "FAILED ! We now have %d+1\n", es->buffer_size); + EDIT_NOTIFY_PARENT(wnd, EN_ERRSPACE, "EN_ERRSPACE"); + return FALSE; + } else { + EDIT_LockBuffer(wnd, es); + DPRINT( "We now have %d+1\n", es->buffer_size); + return TRUE; + } +} + + +/********************************************************************* + * + * EDIT_MakeUndoFit + * + * Try to fit size + 1 bytes in the undo buffer. + * + */ +static BOOL EDIT_MakeUndoFit(WND *wnd, EDITSTATE *es, INT size) +{ + if (size <= es->undo_buffer_size) + return TRUE; + size = ((size / GROWLENGTH) + 1) * GROWLENGTH; + + DPRINT( "trying to ReAlloc to %d+1\n", size); + + if ((es->undo_text = HeapReAlloc(es->heap, 0, es->undo_text, size + 1))) { + es->undo_buffer_size = HeapSize(es->heap, 0, es->undo_text) - 1; + if (es->undo_buffer_size < size) { + DPRINT( "FAILED ! We now have %d+1\n", es->undo_buffer_size); + return FALSE; + } + return TRUE; + } + return FALSE; +} + + +/********************************************************************* + * + * EDIT_MoveBackward + * + */ +static void EDIT_MoveBackward(WND *wnd, EDITSTATE *es, BOOL extend) +{ + INT e = es->selection_end; + + if (e) { + e--; + if ((es->style & ES_MULTILINE) && e && + (es->text[e - 1] == '\r') && (es->text[e] == '\n')) { + e--; + if (e && (es->text[e - 1] == '\r')) + e--; + } + } + EDIT_EM_SetSel(wnd, es, extend ? es->selection_start : e, e, FALSE); + EDIT_EM_ScrollCaret(wnd, es); +} + + +/********************************************************************* + * + * EDIT_MoveDown_ML + * + * Only for multi line controls + * Move the caret one line down, on a column with the nearest + * x coordinate on the screen (might be a different column). + * + */ +static void EDIT_MoveDown_ML(WND *wnd, EDITSTATE *es, BOOL extend) +{ + INT s = es->selection_start; + INT e = es->selection_end; + BOOL after_wrap = (es->flags & EF_AFTER_WRAP); + LRESULT pos = EDIT_EM_PosFromChar(wnd, es, e, after_wrap); + INT x = SLOWORD(pos); + INT y = SHIWORD(pos); + + e = EDIT_CharFromPos(wnd, es, x, y + es->line_height, &after_wrap); + if (!extend) + s = e; + EDIT_EM_SetSel(wnd, es, s, e, after_wrap); + EDIT_EM_ScrollCaret(wnd, es); +} + + +/********************************************************************* + * + * EDIT_MoveEnd + * + */ +static void EDIT_MoveEnd(WND *wnd, EDITSTATE *es, BOOL extend) +{ + BOOL after_wrap = FALSE; + INT e; + + if (es->style & ES_MULTILINE) + e = EDIT_CharFromPos(wnd, es, 0x7fffffff, + HIWORD(EDIT_EM_PosFromChar(wnd, es, es->selection_end, es->flags & EF_AFTER_WRAP)), &after_wrap); + else + e = lstrlenA(es->text); + EDIT_EM_SetSel(wnd, es, extend ? es->selection_start : e, e, after_wrap); + EDIT_EM_ScrollCaret(wnd, es); +} + + +/********************************************************************* + * + * EDIT_MoveForward + * + */ +static void EDIT_MoveForward(WND *wnd, EDITSTATE *es, BOOL extend) +{ + INT e = es->selection_end; + + if (es->text[e]) { + e++; + if ((es->style & ES_MULTILINE) && (es->text[e - 1] == '\r')) { + if (es->text[e] == '\n') + e++; + else if ((es->text[e] == '\r') && (es->text[e + 1] == '\n')) + e += 2; + } + } + EDIT_EM_SetSel(wnd, es, extend ? es->selection_start : e, e, FALSE); + EDIT_EM_ScrollCaret(wnd, es); +} + + +/********************************************************************* + * + * EDIT_MoveHome + * + * Home key: move to beginning of line. + * + */ +static void EDIT_MoveHome(WND *wnd, EDITSTATE *es, BOOL extend) +{ + INT e; + + if (es->style & ES_MULTILINE) + e = EDIT_CharFromPos(wnd, es, 0x80000000, + HIWORD(EDIT_EM_PosFromChar(wnd, es, es->selection_end, es->flags & EF_AFTER_WRAP)), NULL); + else + e = 0; + EDIT_EM_SetSel(wnd, es, e, extend ? es->selection_start : e, FALSE); + EDIT_EM_ScrollCaret(wnd, es); +} + + +/********************************************************************* + * + * EDIT_MovePageDown_ML + * + * Only for multi line controls + * Move the caret one page down, on a column with the nearest + * x coordinate on the screen (might be a different column). + * + */ +static void EDIT_MovePageDown_ML(WND *wnd, EDITSTATE *es, BOOL extend) +{ + INT s = es->selection_start; + INT e = es->selection_end; + BOOL after_wrap = (es->flags & EF_AFTER_WRAP); + LRESULT pos = EDIT_EM_PosFromChar(wnd, es, e, after_wrap); + INT x = SLOWORD(pos); + INT y = SHIWORD(pos); + + e = EDIT_CharFromPos(wnd, es, x, + y + (es->format_rect.bottom - es->format_rect.top), + &after_wrap); + if (!extend) + s = e; + EDIT_EM_SetSel(wnd, es, s, e, after_wrap); + EDIT_EM_ScrollCaret(wnd, es); +} + + +/********************************************************************* + * + * EDIT_MovePageUp_ML + * + * Only for multi line controls + * Move the caret one page up, on a column with the nearest + * x coordinate on the screen (might be a different column). + * + */ +static void EDIT_MovePageUp_ML(WND *wnd, EDITSTATE *es, BOOL extend) +{ + INT s = es->selection_start; + INT e = es->selection_end; + BOOL after_wrap = (es->flags & EF_AFTER_WRAP); + LRESULT pos = EDIT_EM_PosFromChar(wnd, es, e, after_wrap); + INT x = SLOWORD(pos); + INT y = SHIWORD(pos); + + e = EDIT_CharFromPos(wnd, es, x, + y - (es->format_rect.bottom - es->format_rect.top), + &after_wrap); + if (!extend) + s = e; + EDIT_EM_SetSel(wnd, es, s, e, after_wrap); + EDIT_EM_ScrollCaret(wnd, es); +} + + +/********************************************************************* + * + * EDIT_MoveUp_ML + * + * Only for multi line controls + * Move the caret one line up, on a column with the nearest + * x coordinate on the screen (might be a different column). + * + */ +static void EDIT_MoveUp_ML(WND *wnd, EDITSTATE *es, BOOL extend) +{ + INT s = es->selection_start; + INT e = es->selection_end; + BOOL after_wrap = (es->flags & EF_AFTER_WRAP); + LRESULT pos = EDIT_EM_PosFromChar(wnd, es, e, after_wrap); + INT x = SLOWORD(pos); + INT y = SHIWORD(pos); + + e = EDIT_CharFromPos(wnd, es, x, y - es->line_height, &after_wrap); + if (!extend) + s = e; + EDIT_EM_SetSel(wnd, es, s, e, after_wrap); + EDIT_EM_ScrollCaret(wnd, es); +} + + +/********************************************************************* + * + * EDIT_MoveWordBackward + * + */ +static void EDIT_MoveWordBackward(WND *wnd, EDITSTATE *es, BOOL extend) +{ + INT s = es->selection_start; + INT e = es->selection_end; + INT l; + INT ll; + INT li; + + l = EDIT_EM_LineFromChar(wnd, es, e); + ll = EDIT_EM_LineLength(wnd, es, e); + li = EDIT_EM_LineIndex(wnd, es, l); + if (e - li == 0) { + if (l) { + li = EDIT_EM_LineIndex(wnd, es, l - 1); + e = li + EDIT_EM_LineLength(wnd, es, li); + } + } else { + e = li + (INT)EDIT_CallWordBreakProc(wnd, es, + li, e - li, ll, WB_LEFT); + } + if (!extend) + s = e; + EDIT_EM_SetSel(wnd, es, s, e, FALSE); + EDIT_EM_ScrollCaret(wnd, es); +} + + +/********************************************************************* + * + * EDIT_MoveWordForward + * + */ +static void EDIT_MoveWordForward(WND *wnd, EDITSTATE *es, BOOL extend) +{ + INT s = es->selection_start; + INT e = es->selection_end; + INT l; + INT ll; + INT li; + + l = EDIT_EM_LineFromChar(wnd, es, e); + ll = EDIT_EM_LineLength(wnd, es, e); + li = EDIT_EM_LineIndex(wnd, es, l); + if (e - li == ll) { + if ((es->style & ES_MULTILINE) && (l != es->line_count - 1)) + e = EDIT_EM_LineIndex(wnd, es, l + 1); + } else { + e = li + EDIT_CallWordBreakProc(wnd, es, + li, e - li + 1, ll, WB_RIGHT); + } + if (!extend) + s = e; + EDIT_EM_SetSel(wnd, es, s, e, FALSE); + EDIT_EM_ScrollCaret(wnd, es); +} + + +/********************************************************************* + * + * EDIT_PaintLine + * + */ +static void EDIT_PaintLine(WND *wnd, EDITSTATE *es, HDC dc, INT line, BOOL rev) +{ + INT s = es->selection_start; + INT e = es->selection_end; + INT li; + INT ll; + INT x; + INT y; + LRESULT pos; + + if (es->style & ES_MULTILINE) { + INT vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height; + if ((line < es->y_offset) || (line > es->y_offset + vlc) || (line >= es->line_count)) + return; + } else if (line) + return; + + DPRINT( "line=%d\n", line); + + pos = EDIT_EM_PosFromChar(wnd, es, EDIT_EM_LineIndex(wnd, es, line), FALSE); + x = SLOWORD(pos); + y = SHIWORD(pos); + li = EDIT_EM_LineIndex(wnd, es, line); + ll = EDIT_EM_LineLength(wnd, es, li); + s = es->selection_start; + e = es->selection_end; + ORDER_INT(s, e); + s = MIN(li + ll, MAX(li, s)); + e = MIN(li + ll, MAX(li, e)); + if (rev && (s != e) && + ((es->flags & EF_FOCUSED) || (es->style & ES_NOHIDESEL))) { + x += EDIT_PaintText(wnd, es, dc, x, y, line, 0, s - li, FALSE); + x += EDIT_PaintText(wnd, es, dc, x, y, line, s - li, e - s, TRUE); + x += EDIT_PaintText(wnd, es, dc, x, y, line, e - li, li + ll - e, FALSE); + } else + x += EDIT_PaintText(wnd, es, dc, x, y, line, 0, ll, FALSE); +} + + +/********************************************************************* + * + * EDIT_PaintText + * + */ +static INT EDIT_PaintText(WND *wnd, EDITSTATE *es, HDC dc, INT x, INT y, INT line, INT col, INT count, BOOL rev) +{ + COLORREF BkColor; + COLORREF TextColor; + INT ret; + INT li; + SIZE size; + + if (!count) + return 0; + BkColor = GetBkColor(dc); + TextColor = GetTextColor(dc); + if (rev) { + SetBkColor(dc, GetSysColor(COLOR_HIGHLIGHT)); + SetTextColor(dc, GetSysColor(COLOR_HIGHLIGHTTEXT)); + } + li = EDIT_EM_LineIndex(wnd, es, line); + if (es->style & ES_MULTILINE) { + ret = (INT)LOWORD(TabbedTextOutA(dc, x, y, es->text + li + col, count, + es->tabs_count, es->tabs, es->format_rect.left - es->x_offset)); + } else { + LPSTR text = EDIT_GetPasswordPointer_SL(wnd, es); + TextOutA(dc, x, y, text + li + col, count); + GetTextExtentPointA(dc, text + li + col, count, &size); + ret = size.cx; + if (es->style & ES_PASSWORD) + HeapFree(es->heap, 0, text); + } + if (rev) { + SetBkColor(dc, BkColor); + SetTextColor(dc, TextColor); + } + return ret; +} + + +/********************************************************************* + * + * EDIT_SetCaretPos + * + */ +static void EDIT_SetCaretPos(WND *wnd, EDITSTATE *es, INT pos, + BOOL after_wrap) +{ + LRESULT res = EDIT_EM_PosFromChar(wnd, es, pos, after_wrap); + INT x = SLOWORD(res); + INT y = SHIWORD(res); + + if(x < es->format_rect.left) + x = es->format_rect.left; + if(x > es->format_rect.right - 2) + x = es->format_rect.right - 2; + if(y > es->format_rect.bottom) + y = es->format_rect.bottom; + if(y < es->format_rect.top) + y = es->format_rect.top; + SetCaretPos(x, y); + return; +} + + +/********************************************************************* + * + * EDIT_SetRectNP + * + * note: this is not (exactly) the handler called on EM_SETRECTNP + * it is also used to set the rect of a single line control + * + */ +static void EDIT_SetRectNP(WND *wnd, EDITSTATE *es, LPRECT rc) +{ + CopyRect(&es->format_rect, rc); + if (es->style & WS_BORDER) { + INT bw = GetSystemMetrics(SM_CXBORDER) + 1; + if(TWEAK_WineLook == WIN31_LOOK) + bw += 2; + es->format_rect.left += bw; + es->format_rect.top += bw; + es->format_rect.right -= bw; + es->format_rect.bottom -= bw; + } + es->format_rect.left += es->left_margin; + es->format_rect.right -= es->right_margin; + es->format_rect.right = MAX(es->format_rect.right, es->format_rect.left + es->char_width); + if (es->style & ES_MULTILINE) + es->format_rect.bottom = es->format_rect.top + + MAX(1, (es->format_rect.bottom - es->format_rect.top) / es->line_height) * es->line_height; + else + es->format_rect.bottom = es->format_rect.top + es->line_height; + if ((es->style & ES_MULTILINE) && !(es->style & ES_AUTOHSCROLL)) + EDIT_BuildLineDefs_ML(wnd, es); +} + + +/********************************************************************* + * + * EDIT_UnlockBuffer + * + */ +static void EDIT_UnlockBuffer(WND *wnd, EDITSTATE *es, BOOL force) +{ + if (!es) { + DPRINT( "no EDITSTATE ... please report\n"); + return; + } + if (!(es->style & ES_MULTILINE)) + return; + if (!es->lock_count) { + DPRINT( "lock_count == 0 ... please report\n"); + return; + } + if (!es->text) { + DPRINT( "es->text == 0 ... please report\n"); + return; + } + if (force || (es->lock_count == 1)) { + if (es->hloc) { + LocalUnlock(es->hloc); + es->text = NULL; + } + } + es->lock_count--; +} + + +/********************************************************************* + * + * EDIT_WordBreakProc + * + * Find the beginning of words. + * Note: unlike the specs for a WordBreakProc, this function only + * allows to be called without linebreaks between s[0] upto + * s[count - 1]. Remember it is only called + * internally, so we can decide this for ourselves. + * + */ +static INT EDIT_WordBreakProc(LPSTR s, INT index, INT count, INT action) +{ + INT ret = 0; + + DPRINT( "s=%p, index=%u, count=%u, action=%d\n", + s, index, count, action); + + switch (action) { + case WB_LEFT: + if (!count) + break; + if (index) + index--; + if (s[index] == ' ') { + while (index && (s[index] == ' ')) + index--; + if (index) { + while (index && (s[index] != ' ')) + index--; + if (s[index] == ' ') + index++; + } + } else { + while (index && (s[index] != ' ')) + index--; + if (s[index] == ' ') + index++; + } + ret = index; + break; + case WB_RIGHT: + if (!count) + break; + if (index) + index--; + if (s[index] == ' ') + while ((index < count) && (s[index] == ' ')) index++; + else { + while (s[index] && (s[index] != ' ') && (index < count)) + index++; + while ((s[index] == ' ') && (index < count)) index++; + } + ret = index; + break; + case WB_ISDELIMITER: + ret = (s[index] == ' '); + break; + default: + DPRINT( "unknown action code, please report !\n"); + break; + } + return ret; +} + + +/********************************************************************* + * + * EM_CHARFROMPOS + * + * FIXME: do the specs mean to return LineIndex or LineNumber ??? + * Let's assume LineIndex is meant + * FIXME: do the specs mean to return -1 if outside client area or + * if outside formatting rectangle ??? + * + */ +static LRESULT EDIT_EM_CharFromPos(WND *wnd, EDITSTATE *es, INT x, INT y) +{ + POINT pt; + RECT rc; + INT index; + + pt.x = x; + pt.y = y; + GetClientRect(wnd->hwndSelf, &rc); + if (!PtInRect(&rc, pt)) + return -1; + + index = EDIT_CharFromPos(wnd, es, x, y, NULL); + return MAKELONG(index, EDIT_EM_LineIndex(wnd, es, + EDIT_EM_LineFromChar(wnd, es, index))); +} + + +/********************************************************************* + * + * EM_FMTLINES + * + * Enable or disable soft breaks. + */ +static BOOL EDIT_EM_FmtLines(WND *wnd, EDITSTATE *es, BOOL add_eol) +{ + es->flags &= ~EF_USE_SOFTBRK; + if (add_eol) { + es->flags |= EF_USE_SOFTBRK; + DPRINT( "soft break enabled, not implemented\n"); + } + return add_eol; +} + + +/********************************************************************* + * + * EM_GETHANDLE + * + * Hopefully this won't fire back at us. + * We always start with a fixed buffer in our own heap. + * However, with this message a bit application requests + * a handle to bit moveable local heap memory, where it expects + * to find the text. + * It's a pity that from this moment on we have to use this + * local heap, because applications may rely on the handle + * in the future. + * + * In this function we'll try to switch to local heap. + * + */ +static HLOCAL EDIT_EM_GetHandle(WND *wnd, EDITSTATE *es) +{ + HLOCAL newBuf; + LPSTR newText; + INT newSize; + + if (!(es->style & ES_MULTILINE)) + return 0; + + if (es->hloc) + return es->hloc; + + + if (!(newBuf = LocalAlloc(LMEM_MOVEABLE, lstrlenA(es->text) + 1))) { + DPRINT( "could not allocate new bit buffer\n"); + return 0; + } + newSize = MIN(LocalSize(newBuf) - 1, es->buffer_limit); + if (!(newText = LocalLock(newBuf))) { + DPRINT( "could not lock new bit buffer\n"); + LocalFree(newBuf); + return 0; + } + lstrcpyA(newText, es->text); + EDIT_UnlockBuffer(wnd, es, TRUE); + if (es->text) + HeapFree(es->heap, 0, es->text); + es->hloc = newBuf; + es->buffer_size = newSize; + es->text = newText; + EDIT_LockBuffer(wnd, es); + DPRINT( "switched to bit local heap\n"); + + return es->hloc; +} + + + + +/********************************************************************* + * + * EM_GETLINE + * + */ +static INT EDIT_EM_GetLine(WND *wnd, EDITSTATE *es, INT line, LPSTR lpch) +{ + LPSTR src; + INT len; + INT i; + + if (es->style & ES_MULTILINE) { + if (line >= es->line_count) + return 0; + } else + line = 0; + i = EDIT_EM_LineIndex(wnd, es, line); + src = es->text + i; + len = MIN(*(WORD *)lpch, EDIT_EM_LineLength(wnd, es, i)); + for (i = 0 ; i < len ; i++) { + *lpch = *src; + src++; + lpch++; + } + return (LRESULT)len; +} + + +/********************************************************************* + * + * EM_GETSEL + * + */ +static LRESULT EDIT_EM_GetSel(WND *wnd, EDITSTATE *es, UINT * start, UINT * end) +{ + UINT s = es->selection_start; + UINT e = es->selection_end; + + ORDER_UINT(s, e); + if (start) + *start = s; + if (end) + *end = e; + return MAKELONG(s, e); +} + + +/********************************************************************* + * + * EM_GETTHUMB + * + * FIXME: is this right ? (or should it be only VSCROLL) + * (and maybe only for edit controls that really have their + * own scrollbars) (and maybe only for multiline controls ?) + * All in all: very poorly documented + * + * FIXME: now it's also broken, because of the new WM_HSCROLL / + * WM_VSCROLL handlers + * + */ +static LRESULT EDIT_EM_GetThumb(WND *wnd, EDITSTATE *es) +{ + return MAKELONG(EDIT_WM_VScroll(wnd, es, EM_GETTHUMB, 0, 0), + EDIT_WM_HScroll(wnd, es, EM_GETTHUMB, 0, 0)); +} + + +/********************************************************************* + * + * EM_LINEFROMCHAR + * + */ +static INT EDIT_EM_LineFromChar(WND *wnd, EDITSTATE *es, INT index) +{ + INT line; + LINEDEF *line_def; + + if (!(es->style & ES_MULTILINE)) + return 0; + if (index > lstrlenA(es->text)) + return es->line_count - 1; + if (index == -1) + index = MIN(es->selection_start, es->selection_end); + + line = 0; + line_def = es->first_line_def; + index -= line_def->length; + while ((index >= 0) && line_def->next) { + line++; + line_def = line_def->next; + index -= line_def->length; + } + return line; +} + + +/********************************************************************* + * + * EM_LINEINDEX + * + */ +static INT EDIT_EM_LineIndex(WND *wnd, EDITSTATE *es, INT line) +{ + INT line_index; + LINEDEF *line_def; + + if (!(es->style & ES_MULTILINE)) + return 0; + if (line >= es->line_count) + return -1; + + line_index = 0; + line_def = es->first_line_def; + if (line == -1) { + INT index = es->selection_end - line_def->length; + while ((index >= 0) && line_def->next) { + line_index += line_def->length; + line_def = line_def->next; + index -= line_def->length; + } + } else { + while (line > 0) { + line_index += line_def->length; + line_def = line_def->next; + line--; + } + } + return line_index; +} + + +/********************************************************************* + * + * EM_LINELENGTH + * + */ +static INT EDIT_EM_LineLength(WND *wnd, EDITSTATE *es, INT index) +{ + LINEDEF *line_def; + + if (!(es->style & ES_MULTILINE)) + return lstrlenA(es->text); + + if (index == -1) { + /* FIXME: broken + INT sl = EDIT_EM_LineFromChar(wnd, es, es->selection_start); + INT el = EDIT_EM_LineFromChar(wnd, es, es->selection_end); + return es->selection_start - es->line_defs[sl].offset + + es->line_defs[el].offset + + es->line_defs[el].length - es->selection_end; + */ + return 0; + } + line_def = es->first_line_def; + index -= line_def->length; + while ((index >= 0) && line_def->next) { + line_def = line_def->next; + index -= line_def->length; + } + return line_def->net_length; +} + + +/********************************************************************* + * + * EM_LINESCROLL + * + * FIXME: dx is in average character widths + * However, we assume it is in pixels when we use this + * function internally + * + */ +static BOOL EDIT_EM_LineScroll(WND *wnd, EDITSTATE *es, INT dx, INT dy) +{ + INT nyoff; + + if (!(es->style & ES_MULTILINE)) + return FALSE; + + if (-dx > es->x_offset) + dx = -es->x_offset; + if (dx > es->text_width - es->x_offset) + dx = es->text_width - es->x_offset; + nyoff = MAX(0, es->y_offset + dy); + if (nyoff >= es->line_count) + nyoff = es->line_count - 1; + dy = (es->y_offset - nyoff) * es->line_height; + if (dx || dy) { + RECT rc1; + RECT rc; + GetClientRect(wnd->hwndSelf, &rc1); + IntersectRect(&rc, &rc1, &es->format_rect); + ScrollWindowEx(wnd->hwndSelf, -dx, dy, + NULL, &rc, (HRGN)NULL, NULL, SW_INVALIDATE); + es->y_offset = nyoff; + es->x_offset += dx; + } + if (dx && !(es->flags & EF_HSCROLL_TRACK)) + EDIT_NOTIFY_PARENT(wnd, EN_HSCROLL, "EN_HSCROLL"); + if (dy && !(es->flags & EF_VSCROLL_TRACK)) + EDIT_NOTIFY_PARENT(wnd, EN_VSCROLL, "EN_VSCROLL"); + return TRUE; +} + + +/********************************************************************* + * + * EM_POSFROMCHAR + * + */ +static LRESULT EDIT_EM_PosFromChar(WND *wnd, EDITSTATE *es, INT index, BOOL after_wrap) +{ + INT len = lstrlenA(es->text); + INT l; + INT li; + INT x; + INT y = 0; + HDC dc; + HFONT old_font = 0; + SIZE size; + + index = MIN(index, len); + dc = GetDC(wnd->hwndSelf); + if (es->font) + old_font = SelectObject(dc, es->font); + if (es->style & ES_MULTILINE) { + l = EDIT_EM_LineFromChar(wnd, es, index); + y = (l - es->y_offset) * es->line_height; + li = EDIT_EM_LineIndex(wnd, es, l); + if (after_wrap && (li == index) && l) { + INT l2 = l - 1; + LINEDEF *line_def = es->first_line_def; + while (l2) { + line_def = line_def->next; + l2--; + } + if (line_def->ending == END_WRAP) { + l--; + y -= es->line_height; + li = EDIT_EM_LineIndex(wnd, es, l); + } + } + x = LOWORD(GetTabbedTextExtentA(dc, es->text + li, index - li, + es->tabs_count, es->tabs)) - es->x_offset; + } else { + LPSTR text = EDIT_GetPasswordPointer_SL(wnd, es); + if (index < es->x_offset) { + GetTextExtentPointA(dc, text + index, + es->x_offset - index, &size); + x = -size.cx; + } else { + GetTextExtentPointA(dc, text + es->x_offset, + index - es->x_offset, &size); + x = size.cx; + } + y = 0; + if (es->style & ES_PASSWORD) + HeapFree(es->heap, 0 ,text); + } + x += es->format_rect.left; + y += es->format_rect.top; + if (es->font) + SelectObject(dc, old_font); + ReleaseDC(wnd->hwndSelf, dc); + return MAKELONG((INT)x, (INT)y); +} + + +/********************************************************************* + * + * EM_REPLACESEL + * + * FIXME: handle ES_NUMBER and ES_OEMCONVERT here + * + */ +static void EDIT_EM_ReplaceSel(WND *wnd, EDITSTATE *es, BOOL can_undo, LPCSTR lpsz_replace) +{ + INT strl = lstrlenA(lpsz_replace); + INT tl = lstrlenA(es->text); + INT utl; + UINT s; + UINT e; + INT i; + LPSTR p; + + s = es->selection_start; + e = es->selection_end; + + if ((s == e) && !strl) + return; + + ORDER_UINT(s, e); + + if (!EDIT_MakeFit(wnd, es, tl - (e - s) + strl)) + return; + + if (e != s) { + /* there is something to be deleted */ + if (can_undo) { + utl = lstrlenA(es->undo_text); + if (!es->undo_insert_count && (*es->undo_text && (s == es->undo_position))) { + /* undo-buffer is extended to the right */ + EDIT_MakeUndoFit(wnd, es, utl + e - s); + lstrcpynA(es->undo_text + utl, es->text + s, e - s + 1); + } else if (!es->undo_insert_count && (*es->undo_text && (e == es->undo_position))) { + /* undo-buffer is extended to the left */ + EDIT_MakeUndoFit(wnd, es, utl + e - s); + for (p = es->undo_text + utl ; p >= es->undo_text ; p--) + p[e - s] = p[0]; + for (i = 0 , p = es->undo_text ; i < e - s ; i++) + p[i] = (es->text + s)[i]; + es->undo_position = s; + } else { + /* new undo-buffer */ + EDIT_MakeUndoFit(wnd, es, e - s); + lstrcpynA(es->undo_text, es->text + s, e - s + 1); + es->undo_position = s; + } + /* any deletion makes the old insertion-undo invalid */ + es->undo_insert_count = 0; + } else + EDIT_EM_EmptyUndoBuffer(wnd, es); + + /* now delete */ + lstrcpyA(es->text + s, es->text + e); + } + if (strl) { + /* there is an insertion */ + if (can_undo) { + if ((s == es->undo_position) || + ((es->undo_insert_count) && + (s == es->undo_position + es->undo_insert_count))) + /* + * insertion is new and at delete position or + * an extension to either left or right + */ + es->undo_insert_count += strl; + else { + /* new insertion undo */ + es->undo_position = s; + es->undo_insert_count = strl; + /* new insertion makes old delete-buffer invalid */ + *es->undo_text = '\0'; + } + } else + EDIT_EM_EmptyUndoBuffer(wnd, es); + + /* now insert */ + tl = lstrlenA(es->text); + for (p = es->text + tl ; p >= es->text + s ; p--) + p[strl] = p[0]; + for (i = 0 , p = es->text + s ; i < strl ; i++) + p[i] = lpsz_replace[i]; + if(es->style & ES_UPPERCASE) + CharUpperBuffA(p, strl); + else if(es->style & ES_LOWERCASE) + CharLowerBuffA(p, strl); + s += strl; + } + /* FIXME: really inefficient */ + if (es->style & ES_MULTILINE) + EDIT_BuildLineDefs_ML(wnd, es); + + EDIT_EM_SetSel(wnd, es, s, s, FALSE); + es->flags |= EF_MODIFIED; + es->flags |= EF_UPDATE; + EDIT_EM_ScrollCaret(wnd, es); + + /* FIXME: really inefficient */ + InvalidateRect(wnd->hwndSelf, NULL, TRUE); +} + + +/********************************************************************* + * + * EM_SCROLL + * + */ +static LRESULT EDIT_EM_Scroll(WND *wnd, EDITSTATE *es, INT action) +{ + INT dy; + + if (!(es->style & ES_MULTILINE)) + return (LRESULT)FALSE; + + dy = 0; + + switch (action) { + case SB_LINEUP: + if (es->y_offset) + dy = -1; + break; + case SB_LINEDOWN: + if (es->y_offset < es->line_count - 1) + dy = 1; + break; + case SB_PAGEUP: + if (es->y_offset) + dy = -(es->format_rect.bottom - es->format_rect.top) / es->line_height; + break; + case SB_PAGEDOWN: + if (es->y_offset < es->line_count - 1) + dy = (es->format_rect.bottom - es->format_rect.top) / es->line_height; + break; + default: + return (LRESULT)FALSE; + } + if (dy) { + EDIT_EM_LineScroll(wnd, es, 0, dy); + EDIT_NOTIFY_PARENT(wnd, EN_VSCROLL, "EN_VSCROLL"); + } + return MAKELONG((INT)dy, (BOOL)TRUE); +} + + +/********************************************************************* + * + * EM_SCROLLCARET + * + */ +static void EDIT_EM_ScrollCaret(WND *wnd, EDITSTATE *es) +{ + if (es->style & ES_MULTILINE) { + INT l; + INT li; + INT vlc; + INT ww; + INT cw = es->char_width; + INT x; + INT dy = 0; + INT dx = 0; + + l = EDIT_EM_LineFromChar(wnd, es, es->selection_end); + li = EDIT_EM_LineIndex(wnd, es, l); + x = SLOWORD(EDIT_EM_PosFromChar(wnd, es, es->selection_end, es->flags & EF_AFTER_WRAP)); + vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height; + if (l >= es->y_offset + vlc) + dy = l - vlc + 1 - es->y_offset; + if (l < es->y_offset) + dy = l - es->y_offset; + ww = es->format_rect.right - es->format_rect.left; + if (x < es->format_rect.left) + dx = x - es->format_rect.left - ww / HSCROLL_FRACTION / cw * cw; + if (x > es->format_rect.right) + dx = x - es->format_rect.left - (HSCROLL_FRACTION - 1) * ww / HSCROLL_FRACTION / cw * cw; + if (dy || dx) + EDIT_EM_LineScroll(wnd, es, dx, dy); + } else { + INT x; + INT goal; + INT format_width; + + if (!(es->style & ES_AUTOHSCROLL)) + return; + + x = SLOWORD(EDIT_EM_PosFromChar(wnd, es, es->selection_end, FALSE)); + format_width = es->format_rect.right - es->format_rect.left; + if (x < es->format_rect.left) { + goal = es->format_rect.left + format_width / HSCROLL_FRACTION; + do { + es->x_offset--; + x = SLOWORD(EDIT_EM_PosFromChar(wnd, es, es->selection_end, FALSE)); + } while ((x < goal) && es->x_offset); + /* FIXME: use ScrollWindow() somehow to improve performance */ + InvalidateRect(wnd->hwndSelf, NULL, TRUE); + } else if (x > es->format_rect.right) { + INT x_last; + INT len = lstrlenA(es->text); + goal = es->format_rect.right - format_width / HSCROLL_FRACTION; + do { + es->x_offset++; + x = SLOWORD(EDIT_EM_PosFromChar(wnd, es, es->selection_end, FALSE)); + x_last = SLOWORD(EDIT_EM_PosFromChar(wnd, es, len, FALSE)); + } while ((x > goal) && (x_last > es->format_rect.right)); + /* FIXME: use ScrollWindow() somehow to improve performance */ + InvalidateRect(wnd->hwndSelf, NULL, TRUE); + } + } +} + + +/********************************************************************* + * + * EM_SETHANDLE + * + * FIXME: ES_LOWERCASE, ES_UPPERCASE, ES_OEMCONVERT, ES_NUMBER ??? + * + */ +static void EDIT_EM_SetHandle(WND *wnd, EDITSTATE *es, HLOCAL hloc) +{ + if (!(es->style & ES_MULTILINE)) + return; + + if (!hloc) { + DPRINT( "called with NULL handle\n"); + return; + } + + EDIT_UnlockBuffer(wnd, es, TRUE); + /* + * old buffer is freed by caller, unless + * it is still in our own heap. (in that case + * we free it, correcting the buggy caller.) + */ + if (es->text) + HeapFree(es->heap, 0, es->text); + + es->hloc = hloc; + es->text = NULL; + es->buffer_size = LocalSize(es->hloc) - 1; + EDIT_LockBuffer(wnd, es); + + es->x_offset = es->y_offset = 0; + es->selection_start = es->selection_end = 0; + EDIT_EM_EmptyUndoBuffer(wnd, es); + es->flags &= ~EF_MODIFIED; + es->flags &= ~EF_UPDATE; + EDIT_BuildLineDefs_ML(wnd, es); + InvalidateRect(wnd->hwndSelf, NULL, TRUE); + EDIT_EM_ScrollCaret(wnd, es); +} + + + + + +/********************************************************************* + * + * EM_SETLIMITTEXT + * + * FIXME: in WinNT maxsize is 0x7FFFFFFF / 0xFFFFFFFF + * However, the windows version is not complied to yet in all of edit.c + * + */ +static void EDIT_EM_SetLimitText(WND *wnd, EDITSTATE *es, INT limit) +{ + if (es->style & ES_MULTILINE) { + if (limit) + es->buffer_limit = MIN(limit, BUFLIMIT_MULTI); + else + es->buffer_limit = BUFLIMIT_MULTI; + } else { + if (limit) + es->buffer_limit = MIN(limit, BUFLIMIT_SINGLE); + else + es->buffer_limit = BUFLIMIT_SINGLE; + } +} + + +/********************************************************************* + * + * EM_SETMARGINS + * + * EC_USEFONTINFO is used as a left or right value i.e. lParam and not as an + * action wParam despite what the docs say. It also appears not to affect + * multiline controls?? + * + */ +static void EDIT_EM_SetMargins(WND *wnd, EDITSTATE *es, INT action, + INT left, INT right) +{ + if (action & EC_LEFTMARGIN) { + if (left != EC_USEFONTINFO) + es->left_margin = left; + else + if (es->style & ES_MULTILINE) + es->left_margin = 0; /* ?? */ + else + es->left_margin = es->char_width; + } + + if (action & EC_RIGHTMARGIN) { + if (right != EC_USEFONTINFO) + es->right_margin = right; + else + if (es->style & ES_MULTILINE) + es->right_margin = 0; /* ?? */ + else + es->right_margin = es->char_width; + } + DPRINT( "left=%d, right=%d\n", es->left_margin, es->right_margin); +} + + +/********************************************************************* + * + * EM_SETPASSWORDCHAR + * + */ +static void EDIT_EM_SetPasswordChar(WND *wnd, EDITSTATE *es, CHAR c) +{ + if (es->style & ES_MULTILINE) + return; + + if (es->password_char == c) + return; + + es->password_char = c; + if (c) { + wnd->dwStyle |= ES_PASSWORD; + es->style |= ES_PASSWORD; + } else { + wnd->dwStyle &= ~ES_PASSWORD; + es->style &= ~ES_PASSWORD; + } + InvalidateRect(wnd->hwndSelf, NULL, TRUE); +} + + +/********************************************************************* + * + * EDIT_EM_SetSel + * + * note: unlike the specs say: the order of start and end + * _is_ preserved in Windows. (i.e. start can be > end) + * In other words: this handler is OK + * + */ +static void EDIT_EM_SetSel(WND *wnd, EDITSTATE *es, UINT start, UINT end, BOOL after_wrap) +{ + UINT old_start = es->selection_start; + UINT old_end = es->selection_end; + UINT len = lstrlenA(es->text); + + if (start == -1) { + start = es->selection_end; + end = es->selection_end; + } else { + start = MIN(start, len); + end = MIN(end, len); + } + es->selection_start = start; + es->selection_end = end; + if (after_wrap) + es->flags |= EF_AFTER_WRAP; + else + es->flags &= ~EF_AFTER_WRAP; + if (es->flags & EF_FOCUSED) + EDIT_SetCaretPos(wnd, es, end, after_wrap); +/* This is little bit more efficient than before, not sure if it can be improved. FIXME? */ + ORDER_UINT(start, end); + ORDER_UINT(end, old_end); + ORDER_UINT(start, old_start); + ORDER_UINT(old_start, old_end); + if (end != old_start) + { +/* + * One can also do + * ORDER_UINT(end, old_start); + * EDIT_InvalidateText(wnd, es, start, end); + * EDIT_InvalidateText(wnd, es, old_start, old_end); + * in place of the following if statement. + */ + if (old_start > end ) + { + EDIT_InvalidateText(wnd, es, start, end); + EDIT_InvalidateText(wnd, es, old_start, old_end); + } + else + { + EDIT_InvalidateText(wnd, es, start, old_start); + EDIT_InvalidateText(wnd, es, end, old_end); + } + } + else EDIT_InvalidateText(wnd, es, start, old_end); +} + + +/********************************************************************* + * + * EM_SETTABSTOPS + * + */ +static BOOL EDIT_EM_SetTabStops(WND *wnd, EDITSTATE *es, INT count, LPINT tabs) +{ + if (!(es->style & ES_MULTILINE)) + return FALSE; + if (es->tabs) + HeapFree(es->heap, 0, es->tabs); + es->tabs_count = count; + if (!count) + es->tabs = NULL; + else { + es->tabs = HeapAlloc(es->heap, 0, count * sizeof(INT)); + memcpy(es->tabs, tabs, count * sizeof(INT)); + } + return TRUE; +} + + + + +/********************************************************************* + * + * EM_SETWORDBREAKPROC + * + */ +static void EDIT_EM_SetWordBreakProc(WND *wnd, EDITSTATE *es, EDITWORDBREAKPROCA wbp) +{ + if (es->word_break_procA == wbp) + return; + + es->word_break_procA = wbp; + if ((es->style & ES_MULTILINE) && !(es->style & ES_AUTOHSCROLL)) { + EDIT_BuildLineDefs_ML(wnd, es); + InvalidateRect(wnd->hwndSelf, NULL, TRUE); + } +} + + + + + +/********************************************************************* + * + * EM_UNDO / WM_UNDO + * + */ +static BOOL EDIT_EM_Undo(WND *wnd, EDITSTATE *es) +{ + INT ulength = lstrlenA(es->undo_text); + LPSTR utext = HeapAlloc(es->heap, 0, ulength + 1); + + lstrcpyA(utext, es->undo_text); + + DPRINT( "before UNDO:insertion length = %d, deletion buffer = %s\n", + es->undo_insert_count, utext); + + EDIT_EM_SetSel(wnd, es, es->undo_position, es->undo_position + es->undo_insert_count, FALSE); + EDIT_EM_EmptyUndoBuffer(wnd, es); + EDIT_EM_ReplaceSel(wnd, es, TRUE, utext); + EDIT_EM_SetSel(wnd, es, es->undo_position, es->undo_position + es->undo_insert_count, FALSE); + HeapFree(es->heap, 0, utext); + + DPRINT( "after UNDO:insertion length = %d, deletion buffer = %s\n", + es->undo_insert_count, es->undo_text); + + return TRUE; +} + + +/********************************************************************* + * + * WM_CHAR + * + */ +static void EDIT_WM_Char(WND *wnd, EDITSTATE *es, CHAR c, DWORD key_data) +{ + switch (c) { + case '\r': + case '\n': + if (es->style & ES_MULTILINE) { + if (es->style & ES_READONLY) { + EDIT_MoveHome(wnd, es, FALSE); + EDIT_MoveDown_ML(wnd, es, FALSE); + } else + EDIT_EM_ReplaceSel(wnd, es, TRUE, "\r\n"); + } + break; + case '\t': + if ((es->style & ES_MULTILINE) && !(es->style & ES_READONLY)) + EDIT_EM_ReplaceSel(wnd, es, TRUE, "\t"); + break; + default: + if (!(es->style & ES_READONLY) && ((BYTE)c >= ' ') && (c != 127)) { + char str[2]; + str[0] = c; + str[1] = '\0'; + EDIT_EM_ReplaceSel(wnd, es, TRUE, str); + } + break; + } +} + + +/********************************************************************* + * + * WM_COMMAND + * + */ +static void EDIT_WM_Command(WND *wnd, EDITSTATE *es, INT code, INT id, HWND control) +{ + if (code || control) + return; + + switch (id) { + case EM_UNDO: + EDIT_EM_Undo(wnd, es); + break; + case WM_CUT: + EDIT_WM_Cut(wnd, es); + break; + case WM_COPY: + EDIT_WM_Copy(wnd, es); + break; + case WM_PASTE: + EDIT_WM_Paste(wnd, es); + break; + case WM_CLEAR: + EDIT_WM_Clear(wnd, es); + break; + case EM_SETSEL: + EDIT_EM_SetSel(wnd, es, 0, -1, FALSE); + EDIT_EM_ScrollCaret(wnd, es); + break; + default: + DPRINT( "unknown menu item, please report\n"); + break; + } +} + + +/********************************************************************* + * + * WM_CONTEXTMENU + * + * Note: the resource files resource/sysres_??.rc cannot define a + * single popup menu. Hence we use a (dummy) menubar + * containing the single popup menu as its first item. + * + * FIXME: the message identifiers have been chosen arbitrarily, + * hence we use MF_BYPOSITION. + * We might as well use the "real" values (anybody knows ?) + * The menu definition is in resources/sysres_??.rc. + * Once these are OK, we better use MF_BYCOMMAND here + * (as we do in EDIT_WM_Command()). + * + */ +static void EDIT_WM_ContextMenu(WND *wnd, EDITSTATE *es, HWND hwnd, INT x, INT y) +{ + HMENU menu = LoadMenuIndirectA(SYSRES_GetResPtr(SYSRES_MENU_EDITMENU)); + HMENU popup = GetSubMenu(menu, 0); + UINT start = es->selection_start; + UINT end = es->selection_end; + + ORDER_UINT(start, end); + + /* undo */ + EnableMenuItem(popup, 0, MF_BYPOSITION | (EDIT_EM_CanUndo(wnd, es) ? MF_ENABLED : MF_GRAYED)); + /* cut */ + EnableMenuItem(popup, 2, MF_BYPOSITION | ((end - start) && !(es->style & ES_PASSWORD) ? MF_ENABLED : MF_GRAYED)); + /* copy */ + EnableMenuItem(popup, 3, MF_BYPOSITION | ((end - start) && !(es->style & ES_PASSWORD) ? MF_ENABLED : MF_GRAYED)); + /* paste */ + EnableMenuItem(popup, 4, MF_BYPOSITION | (IsClipboardFormatAvailable(CF_TEXT) ? MF_ENABLED : MF_GRAYED)); + /* delete */ + EnableMenuItem(popup, 5, MF_BYPOSITION | ((end - start) ? MF_ENABLED : MF_GRAYED)); + /* select all */ + EnableMenuItem(popup, 7, MF_BYPOSITION | (start || (end != lstrlenA(es->text)) ? MF_ENABLED : MF_GRAYED)); + + TrackPopupMenu(popup, TPM_LEFTALIGN | TPM_RIGHTBUTTON, x, y, 0, wnd->hwndSelf, NULL); + DestroyMenu(menu); +} + + +/********************************************************************* + * + * WM_COPY + * + */ +static void EDIT_WM_Copy(WND *wnd, EDITSTATE *es) +{ + INT s = es->selection_start; + INT e = es->selection_end; + HGLOBAL hdst; + LPSTR dst; + + if (e == s) + return; + ORDER_INT(s, e); + hdst = GlobalAlloc(GMEM_MOVEABLE, (DWORD)(e - s + 1)); + dst = GlobalLock(hdst); + lstrcpynA(dst, es->text + s, e - s + 1); + GlobalUnlock(hdst); + OpenClipboard(wnd->hwndSelf); + EmptyClipboard(); + SetClipboardData(CF_TEXT, hdst); + CloseClipboard(); +} + + +/********************************************************************* + * + * WM_CREATE + * + */ +static LRESULT EDIT_WM_Create(WND *wnd, EDITSTATE *es, LPCREATESTRUCTA cs) +{ + /* + * To initialize some final structure members, we call some helper + * functions. However, since the EDITSTATE is not consistent (i.e. + * not fully initialized), we should be very careful which + * functions can be called, and in what order. + */ + EDIT_WM_SetFont(wnd, es, 0, FALSE); + if (cs->lpszName && *(cs->lpszName) != '\0') { + EDIT_EM_ReplaceSel(wnd, es, FALSE, cs->lpszName); + /* if we insert text to the editline, the text scrolls out of the window, as the caret is placed after the insert pos normally; thus we reset es->selection... to 0 and update caret */ + es->selection_start = es->selection_end = 0; + EDIT_EM_ScrollCaret(wnd, es); + } + return 0; +} + + +/********************************************************************* + * + * WM_DESTROY + * + */ +static void EDIT_WM_Destroy(WND *wnd, EDITSTATE *es) +{ + if (es->hloc) { + while (LocalUnlock(es->hloc)) ; + LocalFree(es->hloc); + } + + HeapDestroy(es->heap); + HeapFree(GetProcessHeap(), 0, es); + *(EDITSTATE **)wnd->wExtra = NULL; +} + + +/********************************************************************* + * + * WM_ERASEBKGND + * + */ +static LRESULT EDIT_WM_EraseBkGnd(WND *wnd, EDITSTATE *es, HDC dc) +{ + HBRUSH brush; + RECT rc; + + if (!(brush = (HBRUSH)EDIT_SEND_CTLCOLOR(wnd, dc))) + brush = (HBRUSH)GetStockObject(WHITE_BRUSH); + + GetClientRect(wnd->hwndSelf, &rc); + IntersectClipRect(dc, rc.left, rc.top, rc.right, rc.bottom); + GetClipBox(dc, &rc); + /* + * FIXME: specs say that we should UnrealizeObject() the brush, + * but the specs of UnrealizeObject() say that we shouldn't + * unrealize a stock object. The default brush that + * DefWndProc() returns is ... a stock object. + */ + FillRect(dc, &rc, brush); + return -1; +} + + +/********************************************************************* + * + * WM_GETTEXT + * + */ +static INT EDIT_WM_GetText(WND *wnd, EDITSTATE *es, INT count, LPSTR text) +{ + INT len = lstrlenA(es->text); + + if (count > len) { + lstrcpyA(text, es->text); + return len; + } else + return -1; +} + + +/********************************************************************* + * + * EDIT_HScroll_Hack + * + * 16 bit notepad needs this. Actually it is not _our_ hack, + * it is notepad's. Notepad is sending us scrollbar messages with + * undocumented parameters without us even having a scrollbar ... !?!? + * + */ +static LRESULT EDIT_HScroll_Hack(WND *wnd, EDITSTATE *es, INT action, INT pos, HWND scroll_bar) +{ + INT dx = 0; + INT fw = es->format_rect.right - es->format_rect.left; + LRESULT ret = 0; + + if (!(es->flags & EF_HSCROLL_HACK)) { + DPRINT( "hacked WM_HSCROLL handler invoked\n"); + DPRINT( " if you are _not_ running 16 bit notepad, please report\n"); + DPRINT( " (this message is only displayed once per edit control)\n"); + es->flags |= EF_HSCROLL_HACK; + } + + switch (action) { + case SB_LINELEFT: + if (es->x_offset) + dx = -es->char_width; + break; + case SB_LINERIGHT: + if (es->x_offset < es->text_width) + dx = es->char_width; + break; + case SB_PAGELEFT: + if (es->x_offset) + dx = -fw / HSCROLL_FRACTION / es->char_width * es->char_width; + break; + case SB_PAGERIGHT: + if (es->x_offset < es->text_width) + dx = fw / HSCROLL_FRACTION / es->char_width * es->char_width; + break; + case SB_LEFT: + if (es->x_offset) + dx = -es->x_offset; + break; + case SB_RIGHT: + if (es->x_offset < es->text_width) + dx = es->text_width - es->x_offset; + break; + case SB_THUMBTRACK: + es->flags |= EF_HSCROLL_TRACK; + dx = pos * es->text_width / 100 - es->x_offset; + break; + case SB_THUMBPOSITION: + es->flags &= ~EF_HSCROLL_TRACK; + if (!(dx = pos * es->text_width / 100 - es->x_offset)) + EDIT_NOTIFY_PARENT(wnd, EN_HSCROLL, "EN_HSCROLL"); + break; + case SB_ENDSCROLL: + break; + + /* + * FIXME : the next two are undocumented ! + * Are we doing the right thing ? + * At least Win 3.1 Notepad makes use of EM_GETTHUMB this way, + * although it's also a regular control message. + */ + case EM_GETTHUMB: + ret = es->text_width ? es->x_offset * 100 / es->text_width : 0; + break; + case EM_LINESCROLL: + dx = pos; + break; + + default: + DPRINT( "undocumented (hacked) WM_HSCROLL parameter, please report\n"); + return 0; + } + if (dx) + EDIT_EM_LineScroll(wnd, es, dx, 0); + return ret; +} + + +/********************************************************************* + * + * WM_HSCROLL + * + */ +static LRESULT EDIT_WM_HScroll(WND *wnd, EDITSTATE *es, INT action, INT pos, HWND scroll_bar) +{ + INT dx; + INT fw; + + if (!(es->style & ES_MULTILINE)) + return 0; + + if (!(es->style & ES_AUTOHSCROLL)) + return 0; + + if (!(es->style & WS_HSCROLL)) + return EDIT_HScroll_Hack(wnd, es, action, pos, scroll_bar); + + dx = 0; + fw = es->format_rect.right - es->format_rect.left; + switch (action) { + case SB_LINELEFT: + if (es->x_offset) + dx = -es->char_width; + break; + case SB_LINERIGHT: + if (es->x_offset < es->text_width) + dx = es->char_width; + break; + case SB_PAGELEFT: + if (es->x_offset) + dx = -fw / HSCROLL_FRACTION / es->char_width * es->char_width; + break; + case SB_PAGERIGHT: + if (es->x_offset < es->text_width) + dx = fw / HSCROLL_FRACTION / es->char_width * es->char_width; + break; + case SB_LEFT: + if (es->x_offset) + dx = -es->x_offset; + break; + case SB_RIGHT: + if (es->x_offset < es->text_width) + dx = es->text_width - es->x_offset; + break; + case SB_THUMBTRACK: + es->flags |= EF_HSCROLL_TRACK; + dx = pos - es->x_offset; + break; + case SB_THUMBPOSITION: + es->flags &= ~EF_HSCROLL_TRACK; + if (!(dx = pos - es->x_offset)) { + SetScrollPos(wnd->hwndSelf, SB_HORZ, pos, TRUE); + EDIT_NOTIFY_PARENT(wnd, EN_HSCROLL, "EN_HSCROLL"); + } + break; + case SB_ENDSCROLL: + break; + + default: + DPRINT( "undocumented WM_HSCROLL parameter, please report\n"); + return 0; + } + if (dx) + EDIT_EM_LineScroll(wnd, es, dx, 0); + return 0; +} + + +/********************************************************************* + * + * EDIT_CheckCombo + * + */ +static BOOL EDIT_CheckCombo(WND *wnd, UINT msg, INT key, DWORD key_data) +{ + HWND hLBox; + + if (WIDGETS_IsControl(wnd->parent, BIC_COMBO) && + (hLBox = COMBO_GetLBWindow(wnd->parent))) { + HWND hCombo = wnd->parent->hwndSelf; + BOOL bUIFlip = TRUE; + + DPRINT( "[%04x]: handling msg %04x (%04x)\n", + wnd->hwndSelf, (UINT)msg, (UINT)key); + + switch (msg) { + case WM_KEYDOWN: /* Handle F4 and arrow keys */ + if (key != VK_F4) { + bUIFlip = (BOOL)SendMessageA(hCombo, CB_GETEXTENDEDUI, 0, 0); + if (SendMessageA(hCombo, CB_GETDROPPEDSTATE, 0, 0)) + bUIFlip = FALSE; + } + if (!bUIFlip) + SendMessageA(hLBox, WM_KEYDOWN, (WPARAM)key, 0); + else { + /* make sure ComboLBox pops up */ + SendMessageA(hCombo, CB_SETEXTENDEDUI, 0, 0); + SendMessageA(hLBox, WM_KEYDOWN, VK_F4, 0); + SendMessageA(hCombo, CB_SETEXTENDEDUI, 1, 0); + } + break; + case WM_SYSKEYDOWN: /* Handle Alt+up/down arrows */ + bUIFlip = (BOOL)SendMessageA(hCombo, CB_GETEXTENDEDUI, 0, 0); + if (bUIFlip) { + bUIFlip = (BOOL)SendMessageA(hCombo, CB_GETDROPPEDSTATE, 0, 0); + SendMessageA(hCombo, CB_SHOWDROPDOWN, (bUIFlip) ? FALSE : TRUE, 0); + } else + SendMessageA(hLBox, WM_KEYDOWN, VK_F4, 0); + break; + } + return TRUE; + } + return FALSE; +} + + +/********************************************************************* + * + * WM_KEYDOWN + * + * Handling of special keys that don't produce a WM_CHAR + * (i.e. non-printable keys) & Backspace & Delete + * + */ +static LRESULT EDIT_WM_KeyDown(WND *wnd, EDITSTATE *es, INT key, DWORD key_data) +{ + BOOL shift; + BOOL control; + + if (GetKeyState(VK_MENU) & 0x8000) + return 0; + + shift = GetKeyState(VK_SHIFT) & 0x8000; + control = GetKeyState(VK_CONTROL) & 0x8000; + + switch (key) { + case VK_F4: + case VK_UP: + if (EDIT_CheckCombo(wnd, WM_KEYDOWN, key, key_data)) + break; + if (key == VK_F4) + break; + /* fall through */ + case VK_LEFT: + if ((es->style & ES_MULTILINE) && (key == VK_UP)) + EDIT_MoveUp_ML(wnd, es, shift); + else + if (control) + EDIT_MoveWordBackward(wnd, es, shift); + else + EDIT_MoveBackward(wnd, es, shift); + break; + case VK_DOWN: + if (EDIT_CheckCombo(wnd, WM_KEYDOWN, key, key_data)) + break; + /* fall through */ + case VK_RIGHT: + if ((es->style & ES_MULTILINE) && (key == VK_DOWN)) + EDIT_MoveDown_ML(wnd, es, shift); + else if (control) + EDIT_MoveWordForward(wnd, es, shift); + else + EDIT_MoveForward(wnd, es, shift); + break; + case VK_HOME: + EDIT_MoveHome(wnd, es, shift); + break; + case VK_END: + EDIT_MoveEnd(wnd, es, shift); + break; + case VK_PRIOR: + if (es->style & ES_MULTILINE) + EDIT_MovePageUp_ML(wnd, es, shift); + break; + case VK_NEXT: + if (es->style & ES_MULTILINE) + EDIT_MovePageDown_ML(wnd, es, shift); + break; + case VK_BACK: + if (!(es->style & ES_READONLY) && !control) { + if (es->selection_start != es->selection_end) + EDIT_WM_Clear(wnd, es); + else { + /* delete character left of caret */ + EDIT_EM_SetSel(wnd, es, -1, 0, FALSE); + EDIT_MoveBackward(wnd, es, TRUE); + EDIT_WM_Clear(wnd, es); + } + } + break; + case VK_DELETE: + if (!(es->style & ES_READONLY) && !(shift && control)) { + if (es->selection_start != es->selection_end) { + if (shift) + EDIT_WM_Cut(wnd, es); + else + EDIT_WM_Clear(wnd, es); + } else { + if (shift) { + /* delete character left of caret */ + EDIT_EM_SetSel(wnd, es, -1, 0, FALSE); + EDIT_MoveBackward(wnd, es, TRUE); + EDIT_WM_Clear(wnd, es); + } else if (control) { + /* delete to end of line */ + EDIT_EM_SetSel(wnd, es, -1, 0, FALSE); + EDIT_MoveEnd(wnd, es, TRUE); + EDIT_WM_Clear(wnd, es); + } else { + /* delete character right of caret */ + EDIT_EM_SetSel(wnd, es, -1, 0, FALSE); + EDIT_MoveForward(wnd, es, TRUE); + EDIT_WM_Clear(wnd, es); + } + } + } + break; + case VK_INSERT: + if (shift) { + if (!(es->style & ES_READONLY)) + EDIT_WM_Paste(wnd, es); + } else if (control) + EDIT_WM_Copy(wnd, es); + break; + } + return 0; +} + + +/********************************************************************* + * + * WM_KILLFOCUS + * + */ +static LRESULT EDIT_WM_KillFocus(WND *wnd, EDITSTATE *es, HWND window_getting_focus) +{ + es->flags &= ~EF_FOCUSED; + DestroyCaret(); + if(!(es->style & ES_NOHIDESEL)) + EDIT_InvalidateText(wnd, es, es->selection_start, es->selection_end); + EDIT_NOTIFY_PARENT(wnd, EN_KILLFOCUS, "EN_KILLFOCUS"); + return 0; +} + + +/********************************************************************* + * + * WM_LBUTTONDBLCLK + * + * The caret position has been set on the WM_LBUTTONDOWN message + * + */ +static LRESULT EDIT_WM_LButtonDblClk(WND *wnd, EDITSTATE *es, DWORD keys, INT x, INT y) +{ + INT s; + INT e = es->selection_end; + INT l; + INT li; + INT ll; + + if (!(es->flags & EF_FOCUSED)) + return 0; + + l = EDIT_EM_LineFromChar(wnd, es, e); + li = EDIT_EM_LineIndex(wnd, es, l); + ll = EDIT_EM_LineLength(wnd, es, e); + s = li + EDIT_CallWordBreakProc (wnd, es, li, e - li, ll, WB_LEFT); + e = li + EDIT_CallWordBreakProc(wnd, es, li, e - li, ll, WB_RIGHT); + EDIT_EM_SetSel(wnd, es, s, e, FALSE); + EDIT_EM_ScrollCaret(wnd, es); + return 0; +} + + +/********************************************************************* + * + * WM_LBUTTONDOWN + * + */ +static LRESULT EDIT_WM_LButtonDown(WND *wnd, EDITSTATE *es, DWORD keys, INT x, INT y) +{ + INT e; + BOOL after_wrap; + + if (!(es->flags & EF_FOCUSED)) + return 0; + + SetCapture(wnd->hwndSelf); + EDIT_ConfinePoint(wnd, es, &x, &y); + e = EDIT_CharFromPos(wnd, es, x, y, &after_wrap); + EDIT_EM_SetSel(wnd, es, (keys & MK_SHIFT) ? es->selection_start : e, e, after_wrap); + EDIT_EM_ScrollCaret(wnd, es); + es->region_posx = es->region_posy = 0; + SetTimer(wnd->hwndSelf, 0, 100, NULL); + return 0; +} + + +/********************************************************************* + * + * WM_LBUTTONUP + * + */ +static LRESULT EDIT_WM_LButtonUp(WND *wnd, EDITSTATE *es, DWORD keys, INT x, INT y) +{ + if (GetCapture() == wnd->hwndSelf) { + KillTimer(wnd->hwndSelf, 0); + ReleaseCapture(); + } + return 0; +} + + +/********************************************************************* + * + * WM_MOUSEMOVE + * + */ +static LRESULT EDIT_WM_MouseMove(WND *wnd, EDITSTATE *es, DWORD keys, INT x, INT y) +{ + INT e; + BOOL after_wrap; + INT prex, prey; + + if (GetCapture() != wnd->hwndSelf) + return 0; + + /* + * FIXME: gotta do some scrolling if outside client + * area. Maybe reset the timer ? + */ + prex = x; prey = y; + EDIT_ConfinePoint(wnd, es, &x, &y); + es->region_posx = (prex < x) ? -1 : ((prex > x) ? 1 : 0); + es->region_posy = (prey < y) ? -1 : ((prey > y) ? 1 : 0); + e = EDIT_CharFromPos(wnd, es, x, y, &after_wrap); + EDIT_EM_SetSel(wnd, es, es->selection_start, e, after_wrap); + return 0; +} + + +/********************************************************************* + * + * WM_NCCREATE + * + */ +static LRESULT EDIT_WM_NCCreate(WND *wnd, LPCREATESTRUCTA cs) +{ + EDITSTATE *es; + + if (!(es = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*es)))) + return FALSE; + *(EDITSTATE **)wnd->wExtra = es; + + /* + * Note: since the EDITSTATE has not been fully initialized yet, + * we can't use any API calls that may send + * WM_XXX messages before WM_NCCREATE is completed. + */ + + if (!(es->heap = HeapCreate(0, 0x10000, 0))) + return FALSE; + es->style = cs->style; + + if ((es->style & WS_BORDER) && !(es->style & WS_DLGFRAME)) + wnd->dwStyle &= ~WS_BORDER; + + if (es->style & ES_MULTILINE) { + es->buffer_size = BUFSTART_MULTI; + es->buffer_limit = BUFLIMIT_MULTI; + if (es->style & WS_VSCROLL) + es->style |= ES_AUTOVSCROLL; + if (es->style & WS_HSCROLL) + es->style |= ES_AUTOHSCROLL; + es->style &= ~ES_PASSWORD; + if ((es->style & ES_CENTER) || (es->style & ES_RIGHT)) { + if (es->style & ES_RIGHT) + es->style &= ~ES_CENTER; + es->style &= ~WS_HSCROLL; + es->style &= ~ES_AUTOHSCROLL; + } + + /* FIXME: for now, all multi line controls are AUTOVSCROLL */ + es->style |= ES_AUTOVSCROLL; + } else { + es->buffer_size = BUFSTART_SINGLE; + es->buffer_limit = BUFLIMIT_SINGLE; + es->style &= ~ES_CENTER; + es->style &= ~ES_RIGHT; + es->style &= ~WS_HSCROLL; + es->style &= ~WS_VSCROLL; + es->style &= ~ES_AUTOVSCROLL; + es->style &= ~ES_WANTRETURN; + if (es->style & ES_UPPERCASE) { + es->style &= ~ES_LOWERCASE; + es->style &= ~ES_NUMBER; + } else if (es->style & ES_LOWERCASE) + es->style &= ~ES_NUMBER; + if (es->style & ES_PASSWORD) + es->password_char = '*'; + + /* FIXME: for now, all single line controls are AUTOHSCROLL */ + es->style |= ES_AUTOHSCROLL; + } + if (!(es->text = HeapAlloc(es->heap, 0, es->buffer_size + 1))) + return FALSE; + es->buffer_size = HeapSize(es->heap, 0, es->text) - 1; + if (!(es->undo_text = HeapAlloc(es->heap, 0, es->buffer_size + 1))) + return FALSE; + es->undo_buffer_size = HeapSize(es->heap, 0, es->undo_text) - 1; + *es->text = '\0'; + if (es->style & ES_MULTILINE) + if (!(es->first_line_def = HeapAlloc(es->heap, HEAP_ZERO_MEMORY, sizeof(LINEDEF)))) + return FALSE; + es->line_count = 1; + + return TRUE; +} + +/********************************************************************* + * + * WM_PAINT + * + */ +static void EDIT_WM_Paint(WND *wnd, EDITSTATE *es) +{ + PAINTSTRUCT ps; + INT i; + HDC dc; + HFONT old_font = 0; + RECT rc; + RECT rcLine; + RECT rcRgn; + BOOL rev = IsWindowEnabled(wnd->hwndSelf) && + ((es->flags & EF_FOCUSED) || + (es->style & ES_NOHIDESEL)); + + if (es->flags & EF_UPDATE) + EDIT_NOTIFY_PARENT(wnd, EN_UPDATE, "EN_UPDATE"); + + dc = BeginPaint(wnd->hwndSelf, &ps); + if(es->style & WS_BORDER) { + GetClientRect(wnd->hwndSelf, &rc); + if(es->style & ES_MULTILINE) { + if(es->style & WS_HSCROLL) rc.bottom++; + if(es->style & WS_VSCROLL) rc.right++; + } + Rectangle(dc, rc.left, rc.top, rc.right, rc.bottom); + } + IntersectClipRect(dc, es->format_rect.left, + es->format_rect.top, + es->format_rect.right, + es->format_rect.bottom); + if (es->style & ES_MULTILINE) { + GetClientRect(wnd->hwndSelf, &rc); + IntersectClipRect(dc, rc.left, rc.top, rc.right, rc.bottom); + } + if (es->font) + old_font = SelectObject(dc, es->font); + EDIT_SEND_CTLCOLOR(wnd, dc); + if (!IsWindowEnabled(wnd->hwndSelf)) + SetTextColor(dc, GetSysColor(COLOR_GRAYTEXT)); + GetClipBox(dc, &rcRgn); + if (es->style & ES_MULTILINE) { + INT vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height; + for (i = es->y_offset ; i <= MIN(es->y_offset + vlc, es->y_offset + es->line_count - 1) ; i++) { + EDIT_GetLineRect(wnd, es, i, 0, -1, &rcLine); + if (IntersectRect(&rc, &rcRgn, &rcLine)) + EDIT_PaintLine(wnd, es, dc, i, rev); + } + } else { + EDIT_GetLineRect(wnd, es, 0, 0, -1, &rcLine); + if (IntersectRect(&rc, &rcRgn, &rcLine)) + EDIT_PaintLine(wnd, es, dc, 0, rev); + } + if (es->font) + SelectObject(dc, old_font); + if (es->flags & EF_FOCUSED) + EDIT_SetCaretPos(wnd, es, es->selection_end, + es->flags & EF_AFTER_WRAP); + EndPaint(wnd->hwndSelf, &ps); + if ((es->style & WS_VSCROLL) && !(es->flags & EF_VSCROLL_TRACK)) { + INT vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height; + SCROLLINFO si; + si.cbSize = sizeof(SCROLLINFO); + si.fMask = SIF_PAGE | SIF_POS | SIF_RANGE | SIF_DISABLENOSCROLL; + si.nMin = 0; + si.nMax = es->line_count + vlc - 2; + si.nPage = vlc; + si.nPos = es->y_offset; + SetScrollInfo(wnd->hwndSelf, SB_VERT, &si, TRUE); + } + if ((es->style & WS_HSCROLL) && !(es->flags & EF_HSCROLL_TRACK)) { + SCROLLINFO si; + INT fw = es->format_rect.right - es->format_rect.left; + si.cbSize = sizeof(SCROLLINFO); + si.fMask = SIF_PAGE | SIF_POS | SIF_RANGE | SIF_DISABLENOSCROLL; + si.nMin = 0; + si.nMax = es->text_width + fw - 1; + si.nPage = fw; + si.nPos = es->x_offset; + SetScrollInfo(wnd->hwndSelf, SB_HORZ, &si, TRUE); + } + + if (es->flags & EF_UPDATE) { + es->flags &= ~EF_UPDATE; + EDIT_NOTIFY_PARENT(wnd, EN_CHANGE, "EN_CHANGE"); + } +} + + +/********************************************************************* + * + * WM_PASTE + * + */ +static void EDIT_WM_Paste(WND *wnd, EDITSTATE *es) +{ + HGLOBAL hsrc; + LPSTR src; + + OpenClipboard(wnd->hwndSelf); + if ((hsrc = GetClipboardData(CF_TEXT))) { + src = (LPSTR)GlobalLock(hsrc); + EDIT_EM_ReplaceSel(wnd, es, TRUE, src); + GlobalUnlock(hsrc); + } + CloseClipboard(); +} + + +/********************************************************************* + * + * WM_SETFOCUS + * + */ +static void EDIT_WM_SetFocus(WND *wnd, EDITSTATE *es, HWND window_losing_focus) +{ + es->flags |= EF_FOCUSED; + CreateCaret(wnd->hwndSelf, 0, 2, es->line_height); + EDIT_SetCaretPos(wnd, es, es->selection_end, + es->flags & EF_AFTER_WRAP); + if(!(es->style & ES_NOHIDESEL)) + EDIT_InvalidateText(wnd, es, es->selection_start, es->selection_end); + ShowCaret(wnd->hwndSelf); + EDIT_NOTIFY_PARENT(wnd, EN_SETFOCUS, "EN_SETFOCUS"); +} + + +/********************************************************************* + * + * WM_SETFONT + * + * With Win95 look the margins are set to default font value unless + * the system font (font == 0) is being set, in which case they are left + * unchanged. + * + */ +static void EDIT_WM_SetFont(WND *wnd, EDITSTATE *es, HFONT font, BOOL redraw) +{ + TEXTMETRIC tm; + HDC dc; + HFONT old_font = 0; + + es->font = font; + dc = GetDC(wnd->hwndSelf); + if (font) + old_font = SelectObject(dc, font); + GetTextMetricsA(dc, &tm); + es->line_height = tm.tmHeight; + es->char_width = tm.tmAveCharWidth; + if (font) + SelectObject(dc, old_font); + ReleaseDC(wnd->hwndSelf, dc); + if (font && (TWEAK_WineLook > WIN31_LOOK)) + EDIT_EM_SetMargins(wnd, es, EC_LEFTMARGIN | EC_RIGHTMARGIN, + EC_USEFONTINFO, EC_USEFONTINFO); + if (es->style & ES_MULTILINE) + EDIT_BuildLineDefs_ML(wnd, es); + else { + RECT r; + GetClientRect(wnd->hwndSelf, &r); + EDIT_SetRectNP(wnd, es, &r); + } + if (redraw) + InvalidateRect(wnd->hwndSelf, NULL, TRUE); + if (es->flags & EF_FOCUSED) { + DestroyCaret(); + CreateCaret(wnd->hwndSelf, 0, 2, es->line_height); + EDIT_SetCaretPos(wnd, es, es->selection_end, + es->flags & EF_AFTER_WRAP); + ShowCaret(wnd->hwndSelf); + } +} + + +/********************************************************************* + * + * WM_SETTEXT + * + * NOTES + * For multiline controls (ES_MULTILINE), reception of WM_SETTEXT triggers: + * The modified flag is reset. No notifications are sent. + * + * For single-line controls, reception of WM_SETTEXT triggers: + * The modified flag is reset. EN_UPDATE and EN_CHANGE notifications are sent. + * + */ +static void EDIT_WM_SetText(WND *wnd, EDITSTATE *es, LPCSTR text) +{ + EDIT_EM_SetSel(wnd, es, 0, -1, FALSE); + if (text) { + DPRINT( "\t'%s'\n", text); + EDIT_EM_ReplaceSel(wnd, es, FALSE, text); + } else { + DPRINT( "\t\n"); + EDIT_EM_ReplaceSel(wnd, es, FALSE, ""); + } + es->x_offset = 0; + if (es->style & ES_MULTILINE) { + es->flags &= ~EF_UPDATE; + } else { + es->flags |= EF_UPDATE; + } + es->flags &= ~EF_MODIFIED; + EDIT_EM_SetSel(wnd, es, 0, 0, FALSE); + EDIT_EM_ScrollCaret(wnd, es); +} + + +/********************************************************************* + * + * WM_SIZE + * + */ +static void EDIT_WM_Size(WND *wnd, EDITSTATE *es, UINT action, INT width, INT height) +{ + if ((action == SIZE_MAXIMIZED) || (action == SIZE_RESTORED)) { + RECT rc; + SetRect(&rc, 0, 0, width, height); + EDIT_SetRectNP(wnd, es, &rc); + InvalidateRect(wnd->hwndSelf, NULL, TRUE); + } +} + + +/********************************************************************* + * + * WM_SYSKEYDOWN + * + */ +static LRESULT EDIT_WM_SysKeyDown(WND *wnd, EDITSTATE *es, INT key, DWORD key_data) +{ + if ((key == VK_BACK) && (key_data & 0x2000)) { + if (EDIT_EM_CanUndo(wnd, es)) + EDIT_EM_Undo(wnd, es); + return 0; + } else if (key == VK_UP || key == VK_DOWN) + if (EDIT_CheckCombo(wnd, WM_SYSKEYDOWN, key, key_data)) + return 0; + return DefWindowProcA(wnd->hwndSelf, WM_SYSKEYDOWN, (WPARAM)key, (LPARAM)key_data); +} + + +/********************************************************************* + * + * WM_TIMER + * + */ +static void EDIT_WM_Timer(WND *wnd, EDITSTATE *es, INT id, TIMERPROC timer_proc) +{ + if (es->region_posx < 0) { + EDIT_MoveBackward(wnd, es, TRUE); + } else if (es->region_posx > 0) { + EDIT_MoveForward(wnd, es, TRUE); + } +/* + * FIXME: gotta do some vertical scrolling here, like + * EDIT_EM_LineScroll(wnd, 0, 1); + */ +} + + +/********************************************************************* + * + * EDIT_VScroll_Hack + * + * 16 bit notepad needs this. Actually it is not _our_ hack, + * it is notepad's. Notepad is sending us scrollbar messages with + * undocumented parameters without us even having a scrollbar ... !?!? + * + */ +static LRESULT EDIT_VScroll_Hack(WND *wnd, EDITSTATE *es, INT action, INT pos, HWND scroll_bar) +{ + INT dy = 0; + LRESULT ret = 0; + + if (!(es->flags & EF_VSCROLL_HACK)) { + DPRINT( "hacked WM_VSCROLL handler invoked\n"); + DPRINT( " if you are _not_ running 16 bit notepad, please report\n"); + DPRINT( " (this message is only displayed once per edit control)\n"); + es->flags |= EF_VSCROLL_HACK; + } + + switch (action) { + case SB_LINEUP: + case SB_LINEDOWN: + case SB_PAGEUP: + case SB_PAGEDOWN: + EDIT_EM_Scroll(wnd, es, action); + return 0; + case SB_TOP: + dy = -es->y_offset; + break; + case SB_BOTTOM: + dy = es->line_count - 1 - es->y_offset; + break; + case SB_THUMBTRACK: + es->flags |= EF_VSCROLL_TRACK; + dy = (pos * (es->line_count - 1) + 50) / 100 - es->y_offset; + break; + case SB_THUMBPOSITION: + es->flags &= ~EF_VSCROLL_TRACK; + if (!(dy = (pos * (es->line_count - 1) + 50) / 100 - es->y_offset)) + EDIT_NOTIFY_PARENT(wnd, EN_VSCROLL, "EN_VSCROLL"); + break; + case SB_ENDSCROLL: + break; + + /* + * FIXME : the next two are undocumented ! + * Are we doing the right thing ? + * At least Win 3.1 Notepad makes use of EM_GETTHUMB this way, + * although it's also a regular control message. + */ + case EM_GETTHUMB: + ret = (es->line_count > 1) ? es->y_offset * 100 / (es->line_count - 1) : 0; + break; + case EM_LINESCROLL: + dy = pos; + break; + + default: + DPRINT( "undocumented (hacked) WM_VSCROLL parameter, please report\n"); + return 0; + } + if (dy) + EDIT_EM_LineScroll(wnd, es, 0, dy); + return ret; +} + + +/********************************************************************* + * + * WM_VSCROLL + * + */ +static LRESULT EDIT_WM_VScroll(WND *wnd, EDITSTATE *es, INT action, INT pos, HWND scroll_bar) +{ + INT dy; + + if (!(es->style & ES_MULTILINE)) + return 0; + + if (!(es->style & ES_AUTOVSCROLL)) + return 0; + + if (!(es->style & WS_VSCROLL)) + return EDIT_VScroll_Hack(wnd, es, action, pos, scroll_bar); + + dy = 0; + switch (action) { + case SB_LINEUP: + case SB_LINEDOWN: + case SB_PAGEUP: + case SB_PAGEDOWN: + EDIT_EM_Scroll(wnd, es, action); + return 0; + + case SB_TOP: + dy = -es->y_offset; + break; + case SB_BOTTOM: + dy = es->line_count - 1 - es->y_offset; + break; + case SB_THUMBTRACK: + es->flags |= EF_VSCROLL_TRACK; + dy = pos - es->y_offset; + break; + case SB_THUMBPOSITION: + es->flags &= ~EF_VSCROLL_TRACK; + if (!(dy = pos - es->y_offset)) { + SetScrollPos(wnd->hwndSelf, SB_VERT, pos, TRUE); + EDIT_NOTIFY_PARENT(wnd, EN_VSCROLL, "EN_VSCROLL"); + } + break; + case SB_ENDSCROLL: + break; + + default: + DPRINT( "undocumented WM_VSCROLL action %d, please report\n", + action); + return 0; + } + if (dy) + EDIT_EM_LineScroll(wnd, es, 0, dy); + return 0; +} + +// temporary hack + +WINBOOL STDCALL IsClipboardFormatAvailable( + UINT format + ) +{ + return FALSE; +} + +WINBOOL +STDCALL +OpenClipboard( + HWND hWndNewOwner) +{ + return FALSE; +} + +WINBOOL +STDCALL +CloseClipboard( + VOID) +{ + return TRUE; +} + +WINBOOL +STDCALL +EmptyClipboard( + VOID) +{ + return TRUE; +} + +HANDLE +STDCALL +SetClipboardData( + UINT uFormat, + HANDLE hMem) +{ + return NULL; +} + + +HANDLE +STDCALL +GetClipboardData( + UINT uFormat) +{ + return NULL; +} \ No newline at end of file diff --git a/reactos/lib/user32/controls/icontitle.c b/reactos/lib/user32/controls/icontitle.c new file mode 100644 index 00000000000..c125ba6135f --- /dev/null +++ b/reactos/lib/user32/controls/icontitle.c @@ -0,0 +1,242 @@ +/* + * Icontitle window class. + * + * Copyright 1997 Alex Korobka + */ + +#include +#include +#include +#include +#include + +#define WM_ISACTIVEICON 0x0035 + +static LPCSTR emptyTitleText = "<...>"; + + WINBOOL bMultiLineTitle; + HFONT hIconTitleFont; + +/*********************************************************************** + * ICONTITLE_Init + */ +WINBOOL ICONTITLE_Init(void) +{ + LOGFONT logFont; + + SystemParametersInfoA( SPI_GETICONTITLELOGFONT, 0, &logFont, 0 ); + SystemParametersInfoA( SPI_GETICONTITLEWRAP, 0, &bMultiLineTitle, 0 ); + hIconTitleFont = CreateFontIndirectA( &logFont ); + return (hIconTitleFont) ? TRUE : FALSE; +} + +/*********************************************************************** + * ICONTITLE_Create + */ +HWND ICONTITLE_Create( WND* wnd ) +{ + WND* wndPtr; + HWND hWnd; + + if( wnd->dwStyle & WS_CHILD ) + hWnd = CreateWindowExA( 0, ICONTITLE_CLASS_ATOM, NULL, + WS_CHILD | WS_CLIPSIBLINGS, 0, 0, 1, 1, + wnd->parent->hwndSelf, 0, wnd->hInstance, NULL ); + else + hWnd = CreateWindowExA( 0, ICONTITLE_CLASS_ATOM, NULL, + WS_CLIPSIBLINGS, 0, 0, 1, 1, + wnd->hwndSelf, 0, wnd->hInstance, NULL ); + wndPtr = WIN_FindWndPtr( hWnd ); + if( wndPtr ) + { + wndPtr->owner = wnd; /* MDI depends on this */ + wndPtr->dwStyle &= ~(WS_CAPTION | WS_BORDER); + if( wnd->dwStyle & WS_DISABLED ) wndPtr->dwStyle |= WS_DISABLED; + return hWnd; + } + return 0; +} + +/*********************************************************************** + * ICONTITLE_GetTitlePos + */ +WINBOOL ICONTITLE_GetTitlePos( WND* wnd, LPRECT lpRect ) +{ + LPSTR str; + int length = lstrlenA( wnd->owner->text ); + + if( length ) + { + str = HeapAlloc( GetProcessHeap(), 0, length + 1 ); + lstrcpyA( str, wnd->owner->text ); + while( str[length - 1] == ' ' ) /* remove trailing spaces */ + { + str[--length] = '\0'; + if( !length ) + { + HeapFree( GetProcessHeap(), 0, str ); + break; + } + } + } + if( !length ) + { + str = (LPSTR)emptyTitleText; + length = lstrlenA( str ); + } + + if( str ) + { + HDC hDC = GetDC( wnd->hwndSelf ); + if( hDC ) + { + HFONT hPrevFont = SelectObject( hDC, hIconTitleFont ); + + SetRect( lpRect, 0, 0, sysMetrics[SM_CXICONSPACING] - + SYSMETRICS_CXBORDER * 2, SYSMETRICS_CYBORDER * 2 ); + + DrawTextA( hDC, str, length, lpRect, DT_CALCRECT | + DT_CENTER | DT_NOPREFIX | DT_WORDBREAK | + (( bMultiLineTitle ) ? 0 : DT_SINGLELINE) ); + + SelectObject( hDC, hPrevFont ); + ReleaseDC( wnd->hwndSelf, hDC ); + + lpRect->right += 4 * SYSMETRICS_CXBORDER - lpRect->left; + lpRect->left = wnd->owner->rectWindow.left + SYSMETRICS_CXICON / 2 - + (lpRect->right - lpRect->left) / 2; + lpRect->bottom -= lpRect->top; + lpRect->top = wnd->owner->rectWindow.top + SYSMETRICS_CYICON; + } + if( str != emptyTitleText ) HeapFree( GetProcessHeap(), 0, str ); + return ( hDC ) ? TRUE : FALSE; + } + return FALSE; +} + +/*********************************************************************** + * ICONTITLE_Paint + */ +WINBOOL ICONTITLE_Paint( WND* wnd, HDC hDC, WINBOOL bActive ) +{ + HFONT hPrevFont; + HBRUSH hBrush = 0; + COLORREF textColor = 0; + + if( bActive ) + { + hBrush = GetSysColorBrush(COLOR_ACTIVECAPTION); + textColor = GetSysColor(COLOR_CAPTIONTEXT); + } + else + { + if( wnd->dwStyle & WS_CHILD ) + { + hBrush = wnd->parent->class->hbrBackground; + if( hBrush ) + { + INT level; + LOGBRUSH logBrush; + GetObjectA( hBrush, sizeof(logBrush), &logBrush ); + level = GetRValue(logBrush.lbColor) + + GetGValue(logBrush.lbColor) + + GetBValue(logBrush.lbColor); + if( level < (0x7F * 3) ) + textColor = RGB( 0xFF, 0xFF, 0xFF ); + } + else + hBrush = GetStockObject( WHITE_BRUSH ); + } + else + { + hBrush = GetStockObject( BLACK_BRUSH ); + textColor = RGB( 0xFF, 0xFF, 0xFF ); + } + } + + FillWindow( wnd->parent->hwndSelf, wnd->hwndSelf, hDC, hBrush ); + + hPrevFont = SelectObject( hDC, hIconTitleFont ); + if( hPrevFont ) + { + RECT rect; + INT length; + char buffer[80]; + + rect.left = rect.top = 0; + rect.right = wnd->rectWindow.right - wnd->rectWindow.left; + rect.bottom = wnd->rectWindow.bottom - wnd->rectWindow.top; + + length = GetWindowTextA( wnd->owner->hwndSelf, buffer, 80 ); + SetTextColor( hDC, textColor ); + SetBkMode( hDC, TRANSPARENT ); + + DrawTextA( hDC, buffer, length, &rect, DT_CENTER | DT_NOPREFIX | + DT_WORDBREAK | ((bMultiLineTitle) ? 0 : DT_SINGLELINE) ); + + SelectObject( hDC, hPrevFont ); + } + return ( hPrevFont ) ? TRUE : FALSE; +} + +/*********************************************************************** + * IconTitleWndProc + */ +LRESULT WINAPI IconTitleWndProc( HWND hWnd, UINT msg, + WPARAM wParam, LPARAM lParam ) +{ + WND *wnd = WIN_FindWndPtr( hWnd ); + + switch( msg ) + { + case WM_NCHITTEST: + return HTCAPTION; + + case WM_NCMOUSEMOVE: + case WM_NCLBUTTONDBLCLK: + return SendMessageA( wnd->owner->hwndSelf, msg, wParam, lParam ); + + case WM_ACTIVATE: + if( wParam ) SetActiveWindow( wnd->owner->hwndSelf ); + /* fall through */ + + case WM_CLOSE: + return 0; + + case WM_SHOWWINDOW: + if( wnd && wParam ) + { + RECT titleRect; + + ICONTITLE_GetTitlePos( wnd, &titleRect ); + if( wnd->owner->next != wnd ) /* keep icon title behind the owner */ + SetWindowPos( hWnd, wnd->owner->hwndSelf, + titleRect.left, titleRect.top, + titleRect.right, titleRect.bottom, SWP_NOACTIVATE ); + else + SetWindowPos( hWnd, 0, titleRect.left, titleRect.top, + titleRect.right, titleRect.bottom, + SWP_NOACTIVATE | SWP_NOZORDER ); + } + return 0; + + case WM_ERASEBKGND: + if( wnd ) + { + WND* iconWnd = wnd->owner; + + if( iconWnd->dwStyle & WS_CHILD ) + lParam = SendMessageA( iconWnd->hwndSelf, WM_ISACTIVEICON, 0, 0 ); + else + lParam = (iconWnd->hwndSelf == GetActiveWindow()); + + if( ICONTITLE_Paint( wnd, (HDC)wParam, (WINBOOL)lParam ) ) + ValidateRect( hWnd, NULL ); + return 1; + } + } + + return DefWindowProcA( hWnd, msg, wParam, lParam ); +} + + diff --git a/reactos/lib/user32/controls/listbox.c b/reactos/lib/user32/controls/listbox.c new file mode 100644 index 00000000000..362132ef6b4 --- /dev/null +++ b/reactos/lib/user32/controls/listbox.c @@ -0,0 +1,2557 @@ +/* + * Listbox controls + * + * Copyright 1996 Alexandre Julliard + */ + +#include +#include +#include +#include +#include +#include +#include + +#define MAX_DOS_DRIVES 26 + +#define MAX(x,y) x > y ? x : y +#define MIN(x,y) x < y ? x : y +#define abs(x) ((x) < 0 ? -(x) : (x)) + +#define WM_LBTRACKPOINT 0x0131 +#define WS_EX_DRAGDETECT 0x00000002L + + /* D&D messages */ +#define WM_DROPOBJECT 0x022A +#define WM_QUERYDROPOBJECT 0x022B +#define WM_BEGINDRAG 0x022C +#define WM_DRAGLOOP 0x022D +#define WM_DRAGSELECT 0x022E +#define WM_DRAGMOVE 0x022F + + +/* Unimplemented yet: + * - LBS_NOSEL + * - LBS_USETABSTOPS + * - Unicode + * - Locale handling + */ + +/* Items array granularity */ +#define LB_ARRAY_GRANULARITY 16 + +/* Scrolling timeout in ms */ +#define LB_SCROLL_TIMEOUT 50 + +/* Listbox system timer id */ +#define LB_TIMER_ID 2 + +/* Item structure */ +typedef struct +{ + LPSTR str; /* Item text */ + BOOL selected; /* Is item selected? */ + UINT height; /* Item height (only for OWNERDRAWVARIABLE) */ + DWORD data; /* User data */ +} LB_ITEMDATA; + +/* Listbox structure */ +typedef struct +{ + HANDLE heap; /* Heap for this listbox */ + HWND owner; /* Owner window to send notifications to */ + UINT style; /* Window style */ + INT width; /* Window width */ + INT height; /* Window height */ + LB_ITEMDATA *items; /* Array of items */ + INT nb_items; /* Number of items */ + INT top_item; /* Top visible item */ + INT selected_item; /* Selected item */ + INT focus_item; /* Item that has the focus */ + INT anchor_item; /* Anchor item for extended selection */ + INT item_height; /* Default item height */ + INT page_size; /* Items per listbox page */ + INT column_width; /* Column width for multi-column listboxes */ + INT horz_extent; /* Horizontal extent (0 if no hscroll) */ + INT horz_pos; /* Horizontal position */ + INT nb_tabs; /* Number of tabs in array */ + INT *tabs; /* Array of tabs */ + BOOL caret_on; /* Is caret on? */ + HFONT font; /* Current font */ + LCID locale; /* Current locale for string comparisons */ + LPHEADCOMBO lphc; /* ComboLBox */ +} LB_DESCR; + + +#define IS_OWNERDRAW(descr) \ + ((descr)->style & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE)) + +#define HAS_STRINGS(descr) \ + (!IS_OWNERDRAW(descr) || ((descr)->style & LBS_HASSTRINGS)) + +#define SEND_NOTIFICATION(wnd,descr,code) \ + (SendMessageA( (descr)->owner, WM_COMMAND, \ + MAKEWPARAM((((descr)->lphc)?ID_CB_LISTBOX:(wnd)->wIDmenu), (code) ), (LPARAM)(wnd)->hwndSelf )) + +/* Current timer status */ +typedef enum +{ + LB_TIMER_NONE, + LB_TIMER_UP, + LB_TIMER_LEFT, + LB_TIMER_DOWN, + LB_TIMER_RIGHT +} TIMER_DIRECTION; + +static TIMER_DIRECTION LISTBOX_Timer = LB_TIMER_NONE; + + +/*********************************************************************** + * LISTBOX_DPRINT + */ +void LISTBOX_DPRINT( WND *wnd ) +{ + INT i; + LB_ITEMDATA *item; + LB_DESCR *descr = *(LB_DESCR **)wnd->wExtra; + + DPRINT( "Listbox:\n" ); + DPRINT( "hwnd=%04x descr=%08x heap=%08x items=%d top=%d\n", + wnd->hwndSelf, (UINT)descr, descr->heap, descr->nb_items, + descr->top_item ); + for (i = 0, item = descr->items; i < descr->nb_items; i++, item++) + { + DPRINT( "%4d: %-40s %d %08lx %3d\n", + i, item->str, item->selected, item->data, item->height ); + } +} + + +/*********************************************************************** + * LISTBOX_GetCurrentPageSize + * + * Return the current page size + */ +static INT LISTBOX_GetCurrentPageSize( WND *wnd, LB_DESCR *descr ) +{ + INT i, height; + if (!(descr->style & LBS_OWNERDRAWVARIABLE)) return descr->page_size; + for (i = descr->top_item, height = 0; i < descr->nb_items; i++) + { + if ((height += descr->items[i].height) > descr->height) break; + } + if (i == descr->top_item) return 1; + else return i - descr->top_item; +} + + +/*********************************************************************** + * LISTBOX_GetMaxTopIndex + * + * Return the maximum possible index for the top of the listbox. + */ +static INT LISTBOX_GetMaxTopIndex( WND *wnd, LB_DESCR *descr ) +{ + INT max, page; + + if (descr->style & LBS_OWNERDRAWVARIABLE) + { + page = descr->height; + for (max = descr->nb_items - 1; max >= 0; max--) + if ((page -= descr->items[max].height) < 0) break; + if (max < descr->nb_items - 1) max++; + } + else if (descr->style & LBS_MULTICOLUMN) + { + if ((page = descr->width / descr->column_width) < 1) page = 1; + max = (descr->nb_items + descr->page_size - 1) / descr->page_size; + max = (max - page) * descr->page_size; + } + else + { + max = descr->nb_items - descr->page_size; + } + if (max < 0) max = 0; + return max; +} + + +/*********************************************************************** + * LISTBOX_UpdateScroll + * + * Update the scrollbars. Should be called whenever the content + * of the listbox changes. + */ +static void LISTBOX_UpdateScroll( WND *wnd, LB_DESCR *descr ) +{ + SCROLLINFO info; + + if (!(descr->style & WS_VSCROLL)) return; + /* It is important that we check descr->style, and not wnd->dwStyle, + for WS_VSCROLL, as the former is exactly the one passed in + argument to CreateWindow. + In Windows (and from now on in Wine :) a listbox created + with such a style (no WS_SCROLL) does not update + the scrollbar with listbox-related data, thus letting + the programmer use it for his/her own purposes. */ + + if (descr->style & LBS_NOREDRAW) return; + info.cbSize = sizeof(info); + + if (descr->style & LBS_MULTICOLUMN) + { + info.nMin = 0; + info.nMax = (descr->nb_items - 1) / descr->page_size; + info.nPos = descr->top_item / descr->page_size; + info.nPage = descr->width / descr->column_width; + if (info.nPage < 1) info.nPage = 1; + info.fMask = SIF_RANGE | SIF_POS | SIF_PAGE; + if (descr->style & LBS_DISABLENOSCROLL) + info.fMask |= SIF_DISABLENOSCROLL; + SetScrollInfo( wnd->hwndSelf, SB_HORZ, &info, TRUE ); + info.nMax = 0; + info.fMask = SIF_RANGE; + SetScrollInfo( wnd->hwndSelf, SB_VERT, &info, TRUE ); + } + else + { + info.nMin = 0; + info.nMax = descr->nb_items - 1; + info.nPos = descr->top_item; + info.nPage = LISTBOX_GetCurrentPageSize( wnd, descr ); + info.fMask = SIF_RANGE | SIF_POS | SIF_PAGE; + if (descr->style & LBS_DISABLENOSCROLL) + info.fMask |= SIF_DISABLENOSCROLL; + SetScrollInfo( wnd->hwndSelf, SB_VERT, &info, TRUE ); + + if (descr->horz_extent) + { + info.nMin = 0; + info.nMax = descr->horz_extent - 1; + info.nPos = descr->horz_pos; + info.nPage = descr->width; + info.fMask = SIF_RANGE | SIF_POS | SIF_PAGE; + if (descr->style & LBS_DISABLENOSCROLL) + info.fMask |= SIF_DISABLENOSCROLL; + SetScrollInfo( wnd->hwndSelf, SB_HORZ, &info, TRUE ); + } + } +} + + +/*********************************************************************** + * LISTBOX_SetTopItem + * + * Set the top item of the listbox, scrolling up or down if necessary. + */ +static LRESULT LISTBOX_SetTopItem( WND *wnd, LB_DESCR *descr, INT index, + BOOL scroll ) +{ + INT max = LISTBOX_GetMaxTopIndex( wnd, descr ); + if (index > max) index = max; + if (index < 0) index = 0; + if (descr->style & LBS_MULTICOLUMN) index -= index % descr->page_size; + if (descr->top_item == index) return LB_OKAY; + if (descr->style & LBS_MULTICOLUMN) + { + INT diff = (descr->top_item - index) / descr->page_size * descr->column_width; + if (scroll && (abs(diff) < descr->width)) + ScrollWindowEx( wnd->hwndSelf, diff, 0, NULL, NULL, 0, NULL, + SW_INVALIDATE | SW_ERASE ); + else + scroll = FALSE; + } + else if (scroll) + { + INT diff; + if (descr->style & LBS_OWNERDRAWVARIABLE) + { + INT i; + diff = 0; + if (index > descr->top_item) + { + for (i = index - 1; i >= descr->top_item; i--) + diff -= descr->items[i].height; + } + else + { + for (i = index; i < descr->top_item; i++) + diff += descr->items[i].height; + } + } + else + diff = (descr->top_item - index) * descr->item_height; + + if (abs(diff) < descr->height) + ScrollWindowEx( wnd->hwndSelf, 0, diff, NULL, NULL, 0, NULL, + SW_INVALIDATE | SW_ERASE ); + else + scroll = FALSE; + } + if (!scroll) InvalidateRect( wnd->hwndSelf, NULL, TRUE ); + descr->top_item = index; + LISTBOX_UpdateScroll( wnd, descr ); + return LB_OKAY; +} + + +/*********************************************************************** + * LISTBOX_UpdatePage + * + * Update the page size. Should be called when the size of + * the client area or the item height changes. + */ +static void LISTBOX_UpdatePage( WND *wnd, LB_DESCR *descr ) +{ + INT page_size; + + if ((page_size = descr->height / descr->item_height) < 1) page_size = 1; + if (page_size == descr->page_size) return; + descr->page_size = page_size; + if (descr->style & LBS_MULTICOLUMN) + InvalidateRect( wnd->hwndSelf, NULL, TRUE ); + LISTBOX_SetTopItem( wnd, descr, descr->top_item, FALSE ); +} + + +/*********************************************************************** + * LISTBOX_UpdateSize + * + * Update the size of the listbox. Should be called when the size of + * the client area changes. + */ +static void LISTBOX_UpdateSize( WND *wnd, LB_DESCR *descr ) +{ + RECT rect; + + GetClientRect( wnd->hwndSelf, &rect ); + descr->width = rect.right - rect.left; + descr->height = rect.bottom - rect.top; + if (!(descr->style & LBS_NOINTEGRALHEIGHT) && !IS_OWNERDRAW(descr)) + { + if ((descr->height > descr->item_height) && + (descr->height % descr->item_height)) + { + DPRINT( "[%04x]: changing height %d -> %d\n", + wnd->hwndSelf, descr->height, + descr->height - descr->height%descr->item_height ); + SetWindowPos( wnd->hwndSelf, 0, 0, 0, + wnd->rectWindow.right - wnd->rectWindow.left, + wnd->rectWindow.bottom - wnd->rectWindow.top - + (descr->height % descr->item_height), + SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE ); + return; + } + } + DPRINT( "[%04x]: new size = %d,%d\n", + wnd->hwndSelf, descr->width, descr->height ); + LISTBOX_UpdatePage( wnd, descr ); + LISTBOX_UpdateScroll( wnd, descr ); +} + + +/*********************************************************************** + * LISTBOX_GetItemRect + * + * Get the rectangle enclosing an item, in listbox client coordinates. + * Return 1 if the rectangle is (partially) visible, 0 if hidden, -1 on error. + */ +static LRESULT LISTBOX_GetItemRect( WND *wnd, LB_DESCR *descr, INT index, + RECT *rect ) +{ + /* Index <= 0 is legal even on empty listboxes */ + if (index && (index >= descr->nb_items)) return -1; + SetRect( rect, 0, 0, descr->width, descr->height ); + if (descr->style & LBS_MULTICOLUMN) + { + INT col = (index / descr->page_size) - + (descr->top_item / descr->page_size); + rect->left += col * descr->column_width; + rect->right = rect->left + descr->column_width; + rect->top += (index % descr->page_size) * descr->item_height; + rect->bottom = rect->top + descr->item_height; + } + else if (descr->style & LBS_OWNERDRAWVARIABLE) + { + INT i; + rect->right += descr->horz_pos; + if ((index >= 0) && (index < descr->nb_items)) + { + if (index < descr->top_item) + { + for (i = descr->top_item-1; i >= index; i--) + rect->top -= descr->items[i].height; + } + else + { + for (i = descr->top_item; i < index; i++) + rect->top += descr->items[i].height; + } + rect->bottom = rect->top + descr->items[index].height; + + } + } + else + { + rect->top += (index - descr->top_item) * descr->item_height; + rect->bottom = rect->top + descr->item_height; + rect->right += descr->horz_pos; + } + + return ((rect->left < descr->width) && (rect->right > 0) && + (rect->top < descr->height) && (rect->bottom > 0)); +} + + +/*********************************************************************** + * LISTBOX_GetItemFromPoint + * + * Return the item nearest from point (x,y) (in client coordinates). + */ +static INT LISTBOX_GetItemFromPoint( WND *wnd, LB_DESCR *descr, + INT x, INT y ) +{ + INT index = descr->top_item; + + if (!descr->nb_items) return -1; /* No items */ + if (descr->style & LBS_OWNERDRAWVARIABLE) + { + INT pos = 0; + if (y >= 0) + { + while (index < descr->nb_items) + { + if ((pos += descr->items[index].height) > y) break; + index++; + } + } + else + { + while (index > 0) + { + index--; + if ((pos -= descr->items[index].height) <= y) break; + } + } + } + else if (descr->style & LBS_MULTICOLUMN) + { + if (y >= descr->item_height * descr->page_size) return -1; + if (y >= 0) index += y / descr->item_height; + if (x >= 0) index += (x / descr->column_width) * descr->page_size; + else index -= (((x + 1) / descr->column_width) - 1) * descr->page_size; + } + else + { + index += (y / descr->item_height); + } + if (index < 0) return 0; + if (index >= descr->nb_items) return -1; + return index; +} + + +/*********************************************************************** + * LISTBOX_PaintItem + * + * Paint an item. + */ +static void LISTBOX_PaintItem( WND *wnd, LB_DESCR *descr, HDC hdc, + const RECT *rect, INT index, UINT action ) +{ + LB_ITEMDATA *item = NULL; + if (index < descr->nb_items) item = &descr->items[index]; + + if (IS_OWNERDRAW(descr)) + { + DRAWITEMSTRUCT dis; + UINT id = (descr->lphc) ? ID_CB_LISTBOX : wnd->wIDmenu; + + dis.CtlType = ODT_LISTBOX; + dis.CtlID = id; + dis.hwndItem = wnd->hwndSelf; + dis.itemAction = action; + dis.hDC = hdc; + dis.itemID = index; + dis.itemState = 0; + if (item && item->selected) dis.itemState |= ODS_SELECTED; + if ((descr->focus_item == index) && + (descr->caret_on) && + (GetFocus() == wnd->hwndSelf)) dis.itemState |= ODS_FOCUS; + if (wnd->dwStyle & WS_DISABLED) dis.itemState |= ODS_DISABLED; + dis.itemData = item ? item->data : 0; + dis.rcItem = *rect; + DPRINT( "[%04x]: drawitem %d (%s) action=%02x " + "state=%02x rect=%d,%d-%d,%d\n", + wnd->hwndSelf, index, item ? item->str : "", action, + dis.itemState, rect->left, rect->top, + rect->right, rect->bottom ); + SendMessageA(descr->owner, WM_DRAWITEM, id, (LPARAM)&dis); + } + else + { + COLORREF oldText = 0, oldBk = 0; + + if (action == ODA_FOCUS) + { + DrawFocusRect( hdc, rect ); + return; + } + if (item && item->selected) + { + oldBk = SetBkColor( hdc, GetSysColor( COLOR_HIGHLIGHT ) ); + oldText = SetTextColor( hdc, GetSysColor(COLOR_HIGHLIGHTTEXT)); + } + + DPRINT( "[%04x]: painting %d (%s) action=%02x " + "rect=%d,%d-%d,%d\n", + wnd->hwndSelf, index, item ? item->str : "", action, + rect->left, rect->top, rect->right, rect->bottom ); + if (!item) + ExtTextOutA( hdc, rect->left + 1, rect->top + 1, + ETO_OPAQUE | ETO_CLIPPED, rect, NULL, 0, NULL ); + else if (!(descr->style & LBS_USETABSTOPS)) + ExtTextOutA( hdc, rect->left + 1, rect->top + 1, + ETO_OPAQUE | ETO_CLIPPED, rect, item->str, + strlen(item->str), NULL ); + else + { + /* Output empty string to paint background in the full width. */ + ExtTextOutA( hdc, rect->left + 1, rect->top + 1, + ETO_OPAQUE | ETO_CLIPPED, rect, NULL, 0, NULL ); + TabbedTextOutA( hdc, rect->left + 1 , rect->top + 1, + item->str, strlen(item->str), + descr->nb_tabs, descr->tabs, 0); + } + if (item && item->selected) + { + SetBkColor( hdc, oldBk ); + SetTextColor( hdc, oldText ); + } + if ((descr->focus_item == index) && + (descr->caret_on) && + (GetFocus() == wnd->hwndSelf)) DrawFocusRect( hdc, rect ); + } +} + + +/*********************************************************************** + * LISTBOX_SetRedraw + * + * Change the redraw flag. + */ +static void LISTBOX_SetRedraw( WND *wnd, LB_DESCR *descr, BOOL on ) +{ + if (on) + { + if (!(descr->style & LBS_NOREDRAW)) return; + descr->style &= ~LBS_NOREDRAW; + LISTBOX_UpdateScroll( wnd, descr ); + } + else descr->style |= LBS_NOREDRAW; +} + + +/*********************************************************************** + * LISTBOX_RepaintItem + * + * Repaint a single item synchronously. + */ +static void LISTBOX_RepaintItem( WND *wnd, LB_DESCR *descr, INT index, + UINT action ) +{ + HDC hdc; + RECT rect; + HFONT oldFont = 0; + HBRUSH hbrush, oldBrush = 0; + + if (descr->style & LBS_NOREDRAW) return; + if (LISTBOX_GetItemRect( wnd, descr, index, &rect ) != 1) return; + if (!(hdc = GetDCEx( wnd->hwndSelf, 0, DCX_CACHE ))) return; + if (descr->font) oldFont = SelectObject( hdc, descr->font ); + hbrush = (HBRUSH)SendMessageA( descr->owner, WM_CTLCOLORLISTBOX, + (WPARAM)hdc, (LPARAM)wnd->hwndSelf ); + if (hbrush) oldBrush = SelectObject( hdc, hbrush ); + if (wnd->dwStyle & WS_DISABLED) + SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) ); + SetWindowOrgEx( hdc, descr->horz_pos, 0, NULL ); + LISTBOX_PaintItem( wnd, descr, hdc, &rect, index, action ); + if (oldFont) SelectObject( hdc, oldFont ); + if (oldBrush) SelectObject( hdc, oldBrush ); + ReleaseDC( wnd->hwndSelf, hdc ); +} + + +/*********************************************************************** + * LISTBOX_InitStorage + */ +static LRESULT LISTBOX_InitStorage( WND *wnd, LB_DESCR *descr, INT nb_items, + DWORD bytes ) +{ + LB_ITEMDATA *item; + + nb_items += LB_ARRAY_GRANULARITY - 1; + nb_items -= (nb_items % LB_ARRAY_GRANULARITY); + if (descr->items) + nb_items += HeapSize( descr->heap, 0, descr->items ) / sizeof(*item); + if (!(item = HeapReAlloc( descr->heap, 0, descr->items, + nb_items * sizeof(LB_ITEMDATA) ))) + { + SEND_NOTIFICATION( wnd, descr, LBN_ERRSPACE ); + return LB_ERRSPACE; + } + descr->items = item; + return LB_OKAY; +} + + +/*********************************************************************** + * LISTBOX_SetTabStops + */ +static BOOL LISTBOX_SetTabStops( WND *wnd, LB_DESCR *descr, INT count, + LPINT tabs, BOOL short_ints ) +{ + if (!(descr->style & LBS_USETABSTOPS)) return TRUE; + if (descr->tabs) HeapFree( descr->heap, 0, descr->tabs ); + if (!(descr->nb_tabs = count)) + { + descr->tabs = NULL; + return TRUE; + } + /* FIXME: count = 1 */ + if (!(descr->tabs = (INT *)HeapAlloc( descr->heap, 0, + descr->nb_tabs * sizeof(INT) ))) + return FALSE; + if (short_ints) + { + INT i; + INT * p = (INT *)tabs; +// dbg_decl_str(listbox, 256); + + for (i = 0; i < descr->nb_tabs; i++) { + descr->tabs[i] = *p++<<1; /* FIXME */ + // if(TRACE_ON(listbox)) + // dsprintf(listbox, "%hd ", descr->tabs[i]); + } + DPRINT( "[%04x]: settabstops %s\n", + wnd->hwndSelf, dbg_str(listbox)); + } + else memcpy( descr->tabs, tabs, descr->nb_tabs * sizeof(INT) ); + /* FIXME: repaint the window? */ + return TRUE; +} + + +/*********************************************************************** + * LISTBOX_GetText + */ +static LRESULT LISTBOX_GetText( WND *wnd, LB_DESCR *descr, INT index, + LPSTR buffer ) +{ + if ((index < 0) || (index >= descr->nb_items)) return LB_ERR; + if (HAS_STRINGS(descr)) + { + if (!buffer) + return strlen(descr->items[index].str); + lstrcpyA( buffer, descr->items[index].str ); + return strlen(buffer); + } else { + if (buffer) + *((LPDWORD)buffer)=*(LPDWORD)(&descr->items[index].data); + return sizeof(DWORD); + } +} + + +/*********************************************************************** + * LISTBOX_FindStringPos + * + * Find the nearest string located before a given string in sort order. + * If 'exact' is TRUE, return an error if we don't get an exact match. + */ +static INT LISTBOX_FindStringPos( WND *wnd, LB_DESCR *descr, LPCSTR str, + BOOL exact ) +{ + INT index, min, max, res = -1; + + if (!(descr->style & LBS_SORT)) return -1; /* Add it at the end */ + min = 0; + max = descr->nb_items; + while (min != max) + { + index = (min + max) / 2; + if (HAS_STRINGS(descr)) + res = lstrcmpiA( descr->items[index].str, str ); + else + { + COMPAREITEMSTRUCT cis; + UINT id = (descr->lphc) ? ID_CB_LISTBOX : wnd->wIDmenu; + + cis.CtlType = ODT_LISTBOX; + cis.CtlID = id; + cis.hwndItem = wnd->hwndSelf; + cis.itemID1 = index; + cis.itemData1 = descr->items[index].data; + cis.itemID2 = -1; + cis.itemData2 = (DWORD)str; + //cis.dwLocaleId = descr->locale; + res = SendMessageA( descr->owner, WM_COMPAREITEM, + id, (LPARAM)&cis ); + } + if (!res) return index; + if (res > 0) max = index; + else min = index + 1; + } + return exact ? -1 : max; +} + + +/*********************************************************************** + * LISTBOX_FindFileStrPos + * + * Find the nearest string located before a given string in directory + * sort order (i.e. first files, then directories, then drives). + */ +static INT LISTBOX_FindFileStrPos( WND *wnd, LB_DESCR *descr, LPCSTR str ) +{ + INT min, max, res = -1; + + if (!HAS_STRINGS(descr)) + return LISTBOX_FindStringPos( wnd, descr, str, FALSE ); + min = 0; + max = descr->nb_items; + while (min != max) + { + INT index = (min + max) / 2; + const char *p = descr->items[index].str; + if (*p == '[') /* drive or directory */ + { + if (*str != '[') res = -1; + else if (p[1] == '-') /* drive */ + { + if (str[1] == '-') res = str[2] - p[2]; + else res = -1; + } + else /* directory */ + { + if (str[1] == '-') res = 1; + else res = lstrcmpiA( str, p ); + } + } + else /* filename */ + { + if (*str == '[') res = 1; + else res = lstrcmpiA( str, p ); + } + if (!res) return index; + if (res < 0) max = index; + else min = index + 1; + } + return max; +} + + +/*********************************************************************** + * LISTBOX_FindString + * + * Find the item beginning with a given string. + */ +static INT LISTBOX_FindString( WND *wnd, LB_DESCR *descr, INT start, + LPCSTR str, BOOL exact ) +{ + INT i; + LB_ITEMDATA *item; + + if (start >= descr->nb_items) start = -1; + item = descr->items + start + 1; + if (HAS_STRINGS(descr)) + { + if (!str) return LB_ERR; + if (exact) + { + for (i = start + 1; i < descr->nb_items; i++, item++) + if (!lstrcmpiA( str, item->str )) return i; + for (i = 0, item = descr->items; i <= start; i++, item++) + if (!lstrcmpiA( str, item->str )) return i; + } + else + { + /* Special case for drives and directories: ignore prefix */ +#define CHECK_DRIVE(item) \ + if ((item)->str[0] == '[') \ + { \ + if (!lstrcmpiA( str, (item)->str+1 )) return i; \ + if (((item)->str[1] == '-') && !lstrcmpiA(str,(item)->str+2)) \ + return i; \ + } + + INT len = lstrlenA(str); + for (i = start + 1; i < descr->nb_items; i++, item++) + { + if (!lstrcmpiA( str, item->str )) return i; + CHECK_DRIVE(item); + } + for (i = 0, item = descr->items; i <= start; i++, item++) + { + if (!lstrcmpiA( str, item->str )) return i; + CHECK_DRIVE(item); + } +#undef CHECK_DRIVE + } + } + else + { + if (exact && (descr->style & LBS_SORT)) + /* If sorted, use a WM_COMPAREITEM binary search */ + return LISTBOX_FindStringPos( wnd, descr, str, TRUE ); + + /* Otherwise use a linear search */ + for (i = start + 1; i < descr->nb_items; i++, item++) + if (item->data == (DWORD)str) return i; + for (i = 0, item = descr->items; i <= start; i++, item++) + if (item->data == (DWORD)str) return i; + } + return LB_ERR; +} + + +/*********************************************************************** + * LISTBOX_GetSelCount + */ +static LRESULT LISTBOX_GetSelCount( WND *wnd, LB_DESCR *descr ) +{ + INT i, count; + LB_ITEMDATA *item = descr->items; + + if (!(descr->style & LBS_MULTIPLESEL)) return LB_ERR; + for (i = count = 0; i < descr->nb_items; i++, item++) + if (item->selected) count++; + return count; +} + + + + +/*********************************************************************** + * LISTBOX_GetSelItems + */ +static LRESULT LISTBOX_GetSelItems( WND *wnd, LB_DESCR *descr, INT max, + LPINT array ) +{ + INT i, count; + LB_ITEMDATA *item = descr->items; + + if (!(descr->style & LBS_MULTIPLESEL)) return LB_ERR; + for (i = count = 0; (i < descr->nb_items) && (count < max); i++, item++) + if (item->selected) array[count++] = i; + return count; +} + + +/*********************************************************************** + * LISTBOX_Paint + */ +static LRESULT LISTBOX_Paint( WND *wnd, LB_DESCR *descr, HDC hdc ) +{ + INT i, col_pos = descr->page_size - 1; + RECT rect; + HFONT oldFont = 0; + HBRUSH hbrush, oldBrush = 0; + + SetRect( &rect, 0, 0, descr->width, descr->height ); + if (descr->style & LBS_NOREDRAW) return 0; + if (descr->style & LBS_MULTICOLUMN) + rect.right = rect.left + descr->column_width; + else if (descr->horz_pos) + { + SetWindowOrgEx( hdc, descr->horz_pos, 0, NULL ); + rect.right += descr->horz_pos; + } + + if (descr->font) oldFont = SelectObject( hdc, descr->font ); + hbrush = SendMessageA( descr->owner, WM_CTLCOLORLISTBOX, + (WPARAM)hdc, (LPARAM)wnd->hwndSelf ); + if (hbrush) oldBrush = SelectObject( hdc, hbrush ); + if (wnd->dwStyle & WS_DISABLED) + SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) ); + + if (!descr->nb_items && (descr->focus_item != -1) && descr->caret_on && + (GetFocus() == wnd->hwndSelf)) + { + /* Special case for empty listbox: paint focus rect */ + rect.bottom = rect.top + descr->item_height; + LISTBOX_PaintItem( wnd, descr, hdc, &rect, descr->focus_item, + ODA_FOCUS ); + rect.top = rect.bottom; + } + + for (i = descr->top_item; i < descr->nb_items; i++) + { + if (!(descr->style & LBS_OWNERDRAWVARIABLE)) + rect.bottom = rect.top + descr->item_height; + else + rect.bottom = rect.top + descr->items[i].height; + + LISTBOX_PaintItem( wnd, descr, hdc, &rect, i, ODA_DRAWENTIRE ); + rect.top = rect.bottom; + + if ((descr->style & LBS_MULTICOLUMN) && !col_pos) + { + if (!IS_OWNERDRAW(descr)) + { + /* Clear the bottom of the column */ + SetBkColor( hdc, GetSysColor( COLOR_WINDOW ) ); + if (rect.top < descr->height) + { + rect.bottom = descr->height; + ExtTextOutA( hdc, 0, 0, ETO_OPAQUE | ETO_CLIPPED, + &rect, NULL, 0, NULL ); + } + } + + /* Go to the next column */ + rect.left += descr->column_width; + rect.right += descr->column_width; + rect.top = 0; + col_pos = descr->page_size - 1; + } + else + { + col_pos--; + if (rect.top >= descr->height) break; + } + } + + if (!IS_OWNERDRAW(descr)) + { + /* Clear the remainder of the client area */ + SetBkColor( hdc, GetSysColor( COLOR_WINDOW ) ); + if (rect.top < descr->height) + { + rect.bottom = descr->height; + ExtTextOutA( hdc, 0, 0, ETO_OPAQUE | ETO_CLIPPED, + &rect, NULL, 0, NULL ); + } + if (rect.right < descr->width) + { + rect.left = rect.right; + rect.right = descr->width; + rect.top = 0; + rect.bottom = descr->height; + ExtTextOutA( hdc, 0, 0, ETO_OPAQUE | ETO_CLIPPED, + &rect, NULL, 0, NULL ); + } + } + if (oldFont) SelectObject( hdc, oldFont ); + if (oldBrush) SelectObject( hdc, oldBrush ); + return 0; +} + + +/*********************************************************************** + * LISTBOX_InvalidateItems + * + * Invalidate all items from a given item. If the specified item is not + * visible, nothing happens. + */ +static void LISTBOX_InvalidateItems( WND *wnd, LB_DESCR *descr, INT index ) +{ + RECT rect; + + if (LISTBOX_GetItemRect( wnd, descr, index, &rect ) == 1) + { + rect.bottom = descr->height; + InvalidateRect( wnd->hwndSelf, &rect, TRUE ); + if (descr->style & LBS_MULTICOLUMN) + { + /* Repaint the other columns */ + rect.left = rect.right; + rect.right = descr->width; + rect.top = 0; + InvalidateRect( wnd->hwndSelf, &rect, TRUE ); + } + } +} + + +/*********************************************************************** + * LISTBOX_GetItemHeight + */ +static LRESULT LISTBOX_GetItemHeight( WND *wnd, LB_DESCR *descr, INT index ) +{ + if (descr->style & LBS_OWNERDRAWVARIABLE) + { + if ((index < 0) || (index >= descr->nb_items)) return LB_ERR; + return descr->items[index].height; + } + else return descr->item_height; +} + + +/*********************************************************************** + * LISTBOX_SetItemHeight + */ +static LRESULT LISTBOX_SetItemHeight( WND *wnd, LB_DESCR *descr, INT index, + UINT height ) +{ + if (!height) height = 1; + + if (descr->style & LBS_OWNERDRAWVARIABLE) + { + if ((index < 0) || (index >= descr->nb_items)) return LB_ERR; + DPRINT( "[%04x]: item %d height = %d\n", + wnd->hwndSelf, index, height ); + descr->items[index].height = height; + LISTBOX_UpdateScroll( wnd, descr ); + LISTBOX_InvalidateItems( wnd, descr, index ); + } + else if (height != descr->item_height) + { + DPRINT( "[%04x]: new height = %d\n", + wnd->hwndSelf, height ); + descr->item_height = height; + LISTBOX_UpdatePage( wnd, descr ); + LISTBOX_UpdateScroll( wnd, descr ); + InvalidateRect( wnd->hwndSelf, 0, TRUE ); + } + return LB_OKAY; +} + + +/*********************************************************************** + * LISTBOX_SetHorizontalPos + */ +static void LISTBOX_SetHorizontalPos( WND *wnd, LB_DESCR *descr, INT pos ) +{ + INT diff; + + if (pos > descr->horz_extent - descr->width) + pos = descr->horz_extent - descr->width; + if (pos < 0) pos = 0; + if (!(diff = descr->horz_pos - pos)) return; + DPRINT( "[%04x]: new horz pos = %d\n", + wnd->hwndSelf, pos ); + descr->horz_pos = pos; + LISTBOX_UpdateScroll( wnd, descr ); + if (abs(diff) < descr->width) + ScrollWindowEx( wnd->hwndSelf, diff, 0, NULL, NULL, 0, NULL, + SW_INVALIDATE | SW_ERASE ); + else + InvalidateRect( wnd->hwndSelf, NULL, TRUE ); +} + + +/*********************************************************************** + * LISTBOX_SetHorizontalExtent + */ +static LRESULT LISTBOX_SetHorizontalExtent( WND *wnd, LB_DESCR *descr, + UINT extent ) +{ + if (!descr->horz_extent || (descr->style & LBS_MULTICOLUMN)) + return LB_OKAY; + if (extent <= 0) extent = 1; + if (extent == descr->horz_extent) return LB_OKAY; + DPRINT( "[%04x]: new horz extent = %d\n", + wnd->hwndSelf, extent ); + descr->horz_extent = extent; + if (descr->horz_pos > extent - descr->width) + LISTBOX_SetHorizontalPos( wnd, descr, extent - descr->width ); + else + LISTBOX_UpdateScroll( wnd, descr ); + return LB_OKAY; +} + + +/*********************************************************************** + * LISTBOX_SetColumnWidth + */ +static LRESULT LISTBOX_SetColumnWidth( WND *wnd, LB_DESCR *descr, UINT width) +{ + width += 2; /* For left and right margin */ + if (width == descr->column_width) return LB_OKAY; + DPRINT( "[%04x]: new column width = %d\n", + wnd->hwndSelf, width ); + descr->column_width = width; + LISTBOX_UpdatePage( wnd, descr ); + return LB_OKAY; +} + + +/*********************************************************************** + * LISTBOX_SetFont + * + * Returns the item height. + */ +static INT LISTBOX_SetFont( WND *wnd, LB_DESCR *descr, HFONT font ) +{ + HDC hdc; + HFONT oldFont = 0; + TEXTMETRIC tm; + + descr->font = font; + + if (!(hdc = GetDCEx( wnd->hwndSelf, 0, DCX_CACHE ))) + { + DPRINT("unable to get DC.\n" ); + return 16; + } + if (font) oldFont = SelectObject( hdc, font ); + GetTextMetricsA( hdc, &tm ); + if (oldFont) SelectObject( hdc, oldFont ); + ReleaseDC( wnd->hwndSelf, hdc ); + if (!IS_OWNERDRAW(descr)) + LISTBOX_SetItemHeight( wnd, descr, 0, tm.tmHeight ); + return tm.tmHeight ; +} + + +/*********************************************************************** + * LISTBOX_MakeItemVisible + * + * Make sure that a given item is partially or fully visible. + */ +static void LISTBOX_MakeItemVisible( WND *wnd, LB_DESCR *descr, INT index, + BOOL fully ) +{ + INT top; + + if (index <= descr->top_item) top = index; + else if (descr->style & LBS_MULTICOLUMN) + { + INT cols = descr->width; + if (!fully) cols += descr->column_width - 1; + if (cols >= descr->column_width) cols /= descr->column_width; + else cols = 1; + if (index < descr->top_item + (descr->page_size * cols)) return; + top = index - descr->page_size * (cols - 1); + } + else if (descr->style & LBS_OWNERDRAWVARIABLE) + { + INT height = fully ? descr->items[index].height : 1; + for (top = index; top > descr->top_item; top--) + if ((height += descr->items[top-1].height) > descr->height) break; + } + else + { + if (index < descr->top_item + descr->page_size) return; + if (!fully && (index == descr->top_item + descr->page_size) && + (descr->height > (descr->page_size * descr->item_height))) return; + top = index - descr->page_size + 1; + } + LISTBOX_SetTopItem( wnd, descr, top, TRUE ); +} + + +/*********************************************************************** + * LISTBOX_SelectItemRange + * + * Select a range of items. Should only be used on a MULTIPLESEL listbox. + */ +static LRESULT LISTBOX_SelectItemRange( WND *wnd, LB_DESCR *descr, INT first, + INT last, BOOL on ) +{ + INT i; + + /* A few sanity checks */ + + if ((last == -1) && (descr->nb_items == 0)) return LB_OKAY; + if (!(descr->style & LBS_MULTIPLESEL)) return LB_ERR; + if (last == -1) last = descr->nb_items - 1; + if ((first < 0) || (first >= descr->nb_items)) return LB_ERR; + if ((last < 0) || (last >= descr->nb_items)) return LB_ERR; + /* selected_item reflects last selected/unselected item on multiple sel */ + descr->selected_item = last; + + if (on) /* Turn selection on */ + { + for (i = first; i <= last; i++) + { + if (descr->items[i].selected) continue; + descr->items[i].selected = TRUE; + LISTBOX_RepaintItem( wnd, descr, i, ODA_SELECT ); + } + } + else /* Turn selection off */ + { + for (i = first; i <= last; i++) + { + if (!descr->items[i].selected) continue; + descr->items[i].selected = FALSE; + LISTBOX_RepaintItem( wnd, descr, i, ODA_SELECT ); + } + } + return LB_OKAY; +} + + +/*********************************************************************** + * LISTBOX_SetCaretIndex + * + * NOTES + * index must be between 0 and descr->nb_items-1, or LB_ERR is returned. + * + */ +static LRESULT LISTBOX_SetCaretIndex( WND *wnd, LB_DESCR *descr, INT index, + BOOL fully_visible ) +{ + INT oldfocus = descr->focus_item; + + if ((index < 0) || (index >= descr->nb_items)) return LB_ERR; + if (index == oldfocus) return LB_OKAY; + descr->focus_item = index; + if ((oldfocus != -1) && descr->caret_on && (GetFocus() == wnd->hwndSelf)) + LISTBOX_RepaintItem( wnd, descr, oldfocus, ODA_FOCUS ); + + LISTBOX_MakeItemVisible( wnd, descr, index, fully_visible ); + if (descr->caret_on && (GetFocus() == wnd->hwndSelf)) + LISTBOX_RepaintItem( wnd, descr, index, ODA_FOCUS ); + + return LB_OKAY; +} + + +/*********************************************************************** + * LISTBOX_SetSelection + */ +static LRESULT LISTBOX_SetSelection( WND *wnd, LB_DESCR *descr, INT index, + BOOL on, BOOL send_notify ) +{ + if ((index < -1) || (index >= descr->nb_items)) return LB_ERR; + if (descr->style & LBS_MULTIPLESEL) + { + if (index == -1) /* Select all items */ + return LISTBOX_SelectItemRange( wnd, descr, 0, -1, on ); + else /* Only one item */ + return LISTBOX_SelectItemRange( wnd, descr, index, index, on ); + } + else + { + INT oldsel = descr->selected_item; + if (index == oldsel) return LB_OKAY; + if (oldsel != -1) descr->items[oldsel].selected = FALSE; + if (index != -1) descr->items[index].selected = TRUE; + descr->selected_item = index; + if (oldsel != -1) LISTBOX_RepaintItem( wnd, descr, oldsel, ODA_SELECT); + if (index != -1) LISTBOX_RepaintItem( wnd, descr, index, ODA_SELECT ); + if (send_notify) SEND_NOTIFICATION( wnd, descr, + (index != -1) ? LBN_SELCHANGE : LBN_SELCANCEL ); + else + if( descr->lphc ) /* set selection change flag for parent combo */ + descr->lphc->wState |= CBF_SELCHANGE; + } + return LB_OKAY; +} + + +/*********************************************************************** + * LISTBOX_MoveCaret + * + * Change the caret position and extend the selection to the new caret. + */ +static void LISTBOX_MoveCaret( WND *wnd, LB_DESCR *descr, INT index, + BOOL fully_visible ) +{ + LISTBOX_SetCaretIndex( wnd, descr, index, fully_visible ); + if (descr->style & LBS_EXTENDEDSEL) + { + if (descr->anchor_item != -1) + { + INT first = MIN( descr->focus_item, descr->anchor_item ); + INT last = MAX( descr->focus_item, descr->anchor_item ); + if (first > 0) + LISTBOX_SelectItemRange( wnd, descr, 0, first - 1, FALSE ); + LISTBOX_SelectItemRange( wnd, descr, last + 1, -1, FALSE ); + LISTBOX_SelectItemRange( wnd, descr, first, last, TRUE ); + } + } + else if (!(descr->style & LBS_MULTIPLESEL) && (descr->selected_item != -1)) + { + /* Set selection to new caret item */ + LISTBOX_SetSelection( wnd, descr, index, TRUE, FALSE ); + } +} + + +/*********************************************************************** + * LISTBOX_InsertItem + */ +static LRESULT LISTBOX_InsertItem( WND *wnd, LB_DESCR *descr, INT index, + LPSTR str, DWORD data ) +{ + LB_ITEMDATA *item; + INT max_items; + + if (index == -1) index = descr->nb_items; + else if ((index < 0) || (index > descr->nb_items)) return LB_ERR; + if (!descr->items) max_items = 0; + else max_items = HeapSize( descr->heap, 0, descr->items ) / sizeof(*item); + if (descr->nb_items == max_items) + { + /* We need to grow the array */ + max_items += LB_ARRAY_GRANULARITY; + if (!(item = HeapReAlloc( descr->heap, 0, descr->items, + max_items * sizeof(LB_ITEMDATA) ))) + { + SEND_NOTIFICATION( wnd, descr, LBN_ERRSPACE ); + return LB_ERRSPACE; + } + descr->items = item; + } + + /* Insert the item structure */ + + item = &descr->items[index]; + if (index < descr->nb_items) + MoveMemory( item + 1, item, (descr->nb_items - index) * sizeof(LB_ITEMDATA) ); + item->str = str; + item->data = data; + item->height = 0; + item->selected = FALSE; + descr->nb_items++; + + /* Get item height */ + + if (descr->style & LBS_OWNERDRAWVARIABLE) + { + MEASUREITEMSTRUCT mis; + UINT id = (descr->lphc) ? ID_CB_LISTBOX : wnd->wIDmenu; + + mis.CtlType = ODT_LISTBOX; + mis.CtlID = id; + mis.itemID = index; + mis.itemData = descr->items[index].data; + mis.itemHeight = descr->item_height; + SendMessageA( descr->owner, WM_MEASUREITEM, id, (LPARAM)&mis ); + item->height = mis.itemHeight ? mis.itemHeight : 1; + DPRINT( "[%04x]: measure item %d (%s) = %d\n", + wnd->hwndSelf, index, str ? str : "", item->height ); + } + + /* Repaint the items */ + + LISTBOX_UpdateScroll( wnd, descr ); + LISTBOX_InvalidateItems( wnd, descr, index ); + + /* Move selection and focused item */ + + if (index <= descr->selected_item) descr->selected_item++; + if (index <= descr->focus_item) + { + descr->focus_item++; + LISTBOX_MoveCaret( wnd, descr, descr->focus_item, FALSE ); + } + + /* If listbox was empty, set focus to the first item */ + + if (descr->nb_items == 1) LISTBOX_SetCaretIndex( wnd, descr, 0, FALSE ); + return LB_OKAY; +} + + +/*********************************************************************** + * LISTBOX_InsertString + */ +static LRESULT LISTBOX_InsertString( WND *wnd, LB_DESCR *descr, INT index, + LPCSTR str ) +{ + LPSTR new_str = NULL; + DWORD data = 0; + LRESULT ret; + + if (HAS_STRINGS(descr)) + { + if (!(new_str = HEAP_strdupA( descr->heap, 0, str ))) + { + SEND_NOTIFICATION( wnd, descr, LBN_ERRSPACE ); + return LB_ERRSPACE; + } + } + else data = (DWORD)str; + + if (index == -1) index = descr->nb_items; + if ((ret = LISTBOX_InsertItem( wnd, descr, index, new_str, data )) != 0) + { + if (new_str) HeapFree( descr->heap, 0, new_str ); + return ret; + } + + DPRINT( "[%04x]: added item %d '%s'\n", + wnd->hwndSelf, index, HAS_STRINGS(descr) ? new_str : "" ); + return index; +} + + +/*********************************************************************** + * LISTBOX_DeleteItem + * + * Delete the content of an item. 'index' must be a valid index. + */ +static void LISTBOX_DeleteItem( WND *wnd, LB_DESCR *descr, INT index ) +{ + /* Note: Win 3.1 only sends DELETEITEM on owner-draw items, + * while Win95 sends it for all items with user data. + * It's probably better to send it too often than not + * often enough, so this is what we do here. + */ + if (IS_OWNERDRAW(descr) || descr->items[index].data) + { + DELETEITEMSTRUCT dis; + UINT id = (descr->lphc) ? ID_CB_LISTBOX : wnd->wIDmenu; + + dis.CtlType = ODT_LISTBOX; + dis.CtlID = id; + dis.itemID = index; + dis.hwndItem = wnd->hwndSelf; + dis.itemData = descr->items[index].data; + SendMessageA( descr->owner, WM_DELETEITEM, id, (LPARAM)&dis ); + } + if (HAS_STRINGS(descr) && descr->items[index].str) + HeapFree( descr->heap, 0, descr->items[index].str ); +} + + +/*********************************************************************** + * LISTBOX_RemoveItem + * + * Remove an item from the listbox and delete its content. + */ +static LRESULT LISTBOX_RemoveItem( WND *wnd, LB_DESCR *descr, INT index ) +{ + LB_ITEMDATA *item; + INT max_items; + + if (index == -1) index = descr->nb_items - 1; + else if ((index < 0) || (index >= descr->nb_items)) return LB_ERR; + LISTBOX_DeleteItem( wnd, descr, index ); + + /* Remove the item */ + + item = &descr->items[index]; + if (index < descr->nb_items-1) + MoveMemory( item, item + 1, + (descr->nb_items - index - 1) * sizeof(LB_ITEMDATA) ); + descr->nb_items--; + if (descr->anchor_item == descr->nb_items) descr->anchor_item--; + + /* Shrink the item array if possible */ + + max_items = HeapSize( descr->heap, 0, descr->items ) / sizeof(LB_ITEMDATA); + if (descr->nb_items < max_items - 2*LB_ARRAY_GRANULARITY) + { + max_items -= LB_ARRAY_GRANULARITY; + item = HeapReAlloc( descr->heap, 0, descr->items, + max_items * sizeof(LB_ITEMDATA) ); + if (item) descr->items = item; + } + + /* Repaint the items */ + + LISTBOX_UpdateScroll( wnd, descr ); + LISTBOX_InvalidateItems( wnd, descr, index ); + + /* Move selection and focused item */ + + if (index <= descr->selected_item) descr->selected_item--; + if (index <= descr->focus_item) + { + descr->focus_item--; + LISTBOX_MoveCaret( wnd, descr, descr->focus_item, FALSE ); + } + return LB_OKAY; +} + + +/*********************************************************************** + * LISTBOX_ResetContent + */ +static void LISTBOX_ResetContent( WND *wnd, LB_DESCR *descr ) +{ + INT i; + + for (i = 0; i < descr->nb_items; i++) LISTBOX_DeleteItem( wnd, descr, i ); + if (descr->items) HeapFree( descr->heap, 0, descr->items ); + descr->nb_items = 0; + descr->top_item = 0; + descr->selected_item = -1; + descr->focus_item = 0; + descr->anchor_item = -1; + descr->items = NULL; + LISTBOX_UpdateScroll( wnd, descr ); + InvalidateRect( wnd->hwndSelf, NULL, TRUE ); +} + + +/*********************************************************************** + * LISTBOX_SetCount + */ +static LRESULT LISTBOX_SetCount( WND *wnd, LB_DESCR *descr, INT count ) +{ + LRESULT ret; + + if (HAS_STRINGS(descr)) return LB_ERR; + /* FIXME: this is far from optimal... */ + if (count > descr->nb_items) + { + while (count > descr->nb_items) + if ((ret = LISTBOX_InsertString( wnd, descr, -1, 0 )) < 0) + return ret; + } + else if (count < descr->nb_items) + { + while (count < descr->nb_items) + if ((ret = LISTBOX_RemoveItem( wnd, descr, -1 )) < 0) + return ret; + } + return LB_OKAY; +} + + +/*********************************************************************** + * LISTBOX_Directory + */ +static LRESULT LISTBOX_Directory( WND *wnd, LB_DESCR *descr, UINT attrib, + LPCSTR filespec, BOOL long_names ) +{ + HANDLE handle; + LRESULT ret = LB_OKAY; + WIN32_FIND_DATA entry; + int pos; + + if ((handle = FindFirstFileA(filespec,&entry)) == INVALID_HANDLE_VALUE) + { + if (GetLastError() != ERROR_NO_MORE_FILES) return LB_ERR; + } + else + { + do + { + char buffer[270]; + if (entry.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + if (!(attrib & DDL_DIRECTORY) || + !strcmp( entry.cAlternateFileName, "." )) continue; + if (long_names) sprintf( buffer, "[%s]", entry.cFileName ); + else sprintf( buffer, "[%s]", entry.cAlternateFileName ); + } + else /* not a directory */ + { +#define ATTRIBS (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | \ + FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE) + + if ((attrib & DDL_EXCLUSIVE) && + ((attrib & ATTRIBS) != (entry.dwFileAttributes & ATTRIBS))) + continue; +#undef ATTRIBS + if (long_names) strcpy( buffer, entry.cFileName ); + else strcpy( buffer, entry.cAlternateFileName ); + } + if (!long_names) CharLowerA( buffer ); + pos = LISTBOX_FindFileStrPos( wnd, descr, buffer ); + if ((ret = LISTBOX_InsertString( wnd, descr, pos, buffer )) < 0) + break; + } while (FindNextFileA( handle, &entry )); + FindClose( handle ); + } + + if ((ret >= 0) && (attrib & DDL_DRIVES)) + { + char buffer[] = "[-a-]"; + int drive; + for (drive = 0; drive < MAX_DOS_DRIVES; drive++, buffer[2]++) + { + //if (!DRIVE_IsValid(drive)) continue; + if ((ret = LISTBOX_InsertString( wnd, descr, -1, buffer )) < 0) + break; + } + } + return ret; +} + + +/*********************************************************************** + * LISTBOX_HandleVScroll + */ +static LRESULT LISTBOX_HandleVScroll( WND *wnd, LB_DESCR *descr, + WPARAM wParam, LPARAM lParam ) +{ + SCROLLINFO info; + + if (descr->style & LBS_MULTICOLUMN) return 0; + switch(LOWORD(wParam)) + { + case SB_LINEUP: + LISTBOX_SetTopItem( wnd, descr, descr->top_item - 1, TRUE ); + break; + case SB_LINEDOWN: + LISTBOX_SetTopItem( wnd, descr, descr->top_item + 1, TRUE ); + break; + case SB_PAGEUP: + LISTBOX_SetTopItem( wnd, descr, descr->top_item - + LISTBOX_GetCurrentPageSize( wnd, descr ), TRUE ); + break; + case SB_PAGEDOWN: + LISTBOX_SetTopItem( wnd, descr, descr->top_item + + LISTBOX_GetCurrentPageSize( wnd, descr ), TRUE ); + break; + case SB_THUMBPOSITION: + LISTBOX_SetTopItem( wnd, descr, HIWORD(wParam), TRUE ); + break; + case SB_THUMBTRACK: + info.cbSize = sizeof(info); + info.fMask = SIF_TRACKPOS; + GetScrollInfo( wnd->hwndSelf, SB_VERT, &info ); + LISTBOX_SetTopItem( wnd, descr, info.nTrackPos, TRUE ); + break; + case SB_TOP: + LISTBOX_SetTopItem( wnd, descr, 0, TRUE ); + break; + case SB_BOTTOM: + LISTBOX_SetTopItem( wnd, descr, descr->nb_items, TRUE ); + break; + } + return 0; +} + + +/*********************************************************************** + * LISTBOX_HandleHScroll + */ +static LRESULT LISTBOX_HandleHScroll( WND *wnd, LB_DESCR *descr, + WPARAM wParam, LPARAM lParam ) +{ + SCROLLINFO info; + INT page; + + if (descr->style & LBS_MULTICOLUMN) + { + switch(LOWORD(wParam)) + { + case SB_LINELEFT: + LISTBOX_SetTopItem( wnd, descr, descr->top_item-descr->page_size, + TRUE ); + break; + case SB_LINERIGHT: + LISTBOX_SetTopItem( wnd, descr, descr->top_item+descr->page_size, + TRUE ); + break; + case SB_PAGELEFT: + page = descr->width / descr->column_width; + if (page < 1) page = 1; + LISTBOX_SetTopItem( wnd, descr, + descr->top_item - page * descr->page_size, TRUE ); + break; + case SB_PAGERIGHT: + page = descr->width / descr->column_width; + if (page < 1) page = 1; + LISTBOX_SetTopItem( wnd, descr, + descr->top_item + page * descr->page_size, TRUE ); + break; + case SB_THUMBPOSITION: + LISTBOX_SetTopItem( wnd, descr, HIWORD(wParam)*descr->page_size, + TRUE ); + break; + case SB_THUMBTRACK: + info.cbSize = sizeof(info); + info.fMask = SIF_TRACKPOS; + GetScrollInfo( wnd->hwndSelf, SB_VERT, &info ); + LISTBOX_SetTopItem( wnd, descr, info.nTrackPos*descr->page_size, + TRUE ); + break; + case SB_LEFT: + LISTBOX_SetTopItem( wnd, descr, 0, TRUE ); + break; + case SB_RIGHT: + LISTBOX_SetTopItem( wnd, descr, descr->nb_items, TRUE ); + break; + } + } + else if (descr->horz_extent) + { + switch(LOWORD(wParam)) + { + case SB_LINELEFT: + LISTBOX_SetHorizontalPos( wnd, descr, descr->horz_pos - 1 ); + break; + case SB_LINERIGHT: + LISTBOX_SetHorizontalPos( wnd, descr, descr->horz_pos + 1 ); + break; + case SB_PAGELEFT: + LISTBOX_SetHorizontalPos( wnd, descr, + descr->horz_pos - descr->width ); + break; + case SB_PAGERIGHT: + LISTBOX_SetHorizontalPos( wnd, descr, + descr->horz_pos + descr->width ); + break; + case SB_THUMBPOSITION: + LISTBOX_SetHorizontalPos( wnd, descr, HIWORD(wParam) ); + break; + case SB_THUMBTRACK: + info.cbSize = sizeof(info); + info.fMask = SIF_TRACKPOS; + GetScrollInfo( wnd->hwndSelf, SB_HORZ, &info ); + LISTBOX_SetHorizontalPos( wnd, descr, info.nTrackPos ); + break; + case SB_LEFT: + LISTBOX_SetHorizontalPos( wnd, descr, 0 ); + break; + case SB_RIGHT: + LISTBOX_SetHorizontalPos( wnd, descr, + descr->horz_extent - descr->width ); + break; + } + } + return 0; +} + + +/*********************************************************************** + * LISTBOX_HandleLButtonDown + */ +static LRESULT LISTBOX_HandleLButtonDown( WND *wnd, LB_DESCR *descr, + WPARAM wParam, INT x, INT y ) +{ + INT index = LISTBOX_GetItemFromPoint( wnd, descr, x, y ); + DPRINT( "[%04x]: lbuttondown %d,%d item %d\n", + wnd->hwndSelf, x, y, index ); + if (!descr->caret_on && (GetFocus() == wnd->hwndSelf)) return 0; + if (index != -1) + { + if (descr->style & LBS_EXTENDEDSEL) + { + if (!(wParam & MK_SHIFT)) descr->anchor_item = index; + if (wParam & MK_CONTROL) + { + LISTBOX_SetCaretIndex( wnd, descr, index, FALSE ); + LISTBOX_SetSelection( wnd, descr, index, + !descr->items[index].selected, FALSE ); + } + else LISTBOX_MoveCaret( wnd, descr, index, FALSE ); + } + else + { + LISTBOX_MoveCaret( wnd, descr, index, FALSE ); + LISTBOX_SetSelection( wnd, descr, index, + (!(descr->style & LBS_MULTIPLESEL) || + !descr->items[index].selected), FALSE ); + } + } + + if( !descr->lphc ) SetFocus( wnd->hwndSelf ); + else SetFocus( (descr->lphc->hWndEdit) ? descr->lphc->hWndEdit + : descr->lphc->self->hwndSelf ) ; + + SetCapture( wnd->hwndSelf ); + if (index != -1 && !descr->lphc) + { + if (descr->style & LBS_NOTIFY ) + SendMessageA( descr->owner, WM_LBTRACKPOINT, index, + MAKELPARAM( x, y ) ); + if (wnd->dwExStyle & WS_EX_DRAGDETECT) + { + POINT pt = { x, y }; + // if (DragDetect( wnd->hwndSelf, pt )) + SendMessageA( descr->owner, WM_BEGINDRAG, 0, 0 ); + } + } + return 0; +} + + +/*********************************************************************** + * LISTBOX_HandleLButtonUp + */ +static LRESULT LISTBOX_HandleLButtonUp( WND *wnd, LB_DESCR *descr ) +{ + if (LISTBOX_Timer != LB_TIMER_NONE) + KillTimer( wnd->hwndSelf, LB_TIMER_ID ); + LISTBOX_Timer = LB_TIMER_NONE; + if (GetCapture() == wnd->hwndSelf) + { + ReleaseCapture(); + if (descr->style & LBS_NOTIFY) + SEND_NOTIFICATION( wnd, descr, LBN_SELCHANGE ); + } + return 0; +} + + +/*********************************************************************** + * LISTBOX_HandleTimer + * + * Handle scrolling upon a timer event. + * Return TRUE if scrolling should continue. + */ +static LRESULT LISTBOX_HandleTimer( WND *wnd, LB_DESCR *descr, + INT index, TIMER_DIRECTION dir ) +{ + switch(dir) + { + case LB_TIMER_UP: + if (descr->top_item) index = descr->top_item - 1; + else index = 0; + break; + case LB_TIMER_LEFT: + if (descr->top_item) index -= descr->page_size; + break; + case LB_TIMER_DOWN: + index = descr->top_item + LISTBOX_GetCurrentPageSize( wnd, descr ); + if (index == descr->focus_item) index++; + if (index >= descr->nb_items) index = descr->nb_items - 1; + break; + case LB_TIMER_RIGHT: + if (index + descr->page_size < descr->nb_items) + index += descr->page_size; + break; + case LB_TIMER_NONE: + break; + } + if (index == descr->focus_item) return FALSE; + LISTBOX_MoveCaret( wnd, descr, index, FALSE ); + return TRUE; +} + + +/*********************************************************************** + * LISTBOX_HandleSystemTimer + * + * WM_SYSTIMER handler. + */ +static LRESULT LISTBOX_HandleSystemTimer( WND *wnd, LB_DESCR *descr ) +{ + if (!LISTBOX_HandleTimer( wnd, descr, descr->focus_item, LISTBOX_Timer )) + { + KillTimer( wnd->hwndSelf, LB_TIMER_ID ); + LISTBOX_Timer = LB_TIMER_NONE; + } + return 0; +} + + +/*********************************************************************** + * LISTBOX_HandleMouseMove + * + * WM_MOUSEMOVE handler. + */ +static void LISTBOX_HandleMouseMove( WND *wnd, LB_DESCR *descr, + INT x, INT y ) +{ + INT index; + TIMER_DIRECTION dir; + + if (descr->style & LBS_MULTICOLUMN) + { + if (y < 0) y = 0; + else if (y >= descr->item_height * descr->page_size) + y = descr->item_height * descr->page_size - 1; + + if (x < 0) + { + dir = LB_TIMER_LEFT; + x = 0; + } + else if (x >= descr->width) + { + dir = LB_TIMER_RIGHT; + x = descr->width - 1; + } + else dir = LB_TIMER_NONE; /* inside */ + } + else + { + if (y < 0) dir = LB_TIMER_UP; /* above */ + else if (y >= descr->height) dir = LB_TIMER_DOWN; /* below */ + else dir = LB_TIMER_NONE; /* inside */ + } + + index = LISTBOX_GetItemFromPoint( wnd, descr, x, y ); + if (index == -1) index = descr->focus_item; + if (!LISTBOX_HandleTimer( wnd, descr, index, dir )) dir = LB_TIMER_NONE; + + /* Start/stop the system timer */ + + if (dir != LB_TIMER_NONE) + SetTimer( wnd->hwndSelf, LB_TIMER_ID, LB_SCROLL_TIMEOUT, NULL); + else if (LISTBOX_Timer != LB_TIMER_NONE) + KillTimer( wnd->hwndSelf, LB_TIMER_ID ); + LISTBOX_Timer = dir; +} + + +/*********************************************************************** + * LISTBOX_HandleKeyDown + */ +static LRESULT LISTBOX_HandleKeyDown( WND *wnd, LB_DESCR *descr, WPARAM wParam ) +{ + INT caret = -1; + if (descr->style & LBS_WANTKEYBOARDINPUT) + { + caret = SendMessageA( descr->owner, WM_VKEYTOITEM, + MAKEWPARAM(LOWORD(wParam), descr->focus_item), + wnd->hwndSelf ); + if (caret == -2) return 0; + } + if (caret == -1) switch(wParam) + { + case VK_LEFT: + if (descr->style & LBS_MULTICOLUMN) + { + if (descr->focus_item >= descr->page_size) + caret = descr->focus_item - descr->page_size; + break; + } + /* fall through */ + case VK_UP: + caret = descr->focus_item - 1; + if (caret < 0) caret = 0; + break; + case VK_RIGHT: + if (descr->style & LBS_MULTICOLUMN) + { + if (descr->focus_item + descr->page_size < descr->nb_items) + caret = descr->focus_item + descr->page_size; + break; + } + /* fall through */ + case VK_DOWN: + caret = descr->focus_item + 1; + if (caret >= descr->nb_items) caret = descr->nb_items - 1; + break; + case VK_PRIOR: + if (descr->style & LBS_MULTICOLUMN) + { + INT page = descr->width / descr->column_width; + if (page < 1) page = 1; + caret = descr->focus_item - (page * descr->page_size) + 1; + } + else caret = descr->focus_item-LISTBOX_GetCurrentPageSize(wnd,descr)+1; + if (caret < 0) caret = 0; + break; + case VK_NEXT: + if (descr->style & LBS_MULTICOLUMN) + { + INT page = descr->width / descr->column_width; + if (page < 1) page = 1; + caret = descr->focus_item + (page * descr->page_size) - 1; + } + else caret = descr->focus_item+LISTBOX_GetCurrentPageSize(wnd,descr)-1; + if (caret >= descr->nb_items) caret = descr->nb_items - 1; + break; + case VK_HOME: + caret = 0; + break; + case VK_END: + caret = descr->nb_items - 1; + break; + case VK_SPACE: + if (descr->style & LBS_EXTENDEDSEL) caret = descr->focus_item; + else if (descr->style & LBS_MULTIPLESEL) + { + LISTBOX_SetSelection( wnd, descr, descr->focus_item, + !descr->items[descr->focus_item].selected, + (descr->style & LBS_NOTIFY) != 0 ); + } + else if (descr->selected_item == -1) + { + LISTBOX_SetSelection( wnd, descr, descr->focus_item, TRUE, + (descr->style & LBS_NOTIFY) != 0 ); + } + break; + } + if (caret >= 0) + { + if ((descr->style & LBS_EXTENDEDSEL) && + !(GetKeyState( VK_SHIFT ) & 0x8000)) + descr->anchor_item = caret; + LISTBOX_MoveCaret( wnd, descr, caret, TRUE ); + if (descr->style & LBS_NOTIFY) + { + if( descr->lphc && CB_GETTYPE(descr->lphc) != CBS_SIMPLE ) + { + /* make sure that combo parent doesn't hide us */ + descr->lphc->wState |= CBF_NOROLLUP; + } + SEND_NOTIFICATION( wnd, descr, LBN_SELCHANGE ); + } + } + return 0; +} + + +/*********************************************************************** + * LISTBOX_HandleChar + */ +static LRESULT LISTBOX_HandleChar( WND *wnd, LB_DESCR *descr, + WPARAM wParam ) +{ + INT caret = -1; + char str[2] = { wParam & 0xff, '\0' }; + + if (descr->style & LBS_WANTKEYBOARDINPUT) + { + caret = SendMessageA( descr->owner, WM_CHARTOITEM, + MAKEWPARAM(LOWORD(wParam), descr->focus_item), + wnd->hwndSelf ); + if (caret == -2) return 0; + } + if (caret == -1) + caret = LISTBOX_FindString( wnd, descr, descr->focus_item, str, FALSE); + if (caret != -1) + { + LISTBOX_MoveCaret( wnd, descr, caret, TRUE ); + if (descr->style & LBS_NOTIFY) + SEND_NOTIFICATION( wnd, descr, LBN_SELCHANGE ); + } + return 0; +} + + +/*********************************************************************** + * LISTBOX_Create + */ +static BOOL LISTBOX_Create( WND *wnd, LPHEADCOMBO lphc ) +{ + LB_DESCR *descr; + MEASUREITEMSTRUCT mis; + RECT rect; + + if (!(descr = HeapAlloc( GetProcessHeap(), 0, sizeof(*descr) ))) + return FALSE; + if (!(descr->heap = HeapCreate( 0, 0x10000, 0 ))) + { + HeapFree( GetProcessHeap(), 0, descr ); + return FALSE; + } + GetClientRect( wnd->hwndSelf, &rect ); + descr->owner = GetParent( wnd->hwndSelf ); + descr->style = wnd->dwStyle; + descr->width = rect.right - rect.left; + descr->height = rect.bottom - rect.top; + descr->items = NULL; + descr->nb_items = 0; + descr->top_item = 0; + descr->selected_item = -1; + descr->focus_item = 0; + descr->anchor_item = -1; + descr->item_height = 1; + descr->page_size = 1; + descr->column_width = 150; + descr->horz_extent = (wnd->dwStyle & WS_HSCROLL) ? 1 : 0; + descr->horz_pos = 0; + descr->nb_tabs = 0; + descr->tabs = NULL; + descr->caret_on = TRUE; + descr->font = 0; + descr->locale = 0; /* FIXME */ + descr->lphc = lphc; + + if( lphc ) + { + DPRINT("[%04x]: resetting owner %04x -> %04x\n", + wnd->hwndSelf, descr->owner, lphc->self->hwndSelf ); + descr->owner = lphc->self->hwndSelf; + } + + *(LB_DESCR **)wnd->wExtra = descr; + +/* if (wnd->dwExStyle & WS_EX_NOPARENTNOTIFY) descr->style &= ~LBS_NOTIFY; + */ + if (descr->style & LBS_EXTENDEDSEL) descr->style |= LBS_MULTIPLESEL; + if (descr->style & LBS_MULTICOLUMN) descr->style &= ~LBS_OWNERDRAWVARIABLE; + if (descr->style & LBS_OWNERDRAWVARIABLE) descr->style |= LBS_NOINTEGRALHEIGHT; + descr->item_height = LISTBOX_SetFont( wnd, descr, 0 ); + + if (descr->style & LBS_OWNERDRAWFIXED) + { + if( descr->lphc && (descr->lphc->dwStyle & CBS_DROPDOWN)) + { + /* WinWord gets VERY unhappy if we send WM_MEASUREITEM from here */ + descr->item_height = lphc->RectButton.bottom - lphc->RectButton.top - 6; + } + else + { + UINT id = (descr->lphc ) ? ID_CB_LISTBOX : wnd->wIDmenu; + + mis.CtlType = ODT_LISTBOX; + mis.CtlID = id; + mis.itemID = -1; + mis.itemWidth = 0; + mis.itemData = 0; + mis.itemHeight = descr->item_height; + SendMessageA( descr->owner, WM_MEASUREITEM, id, (LPARAM)&mis ); + descr->item_height = mis.itemHeight ? mis.itemHeight : 1; + } + } + + return TRUE; +} + + +/*********************************************************************** + * LISTBOX_Destroy + */ +static BOOL LISTBOX_Destroy( WND *wnd, LB_DESCR *descr ) +{ + LISTBOX_ResetContent( wnd, descr ); + HeapDestroy( descr->heap ); + HeapFree( GetProcessHeap(), 0, descr ); + wnd->wExtra[0] = 0; + return TRUE; +} + + +/*********************************************************************** + * ListBoxWndProc + */ +LRESULT WINAPI ListBoxWndProc( HWND hwnd, UINT msg, + WPARAM wParam, LPARAM lParam ) +{ + LRESULT ret; + LB_DESCR *descr; + WND *wnd = WIN_FindWndPtr( hwnd ); + + if (!wnd) return 0; + if (!(descr = *(LB_DESCR **)wnd->wExtra)) + { + if (msg == WM_CREATE) + { + if (!LISTBOX_Create( wnd, NULL )) return -1; + DPRINT( "creating wnd=%04x descr=%p\n", + hwnd, *(LB_DESCR **)wnd->wExtra ); + return 0; + } + /* Ignore all other messages before we get a WM_CREATE */ + return DefWindowProcA( hwnd, msg, wParam, lParam ); + } + + DPRINT( "[%04x]: msg %s wp %08x lp %08lx\n", + wnd->hwndSelf, SPY_GetMsgName(msg), wParam, lParam ); + switch(msg) + { + case LB_RESETCONTENT: + LISTBOX_ResetContent( wnd, descr ); + return 0; + + case LB_ADDSTRING: + wParam = LISTBOX_FindStringPos( wnd, descr, (LPCSTR)lParam, FALSE ); + return LISTBOX_InsertString( wnd, descr, wParam, (LPCSTR)lParam ); + + case LB_INSERTSTRING: + return LISTBOX_InsertString( wnd, descr, wParam, (LPCSTR)lParam ); + + + case LB_ADDFILE: + wParam = LISTBOX_FindFileStrPos( wnd, descr, (LPCSTR)lParam ); + return LISTBOX_InsertString( wnd, descr, wParam, (LPCSTR)lParam ); + + case LB_DELETESTRING: + return LISTBOX_RemoveItem( wnd, descr, wParam ); + + case LB_GETITEMDATA: + if (((INT)wParam < 0) || ((INT)wParam >= descr->nb_items)) + return LB_ERR; + return descr->items[wParam].data; + + case LB_SETITEMDATA: + if (((INT)wParam < 0) || ((INT)wParam >= descr->nb_items)) + return LB_ERR; + descr->items[wParam].data = (DWORD)lParam; + return LB_OKAY; + + case LB_GETCOUNT: + return descr->nb_items; + + case LB_GETTEXT: + return LISTBOX_GetText( wnd, descr, wParam, (LPSTR)lParam ); + + case LB_GETTEXTLEN: + if (wParam >= descr->nb_items) return LB_ERR; + return (HAS_STRINGS(descr) ? strlen(descr->items[wParam].str) + : sizeof(DWORD)); + + + case LB_GETCURSEL: + return descr->selected_item; + + + case LB_GETTOPINDEX: + return descr->top_item; + + case LB_GETITEMHEIGHT: + return LISTBOX_GetItemHeight( wnd, descr, wParam ); + + + case LB_SETITEMHEIGHT: + return LISTBOX_SetItemHeight( wnd, descr, wParam, lParam ); + + case LB_ITEMFROMPOINT: + { + POINT pt = { LOWORD(lParam), HIWORD(lParam) }; + RECT rect = { 0, 0, descr->width, descr->height }; + return MAKELONG( LISTBOX_GetItemFromPoint(wnd, descr, pt.x, pt.y), + PtInRect( &rect, pt ) ); + } + + + case LB_SETCARETINDEX: + return LISTBOX_SetCaretIndex( wnd, descr, wParam, !lParam ); + + + case LB_GETCARETINDEX: + return descr->focus_item; + + + case LB_SETTOPINDEX: + return LISTBOX_SetTopItem( wnd, descr, wParam, TRUE ); + + + case LB_SETCOLUMNWIDTH: + return LISTBOX_SetColumnWidth( wnd, descr, wParam ); + + + + case LB_GETITEMRECT: + return LISTBOX_GetItemRect( wnd, descr, wParam, (RECT *)lParam ); + + + case LB_FINDSTRING: + return LISTBOX_FindString( wnd, descr, wParam, (LPCSTR)lParam, FALSE ); + + + case LB_FINDSTRINGEXACT: + return LISTBOX_FindString( wnd, descr, wParam, (LPCSTR)lParam, TRUE ); + + + case LB_SELECTSTRING: + { + INT index = LISTBOX_FindString( wnd, descr, wParam, + (LPCSTR)lParam, FALSE ); + if (index == LB_ERR) return LB_ERR; + LISTBOX_SetSelection( wnd, descr, index, TRUE, FALSE ); + return index; + } + + + case LB_GETSEL: + if (((INT)wParam < 0) || ((INT)wParam >= descr->nb_items)) + return LB_ERR; + return descr->items[wParam].selected; + + case LB_SETSEL: + return LISTBOX_SetSelection( wnd, descr, lParam, wParam, FALSE ); + + + case LB_SETCURSEL: + LISTBOX_SetCaretIndex( wnd, descr, wParam, TRUE ); + return LISTBOX_SetSelection( wnd, descr, wParam, TRUE, FALSE ); + + case LB_GETSELCOUNT: + return LISTBOX_GetSelCount( wnd, descr ); + + + case LB_GETSELITEMS: + return LISTBOX_GetSelItems( wnd, descr, wParam, (LPINT)lParam ); + + case LB_SELITEMRANGE: + if (LOWORD(lParam) <= HIWORD(lParam)) + return LISTBOX_SelectItemRange( wnd, descr, LOWORD(lParam), + HIWORD(lParam), wParam ); + else + return LISTBOX_SelectItemRange( wnd, descr, HIWORD(lParam), + LOWORD(lParam), wParam ); + + + case LB_SELITEMRANGEEX: + if ((INT)lParam >= (INT)wParam) + return LISTBOX_SelectItemRange( wnd, descr, wParam, lParam, TRUE ); + else + return LISTBOX_SelectItemRange( wnd, descr, lParam, wParam, FALSE); + + + case LB_GETHORIZONTALEXTENT: + return descr->horz_extent; + + + case LB_SETHORIZONTALEXTENT: + return LISTBOX_SetHorizontalExtent( wnd, descr, wParam ); + + case LB_GETANCHORINDEX: + return descr->anchor_item; + + + case LB_SETANCHORINDEX: + if (((INT)wParam < -1) || ((INT)wParam >= descr->nb_items)) + return LB_ERR; + descr->anchor_item = (INT)wParam; + return LB_OKAY; + + + + case LB_DIR: + return LISTBOX_Directory( wnd, descr, wParam, (LPCSTR)lParam, TRUE ); + + case LB_GETLOCALE: + return descr->locale; + + case LB_SETLOCALE: + descr->locale = (LCID)wParam; /* FIXME: should check for valid lcid */ + return LB_OKAY; + + case LB_INITSTORAGE: + return LISTBOX_InitStorage( wnd, descr, wParam, (DWORD)lParam ); + + case LB_SETCOUNT: + return LISTBOX_SetCount( wnd, descr, (INT)wParam ); + + + + case LB_SETTABSTOPS: + return LISTBOX_SetTabStops( wnd, descr, wParam, + (LPINT)lParam, FALSE ); + + + case LB_CARETON: + if (descr->caret_on) return LB_OKAY; + descr->caret_on = TRUE; + if ((descr->focus_item != -1) && (GetFocus() == wnd->hwndSelf)) + LISTBOX_RepaintItem( wnd, descr, descr->focus_item, ODA_FOCUS ); + return LB_OKAY; + + + case LB_CARETOFF: + if (!descr->caret_on) return LB_OKAY; + descr->caret_on = FALSE; + if ((descr->focus_item != -1) && (GetFocus() == wnd->hwndSelf)) + LISTBOX_RepaintItem( wnd, descr, descr->focus_item, ODA_FOCUS ); + return LB_OKAY; + + case WM_DESTROY: + return LISTBOX_Destroy( wnd, descr ); + + case WM_ENABLE: + InvalidateRect( hwnd, NULL, TRUE ); + return 0; + + case WM_SETREDRAW: + LISTBOX_SetRedraw( wnd, descr, wParam != 0 ); + return 0; + + case WM_GETDLGCODE: + return DLGC_WANTARROWS | DLGC_WANTCHARS; + + case WM_PAINT: + { + PAINTSTRUCT ps; + HDC hdc = ( wParam ) ? ((HDC)wParam) + : BeginPaint( hwnd, &ps ); + ret = LISTBOX_Paint( wnd, descr, hdc ); + if( !wParam ) EndPaint( hwnd, &ps ); + } + return ret; + + case WM_SIZE: + LISTBOX_UpdateSize( wnd, descr ); + return 0; + + case WM_GETFONT: + return descr->font; + + case WM_SETFONT: + LISTBOX_SetFont( wnd, descr, (HFONT)wParam ); + if (lParam) InvalidateRect( wnd->hwndSelf, 0, TRUE ); + return 0; + + case WM_SETFOCUS: + descr->caret_on = TRUE; + if (descr->focus_item != -1) + LISTBOX_RepaintItem( wnd, descr, descr->focus_item, ODA_FOCUS ); + SEND_NOTIFICATION( wnd, descr, LBN_SETFOCUS ); + return 0; + + case WM_KILLFOCUS: + if ((descr->focus_item != -1) && descr->caret_on) + LISTBOX_RepaintItem( wnd, descr, descr->focus_item, ODA_FOCUS ); + SEND_NOTIFICATION( wnd, descr, LBN_KILLFOCUS ); + return 0; + + case WM_HSCROLL: + return LISTBOX_HandleHScroll( wnd, descr, wParam, lParam ); + + case WM_VSCROLL: + return LISTBOX_HandleVScroll( wnd, descr, wParam, lParam ); + + case WM_LBUTTONDOWN: + return LISTBOX_HandleLButtonDown( wnd, descr, wParam, + (INT)LOWORD(lParam), + (INT)HIWORD(lParam) ); + + case WM_LBUTTONDBLCLK: + if (descr->style & LBS_NOTIFY) + SEND_NOTIFICATION( wnd, descr, LBN_DBLCLK ); + return 0; + + case WM_MOUSEMOVE: + if (GetCapture() == hwnd) + LISTBOX_HandleMouseMove( wnd, descr, (INT)LOWORD(lParam), + (INT)HIWORD(lParam) ); + return 0; + + case WM_LBUTTONUP: + return LISTBOX_HandleLButtonUp( wnd, descr ); + + case WM_KEYDOWN: + return LISTBOX_HandleKeyDown( wnd, descr, wParam ); + + case WM_CHAR: + return LISTBOX_HandleChar( wnd, descr, wParam ); + + case WM_SYSTIMER: + return LISTBOX_HandleSystemTimer( wnd, descr ); + + case WM_ERASEBKGND: + if (IS_OWNERDRAW(descr)) + { + RECT rect = { 0, 0, descr->width, descr->height }; + HBRUSH hbrush = SendMessageA( descr->owner, WM_CTLCOLORLISTBOX, + wParam, (LPARAM)wnd->hwndSelf ); + if (hbrush) FillRect( (HDC)wParam, &rect, hbrush ); + } + return 1; + + case WM_DROPFILES: + if( !descr->lphc ) + return SendMessageA( descr->owner, msg, wParam, lParam ); + break; + + case WM_DROPOBJECT: + case WM_QUERYDROPOBJECT: + case WM_DRAGSELECT: + case WM_DRAGMOVE: + if( !descr->lphc ) + { + // LPDRAGINFO dragInfo = (LPDRAGINFO)lParam; + // dragInfo->l = LISTBOX_GetItemFromPoint( wnd, descr, dragInfo->pt.x, + // dragInfo->pt.y ); + return SendMessageA( descr->owner, msg, wParam, lParam ); + } + break; + + case WM_NCCREATE: + if (TWEAK_WineLook > WIN31_LOOK) + wnd->dwExStyle |= WS_EX_CLIENTEDGE; + return DefWindowProcA( hwnd, msg, wParam, lParam ); + + default: + if ((msg >= WM_USER) && (msg < 0xc000)) + DPRINT( "[%04x]: unknown msg %04x wp %08x lp %08lx\n", + hwnd, msg, wParam, lParam ); + return DefWindowProcA( hwnd, msg, wParam, lParam ); + } + return 0; +} + +/*********************************************************************** + * COMBO_Directory + */ +LRESULT COMBO_Directory( LPHEADCOMBO lphc, UINT attrib, LPSTR dir, BOOL bLong) +{ + WND *wnd = WIN_FindWndPtr( lphc->hWndLBox ); + + if( wnd ) + { + LB_DESCR *descr = *(LB_DESCR **)wnd->wExtra; + if( descr ) + { + LRESULT lRet = LISTBOX_Directory( wnd, descr, attrib, dir, bLong ); + + RedrawWindow( lphc->self->hwndSelf, NULL, 0, + RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW ); + return lRet; + } + } + return CB_ERR; +} + +/*********************************************************************** + * ComboLBWndProc + * + * NOTE: in Windows, winproc address of the ComboLBox is the same + * as that of the Listbox. + */ +LRESULT WINAPI ComboLBWndProc( HWND hwnd, UINT msg, + WPARAM wParam, LPARAM lParam ) +{ + LRESULT lRet = 0; + WND *wnd = WIN_FindWndPtr( hwnd ); + + if (wnd) + { + LB_DESCR *descr = *(LB_DESCR **)wnd->wExtra; + + DPRINT( "[%04x]: msg %s wp %08x lp %08lx\n", + wnd->hwndSelf, SPY_GetMsgName(msg), wParam, lParam ); + + if( descr || msg == WM_CREATE ) + { + LPHEADCOMBO lphc = (descr) ? descr->lphc : NULL; + + switch( msg ) + { + case WM_CREATE: +#define lpcs ((LPCREATESTRUCTA)lParam) + DPRINT( "\tpassed parent handle = 0x%08x\n", + (UINT)lpcs->lpCreateParams); + + lphc = (LPHEADCOMBO)(lpcs->lpCreateParams); +#undef lpcs + return LISTBOX_Create( wnd, lphc ); + + case WM_LBUTTONDOWN: + return LISTBOX_HandleLButtonDown( wnd, descr, wParam, + (INT)LOWORD(lParam), (INT)HIWORD(lParam)); + + /* avoid activation at all costs */ + + case WM_MOUSEACTIVATE: + return MA_NOACTIVATE; + + case WM_NCACTIVATE: + return FALSE; + + case WM_KEYDOWN: + if( CB_GETTYPE(lphc) != CBS_SIMPLE ) + { + /* for some reason(?) Windows makes it possible to + * show/hide ComboLBox by sending it WM_KEYDOWNs */ + + if( (!(lphc->wState & CBF_EUI) && wParam == VK_F4) || + ( (lphc->wState & CBF_EUI) && !(lphc->wState & CBF_DROPPED) + && (wParam == VK_DOWN || wParam == VK_UP)) ) + { + COMBO_FlipListbox( lphc, FALSE ); + return 0; + } + } + return LISTBOX_HandleKeyDown( wnd, descr, wParam ); + + case LB_SETCURSEL: + lRet = ListBoxWndProc( hwnd, msg, wParam, lParam ); + return (lRet == LB_ERR) ? lRet : descr->selected_item; + + case WM_NCDESTROY: + if( CB_GETTYPE(lphc) != CBS_SIMPLE ) + lphc->hWndLBox = 0; + /* fall through */ + + default: + return ListBoxWndProc( hwnd, msg, wParam, lParam ); + } + } + lRet = DefWindowProcA( hwnd, msg, wParam, lParam ); + + DPRINT("\t default on msg [%04x]\n", (UINT)msg ); + } + + return lRet; +} + diff --git a/reactos/lib/user32/windows/menu.c b/reactos/lib/user32/controls/menu.c similarity index 94% rename from reactos/lib/user32/windows/menu.c rename to reactos/lib/user32/controls/menu.c index c25327b057b..322925dcf89 100644 --- a/reactos/lib/user32/windows/menu.c +++ b/reactos/lib/user32/controls/menu.c @@ -14,20 +14,20 @@ -#include #include #include #include -#undef WIN32_LEAN_AND_MEAN + + #include #include -//#include +#include #include #include #include +#include + -#include -#define DPRINT printf /********************************************************************** @@ -49,7 +49,7 @@ HMENU STDCALL CreateMenu(void) menu->hWnd = 0; menu->items = NULL; menu->FocusedItem = NO_SELECTED_ITEM; - //TRACE(menu, "return %04x\n", hMenu ); + DPRINT( "return %04x\n", hMenu ); return hMenu; } @@ -254,10 +254,10 @@ WINBOOL STDCALL DrawMenuBar( HWND hWnd ) */ HMENU STDCALL LoadMenuA( HINSTANCE instance, LPCSTR name ) { -// instance should be a module handle GetModuleHandle(NULL) - HRSRC hrsrc = FindResourceA( instance, name, (LPCSTR)RT_MENU ); + + HRSRC hrsrc = FindResourceA( GetModuleHandle(NULL), name, (LPCSTR)RT_MENU ); if (!hrsrc) return 0; - return LoadMenuIndirectA( (LPCVOID)LoadResource( instance, hrsrc )); + return LoadMenuIndirectA( (LPCVOID)LoadResource( GetModuleHandle(NULL), hrsrc )); } @@ -267,19 +267,61 @@ HMENU STDCALL LoadMenuA( HINSTANCE instance, LPCSTR name ) HMENU STDCALL LoadMenuW( HINSTANCE hInstance, LPCWSTR name ) { - HRSRC hrsrc = FindResourceW( hInstance, name, (LPCWSTR)RT_MENU ); - if (!hrsrc) - return 0; - return LoadMenuIndirectW( (LPCVOID)LoadResource( hInstance, hrsrc )); + HRSRC hrsrc = FindResourceW( GetModuleHandle(NULL), name, (LPCSTR)RT_MENU ); + if (!hrsrc) return 0; + return LoadMenuIndirectW( (LPCVOID)LoadResource( GetModuleHandle(NULL), hrsrc )); } /* +A menu template consists of a MENUITEMTEMPLATEHEADER structure +followed by one or more contiguous MENUITEMTEMPLATE structures. +In Windows 95, an extended menu template consists of a +MENUEX_TEMPLATE_HEADER structure followed by one or more +contiguous MENUEX_TEMPLATE_ITEM structures. -typedef struct { - WORD mtOption; - WORD mtID; - WCHAR mtString[1]; + +typedef struct { + WORD wVersion; + WORD wOffset; + DWORD dwHelpId; +} MENUEX_TEMPLATE_HEADER; + +typedef struct { + DWORD dwType; + DWORD dwState; + UINT uId; + BYTE bResInfo; + WCHAR szText[1]; + DWORD dwHelpId; +} MENUEX_TEMPLATE_ITEM; + +typedef struct tagMENUITEMINFO { + UINT cbSize; + UINT fMask; + UINT fType; + UINT fState; + UINT wID; + HMENU hSubMenu; + HBITMAP hbmpChecked; + HBITMAP hbmpUnchecked; + DWORD dwItemData; + LPTSTR dwTypeData; + UINT cch; +} MENUITEMINFO, *LPMENUITEMINFO; +typedef MENUITEMINFO CONST *LPCMENUITEMINFO; + +typedef struct { + WORD mtOption; + WORD mtID; + WCHAR mtString[1]; } MENUITEMTEMPLATE; + +typedef struct { + WORD versionNumber; + WORD offset; +} MENUITEMTEMPLATEHEADER; +typedef VOID MENUTEMPLATE, *LPMENUTEMPLATE; + */ /********************************************************************** @@ -986,8 +1028,7 @@ INT STDCALL GetMenuStringA( HMENU hMenu, UINT wItemID, MENUITEM *item; int i; int len; - //TRACE(menu, "menu=%04x item=%04x ptr=%p len=%d flags=%04x\n", - // hMenu, wItemID, str, nMaxSiz, wFlags ); + DPRINT( "menu=%04x item=%04x ptr=%p len=%d flags=%04x\n", hMenu, wItemID, str, nMaxSiz, wFlags ); if (!str || !nMaxSiz) return 0; str[0] = '\0'; @@ -1012,8 +1053,7 @@ INT STDCALL GetMenuStringW( HMENU hMenu, UINT wItemID, { MENUITEM *item; - //TRACE(menu, "menu=%04x item=%04x ptr=%p len=%d flags=%04x\n", - // hMenu, wItemID, str, nMaxSiz, wFlags ); + DPRINT( "menu=%04x item=%04x ptr=%p len=%d flags=%04x\n", hMenu, wItemID, str, nMaxSiz, wFlags ); if (!str || !nMaxSiz) return 0; str[0] = '\0'; @@ -1030,8 +1070,8 @@ WINBOOL STDCALL HiliteMenuItem( HWND hWnd, HMENU hMenu, UINT wItemID, UINT wHilite ) { LPPOPUPMENU menu; -// DPRINT("menu (%04x, %04x, %04x, %04x);\n", -// hWnd, hMenu, wItemID, wHilite); + DPRINT("menu (%04x, %04x, %04x, %04x);\n", hWnd, hMenu, wItemID, wHilite); + if (!MENU_FindItem( &hMenu, &wItemID, wHilite )) return FALSE; if (!(menu = (LPPOPUPMENU) (hMenu))) return FALSE; if (menu->FocusedItem == wItemID) return TRUE; @@ -1269,7 +1309,6 @@ STDCALL GetMenuCheckMarkDimensions(VOID) { - return MAKELONG(GetSystemMetrics(SM_CXMENUCHECK), GetSystemMetrics(SM_CYMENUCHECK) ); } diff --git a/reactos/lib/user32/controls/scroll.c b/reactos/lib/user32/controls/scroll.c new file mode 100644 index 00000000000..f0960d22386 --- /dev/null +++ b/reactos/lib/user32/controls/scroll.c @@ -0,0 +1,1445 @@ +/* + * Scrollbar control + * + * Copyright 1993 Martin Ayotte + * Copyright 1994, 1996 Alexandre Julliard + */ + +#include +#include +#include +#include +#include +#include +#include + +#define MAX(x,y) x > y ? x : y +#define MIN(x,y) x < y ? x : y + +static HBITMAP hUpArrow = 0; +static HBITMAP hDnArrow = 0; +static HBITMAP hLfArrow = 0; +static HBITMAP hRgArrow = 0; +static HBITMAP hUpArrowD = 0; +static HBITMAP hDnArrowD = 0; +static HBITMAP hLfArrowD = 0; +static HBITMAP hRgArrowD = 0; +static HBITMAP hUpArrowI = 0; +static HBITMAP hDnArrowI = 0; +static HBITMAP hLfArrowI = 0; +static HBITMAP hRgArrowI = 0; + +#define TOP_ARROW(flags,pressed) \ + (((flags)&ESB_DISABLE_UP) ? hUpArrowI : ((pressed) ? hUpArrowD:hUpArrow)) +#define BOTTOM_ARROW(flags,pressed) \ + (((flags)&ESB_DISABLE_DOWN) ? hDnArrowI : ((pressed) ? hDnArrowD:hDnArrow)) +#define LEFT_ARROW(flags,pressed) \ + (((flags)&ESB_DISABLE_LEFT) ? hLfArrowI : ((pressed) ? hLfArrowD:hLfArrow)) +#define RIGHT_ARROW(flags,pressed) \ + (((flags)&ESB_DISABLE_RIGHT) ? hRgArrowI : ((pressed) ? hRgArrowD:hRgArrow)) + + + /* Minimum size of the rectangle between the arrows */ +#define SCROLL_MIN_RECT 4 + + /* Minimum size of the thumb in pixels */ +#define SCROLL_MIN_THUMB 6 + + /* Overlap between arrows and thumb */ +#define SCROLL_ARROW_THUMB_OVERLAP 1 + + /* Delay (in ms) before first repetition when holding the button down */ +#define SCROLL_FIRST_DELAY 200 + + /* Delay (in ms) between scroll repetitions */ +#define SCROLL_REPEAT_DELAY 50 + + /* Scroll timer id */ +#define SCROLL_TIMER 0 + + /* Scroll-bar hit testing */ +enum SCROLL_HITTEST +{ + SCROLL_NOWHERE, /* Outside the scroll bar */ + SCROLL_TOP_ARROW, /* Top or left arrow */ + SCROLL_TOP_RECT, /* Rectangle between the top arrow and the thumb */ + SCROLL_THUMB, /* Thumb rectangle */ + SCROLL_BOTTOM_RECT, /* Rectangle between the thumb and the bottom arrow */ + SCROLL_BOTTOM_ARROW /* Bottom or right arrow */ +}; + + /* What to do after SCROLL_SetScrollInfo() */ +#define SA_SSI_HIDE 0x0001 +#define SA_SSI_SHOW 0x0002 +#define SA_SSI_REFRESH 0x0004 +#define SA_SSI_REPAINT_ARROWS 0x0008 + + /* Thumb-tracking info */ +static HWND SCROLL_TrackingWin = 0; +static INT SCROLL_TrackingBar = 0; +static INT SCROLL_TrackingPos = 0; +static INT SCROLL_TrackingVal = 0; + /* Hit test code of the last button-down event */ +static enum SCROLL_HITTEST SCROLL_trackHitTest; +static BOOL SCROLL_trackVertical; + + /* Is the moving thumb being displayed? */ +static BOOL SCROLL_MovingThumb = FALSE; + + /* Local functions */ +static BOOL SCROLL_ShowScrollBar( HWND hwnd, INT nBar, + BOOL fShowH, BOOL fShowV ); +static INT SCROLL_SetScrollInfo( HWND hwnd, INT nBar, + const SCROLLINFO *info, INT *action ); + +/*********************************************************************** + * SCROLL_LoadBitmaps + */ +static void SCROLL_LoadBitmaps(void) +{ + hUpArrow = LoadBitmapA( 0, MAKEINTRESOURCE(OBM_UPARROW) ); + hDnArrow = LoadBitmapA( 0, MAKEINTRESOURCE(OBM_DNARROW) ); + hLfArrow = LoadBitmapA( 0, MAKEINTRESOURCE(OBM_LFARROW) ); + hRgArrow = LoadBitmapA( 0, MAKEINTRESOURCE(OBM_RGARROW) ); + hUpArrowD = LoadBitmapA( 0, MAKEINTRESOURCE(OBM_UPARROWD) ); + hDnArrowD = LoadBitmapA( 0, MAKEINTRESOURCE(OBM_DNARROWD) ); + hLfArrowD = LoadBitmapA( 0, MAKEINTRESOURCE(OBM_LFARROWD) ); + hRgArrowD = LoadBitmapA( 0, MAKEINTRESOURCE(OBM_RGARROWD) ); + hUpArrowI = LoadBitmapA( 0, MAKEINTRESOURCE(OBM_UPARROWI) ); + hDnArrowI = LoadBitmapA( 0, MAKEINTRESOURCE(OBM_DNARROWI) ); + hLfArrowI = LoadBitmapA( 0, MAKEINTRESOURCE(OBM_LFARROWI) ); + hRgArrowI = LoadBitmapA( 0, MAKEINTRESOURCE(OBM_RGARROWI) ); +} + + +/*********************************************************************** + * SCROLL_GetPtrScrollInfo + */ +static SCROLLBAR_INFO *SCROLL_GetPtrScrollInfo( WND* wndPtr, INT nBar ) +{ + SCROLLBAR_INFO *infoPtr; + + if (!wndPtr) return NULL; + switch(nBar) + { + case SB_HORZ: infoPtr = (SCROLLBAR_INFO *)wndPtr->pHScroll; break; + case SB_VERT: infoPtr = (SCROLLBAR_INFO *)wndPtr->pVScroll; break; + case SB_CTL: infoPtr = (SCROLLBAR_INFO *)wndPtr->wExtra; break; + default: return NULL; + } + + if (!infoPtr) /* Create the info structure if needed */ + { + if ((infoPtr = HeapAlloc( GetProcessHeap(), 0, sizeof(SCROLLBAR_INFO) ))) + { + infoPtr->MinVal = infoPtr->CurVal = infoPtr->Page = 0; + infoPtr->MaxVal = 100; + infoPtr->flags = ESB_ENABLE_BOTH; + if (nBar == SB_HORZ) wndPtr->pHScroll = infoPtr; + else wndPtr->pVScroll = infoPtr; + } + if (!hUpArrow) SCROLL_LoadBitmaps(); + } + return infoPtr; +} + + +/*********************************************************************** + * SCROLL_GetScrollInfo + */ +static SCROLLBAR_INFO *SCROLL_GetScrollInfo( HWND hwnd, INT nBar ) +{ + WND *wndPtr = WIN_FindWndPtr( hwnd ); + return SCROLL_GetPtrScrollInfo( wndPtr, nBar ); +} + + +/*********************************************************************** + * SCROLL_GetScrollBarRect + * + * Compute the scroll bar rectangle, in drawing coordinates (i.e. client + * coords for SB_CTL, window coords for SB_VERT and SB_HORZ). + * 'arrowSize' returns the width or height of an arrow (depending on + * the orientation of the scrollbar), 'thumbSize' returns the size of + * the thumb, and 'thumbPos' returns the position of the thumb + * relative to the left or to the top. + * Return TRUE if the scrollbar is vertical, FALSE if horizontal. + */ +static BOOL SCROLL_GetScrollBarRect( HWND hwnd, INT nBar, RECT *lprect, + INT *arrowSize, INT *thumbSize, + INT *thumbPos ) +{ + INT pixels; + BOOL vertical; + WND *wndPtr = WIN_FindWndPtr( hwnd ); + + switch(nBar) + { + case SB_HORZ: + lprect->left = wndPtr->rectClient.left - wndPtr->rectWindow.left; + lprect->top = wndPtr->rectClient.bottom - wndPtr->rectWindow.top; + lprect->right = wndPtr->rectClient.right - wndPtr->rectWindow.left; + lprect->bottom = lprect->top + SYSMETRICS_CYHSCROLL; + if(wndPtr->dwStyle & WS_BORDER) { + lprect->left--; + lprect->right++; + } else if(wndPtr->dwStyle & WS_VSCROLL) + lprect->right++; + vertical = FALSE; + break; + + case SB_VERT: + lprect->left = wndPtr->rectClient.right - wndPtr->rectWindow.left; + lprect->top = wndPtr->rectClient.top - wndPtr->rectWindow.top; + lprect->right = lprect->left + SYSMETRICS_CXVSCROLL; + lprect->bottom = wndPtr->rectClient.bottom - wndPtr->rectWindow.top; + if(wndPtr->dwStyle & WS_BORDER) { + lprect->top--; + lprect->bottom++; + } else if(wndPtr->dwStyle & WS_HSCROLL) + lprect->bottom++; + vertical = TRUE; + break; + + case SB_CTL: + GetClientRect( hwnd, lprect ); + vertical = ((wndPtr->dwStyle & SBS_VERT) != 0); + break; + + default: + return FALSE; + } + + if (vertical) pixels = lprect->bottom - lprect->top; + else pixels = lprect->right - lprect->left; + + if (pixels <= 2*SYSMETRICS_CXVSCROLL + SCROLL_MIN_RECT) + { + if (pixels > SCROLL_MIN_RECT) + *arrowSize = (pixels - SCROLL_MIN_RECT) / 2; + else + *arrowSize = 0; + *thumbPos = *thumbSize = 0; + } + else + { + SCROLLBAR_INFO *info = SCROLL_GetPtrScrollInfo( wndPtr, nBar ); + + *arrowSize = SYSMETRICS_CXVSCROLL; + pixels -= (2 * (SYSMETRICS_CXVSCROLL - SCROLL_ARROW_THUMB_OVERLAP)); + + if (info->Page) + { + *thumbSize = pixels * info->Page / (info->MaxVal-info->MinVal+1); + if (*thumbSize < SCROLL_MIN_THUMB) *thumbSize = SCROLL_MIN_THUMB; + } + else *thumbSize = SYSMETRICS_CXVSCROLL; + + if (((pixels -= *thumbSize ) < 0) || + ((info->flags & ESB_DISABLE_BOTH) == ESB_DISABLE_BOTH)) + { + /* Rectangle too small or scrollbar disabled -> no thumb */ + *thumbPos = *thumbSize = 0; + } + else + { + INT max = info->MaxVal - MAX( info->Page-1, 0 ); + if (info->MinVal >= max) + *thumbPos = *arrowSize - SCROLL_ARROW_THUMB_OVERLAP; + else + *thumbPos = *arrowSize - SCROLL_ARROW_THUMB_OVERLAP + + pixels * (info->CurVal-info->MinVal) / (max - info->MinVal); + } + } + return vertical; +} + + +/*********************************************************************** + * SCROLL_GetThumbVal + * + * Compute the current scroll position based on the thumb position in pixels + * from the top of the scroll-bar. + */ +static UINT SCROLL_GetThumbVal( SCROLLBAR_INFO *infoPtr, RECT *rect, + BOOL vertical, INT pos ) +{ + INT thumbSize; + INT pixels = vertical ? rect->bottom-rect->top : rect->right-rect->left; + + if ((pixels -= 2*(SYSMETRICS_CXVSCROLL - SCROLL_ARROW_THUMB_OVERLAP)) <= 0) + return infoPtr->MinVal; + + if (infoPtr->Page) + { + thumbSize = pixels * infoPtr->Page/(infoPtr->MaxVal-infoPtr->MinVal+1); + if (thumbSize < SCROLL_MIN_THUMB) thumbSize = SCROLL_MIN_THUMB; + } + else thumbSize = SYSMETRICS_CXVSCROLL; + + if ((pixels -= thumbSize) <= 0) return infoPtr->MinVal; + + pos = MAX( 0, pos - (SYSMETRICS_CXVSCROLL - SCROLL_ARROW_THUMB_OVERLAP) ); + if (pos > pixels) pos = pixels; + + if (!infoPtr->Page) pos *= infoPtr->MaxVal - infoPtr->MinVal; + else pos *= infoPtr->MaxVal - infoPtr->MinVal - infoPtr->Page + 1; + return infoPtr->MinVal + ((pos + pixels / 2) / pixels); +} + +/*********************************************************************** + * SCROLL_PtInRectEx + */ +static BOOL SCROLL_PtInRectEx( LPRECT lpRect, POINT pt, BOOL vertical ) +{ + RECT rect = *lpRect; + + if (vertical) + { + rect.left -= lpRect->right - lpRect->left; + rect.right += lpRect->right - lpRect->left; + } + else + { + rect.top -= lpRect->bottom - lpRect->top; + rect.bottom += lpRect->bottom - lpRect->top; + } + return PtInRect( &rect, pt ); +} + +/*********************************************************************** + * SCROLL_ClipPos + */ +static POINT SCROLL_ClipPos( LPRECT lpRect, POINT pt ) +{ + if( pt.x < lpRect->left ) + pt.x = lpRect->left; + else + if( pt.x > lpRect->right ) + pt.x = lpRect->right; + + if( pt.y < lpRect->top ) + pt.y = lpRect->top; + else + if( pt.y > lpRect->bottom ) + pt.y = lpRect->bottom; + + return pt; +} + + +/*********************************************************************** + * SCROLL_HitTest + * + * Scroll-bar hit testing (don't confuse this with WM_NCHITTEST!). + */ +static enum SCROLL_HITTEST SCROLL_HitTest( HWND hwnd, INT nBar, + POINT pt, BOOL bDragging ) +{ + INT arrowSize, thumbSize, thumbPos; + RECT rect; + + BOOL vertical = SCROLL_GetScrollBarRect( hwnd, nBar, &rect, + &arrowSize, &thumbSize, &thumbPos ); + + if ( (bDragging && !SCROLL_PtInRectEx( &rect, pt, vertical )) || + (!PtInRect( &rect, pt )) ) return SCROLL_NOWHERE; + + if (vertical) + { + if (pt.y < rect.top + arrowSize) return SCROLL_TOP_ARROW; + if (pt.y >= rect.bottom - arrowSize) return SCROLL_BOTTOM_ARROW; + if (!thumbPos) return SCROLL_TOP_RECT; + pt.y -= rect.top; + if (pt.y < thumbPos) return SCROLL_TOP_RECT; + if (pt.y >= thumbPos + thumbSize) return SCROLL_BOTTOM_RECT; + } + else /* horizontal */ + { + if (pt.x < rect.left + arrowSize) return SCROLL_TOP_ARROW; + if (pt.x >= rect.right - arrowSize) return SCROLL_BOTTOM_ARROW; + if (!thumbPos) return SCROLL_TOP_RECT; + pt.x -= rect.left; + if (pt.x < thumbPos) return SCROLL_TOP_RECT; + if (pt.x >= thumbPos + thumbSize) return SCROLL_BOTTOM_RECT; + } + return SCROLL_THUMB; +} + + +/*********************************************************************** + * SCROLL_DrawArrows + * + * Draw the scroll bar arrows. + */ +static void SCROLL_DrawArrows( HDC hdc, SCROLLBAR_INFO *infoPtr, + RECT *rect, INT arrowSize, BOOL vertical, + BOOL top_pressed, BOOL bottom_pressed ) +{ + HDC hdcMem = CreateCompatibleDC( hdc ); + HBITMAP hbmpPrev = SelectObject( hdcMem, vertical ? + TOP_ARROW(infoPtr->flags, top_pressed) + : LEFT_ARROW(infoPtr->flags, top_pressed)); + + SetStretchBltMode( hdc, STRETCH_DELETESCANS ); + StretchBlt( hdc, rect->left, rect->top, + vertical ? rect->right-rect->left : arrowSize, + vertical ? arrowSize : rect->bottom-rect->top, + hdcMem, 0, 0, + SYSMETRICS_CXVSCROLL, SYSMETRICS_CYHSCROLL, + SRCCOPY ); + + SelectObject( hdcMem, vertical ? + BOTTOM_ARROW( infoPtr->flags, bottom_pressed ) + : RIGHT_ARROW( infoPtr->flags, bottom_pressed ) ); + if (vertical) + StretchBlt( hdc, rect->left, rect->bottom - arrowSize, + rect->right - rect->left, arrowSize, + hdcMem, 0, 0, + SYSMETRICS_CXVSCROLL, SYSMETRICS_CYHSCROLL, + SRCCOPY ); + else + StretchBlt( hdc, rect->right - arrowSize, rect->top, + arrowSize, rect->bottom - rect->top, + hdcMem, 0, 0, + SYSMETRICS_CXVSCROLL, SYSMETRICS_CYHSCROLL, + SRCCOPY ); + SelectObject( hdcMem, hbmpPrev ); + DeleteDC( hdcMem ); +} + + +/*********************************************************************** + * SCROLL_DrawMovingThumb + * + * Draw the moving thumb rectangle. + */ +static void SCROLL_DrawMovingThumb( HDC hdc, RECT *rect, BOOL vertical, + INT arrowSize, INT thumbSize ) +{ + RECT r = *rect; + if (vertical) + { + r.top += SCROLL_TrackingPos; + if (r.top < rect->top + arrowSize - SCROLL_ARROW_THUMB_OVERLAP) + r.top = rect->top + arrowSize - SCROLL_ARROW_THUMB_OVERLAP; + if (r.top + thumbSize > + rect->bottom - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP)) + r.top = rect->bottom - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP) + - thumbSize; + r.bottom = r.top + thumbSize; + } + else + { + r.left += SCROLL_TrackingPos; + if (r.left < rect->left + arrowSize - SCROLL_ARROW_THUMB_OVERLAP) + r.left = rect->left + arrowSize - SCROLL_ARROW_THUMB_OVERLAP; + if (r.left + thumbSize > + rect->right - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP)) + r.left = rect->right - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP) + - thumbSize; + r.right = r.left + thumbSize; + } + DrawFocusRect( hdc, &r ); + SCROLL_MovingThumb = !SCROLL_MovingThumb; +} + + +/*********************************************************************** + * SCROLL_DrawInterior + * + * Draw the scroll bar interior (everything except the arrows). + */ +static void SCROLL_DrawInterior( HWND hwnd, HDC hdc, INT nBar, + RECT *rect, INT arrowSize, + INT thumbSize, INT thumbPos, + UINT flags, BOOL vertical, + BOOL top_selected, BOOL bottom_selected ) +{ + RECT r; + + /* Select the correct brush and pen */ + + SelectObject( hdc, GetSysColorPen(COLOR_WINDOWFRAME) ); + if ((flags & ESB_DISABLE_BOTH) == ESB_DISABLE_BOTH) + { + /* This ought to be the color of the parent window */ + SelectObject( hdc, GetSysColorBrush(COLOR_WINDOW) ); + } + else + { + if (nBar == SB_CTL) /* Only scrollbar controls send WM_CTLCOLOR */ + { + HBRUSH hbrush = SendMessageA(GetParent(hwnd), + WM_CTLCOLORSCROLLBAR, hdc, hwnd ); + SelectObject( hdc, hbrush ); + } + else SelectObject( hdc, GetSysColorBrush(COLOR_SCROLLBAR) ); + } + + /* Calculate the scroll rectangle */ + + r = *rect; + if (vertical) + { + r.top += arrowSize - SCROLL_ARROW_THUMB_OVERLAP; + r.bottom -= (arrowSize - SCROLL_ARROW_THUMB_OVERLAP); + } + else + { + r.left += arrowSize - SCROLL_ARROW_THUMB_OVERLAP; + r.right -= (arrowSize - SCROLL_ARROW_THUMB_OVERLAP); + } + + /* Draw the scroll bar frame */ + + Rectangle( hdc, r.left, r.top, r.right, r.bottom ); + + /* Draw the scroll rectangles and thumb */ + + if (!thumbPos) /* No thumb to draw */ + { + PatBlt( hdc, r.left+1, r.top+1, r.right - r.left - 2, + r.bottom - r.top - 2, PATCOPY ); + return; + } + + if (vertical) + { + PatBlt( hdc, r.left + 1, r.top + 1, + r.right - r.left - 2, + thumbPos - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP) - 1, + top_selected ? 0x0f0000 : PATCOPY ); + r.top += thumbPos - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP); + PatBlt( hdc, r.left + 1, r.top + thumbSize, + r.right - r.left - 2, + r.bottom - r.top - thumbSize - 1, + bottom_selected ? 0x0f0000 : PATCOPY ); + r.bottom = r.top + thumbSize; + } + else /* horizontal */ + { + PatBlt( hdc, r.left + 1, r.top + 1, + thumbPos - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP) - 1, + r.bottom - r.top - 2, + top_selected ? 0x0f0000 : PATCOPY ); + r.left += thumbPos - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP); + PatBlt( hdc, r.left + thumbSize, r.top + 1, + r.right - r.left - thumbSize - 1, + r.bottom - r.top - 2, + bottom_selected ? 0x0f0000 : PATCOPY ); + r.right = r.left + thumbSize; + } + + /* Draw the thumb */ + + SelectObject( hdc, GetSysColorBrush(COLOR_BTNFACE) ); + Rectangle( hdc, r.left, r.top, r.right, r.bottom ); + r.top++, r.left++; + DrawEdge( hdc, &r, EDGE_RAISED, BF_RECT ); + if (SCROLL_MovingThumb && + (SCROLL_TrackingWin == hwnd) && + (SCROLL_TrackingBar == nBar)) + { + SCROLL_DrawMovingThumb( hdc, rect, vertical, arrowSize, thumbSize ); + SCROLL_MovingThumb = TRUE; + } +} + + +/*********************************************************************** + * SCROLL_DrawScrollBar + * + * Redraw the whole scrollbar. + */ +void SCROLL_DrawScrollBar( HWND hwnd, HDC hdc, INT nBar, + BOOL arrows, BOOL interior ) +{ + INT arrowSize, thumbSize, thumbPos; + RECT rect; + BOOL vertical; + WND *wndPtr = WIN_FindWndPtr( hwnd ); + SCROLLBAR_INFO *infoPtr = SCROLL_GetPtrScrollInfo( wndPtr, nBar ); + + if (!wndPtr || !infoPtr || + ((nBar == SB_VERT) && !(wndPtr->dwStyle & WS_VSCROLL)) || + ((nBar == SB_HORZ) && !(wndPtr->dwStyle & WS_HSCROLL))) return; + if (!WIN_IsWindowDrawable( wndPtr, FALSE )) return; + + vertical = SCROLL_GetScrollBarRect( hwnd, nBar, &rect, + &arrowSize, &thumbSize, &thumbPos ); + + /* Draw the arrows */ + + if (arrows && arrowSize) + { + if( vertical == SCROLL_trackVertical && GetCapture() == hwnd ) + SCROLL_DrawArrows( hdc, infoPtr, &rect, arrowSize, vertical, + (SCROLL_trackHitTest == SCROLL_TOP_ARROW), + (SCROLL_trackHitTest == SCROLL_BOTTOM_ARROW) ); + else + SCROLL_DrawArrows( hdc, infoPtr, &rect, arrowSize, vertical, + FALSE, FALSE ); + } + if( interior ) + SCROLL_DrawInterior( hwnd, hdc, nBar, &rect, arrowSize, thumbSize, + thumbPos, infoPtr->flags, vertical, FALSE, FALSE ); +} + + +/*********************************************************************** + * SCROLL_RefreshScrollBar + * + * Repaint the scroll bar interior after a SetScrollRange() or + * SetScrollPos() call. + */ +static void SCROLL_RefreshScrollBar( HWND hwnd, INT nBar, + BOOL arrows, BOOL interior ) +{ + HDC hdc = GetDCEx( hwnd, 0, + DCX_CACHE | ((nBar == SB_CTL) ? 0 : DCX_WINDOW) ); + if (!hdc) return; + + SCROLL_DrawScrollBar( hwnd, hdc, nBar, arrows, interior ); + ReleaseDC( hwnd, hdc ); +} + + +/*********************************************************************** + * SCROLL_HandleKbdEvent + * + * Handle a keyboard event (only for SB_CTL scrollbars). + */ +static void SCROLL_HandleKbdEvent( HWND hwnd, WPARAM wParam ) +{ + WND *wndPtr = WIN_FindWndPtr( hwnd ); + WPARAM msg; + + switch(wParam) + { + case VK_PRIOR: msg = SB_PAGEUP; break; + case VK_NEXT: msg = SB_PAGEDOWN; break; + case VK_HOME: msg = SB_TOP; break; + case VK_END: msg = SB_BOTTOM; break; + case VK_UP: msg = SB_LINEUP; break; + case VK_DOWN: msg = SB_LINEDOWN; break; + default: + return; + } + SendMessageA( GetParent(hwnd), + (wndPtr->dwStyle & SBS_VERT) ? WM_VSCROLL : WM_HSCROLL, + msg, hwnd ); +} + + +/*********************************************************************** + * SCROLL_HandleScrollEvent + * + * Handle a mouse or timer event for the scrollbar. + * 'pt' is the location of the mouse event in client (for SB_CTL) or + * windows coordinates. + */ +void SCROLL_HandleScrollEvent( HWND hwnd, INT nBar, UINT msg, POINT pt) +{ + /* Previous mouse position for timer events */ + static POINT prevPt; + /* Thumb position when tracking started. */ + static UINT trackThumbPos; + /* Position in the scroll-bar of the last button-down event. */ + static INT lastClickPos; + /* Position in the scroll-bar of the last mouse event. */ + static INT lastMousePos; + + enum SCROLL_HITTEST hittest; + HWND hwndOwner, hwndCtl; + BOOL vertical; + INT arrowSize, thumbSize, thumbPos; + RECT rect; + HDC hdc; + + SCROLLBAR_INFO *infoPtr = SCROLL_GetScrollInfo( hwnd, nBar ); + if (!infoPtr) return; + if ((SCROLL_trackHitTest == SCROLL_NOWHERE) && (msg != WM_LBUTTONDOWN)) + return; + + hdc = GetDCEx( hwnd, 0, DCX_CACHE | ((nBar == SB_CTL) ? 0 : DCX_WINDOW)); + vertical = SCROLL_GetScrollBarRect( hwnd, nBar, &rect, + &arrowSize, &thumbSize, &thumbPos ); + hwndOwner = (nBar == SB_CTL) ? GetParent(hwnd) : hwnd; + hwndCtl = (nBar == SB_CTL) ? hwnd : 0; + + switch(msg) + { + case WM_LBUTTONDOWN: /* Initialise mouse tracking */ + SCROLL_trackVertical = vertical; + SCROLL_trackHitTest = hittest = SCROLL_HitTest( hwnd, nBar, pt, FALSE ); + lastClickPos = vertical ? (pt.y - rect.top) : (pt.x - rect.left); + lastMousePos = lastClickPos; + trackThumbPos = thumbPos; + prevPt = pt; + SetCapture( hwnd ); + if (nBar == SB_CTL) SetFocus( hwnd ); + break; + + case WM_MOUSEMOVE: + hittest = SCROLL_HitTest( hwnd, nBar, pt, TRUE ); + prevPt = pt; + break; + + case WM_LBUTTONUP: + hittest = SCROLL_NOWHERE; + ReleaseCapture(); + break; + + case WM_TIMER: + pt = prevPt; + hittest = SCROLL_HitTest( hwnd, nBar, pt, FALSE ); + break; + + default: + return; /* Should never happen */ + } + + DPRINT( "Event: hwnd=%04x bar=%d msg=%x pt=%d,%d hit=%d\n", + hwnd, nBar, msg, pt.x, pt.y, hittest ); + + switch(SCROLL_trackHitTest) + { + case SCROLL_NOWHERE: /* No tracking in progress */ + break; + + case SCROLL_TOP_ARROW: + SCROLL_DrawArrows( hdc, infoPtr, &rect, arrowSize, vertical, + (hittest == SCROLL_trackHitTest), FALSE ); + if (hittest == SCROLL_trackHitTest) + { + if ((msg == WM_LBUTTONDOWN) || (msg == WM_TIMER)) + { + SendMessageA( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL, + SB_LINEUP, hwndCtl ); + SetTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ? + SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY, + (TIMERPROC)0 ); + } + } + else KillTimer( hwnd, SCROLL_TIMER ); + break; + + case SCROLL_TOP_RECT: + SCROLL_DrawInterior( hwnd, hdc, nBar, &rect, arrowSize, thumbSize, + thumbPos, infoPtr->flags, vertical, + (hittest == SCROLL_trackHitTest), FALSE ); + if (hittest == SCROLL_trackHitTest) + { + if ((msg == WM_LBUTTONDOWN) || (msg == WM_TIMER)) + { + SendMessageA( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL, + SB_PAGEUP, hwndCtl ); + SetTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ? + SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY, + (TIMERPROC)0 ); + } + } + else KillTimer( hwnd, SCROLL_TIMER ); + break; + + case SCROLL_THUMB: + if (msg == WM_LBUTTONDOWN) + { + SCROLL_TrackingWin = hwnd; + SCROLL_TrackingBar = nBar; + SCROLL_TrackingPos = trackThumbPos + lastMousePos - lastClickPos; + SCROLL_DrawMovingThumb(hdc, &rect, vertical, arrowSize, thumbSize); + } + else if (msg == WM_LBUTTONUP) + { + SCROLL_TrackingWin = 0; + SCROLL_MovingThumb = FALSE; + SCROLL_DrawInterior( hwnd, hdc, nBar, &rect, arrowSize, thumbSize, + thumbPos, infoPtr->flags, vertical, + FALSE, FALSE ); + } + else /* WM_MOUSEMOVE */ + { + UINT pos; + + if (!SCROLL_PtInRectEx( &rect, pt, vertical )) pos = lastClickPos; + else + { + pt = SCROLL_ClipPos( &rect, pt ); + pos = vertical ? (pt.y - rect.top) : (pt.x - rect.left); + } + if (pos != lastMousePos) + { + SCROLL_DrawMovingThumb( hdc, &rect, vertical, + arrowSize, thumbSize ); + lastMousePos = pos; + SCROLL_TrackingPos = trackThumbPos + pos - lastClickPos; + SCROLL_TrackingVal = SCROLL_GetThumbVal( infoPtr, &rect, + vertical, + SCROLL_TrackingPos ); + SendMessageA( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL, + MAKEWPARAM( SB_THUMBTRACK, SCROLL_TrackingVal), + hwndCtl ); + SCROLL_DrawMovingThumb( hdc, &rect, vertical, + arrowSize, thumbSize ); + } + } + break; + + case SCROLL_BOTTOM_RECT: + SCROLL_DrawInterior( hwnd, hdc, nBar, &rect, arrowSize, thumbSize, + thumbPos, infoPtr->flags, vertical, + FALSE, (hittest == SCROLL_trackHitTest) ); + if (hittest == SCROLL_trackHitTest) + { + if ((msg == WM_LBUTTONDOWN) || (msg == WM_TIMER)) + { + SendMessageA( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL, + SB_PAGEDOWN, hwndCtl ); + SetTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ? + SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY, + (TIMERPROC)0 ); + } + } + else KillTimer( hwnd, SCROLL_TIMER ); + break; + + case SCROLL_BOTTOM_ARROW: + SCROLL_DrawArrows( hdc, infoPtr, &rect, arrowSize, vertical, + FALSE, (hittest == SCROLL_trackHitTest) ); + if (hittest == SCROLL_trackHitTest) + { + if ((msg == WM_LBUTTONDOWN) || (msg == WM_TIMER)) + { + SendMessageA( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL, + SB_LINEDOWN, (LPARAM)hwndCtl ); + SetTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ? + SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY, + (TIMERPROC)0 ); + } + } + else KillTimer( hwnd, SCROLL_TIMER ); + break; + } + + if (msg == WM_LBUTTONUP) + { + hittest = SCROLL_trackHitTest; + SCROLL_trackHitTest = SCROLL_NOWHERE; /* Terminate tracking */ + + if (hittest == SCROLL_THUMB) + { + UINT val = SCROLL_GetThumbVal( infoPtr, &rect, vertical, + trackThumbPos + lastMousePos - lastClickPos ); + SendMessageA( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL, + MAKEWPARAM( SB_THUMBPOSITION, val ), (LPARAM)hwndCtl ); + } + else + SendMessageA( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL, + SB_ENDSCROLL, (LPARAM)hwndCtl ); + } + + ReleaseDC( hwnd, hdc ); +} + + +/*********************************************************************** + * ScrollBarWndProc + */ +LRESULT STDCALL ScrollBarWndProc( HWND hwnd, UINT message, WPARAM wParam, + LPARAM lParam ) +{ + POINT *pt; + switch(message) + { + case WM_CREATE: + { + CREATESTRUCTA *lpCreat = (CREATESTRUCTA *)lParam; + if (lpCreat->style & SBS_SIZEBOX) + { + DPRINT( "FIXME Unimplemented style SBS_SIZEBOX.\n" ); + return 0; + } + + if (lpCreat->style & SBS_VERT) + { + if (lpCreat->style & SBS_LEFTALIGN) + MoveWindow( hwnd, lpCreat->x, lpCreat->y, + SYSMETRICS_CXVSCROLL+1, lpCreat->cy, FALSE ); + else if (lpCreat->style & SBS_RIGHTALIGN) + MoveWindow( hwnd, + lpCreat->x+lpCreat->cx-SYSMETRICS_CXVSCROLL-1, + lpCreat->y, + SYSMETRICS_CXVSCROLL+1, lpCreat->cy, FALSE ); + } + else /* SBS_HORZ */ + { + if (lpCreat->style & SBS_TOPALIGN) + MoveWindow( hwnd, lpCreat->x, lpCreat->y, + lpCreat->cx, SYSMETRICS_CYHSCROLL+1, FALSE ); + else if (lpCreat->style & SBS_BOTTOMALIGN) + MoveWindow( hwnd, + lpCreat->x, + lpCreat->y+lpCreat->cy-SYSMETRICS_CYHSCROLL-1, + lpCreat->cx, SYSMETRICS_CYHSCROLL+1, FALSE ); + } + } + if (!hUpArrow) SCROLL_LoadBitmaps(); + DPRINT( "ScrollBar creation, hwnd=%04x\n", hwnd ); + return 0; + + case WM_LBUTTONDOWN: + case WM_LBUTTONUP: + case WM_MOUSEMOVE: + case WM_TIMER: + pt = (POINT *)&lParam; + SCROLL_HandleScrollEvent( hwnd, SB_CTL, message,*pt ); + break; + + case WM_KEYDOWN: + SCROLL_HandleKbdEvent( hwnd, wParam ); + break; + + case WM_ERASEBKGND: + return 1; + + case WM_GETDLGCODE: + return DLGC_WANTARROWS; /* Windows returns this value */ + + case WM_PAINT: + { + PAINTSTRUCT ps; + HDC hdc = BeginPaint( hwnd, &ps ); + SCROLL_DrawScrollBar( hwnd, hdc, SB_CTL, TRUE, TRUE ); + EndPaint( hwnd, &ps ); + } + break; + + + case SBM_SETPOS: + return SetScrollPos( hwnd, SB_CTL, wParam, (BOOL)lParam ); + + + case SBM_GETPOS: + return GetScrollPos( hwnd, SB_CTL ); + + + case SBM_SETRANGE: + SetScrollRange( hwnd, SB_CTL, wParam, lParam, FALSE ); + return 0; /* FIXME: return previous position */ + + + + case SBM_GETRANGE: + GetScrollRange( hwnd, SB_CTL, (LPINT)wParam, (LPINT)lParam ); + return 0; + + + case SBM_ENABLE_ARROWS: + return EnableScrollBar( hwnd, SB_CTL, wParam ); + + case SBM_SETRANGEREDRAW: + SetScrollRange( hwnd, SB_CTL, wParam, lParam, TRUE ); + return 0; /* FIXME: return previous position */ + + case SBM_SETSCROLLINFO: + return SetScrollInfo( hwnd, SB_CTL, (SCROLLINFO *)lParam, wParam ); + + case SBM_GETSCROLLINFO: + return GetScrollInfo( hwnd, SB_CTL, (SCROLLINFO *)lParam ); + + case 0x00e5: + case 0x00e7: + case 0x00e8: + case 0x00eb: + case 0x00ec: + case 0x00ed: + case 0x00ee: + case 0x00ef: + DPRINT( "unknown Win msg %04x wp=%08x lp=%08lx\n", + message, wParam, lParam ); + break; + + default: + if (message >= WM_USER) + DPRINT( "unknown msg %04x wp=%04x lp=%08lx\n", + message, wParam, lParam ); + return DefWindowProcA( hwnd, message, wParam, lParam ); + } + return 0; +} + + + + + +/************************************************************************* + * SetScrollInfo (USER.501) + * SetScrollInfo can be used to set the position, upper bound, + * lower bound, and page size of a scrollbar control. + * + * RETURNS + * Scrollbar position + * + * NOTE + * For 100 lines of text to be displayed in a window of 25 lines, + * one would for instance use info->nMin=0, info->nMax=75 + * (corresponding to the 76 different positions of the window on + * the text), and info->nPage=25. + */ +INT STDCALL SetScrollInfo( HWND hwnd, INT nBar , +const SCROLLINFO *info , BOOL bRedraw ) +{ + INT action; + INT retVal = SCROLL_SetScrollInfo( hwnd, nBar, info, &action ); + + if( action & SA_SSI_HIDE ) + SCROLL_ShowScrollBar( hwnd, nBar, FALSE, FALSE ); + else + { + if( action & SA_SSI_SHOW ) + if( SCROLL_ShowScrollBar( hwnd, nBar, TRUE, TRUE ) ) + return retVal; /* SetWindowPos() already did the painting */ + + if( bRedraw && (action & SA_SSI_REFRESH)) + SCROLL_RefreshScrollBar( hwnd, nBar, TRUE, TRUE ); + else if( action & SA_SSI_REPAINT_ARROWS ) + SCROLL_RefreshScrollBar( hwnd, nBar, TRUE, FALSE ); + } + return retVal; +} + +INT SCROLL_SetScrollInfo( HWND hwnd, INT nBar, + const SCROLLINFO *info, INT *action ) +{ + /* Update the scrollbar state and set action flags according to + * what has to be done graphics wise. */ + + SCROLLBAR_INFO *infoPtr; + UINT new_flags; + +// dbg_decl_str(scroll, 256); + + *action = 0; + + if (!(infoPtr = SCROLL_GetScrollInfo(hwnd, nBar))) return 0; + if (info->fMask & ~(SIF_ALL | SIF_DISABLENOSCROLL)) return 0; + if ((info->cbSize != sizeof(*info)) && + (info->cbSize != sizeof(*info)-sizeof(info->nTrackPos))) return 0; + + /* Set the page size */ + + if (info->fMask & SIF_PAGE) + { + // dsprintf(scroll, " page=%d", info->nPage ); + if( infoPtr->Page != info->nPage ) + { + infoPtr->Page = info->nPage; + *action |= SA_SSI_REFRESH; + } + } + + /* Set the scroll pos */ + + if (info->fMask & SIF_POS) + { + // dsprintf(scroll, " pos=%d", info->nPos ); + if( infoPtr->CurVal != info->nPos ) + { + infoPtr->CurVal = info->nPos; + *action |= SA_SSI_REFRESH; + } + } + + /* Set the scroll range */ + + if (info->fMask & SIF_RANGE) + { + // dsprintf(scroll, " min=%d max=%d", info->nMin, info->nMax ); + + /* Invalid range -> range is set to (0,0) */ + if ((info->nMin > info->nMax) || + ((UINT)(info->nMax - info->nMin) >= 0x80000000)) + { + infoPtr->MinVal = 0; + infoPtr->MaxVal = 0; + } + else + { + if( infoPtr->MinVal != info->nMin || + infoPtr->MaxVal != info->nMax ) + { + *action |= SA_SSI_REFRESH; + infoPtr->MinVal = info->nMin; + infoPtr->MaxVal = info->nMax; + } + } + } + + DPRINT( "hwnd=%04x bar=%d %s\n", + hwnd, nBar, dbg_str(scroll)); + + /* Make sure the page size is valid */ + + if (infoPtr->Page < 0) infoPtr->Page = 0; + else if (infoPtr->Page > infoPtr->MaxVal - infoPtr->MinVal + 1 ) + infoPtr->Page = infoPtr->MaxVal - infoPtr->MinVal + 1; + + /* Make sure the pos is inside the range */ + + if (infoPtr->CurVal < infoPtr->MinVal) + infoPtr->CurVal = infoPtr->MinVal; + else if (infoPtr->CurVal > infoPtr->MaxVal - MAX( infoPtr->Page-1, 0 )) + infoPtr->CurVal = infoPtr->MaxVal - MAX( infoPtr->Page-1, 0 ); + + DPRINT( " new values: page=%d pos=%d min=%d max=%d\n", + infoPtr->Page, infoPtr->CurVal, + infoPtr->MinVal, infoPtr->MaxVal ); + + /* Check if the scrollbar should be hidden or disabled */ + + if (info->fMask & (SIF_RANGE | SIF_PAGE | SIF_DISABLENOSCROLL)) + { + new_flags = infoPtr->flags; + if (infoPtr->MinVal >= infoPtr->MaxVal - MAX( infoPtr->Page-1, 0 )) + { + /* Hide or disable scroll-bar */ + if (info->fMask & SIF_DISABLENOSCROLL) + { + new_flags = ESB_DISABLE_BOTH; + *action |= SA_SSI_REFRESH; + } + else if (nBar != SB_CTL) + { + *action = SA_SSI_HIDE; + goto done; + } + } + else /* Show and enable scroll-bar */ + { + new_flags = 0; + if (nBar != SB_CTL) + *action |= SA_SSI_SHOW; + } + + if (infoPtr->flags != new_flags) /* check arrow flags */ + { + infoPtr->flags = new_flags; + *action |= SA_SSI_REPAINT_ARROWS; + } + } + +done: + /* Return current position */ + + return infoPtr->CurVal; +} + + + + +/************************************************************************* + * GetScrollInfo (USER.284) + * GetScrollInfo can be used to retrieve the position, upper bound, + * lower bound, and page size of a scrollbar control. + * + * RETURNS STD + */ +BOOL STDCALL GetScrollInfo( HWND hwnd , + INT nBar , LPSCROLLINFO info ) +{ + SCROLLBAR_INFO *infoPtr; + + if (!(infoPtr = SCROLL_GetScrollInfo( hwnd, nBar ))) return FALSE; + if (info->fMask & ~(SIF_ALL | SIF_DISABLENOSCROLL)) return FALSE; + if ((info->cbSize != sizeof(*info)) && + (info->cbSize != sizeof(*info)-sizeof(info->nTrackPos))) return FALSE; + + if (info->fMask & SIF_PAGE) info->nPage = infoPtr->Page; + if (info->fMask & SIF_POS) info->nPos = infoPtr->CurVal; + if ((info->fMask & SIF_TRACKPOS) && (info->cbSize == sizeof(*info))) + info->nTrackPos = (SCROLL_TrackingWin==hwnd) ? SCROLL_TrackingVal : 0; + if (info->fMask & SIF_RANGE) + { + info->nMin = infoPtr->MinVal; + info->nMax = infoPtr->MaxVal; + } + return (info->fMask & SIF_ALL) != 0; +} + + + + +/************************************************************************* + * SetScrollPos (USER.502) + * + * RETURNS + * Success: Scrollbar position + * Failure: 0 + * + * REMARKS + * Note the ambiguity when 0 is returned. Use GetLastError + * to make sure there was an error (and to know which one). + */ +INT STDCALL SetScrollPos( HWND hwnd , INT nBar , INT nPos ,BOOL bRedraw ) +{ + SCROLLINFO info; + SCROLLBAR_INFO *infoPtr; + INT oldPos; + + if (!(infoPtr = SCROLL_GetScrollInfo( hwnd, nBar ))) return 0; + oldPos = infoPtr->CurVal; + info.cbSize = sizeof(info); + info.nPos = nPos; + info.fMask = SIF_POS; + SetScrollInfo( hwnd, nBar, &info, bRedraw ); + return oldPos; +} + + + + +/************************************************************************* + * GetScrollPos (USER.285) + * + * RETURNS + * Success: Current position + * Failure: 0 + * + * REMARKS + * Note the ambiguity when 0 is returned. Use GetLastError + * to make sure there was an error (and to know which one). + */ +INT STDCALL GetScrollPos( HWND hwnd,INT nBar ) +{ + SCROLLBAR_INFO *infoPtr; + + if (!(infoPtr = SCROLL_GetScrollInfo( hwnd, nBar ))) return 0; + return infoPtr->CurVal; +} + + + + +/************************************************************************* + * SetScrollRange (USER.503) + * + * RETURNS STD + */ +BOOL STDCALL SetScrollRange( HWND hwnd, INT nBar, +INT MinVal, INT MaxVal, BOOL bRedraw ) +{ + SCROLLINFO info; + + info.cbSize = sizeof(info); + info.nMin = MinVal; + info.nMax = MaxVal; + info.fMask = SIF_RANGE; + SetScrollInfo( hwnd, nBar, &info, bRedraw ); + return TRUE; +} + + +/************************************************************************* + * SCROLL_SetNCSbState + * + * Updates both scrollbars at the same time. Used by MDI CalcChildScroll(). + */ +INT SCROLL_SetNCSbState(WND* wndPtr, int vMin, int vMax, int vPos, + int hMin, int hMax, int hPos) +{ + INT vA, hA; + SCROLLINFO vInfo, hInfo; + + vInfo.cbSize = hInfo.cbSize = sizeof(SCROLLINFO); + vInfo.nMin = vMin; hInfo.nMin = hMin; + vInfo.nMax = vMax; hInfo.nMax = hMax; + vInfo.nPos = vPos; hInfo.nPos = hPos; + vInfo.fMask = hInfo.fMask = SIF_RANGE | SIF_POS; + + SCROLL_SetScrollInfo( wndPtr->hwndSelf, SB_VERT, &vInfo, &vA ); + SCROLL_SetScrollInfo( wndPtr->hwndSelf, SB_HORZ, &hInfo, &hA ); + + if( !SCROLL_ShowScrollBar( wndPtr->hwndSelf, SB_BOTH, + (hA & SA_SSI_SHOW),(vA & SA_SSI_SHOW) ) ) + { + /* SetWindowPos() wasn't called, just redraw the scrollbars if needed */ + if( vA & SA_SSI_REFRESH ) + SCROLL_RefreshScrollBar( wndPtr->hwndSelf, SB_VERT, FALSE, TRUE ); + + if( hA & SA_SSI_REFRESH ) + SCROLL_RefreshScrollBar( wndPtr->hwndSelf, SB_HORZ, FALSE, TRUE ); + } + return 0; +} + + + + +/************************************************************************* + * GetScrollRange (USER.286) + * + * RETURNS STD + */ +BOOL STDCALL GetScrollRange( HWND hwnd, INT nBar, + LPINT lpMin,LPINT lpMax ) +{ + SCROLLBAR_INFO *infoPtr; + + if (!(infoPtr = SCROLL_GetScrollInfo( hwnd, nBar ))) + { + if (lpMin) lpMin = 0; + if (lpMax) lpMax = 0; + return FALSE; + } + if (lpMin) *lpMin = infoPtr->MinVal; + if (lpMax) *lpMax = infoPtr->MaxVal; + return TRUE; +} + + +/************************************************************************* + * SCROLL_ShowScrollBar() + * + * Back-end for ShowScrollBar(). Returns FALSE if no action was taken. + * NOTE: fShowV/fShowH must be zero when nBar is SB_HORZ/SB_VERT. + */ +BOOL SCROLL_ShowScrollBar( HWND hwnd, INT nBar, + BOOL fShowH, BOOL fShowV ) +{ + WND *wndPtr = WIN_FindWndPtr( hwnd ); + + if (!wndPtr) return FALSE; + DPRINT( "hwnd=%04x bar=%d horz=%d, vert=%d\n", + hwnd, nBar, fShowH, fShowV ); + + switch(nBar) + { + case SB_CTL: + ShowWindow( hwnd, fShowH ? SW_SHOW : SW_HIDE ); + return TRUE; + + case SB_BOTH: + case SB_HORZ: + if (fShowH) + { + fShowH = !(wndPtr->dwStyle & WS_HSCROLL); + wndPtr->dwStyle |= WS_HSCROLL; + } + else /* hide it */ + { + fShowH = (wndPtr->dwStyle & WS_HSCROLL); + wndPtr->dwStyle &= ~WS_HSCROLL; + } + if( nBar == SB_HORZ ) break; + /* fall through */ + + case SB_VERT: + if (fShowV) + { + fShowV = !(wndPtr->dwStyle & WS_VSCROLL); + wndPtr->dwStyle |= WS_VSCROLL; + } + else /* hide it */ + { + fShowV = (wndPtr->dwStyle & WS_VSCROLL); + wndPtr->dwStyle &= ~WS_VSCROLL; + } + break; + + default: + return FALSE; /* Nothing to do! */ + } + + if( fShowH || fShowV ) /* frame has been changed, let the window redraw itself */ + { + SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE + | SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED ); + return TRUE; + } + + return FALSE; /* no frame changes */ +} + + + +/************************************************************************* + * SCROLL_FixCaret + */ +WINBOOL SCROLL_FixCaret(HWND hWnd, LPRECT lprc, UINT flags) +{ + HWND hCaret = CARET_GetHwnd(); + + if( hCaret ) + { + RECT rc; + CARET_GetRect( &rc ); + if( hCaret == hWnd || + (flags & SW_SCROLLCHILDREN && IsChild(hWnd, hCaret)) ) + { + POINT pt; + + pt.x = rc.left; pt.y = rc.top; + MapWindowPoints( hCaret, hWnd, (LPPOINT)&rc, 2 ); + if( IntersectRect(lprc, lprc, &rc) ) + { + HideCaret(0); + lprc->left = pt.x; lprc->top = pt.y; + return TRUE; + } + } + } + return FALSE; +} + +/************************************************************************* + * ShowScrollBar (USER.5) + * + * RETURNS STD + */ +BOOL STDCALL ShowScrollBar( + HWND hwnd, INT nBar, BOOL fShow ) +{ + SCROLL_ShowScrollBar( hwnd, nBar, (nBar == SB_VERT) ? 0 : fShow, + (nBar == SB_HORZ) ? 0 : fShow ); + return TRUE; +} + + + + +/************************************************************************* + * EnableScrollBar (USER.171) + */ +WINBOOL +STDCALL +EnableScrollBar(HWND hWnd,UINT wSBflags, UINT wArrows) +{ + BOOL bFineWithMe; + SCROLLBAR_INFO *infoPtr; + + DPRINT( "%04x %d %d\n", hwnd, nBar, flags ); + + wArrows &= ESB_DISABLE_BOTH; + + if (wSBflags == SB_BOTH) + { + if (!(infoPtr = SCROLL_GetScrollInfo( hWnd, SB_VERT ))) return FALSE; + if (!(bFineWithMe = (infoPtr->flags == wArrows)) ) + { + infoPtr->flags = wArrows; + SCROLL_RefreshScrollBar( hWnd, SB_VERT, TRUE, TRUE ); + } + wSBflags = SB_HORZ; + } + else + bFineWithMe = TRUE; + + if (!(infoPtr = SCROLL_GetScrollInfo( hWnd, wSBflags ))) return FALSE; + if (bFineWithMe && infoPtr->flags == wArrows) return FALSE; + infoPtr->flags = wArrows; + + SCROLL_RefreshScrollBar( hWnd, wSBflags, TRUE, TRUE ); + return TRUE; +} diff --git a/reactos/lib/user32/controls/static.c b/reactos/lib/user32/controls/static.c new file mode 100644 index 00000000000..779961efd3d --- /dev/null +++ b/reactos/lib/user32/controls/static.c @@ -0,0 +1,509 @@ +/* + * Static control + * + * Copyright David W. Metcalfe, 1993 + * + */ + +#include +#include +#include +#include +#include +#include +#include + + +/* Static Control Styles */ + + + + +//#define SS_ETCHEDHORZ 0x00000010L +//#define SS_ETCHEDVERT 0x00000011L +//#define SS_ETCHEDFRAME 0x00000012L +#define SS_TYPEMASK 0x0000001FL + +//#define SS_NOPREFIX 0x00000080L +//#define SS_NOTIFY 0x00000100L +//#define SS_CENTERIMAGE 0x00000200L +//#define SS_RIGHTJUST 0x00000400L +//#define SS_REALSIZEIMAGE 0x00000800L +//#define SS_SUNKEN 0x00001000L + +/* Static Control Messages */ + +//#define STM_SETICON 0x0170 +//#define STM_GETICON 0x0171 +//#define STM_SETIMAGE 0x0172 +//#define STM_GETIMAGE 0x0173 + +static void STATIC_PaintTextfn( WND *wndPtr, HDC hdc ); +static void STATIC_PaintRectfn( WND *wndPtr, HDC hdc ); +static void STATIC_PaintIconfn( WND *wndPtr, HDC hdc ); +static void STATIC_PaintBitmapfn( WND *wndPtr, HDC hdc ); +static void STATIC_PaintEtchedfn( WND *wndPtr, HDC hdc ); + +static COLORREF color_windowframe, color_background, color_window; + + +typedef void (*pfPaint)( WND *, HDC ); + +static pfPaint staticPaintFunc[SS_TYPEMASK+1] = +{ + STATIC_PaintTextfn, /* SS_LEFT */ + STATIC_PaintTextfn, /* SS_CENTER */ + STATIC_PaintTextfn, /* SS_RIGHT */ + STATIC_PaintIconfn, /* SS_ICON */ + STATIC_PaintRectfn, /* SS_BLACKRECT */ + STATIC_PaintRectfn, /* SS_GRAYRECT */ + STATIC_PaintRectfn, /* SS_WHITERECT */ + STATIC_PaintRectfn, /* SS_BLACKFRAME */ + STATIC_PaintRectfn, /* SS_GRAYFRAME */ + STATIC_PaintRectfn, /* SS_WHITEFRAME */ + NULL, /* Not defined */ + STATIC_PaintTextfn, /* SS_SIMPLE */ + STATIC_PaintTextfn, /* SS_LEFTNOWORDWRAP */ + NULL, /* SS_OWNERDRAW */ + STATIC_PaintBitmapfn, /* SS_BITMAP */ + NULL, /* SS_ENHMETAFILE */ + STATIC_PaintEtchedfn, /* SS_ETCHEDHORIZ */ + STATIC_PaintEtchedfn, /* SS_ETCHEDVERT */ + STATIC_PaintEtchedfn, /* SS_ETCHEDFRAME */ +}; + +HICON STATIC_LoadIcon(WND *wndPtr,const void *name ) +{ + HICON hIcon; + if ( wndPtr->class->bUnicode ) { + hIcon = LoadIconW(wndPtr->hInstance,(LPCWSTR)name); + } + else + hIcon = LoadIconA(wndPtr->hInstance,(LPCSTR)name); + + return hIcon; +} + +/*********************************************************************** + * STATIC_SetIcon + * + * Set the icon for an SS_ICON control. + */ +HICON STATIC_SetIcon( WND *wndPtr, HICON hicon ) +{ + HICON prevIcon; + STATICINFO *infoPtr = (STATICINFO *)wndPtr->wExtra; + ICONINFO iconinfo; + BITMAP info; + + if ( !GetIconInfo(hicon, &iconinfo ) ) + return NULL; + + if ( iconinfo.hbmColor ) + GetObject(iconinfo.hbmColor, sizeof(BITMAP),&info); + else + GetObject(iconinfo.hbmMask, sizeof(BITMAP),&info); + + if ((wndPtr->dwStyle & SS_TYPEMASK) != SS_ICON) return 0; + + prevIcon = infoPtr->hIcon; + infoPtr->hIcon = hicon; + if (hicon) + { + SetWindowPos( wndPtr->hwndSelf, 0, 0, 0, info.bmWidth, info.bmHeight, + SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER ); + } + return prevIcon; +} + + +HBITMAP STATIC_LoadBitmap(WND *wndPtr,const void *name ) +{ + HBITMAP hBitmap; + if ( wndPtr->class->bUnicode ) { + hBitmap = LoadBitmapW(wndPtr->hInstance,(LPCWSTR)name); + } + else + hBitmap = LoadBitmapA(wndPtr->hInstance,(LPCSTR)name); + return hBitmap; +} +/*********************************************************************** + * STATIC_SetBitmap + * + * Set the bitmap for an SS_BITMAP control. + */ +HICON STATIC_SetBitmap( WND *wndPtr, HICON hicon ) +{ + + HICON prevIcon; + STATICINFO *infoPtr = (STATICINFO *)wndPtr->wExtra; + BITMAP info; + + if ( hicon == NULL ) + return NULL; + + GetObject(hicon, sizeof(BITMAP),&info); + + if ((wndPtr->dwStyle & SS_TYPEMASK) != SS_BITMAP) return 0; + + prevIcon = infoPtr->hIcon; + infoPtr->hIcon = hicon; + if (hicon) + { + SetWindowPos( wndPtr->hwndSelf, 0, 0, 0, info.bmWidth, info.bmHeight, + SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER ); + } + + return prevIcon; + +} + + + + +/*********************************************************************** + * StaticWndProc + */ +LRESULT WINAPI StaticWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, + LPARAM lParam ) +{ + LRESULT lResult = 0; + WND *wndPtr = WIN_FindWndPtr(hWnd); + LONG style = wndPtr->dwStyle & SS_TYPEMASK; + STATICINFO *infoPtr = (STATICINFO *)wndPtr->wExtra; + + switch (uMsg) + { + case WM_NCCREATE: { + CREATESTRUCT *cs = (CREATESTRUCT *)lParam; + + if ((TWEAK_WineLook > WIN31_LOOK) && (wndPtr->dwStyle & SS_SUNKEN)) + wndPtr->dwExStyle |= WS_EX_STATICEDGE; + + if (style == SS_ICON) + { + if (cs->lpszName) { + STATIC_SetIcon( wndPtr,STATIC_LoadIcon(wndPtr,cs->lpszName)); + } + return 1; + } + if (style == SS_BITMAP) + { + if (cs->lpszName) { + STATIC_SetBitmap( wndPtr,STATIC_LoadBitmap(wndPtr,cs->lpszName)); + } + return 1; + } + + if ( wndPtr->class->bUnicode ) + return DefWindowProcW( hWnd, uMsg, wParam, lParam ); + else + return DefWindowProcA( hWnd, uMsg, wParam, lParam ); + } + case WM_CREATE: + if (style < 0L || style > SS_TYPEMASK) + { + DPRINT( "Unknown style 0x%02lx\n", style ); + lResult = -1L; + break; + } + /* initialise colours */ + color_windowframe = GetSysColor(COLOR_WINDOWFRAME); + color_background = GetSysColor(COLOR_BACKGROUND); + color_window = GetSysColor(COLOR_WINDOW); + break; + + case WM_NCDESTROY: + if (style == SS_ICON) { +/* + * FIXME + * DestroyIcon( STATIC_SetIcon( wndPtr, 0 ) ); + * + * We don't want to do this yet because DestroyIcon is broken. If the icon + * had already been loaded by the application the last thing we want to do is + * GlobalFree the handle. + */ + } else { + if ( wndPtr->class->bUnicode ) + lResult = DefWindowProcW( hWnd, uMsg, wParam, lParam ); + else + lResult = DefWindowProcA( hWnd, uMsg, wParam, lParam ); + + } + break; + + case WM_PAINT: + { + PAINTSTRUCT ps; + BeginPaint( hWnd, &ps ); + if (staticPaintFunc[style]) + (staticPaintFunc[style])( wndPtr, ps.hdc ); + EndPaint( hWnd, &ps ); + } + break; + + case WM_ENABLE: + InvalidateRect( hWnd, NULL, FALSE ); + break; + + case WM_SYSCOLORCHANGE: + color_windowframe = GetSysColor(COLOR_WINDOWFRAME); + color_background = GetSysColor(COLOR_BACKGROUND); + color_window = GetSysColor(COLOR_WINDOW); + InvalidateRect( hWnd, NULL, TRUE ); + break; + + case WM_SETTEXT: + if (style == SS_ICON) + { + if (lParam) { + STATIC_SetIcon( wndPtr,STATIC_LoadIcon(wndPtr,(const void *)lParam)); + } + + } + else if (style == SS_BITMAP) + { + if (lParam) { + STATIC_SetBitmap( wndPtr,STATIC_LoadBitmap(wndPtr,(const void *)lParam)); + } + + } + else { + DEFWND_SetText( wndPtr, (const void *)lParam ); + + } + InvalidateRect( hWnd, NULL, FALSE ); + UpdateWindow( hWnd ); + break; + + case WM_SETFONT: + if (style == SS_ICON) return 0; + if (style == SS_BITMAP) return 0; + infoPtr->hFont = (HFONT)wParam; + if (LOWORD(lParam)) + { + InvalidateRect( hWnd, NULL, FALSE ); + UpdateWindow( hWnd ); + } + break; + + case WM_GETFONT: + return infoPtr->hFont; + + case WM_NCHITTEST: + return HTTRANSPARENT; + + case WM_GETDLGCODE: + return DLGC_STATIC; + + case STM_GETIMAGE: + case STM_GETICON: + return infoPtr->hIcon; + + case STM_SETIMAGE: + /* FIXME: handle wParam */ + lResult = STATIC_SetBitmap( wndPtr, (HBITMAP)lParam ); + InvalidateRect( hWnd, NULL, FALSE ); + UpdateWindow( hWnd ); + break; + + + case STM_SETICON: + lResult = STATIC_SetIcon( wndPtr, (HICON)wParam ); + InvalidateRect( hWnd, NULL, FALSE ); + UpdateWindow( hWnd ); + break; + + default: + if ( wndPtr->class->bUnicode ) + lResult = DefWindowProcW( hWnd, uMsg, wParam, lParam ); + else + lResult = DefWindowProcA( hWnd, uMsg, wParam, lParam ); + break; + } + + return lResult; +} + + +static void STATIC_PaintTextfn( WND *wndPtr, HDC hdc ) +{ + RECT rc; + HBRUSH hBrush; + WORD wFormat; + + LONG style = wndPtr->dwStyle; + STATICINFO *infoPtr = (STATICINFO *)wndPtr->wExtra; + + GetClientRect( wndPtr->hwndSelf, &rc); + + switch (style & SS_TYPEMASK) + { + case SS_LEFT: + wFormat = DT_LEFT | DT_EXPANDTABS | DT_WORDBREAK | DT_NOCLIP; + break; + + case SS_CENTER: + wFormat = DT_CENTER | DT_EXPANDTABS | DT_WORDBREAK | DT_NOCLIP; + break; + + case SS_RIGHT: + wFormat = DT_RIGHT | DT_EXPANDTABS | DT_WORDBREAK | DT_NOCLIP; + break; + + case SS_SIMPLE: + wFormat = DT_LEFT | DT_SINGLELINE | DT_VCENTER | DT_NOCLIP; + break; + + case SS_LEFTNOWORDWRAP: + wFormat = DT_LEFT | DT_SINGLELINE | DT_EXPANDTABS | DT_VCENTER | DT_NOCLIP; + break; + + default: + return; + } + + if (style & SS_NOPREFIX) + wFormat |= DT_NOPREFIX; + + if (infoPtr->hFont) SelectObject( hdc, infoPtr->hFont ); + hBrush = MSG_SendMessage( wndPtr->parent, WM_CTLCOLORSTATIC, + (WPARAM)hdc,(LPARAM) wndPtr->hwndSelf ); + if (!hBrush) hBrush = GetStockObject(WHITE_BRUSH); + FillRect( hdc, &rc, hBrush ); + if (wndPtr->text) { + if ( wndPtr->class->bUnicode ) { + DrawTextW( hdc, wndPtr->text, -1, &rc, wFormat ); + } + else { + DrawTextA( hdc, wndPtr->text, -1, &rc, wFormat ); + } + } + +} + + +static void STATIC_PaintRectfn( WND *wndPtr, HDC hdc ) +{ + RECT rc; + HBRUSH hBrush; + + GetClientRect( wndPtr->hwndSelf, &rc); + + switch (wndPtr->dwStyle & SS_TYPEMASK) + { + case SS_BLACKRECT: + hBrush = CreateSolidBrush(color_windowframe); + FillRect( hdc, &rc, hBrush ); + break; + case SS_GRAYRECT: + hBrush = CreateSolidBrush(color_background); + FillRect( hdc, &rc, hBrush ); + break; + case SS_WHITERECT: + hBrush = CreateSolidBrush(color_window); + FillRect( hdc, &rc, hBrush ); + break; + case SS_BLACKFRAME: + hBrush = CreateSolidBrush(color_windowframe); + FrameRect( hdc, &rc, hBrush ); + break; + case SS_GRAYFRAME: + hBrush = CreateSolidBrush(color_background); + FrameRect( hdc, &rc, hBrush ); + break; + case SS_WHITEFRAME: + hBrush = CreateSolidBrush(color_window); + FrameRect( hdc, &rc, hBrush ); + break; + default: + return; + } + DeleteObject( hBrush ); +} + + +static void STATIC_PaintIconfn( WND *wndPtr, HDC hdc ) +{ + RECT rc; + HBRUSH hbrush; + STATICINFO *infoPtr = (STATICINFO *)wndPtr->wExtra; + + GetClientRect( wndPtr->hwndSelf, &rc ); + hbrush = MSG_SendMessage( wndPtr->parent, WM_CTLCOLORSTATIC, + (WPARAM)hdc, (LPARAM)wndPtr->hwndSelf ); + FillRect( hdc, &rc, hbrush ); + if (infoPtr->hIcon) DrawIcon( hdc, rc.left, rc.top, infoPtr->hIcon ); +} + +static void STATIC_PaintBitmapfn(WND *wndPtr, HDC hdc ) +{ + RECT rc; + HBRUSH hbrush; + STATICINFO *infoPtr = (STATICINFO *)wndPtr->wExtra; + HDC hMemDC; + HBITMAP oldbitmap; + + GetClientRect( wndPtr->hwndSelf, &rc ); + hbrush = MSG_SendMessage( wndPtr->parent, WM_CTLCOLORSTATIC, + (WPARAM)hdc,(LPARAM) wndPtr->hwndSelf ); + FillRect( hdc, &rc, hbrush ); + if (infoPtr->hIcon) { + BITMAP bmp; + GetObject( infoPtr->hIcon, sizeof(BITMAP),&bmp); + + if (!(hMemDC = CreateCompatibleDC( hdc ))) return; + + oldbitmap = SelectObject(hMemDC,infoPtr->hIcon); + BitBlt(hdc,bmp.bmWidth,bmp.bmHeight,bmp.bmWidth,bmp.bmHeight,hMemDC,0,0,SRCCOPY); +// BitBlt(hdc,bmp.size.cx,bmp.size.cy,bmp.bmWidth,bmp.bmHeight,hMemDC,0,0,SRCCOPY); + DeleteDC(hMemDC); + + } +} + + +static void STATIC_PaintEtchedfn( WND *wndPtr, HDC hdc ) +{ + RECT rc; + HBRUSH hbrush; + HPEN hpen; + + if (TWEAK_WineLook == WIN31_LOOK) + return; + + GetClientRect( wndPtr->hwndSelf, &rc ); + hbrush = MSG_SendMessage( wndPtr->parent, WM_CTLCOLORSTATIC, + (WPARAM)hdc, (LPARAM)wndPtr->hwndSelf ); + FillRect( hdc, &rc, hbrush ); + + switch (wndPtr->dwStyle & SS_TYPEMASK) + { + case SS_ETCHEDHORZ: + hpen = SelectObject (hdc, GetSysColorPen (COLOR_3DSHADOW)); + MoveToEx (hdc, rc.left, rc.bottom / 2 - 1, NULL); + LineTo (hdc, rc.right - 1, rc.bottom / 2 - 1); + SelectObject (hdc, GetSysColorPen (COLOR_3DHIGHLIGHT)); + MoveToEx (hdc, rc.left, rc.bottom / 2, NULL); + LineTo (hdc, rc.right, rc.bottom / 2); + LineTo (hdc, rc.right, rc.bottom / 2 - 1); + SelectObject (hdc, hpen); + break; + + case SS_ETCHEDVERT: + hpen = SelectObject (hdc, GetSysColorPen (COLOR_3DSHADOW)); + MoveToEx (hdc, rc.right / 2 - 1, rc.top, NULL); + LineTo (hdc, rc.right / 2 - 1, rc.bottom - 1); + SelectObject (hdc, GetSysColorPen (COLOR_3DHIGHLIGHT)); + MoveToEx (hdc, rc.right / 2, rc.top, NULL); + LineTo (hdc, rc.right / 2, rc.bottom); + LineTo (hdc, rc.right / 2 -1 , rc.bottom); + SelectObject (hdc, hpen); + break; + + case SS_ETCHEDFRAME: + DrawEdge (hdc, &rc, EDGE_ETCHED, BF_RECT); + break; + } +} + diff --git a/reactos/lib/user32/controls/widgets.c b/reactos/lib/user32/controls/widgets.c new file mode 100644 index 00000000000..aa7b54494d2 --- /dev/null +++ b/reactos/lib/user32/controls/widgets.c @@ -0,0 +1,112 @@ +/* + * Windows widgets (built-in window classes) + * + * Copyright 1993 Alexandre Julliard + */ + +#define UNICODE +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* Built-in classes */ + +#define DLGWINDOWEXTRA sizeof(DIALOGINFO) + + +static WNDCLASS WIDGETS_BuiltinClasses[BIC_NB_CLASSES+1] = +{ + /* BIC_BUTTON */ + { CS_GLOBALCLASS | CS_DBLCLKS | CS_VREDRAW | CS_HREDRAW | CS_PARENTDC, + ButtonWndProc, 0, sizeof(BUTTONINFO), 0, 0, + (HCURSOR)IDC_ARROW, 0, 0, BUTTON_CLASS_NAME }, + /* BIC_EDIT */ + { CS_GLOBALCLASS | CS_DBLCLKS /*| CS_PARENTDC*/, + EditWndProc, 0, sizeof(void *), 0, 0, + (HCURSOR)IDC_IBEAM, 0, 0, EDIT_CLASS_NAME }, + /* BIC_LISTBOX */ + { CS_GLOBALCLASS | CS_DBLCLKS /*| CS_PARENTDC*/, + ListBoxWndProc, 0, sizeof(void *), 0, 0, + (HCURSOR)IDC_ARROW, 0, 0, LISTBOX_CLASS_NAME }, + /* BIC_COMBO */ + { CS_GLOBALCLASS | CS_PARENTDC | CS_DBLCLKS, + ComboWndProc, 0, sizeof(void *), 0, 0, + (HCURSOR)IDC_ARROW, 0, 0, COMBOBOX_CLASS_NAME }, + /* BIC_COMBOLB */ + { CS_GLOBALCLASS | CS_DBLCLKS | CS_SAVEBITS, ComboLBWndProc, + 0, sizeof(void *), 0, 0, (HCURSOR)IDC_ARROW, 0, 0,COMBOLBOX_CLASS_NAME}, + /* BIC_POPUPMENU */ +// { CS_GLOBALCLASS | CS_SAVEBITS, PopupMenuWndProc, 0, sizeof(HMENU), +// 0, 0, (HCURSOR)IDC_ARROW, NULL_BRUSH, 0, POPUPMENU_CLASS_NAME }, + /* BIC_STATIC */ + { CS_GLOBALCLASS | CS_PARENTDC, StaticWndProc, + 0, sizeof(STATICINFO), 0, 0, (HCURSOR)IDC_ARROW, 0, 0, STATIC_CLASS_NAME }, + /* BIC_SCROLL */ + { CS_GLOBALCLASS | CS_DBLCLKS | CS_VREDRAW | CS_HREDRAW | CS_PARENTDC, + ScrollBarWndProc, 0, sizeof(SCROLLBAR_INFO), 0, 0, + (HCURSOR)IDC_ARROW, 0, 0, SCROLLBAR_CLASS_NAME}, + /* BIC_MDICLIENT */ +// { CS_GLOBALCLASS, MDIClientWndProc, +// 0, sizeof(MDICLIENTINFO), 0, 0, 0, LTGRAY_BRUSH, 0, "MDIClient" }, + /* BIC_DESKTOP */ + // { CS_GLOBALCLASS, DesktopWndProc, 0, sizeof(DESKTOPINFO), + // 0, 0, (HCURSOR)IDC_ARROW, 0, 0, DESKTOP_CLASS_NAME }, + /* BIC_DIALOG */ + { CS_GLOBALCLASS | CS_SAVEBITS, DefDlgProc, 100, 100, + 0, 0, (HCURSOR)IDC_ARROW, 0, 0, DIALOG_CLASS_NAMEW }, + /* BIC_ICONTITLE */ + { CS_GLOBALCLASS, IconTitleWndProc, 0, 0, + 0, 0, (HCURSOR)IDC_ARROW, 0, 0, ICONTITLE_CLASS_NAME }, + /* BIC_DIALOG Ascii */ + { CS_GLOBALCLASS, DefDlgProcA, 100, 100, + 0, 0, (HCURSOR)IDC_ARROW, 0, 0, (LPWSTR)DIALOG_CLASS_NAME_A } +}; + + +static ATOM bicAtomTable[BIC_NB_CLASSES+1]; + +/*********************************************************************** + * WIDGETS_Init + * + * Initialize the built-in window classes. + */ +WINBOOL WIDGETS_Init(void) +{ + int i; + WNDCLASS *cls = WIDGETS_BuiltinClasses; + + /* Create builtin classes */ + + for (i = 0; i < BIC_NB_CLASSES; i++) + { + + cls[i].hCursor = LoadCursorW( 0, (LPCWSTR)cls[i].hCursor ); + if (!(bicAtomTable[i] = RegisterClassW( &cls[i] ))) return FALSE; + } + + cls[i].hCursor = LoadCursorW( 0, (LPCWSTR)cls[i].hCursor ); + if (!(bicAtomTable[i] = RegisterClassA( &cls[i] ))) return FALSE; + + + return TRUE; +} + + +/*********************************************************************** + * WIDGETS_IsControl + * + * Check whether pWnd is a built-in control or not. + */ +WINBOOL WIDGETS_IsControl( WND* pWnd, BUILTIN_CLASS cls ) +{ + if( cls >= BIC_NB_CLASSES ) + return FALSE; + return (pWnd->class->atomName == bicAtomTable[cls]); +} diff --git a/reactos/lib/user32/graphics/fill.c b/reactos/lib/user32/graphics/fill.c index 29aaea6847e..ef49ec22483 100644 --- a/reactos/lib/user32/graphics/fill.c +++ b/reactos/lib/user32/graphics/fill.c @@ -1,6 +1,37 @@ #include + +INT STDCALL FrameRect( HDC hdc, const RECT *rect, HBRUSH hbrush ) +{ + HBRUSH prevBrush; + //int left, top, right, bottom; + + if ( hdc == NULL ) + return 0; + + //left = XLPTODP( dc, rect->left ); + //top = YLPTODP( dc, rect->top ); + //right = XLPTODP( dc, rect->right ); + //bottom = YLPTODP( dc, rect->bottom ); + + //if ( (right <= left) || (bottom <= top) ) return 0; + if (!(prevBrush = SelectObject( hdc, hbrush ))) return 0; + + PatBlt( hdc, rect->left, rect->top, 1, + rect->bottom - rect->top, PATCOPY ); + PatBlt( hdc, rect->right - 1, rect->top, 1, + rect->bottom - rect->top, PATCOPY ); + PatBlt( hdc, rect->left, rect->top, + rect->right - rect->left, 1, PATCOPY ); + PatBlt( hdc, rect->left, rect->bottom - 1, + rect->right - rect->left, 1, PATCOPY ); + + SelectObject( hdc, prevBrush ); + return 1; +} + + INT STDCALL FillRect( HDC hdc, const RECT *rect, HBRUSH hbrush ) { HBRUSH prevBrush; diff --git a/reactos/lib/user32/graphics/icon.c b/reactos/lib/user32/graphics/icon.c index bcb303cfc86..d6111b68c32 100644 --- a/reactos/lib/user32/graphics/icon.c +++ b/reactos/lib/user32/graphics/icon.c @@ -1,7 +1,9 @@ #include +#include +HICON LoadStandardIcon(UINT IconId); HICON STDCALL @@ -27,8 +29,42 @@ CreateIcon( HICON STDCALL CreateIconIndirect( - PICONINFO piconinfo) + PICONINFO lpIconInfo) { + BITMAP bmpXor,bmpAnd; + HICON hObj; + int sizeXor,sizeAnd; + + GetObject(lpIconInfo->hbmColor,sizeof(BITMAP),&bmpXor); + GetObject(lpIconInfo->hbmMask,sizeof(BITMAP),&bmpAnd); + + + + sizeXor = bmpXor.bmHeight * bmpXor.bmWidthBytes; + sizeAnd = bmpAnd.bmHeight * bmpAnd.bmWidthBytes; + + hObj = GlobalAlloc( GMEM_MOVEABLE, + sizeof(ICONINFO) + sizeXor + sizeAnd ); + if (hObj) + { + ICONINFO *info; + + info = (ICONINFO *)( hObj ); + info->xHotspot = lpIconInfo->xHotspot; + info->yHotspot = lpIconInfo->yHotspot; + //info->nWidth = bmpXor.bmWidth; + //info->nHeight = bmpXor.bmHeight; + //info->nWidthBytes = bmpXor.bmWidthBytes; + //info->bPlanes = bmpXor.bmPlanes; + //info->bBitsPerPixel = bmpXor.bmBitsPixel; + + /* Transfer the bitmap bits to the CURSORICONINFO structure */ + + GetBitmapBits( lpIconInfo->hbmMask ,sizeAnd,(char*)(info + 1) ); + GetBitmapBits( lpIconInfo->hbmColor,sizeXor,(char*)(info + 1) +sizeAnd); + + } + return hObj; } @@ -53,14 +89,79 @@ GetIconInfo( HICON LoadIconA(HINSTANCE hInstance,LPCSTR lpIconName ) { - return CreateIcon(hInstance, GetSystemMetrics(SM_CXSMICON), - GetSystemMetrics(SM_CYSMICON), - 0,0,NULL,NULL); + HRSRC hrsrc; + ICONINFO *IconInfo; + + if ( hInstance == NULL ) { + return LoadStandardIcon((UINT)lpIconName); + } +//RT_GROUP_ICON +hrsrc = FindResourceExA(hInstance,RT_GROUP_ICON, lpIconName, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)); + + if ( hrsrc == NULL ) + return NULL; + + IconInfo = (ICONINFO *)LoadResource(hInstance, hrsrc); + if ( IconInfo != NULL || IconInfo->fIcon == FALSE ) + return NULL; + + return CreateIconIndirect(IconInfo); } HICON LoadIconW(HINSTANCE hInstance,LPCWSTR lpIconName ) { - return CreateIcon(hInstance, GetSystemMetrics(SM_CXSMICON), - GetSystemMetrics(SM_CYSMICON), - 0,0,NULL,NULL); + HRSRC hrsrc; + ICONINFO *IconInfo; + + if ( hInstance == NULL ) { + return LoadStandardIcon((UINT)lpIconName); + } + + hrsrc = FindResourceW(hInstance,lpIconName,RT_GROUP_ICON); + if ( hrsrc == NULL ) + return NULL; + + IconInfo = (ICONINFO *)LoadResource(hInstance, hrsrc); + if ( IconInfo != NULL || IconInfo->fIcon == FALSE ) + return NULL; + + return CreateIconIndirect(IconInfo); +} + +HICON LoadStandardIcon(UINT IconId) +{ + HMODULE hModule = LoadLibraryA("user32.dll"); + switch (IconId ) + { + case IDI_APPLICATION: + IconId = 100; + return LoadIconW(hModule,(LPWSTR)IconId); + break; + case IDI_ASTERISK: + // + IconId = 103; + return LoadIconW(hModule,(LPWSTR)IconId); + break; + case IDI_EXCLAMATION: + IconId = 101; + return LoadIconW(hModule,(LPWSTR)IconId); + break; + case IDI_HAND: + // + return LoadIconW(hModule,(LPWSTR)MAKEINTRESOURCE(104)); + break; + case IDI_QUESTION: + IconId = 102; + return LoadIconW(hModule,(LPWSTR)IconId); + break; + case IDI_WINLOGO: + IconId = 105; + return LoadIconW(hModule,(LPWSTR)IconId); + break; + default: + return NULL; + break; + + } + return NULL; } \ No newline at end of file diff --git a/reactos/lib/user32/graphics/syscol.c b/reactos/lib/user32/graphics/syscol.c index feced1cabea..fbceacd2892 100644 --- a/reactos/lib/user32/graphics/syscol.c +++ b/reactos/lib/user32/graphics/syscol.c @@ -8,12 +8,10 @@ #include -//#include +#include #include -void SYSCOLOR_SetColor( int index, COLORREF color ); -void SYSCOLOR_Init(void); static const char * const DefSysColors[] = { @@ -149,7 +147,7 @@ HBRUSH STDCALL GetSysColorBrush( INT index ) * Windows. However, it is a natural complement for GetSysColorBrush * in the Win API and is needed quite a bit inside Wine. */ -HPEN STDCALL GetSysColorPen( INT index ) +HPEN GetSysColorPen( INT index ) { /* We can assert here, because this function is internal to Wine */ //assert (0 <= index && index < NUM_SYS_COLORS); diff --git a/reactos/lib/user32/graphics/text.c b/reactos/lib/user32/graphics/text.c index 6f8b18e1cb5..3ab4c6700c1 100644 --- a/reactos/lib/user32/graphics/text.c +++ b/reactos/lib/user32/graphics/text.c @@ -1,4 +1,5 @@ #include +#include int @@ -25,4 +26,48 @@ DrawTextW( dtp.iTabLength = 0; return TEXT_DrawTextEx(hDC,(void *)lpString,nCount,lpRect,uFormat, &dtp,TRUE); -} \ No newline at end of file +} + +/*********************************************************************** + * GetTabbedTextExtentA (USER32.293) + */ +DWORD +STDCALL +GetTabbedTextExtentA(HDC hDC, LPCSTR lpString, int nCount, int nTabPositions, + LPINT lpnTabStopPositions) +{ + + return TEXT_TabbedTextOutA( hDC, 0, 0, lpString, nCount, nTabPositions, + lpnTabStopPositions,0, FALSE ); +} + + +DWORD +STDCALL +GetTabbedTextExtentW(HDC hDC, LPCWSTR lpString, int nCount, int nTabPositions, + LPINT lpnTabStopPositions) +{ + + return TEXT_TabbedTextOutW( hDC, 0, 0, lpString, nCount, nTabPositions, + lpnTabStopPositions, 0, FALSE ); +} + + +LONG +STDCALL +TabbedTextOutA( HDC hDC, int X, int Y, LPCSTR lpString, + int nCount, int nTabPositions, LPINT lpnTabStopPositions, int nTabOrigin) +{ + return TEXT_TabbedTextOutA( hDC, X, Y, lpString, nCount, nTabPositions, + lpnTabStopPositions, nTabOrigin, TRUE ); +} + +LONG +STDCALL +TabbedTextOutW( HDC hDC, int X, int Y, LPCWSTR lpString, + int nCount, int nTabPositions, LPINT lpnTabStopPositions, int nTabOrigin) +{ + return TEXT_TabbedTextOutW( hDC, 0, 0, lpString, nCount, nTabPositions, + lpnTabStopPositions, nTabOrigin, TRUE ); +} + diff --git a/reactos/lib/user32/internal/defwnd.c b/reactos/lib/user32/internal/defwnd.c index ac90ae5c151..61c4fe2df46 100644 --- a/reactos/lib/user32/internal/defwnd.c +++ b/reactos/lib/user32/internal/defwnd.c @@ -14,6 +14,7 @@ #include #include #include +#include #include @@ -65,11 +66,22 @@ void DEFWND_HandleWindowPosChanged( WND *wndPtr, UINT flags ) * * Set the window text. */ + +void DEFWND_SetText( WND *wndPtr,const void *text ) +{ + if ( wndPtr->class->bUnicode ) + DEFWND_SetTextW( wndPtr, (LPCWSTR) text ); + else + DEFWND_SetTextA( wndPtr, (LPCSTR) text ); + +} + void DEFWND_SetTextA( WND *wndPtr, LPCSTR text ) { if (!text) text = ""; if (wndPtr->text) HeapFree( GetProcessHeap(), 0, wndPtr->text ); - wndPtr->text = (void *)HEAP_strdupA( GetProcessHeap(), 0, text ); + wndPtr->text = (void *)HEAP_strdupA( GetProcessHeap(), 0, text ); + NC_HandleNCPaint( wndPtr->hwndSelf , (HRGN)1 ); /* Repaint caption */ } @@ -77,7 +89,8 @@ void DEFWND_SetTextW( WND *wndPtr, LPCWSTR text ) { if (!text) text = L""; if (wndPtr->text) HeapFree( GetProcessHeap(), 0, wndPtr->text ); - wndPtr->text = (void *)HEAP_strdupW( GetProcessHeap(), 0, text ); + wndPtr->text = (void *)HEAP_strdupW( GetProcessHeap(), 0, text ); + NC_HandleNCPaint( wndPtr->hwndSelf , (HRGN)1 ); /* Repaint caption */ } /*********************************************************************** @@ -125,7 +138,7 @@ void DEFWND_SetRedraw( WND* wndPtr, WPARAM wParam ) { if( !bVisible ) { - wndPtr->dwStyle |= WS_VISIBLE; + //wndPtr->dwStyle |= WS_VISIBLE; DCE_InvalidateDCE( wndPtr, &wndPtr->rectWindow ); } } @@ -136,7 +149,7 @@ void DEFWND_SetRedraw( WND* wndPtr, WPARAM wParam ) PAINT_RedrawWindow( wndPtr->hwndSelf, NULL, 0, wParam, 0 ); DCE_InvalidateDCE( wndPtr, &wndPtr->rectWindow ); - wndPtr->dwStyle &= ~WS_VISIBLE; +// wndPtr->dwStyle &= ~WS_VISIBLE; } } @@ -171,8 +184,8 @@ LRESULT DEFWND_DefWinProc( WND *wndPtr, UINT msg, WPARAM wParam, if ((wndPtr->flags & WIN_ISWIN) || (TWEAK_WineLook > WIN31_LOOK)) { ClientToScreen(wndPtr->hwndSelf, (LPPOINT)&lParam); - SendMessageA( wndPtr->hwndSelf, WM_CONTEXTMENU, - wndPtr->hwndSelf, lParam); + MSG_SendMessage( wndPtr, WM_CONTEXTMENU, + (WPARAM)wndPtr->hwndSelf,(LPARAM) lParam); } break; diff --git a/reactos/lib/user32/internal/dialog.c b/reactos/lib/user32/internal/dialog.c index 8fdef993926..6fff013ada0 100644 --- a/reactos/lib/user32/internal/dialog.c +++ b/reactos/lib/user32/internal/dialog.c @@ -5,62 +5,24 @@ */ #include -#include #include #include #include -#include "windows.h" -#include "dialog.h" -#include "drive.h" -#include "heap.h" -#include "win.h" -#include "ldt.h" -#include "user.h" -#include "winproc.h" -#include "message.h" -#include "sysmetrics.h" -#include "debug.h" + +#define UNICODE +#include +#include +#include +#include +#include +#include +#include +#include - /* Dialog control information */ -typedef struct -{ - DWORD style; - DWORD exStyle; - DWORD helpId; - INT16 x; - INT16 y; - INT16 cx; - INT16 cy; - UINT32 id; - LPCSTR className; - LPCSTR windowName; - LPVOID data; -} DLG_CONTROL_INFO; - - /* Dialog template */ -typedef struct -{ - DWORD style; - DWORD exStyle; - DWORD helpId; - UINT16 nbItems; - INT16 x; - INT16 y; - INT16 cx; - INT16 cy; - LPCSTR menuName; - LPCSTR className; - LPCSTR caption; - WORD pointSize; - WORD weight; - WINBOOL italic; - LPCSTR faceName; - WINBOOL dialogEx; -} DLG_TEMPLATE; /* Dialog base units */ -static WORD xBaseUnit = 0, yBaseUnit = 0; +WORD xBaseUnit = 0, yBaseUnit = 0; /*********************************************************************** @@ -70,14 +32,14 @@ static WORD xBaseUnit = 0, yBaseUnit = 0; */ WINBOOL DIALOG_Init(void) { - TEXTMETRIC16 tm; - HDC16 hdc; + TEXTMETRIC tm; + HDC hdc; /* Calculate the dialog base units */ - if (!(hdc = CreateDC16( "DISPLAY", NULL, NULL, NULL ))) return FALSE; - GetTextMetrics16( hdc, &tm ); - DeleteDC32( hdc ); + if (!(hdc = CreateDC( L"DISPLAY", NULL, NULL, NULL ))) return FALSE; + GetTextMetrics( hdc, &tm ); + DeleteDC( hdc ); xBaseUnit = tm.tmAveCharWidth; yBaseUnit = tm.tmHeight; @@ -86,184 +48,423 @@ WINBOOL DIALOG_Init(void) if (!(tm.tmPitchAndFamily & TMPF_FIXED_PITCH)) xBaseUnit = xBaseUnit * 5 / 4; - TRACE(dialog, "base units = %d,%d\n", + DPRINT( "base units = %d,%d\n", xBaseUnit, yBaseUnit ); return TRUE; } +/*********************************************************************** + * DIALOG_DoDialogBox + */ +INT DIALOG_DoDialogBox( HWND hwnd, HWND owner ) +{ + WND * wndPtr; + DIALOGINFO * dlgInfo; + MSG msg; + INT retval; + + /* Owner must be a top-level window */ + owner = WIN_GetTopParent( owner ); + if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return -1; + dlgInfo = (DIALOGINFO *)wndPtr->wExtra; + EnableWindow( owner, FALSE ); + ShowWindow( hwnd, SW_SHOW ); + + while (MSG_InternalGetMessage(&msg, hwnd, owner, MSGF_DIALOGBOX, PM_REMOVE, + !(wndPtr->dwStyle & DS_NOIDLEMSG) )) + { + if (!IsDialogMessage( hwnd, &msg)) + { + TranslateMessage( &msg ); + DispatchMessage( &msg ); + } + if (dlgInfo->flags & DF_END) break; + } + retval = dlgInfo->idResult; + EnableWindow( owner, TRUE ); + dlgInfo->flags |= DF_ENDING; /* try to stop it being destroyed twice */ + DestroyWindow( hwnd ); + return retval; +} + + /*********************************************************************** - * DIALOG_GetControl16 + * DIALOG_ParseTemplate * - * Return the class and text of the control pointed to by ptr, - * fill the header structure and return a pointer to the next control. + * Fill a DLG_TEMPLATE structure from the dialog template, and return + * a pointer to the first control. */ -static LPCSTR DIALOG_GetControl16( LPCSTR p, DLG_CONTROL_INFO *info ) +LPCDLGITEMTEMPLATE DIALOG_ParseTemplate( LPCDLGTEMPLATE DlgTemplate, DLG_TEMPLATE * result, WINBOOL bUnicode ) { - static char buffer[10]; - int int_id; + WORD *p; + + + result->dialogEx = FALSE; + result->helpId = 0; + result->exStyle = DlgTemplate->dwExtendedStyle; + + result->nbItems = DlgTemplate->cdit; + result->x = DlgTemplate->x; + result->y = DlgTemplate->y; + result->cx = DlgTemplate->cx; + result->cy = DlgTemplate->cy; + + + p = &(DlgTemplate->cy); + p++; - info->x = GET_WORD(p); p += sizeof(WORD); - info->y = GET_WORD(p); p += sizeof(WORD); - info->cx = GET_WORD(p); p += sizeof(WORD); - info->cy = GET_WORD(p); p += sizeof(WORD); - info->id = GET_WORD(p); p += sizeof(WORD); - info->style = GET_DWORD(p); p += sizeof(DWORD); - info->exStyle = 0; + + /* Get the menu name */ - if (*p & 0x80) + switch((WORD)*p) { - switch((BYTE)*p) - { - case 0x80: strcpy( buffer, "BUTTON" ); break; - case 0x81: strcpy( buffer, "EDIT" ); break; - case 0x82: strcpy( buffer, "STATIC" ); break; - case 0x83: strcpy( buffer, "LISTBOX" ); break; - case 0x84: strcpy( buffer, "SCROLLBAR" ); break; - case 0x85: strcpy( buffer, "COMBOBOX" ); break; - default: buffer[0] = '\0'; break; - } - info->className = buffer; + case 0x0000: + result->menuName = NULL; p++; + break; + case 0xffff: + p++; + result->menuName = (LPWSTR) *p; // Ordinal of Menu resource + p++; + break; + default: + result->menuName = (LPCWSTR)p; + p += lstrlenW( (LPCWSTR)p ); + p++; + break; } - else + + /* Get the class name */ + + + + switch((WORD)*p) { - info->className = p; - p += strlen(p) + 1; + case 0x0000: + if ( bUnicode == TRUE ) + result->className = DIALOG_CLASS_NAMEW; + else + result->className = DIALOG_CLASS_NAMEA; + p++; + break; + case 0xffff: + p++; + result->className = (LPCWSTR)p; // Ordinal of predefined class + p++; + break; + default: + result->className = (LPCWSTR)p; + p += lstrlenW( (LPCWSTR)p ); + p++; + break; } - int_id = ((BYTE)*p == 0xff); - if (int_id) + /* Get the window caption */ + if ( *p != 0 ) { + result->caption = (LPCWSTR)p; + p += lstrlenW( (LPCWSTR)p ) + 1; + + /* Get the font name */ + + if (result->style & DS_SETFONT) + { + result->pointSize = *p; + p++; + if (result->dialogEx) + { + result->weight = *p; p++; + result->italic = *p; p++; + } + else + { + result->weight = FW_DONTCARE; + result->italic = FALSE; + } + result->faceName = (LPCWSTR)p; + p += lstrlenW( (LPCWSTR)p ); + p++; + + } + } else { + result->caption = L""; + } + + + + /* First control is on dword boundary */ + return (LPCDLGITEMTEMPLATE )((((int)p) + 3) & ~3); +} + +/*********************************************************************** + * DIALOG_ParseTemplate + * + * Fill a DLG_TEMPLATE structure from the dialog template, and return + * a pointer to the first control. + */ +LPCDLGITEMTEMPLATEEX DIALOG_ParseTemplateEx( LPCDLGTEMPLATEEX DlgTemplate, DLG_TEMPLATE * result,WINBOOL bUnicode ) +{ + WORD *p; + + + result->dialogEx = TRUE; + result->helpId = DlgTemplate->helpID; + result->exStyle = DlgTemplate->exStyle; + result->style = DlgTemplate->style; + + result->nbItems = DlgTemplate->cDlgItems; + result->x = DlgTemplate->x; + result->y = DlgTemplate->y; + result->cx = DlgTemplate->cx; + result->cy = DlgTemplate->cy; + + p = &(DlgTemplate->cy); + p++; + + /* Get the menu name */ + + switch(*p) { - /* Integer id, not documented (?). Only works for SS_ICON controls */ - info->windowName = (LPCSTR)(UINT32)GET_WORD(p+1); - p += 3; + case 0x0000: + result->menuName = NULL; + p++; + break; + case 0xffff: + p++; + result->menuName = (LPCWSTR)(WORD)*( p ); // Ordinal of Menu resource + p++; + break; + default: + result->menuName = (LPCWSTR)p; + p += lstrlenW( (LPCWSTR)p ) + 1; + break; } - else + + /* Get the class name */ + + switch(*p) { - info->windowName = p; - p += strlen(p) + 1; + case 0x0000: + if ( bUnicode == TRUE ) + result->className = DIALOG_CLASS_NAMEW; + else + result->className = DIALOG_CLASS_NAMEA; + p++; + break; + case 0xffff: + p++; + result->className = (LPCWSTR)(WORD)*( p ); + p ++; + DPRINT( " CLASS %04x\n", LOWORD(result->className) ); + break; + default: + result->className = (LPCWSTR)p; + DPRINT( " CLASS %s\n", debugstr_w( (LPCWSTR)p )); + p += lstrlenW( (LPCWSTR)p ) + 1; + break; } - info->data = (LPVOID)(*p ? p + 1 : NULL); /* FIXME: should be a segptr */ - p += *p + 1; + /* Get the window caption */ + if ( *p != 0 ) { + result->caption = (LPCWSTR)p; + p += lstrlenW( (LPCWSTR)p ) + 1; + + /* Get the font name */ - if(int_id) - TRACE(dialog," %s %04x %d, %d, %d, %d, %d, %08lx, %08lx\n", - info->className, LOWORD(info->windowName), - info->id, info->x, info->y, info->cx, info->cy, - info->style, (DWORD)info->data); - else - TRACE(dialog," %s '%s' %d, %d, %d, %d, %d, %08lx, %08lx\n", - info->className, info->windowName, - info->id, info->x, info->y, info->cx, info->cy, - info->style, (DWORD)info->data); + if (result->style & DS_SETFONT) + { + result->pointSize = LOWORD(p); + p++; + if (result->dialogEx) + { + result->weight = *p; p++; + result->italic = LOBYTE(*p); p++; + } + else + { + result->weight = FW_DONTCARE; + result->italic = FALSE; + } + result->faceName = (LPCWSTR)p; + p += lstrlenW( (LPCWSTR)p ) + 1; + + } + } else + result->caption = L""; + - return p; + /* First control is on dword boundary */ + return (LPDLGITEMTEMPLATEEX )((((int)p) + 3) & ~3); } /*********************************************************************** - * DIALOG_GetControl32 + * DIALOG_GetControl * * Return the class and text of the control pointed to by ptr, * fill the header structure and return a pointer to the next control. */ -static const WORD *DIALOG_GetControl32( const WORD *p, DLG_CONTROL_INFO *info, - WINBOOL dialogEx ) +LPCDLGITEMTEMPLATE DIALOG_GetControl( LPCDLGITEMTEMPLATE DlgItemTemplate, DLG_CONTROL_INFO *info) { - if (dialogEx) - { - info->helpId = GET_DWORD(p); p += 2; - info->exStyle = GET_DWORD(p); p += 2; - info->style = GET_DWORD(p); p += 2; - } - else - { - info->helpId = 0; - info->style = GET_DWORD(p); p += 2; - info->exStyle = GET_DWORD(p); p += 2; - } - info->x = GET_WORD(p); p++; - info->y = GET_WORD(p); p++; - info->cx = GET_WORD(p); p++; - info->cy = GET_WORD(p); p++; + WORD *p; + WORD id; - if (dialogEx) + info->helpId = 0; + info->exStyle = DlgItemTemplate->dwExtendedStyle; + info->style = DlgItemTemplate->style; + + info->x = DlgItemTemplate->x; + info->y = DlgItemTemplate->y; + info->cx = DlgItemTemplate->cx; + info->cy = DlgItemTemplate->cy; + + + info->id = DlgItemTemplate->id; + + + p = (char *)DlgItemTemplate + sizeof(DLGITEMTEMPLATE); + p--; + + if (*p == 0xffff) { - /* id is a DWORD for DIALOGEX */ - info->id = GET_DWORD(p); - p += 2; - } - else - { - info->id = GET_WORD(p); + + static const WCHAR class_names[6][10] = + { + { BUTTON_CLASS_NAME }, /* 0x80 */ + { EDIT_CLASS_NAME }, /* 0x81 */ + { STATIC_CLASS_NAME }, /* 0x82 */ + { LISTBOX_CLASS_NAME}, /* 0x83 */ + { SCROLLBAR_CLASS_NAME }, /* 0x84 */ + { COMBOBOX_CLASS_NAME } /* 0x85 */ + }; + p++; + id = (WORD)*(p); + if ((id >= 0x80) && (id <= 0x85)) + info->className = (LPCSTR)HEAP_strdupW(GetProcessHeap(),0,class_names[id - 0x80]); + else + info->className = NULL; + + printf("%S\n",info->className); + p++; } - - if (GET_WORD(p) == 0xffff) + else { - static const WCHAR class_names[6][10] = - { - { 'B','u','t','t','o','n', }, /* 0x80 */ - { 'E','d','i','t', }, /* 0x81 */ - { 'S','t','a','t','i','c', }, /* 0x82 */ - { 'L','i','s','t','B','o','x', }, /* 0x83 */ - { 'S','c','r','o','l','l','B','a','r', }, /* 0x84 */ - { 'C','o','m','b','o','B','o','x', } /* 0x85 */ - }; - WORD id = GET_WORD(p+1); - if ((id >= 0x80) && (id <= 0x85)) - info->className = (LPCSTR)class_names[id - 0x80]; - else - { - info->className = NULL; - ERR( dialog, "Unknown built-in class id %04x\n", id ); - } - p += 2; + info->className = (LPCWSTR)p; + p += lstrlenW( (LPCWSTR)p ) + 1; + } + + if (*p == 0xffff) /* Is it an integer id? */ + { + p++; + info->windowName = (LPCWSTR)(WORD)*(p + 1); + p++; } else { - info->className = (LPCSTR)p; - p += lstrlen32W( (LPCWSTR)p ) + 1; + info->windowName = (LPCWSTR)p; + p += lstrlenW( (LPCWSTR)p ) + 1; } - if (GET_WORD(p) == 0xffff) /* Is it an integer id? */ - { - info->windowName = (LPCSTR)(UINT32)GET_WORD(p + 1); - p += 2; - } - else - { - info->windowName = (LPCSTR)p; - p += lstrlen32W( (LPCWSTR)p ) + 1; - } - TRACE(dialog," %s %s %d, %d, %d, %d, %d, %08lx, %08lx, %08lx\n", - debugstr_w( (LPCWSTR)info->className ), - debugres_w( (LPCWSTR)info->windowName ), - info->id, info->x, info->y, info->cx, info->cy, - info->style, info->exStyle, info->helpId ); - if (GET_WORD(p)) + if (*p) { - if (TRACE_ON(dialog)) - { - WORD i, count = GET_WORD(p) / sizeof(WORD); - TRACE(dialog, " BEGIN\n"); - TRACE(dialog, " "); - for (i = 0; i < count; i++) DUMP( "%04x,", GET_WORD(p+i+1) ); - DUMP("\n"); - TRACE(dialog, " END\n" ); - } - info->data = (LPVOID)(p + 1); - p += GET_WORD(p) / sizeof(WORD); + p++; + info->data = (LPVOID)(p); + p += *p / sizeof(WORD); + } + else { + info->data = NULL; + p++; } - else info->data = NULL; - p++; /* Next control is on dword boundary */ - return (const WORD *)((((int)p) + 3) & ~3); + return (LPCDLGITEMTEMPLATE)((((int)p) + 3) & ~3); +} + + +/*********************************************************************** + * DIALOG_GetControl + * + * Return the class and text of the control pointed to by ptr, + * fill the header structure and return a pointer to the next control. + */ +LPCDLGITEMTEMPLATEEX DIALOG_GetControlEx( LPCDLGITEMTEMPLATEEX DlgItemTemplate, DLG_CONTROL_INFO *info ) +{ + WORD *p; + WORD id; + info->helpId = DlgItemTemplate->helpID; + info->exStyle = DlgItemTemplate->exStyle; + info->style = DlgItemTemplate->style; + + info->x = DlgItemTemplate->x; + info->y = DlgItemTemplate->y; + info->cx = DlgItemTemplate->cx; + info->cy = DlgItemTemplate->cy; + + + /* id is a DWORD for DIALOGEX */ + info->id = DlgItemTemplate->id; + + p = (char *)DlgItemTemplate + sizeof(DLGITEMTEMPLATEEX); + p--; + + if (*p == 0xffff) + { + + static const WCHAR class_names[6][10] = + { + { L"Button" }, /* 0x80 */ + { L"Edit"}, /* 0x81 */ + { L"Static" }, /* 0x82 */ + { L"ListBox"}, /* 0x83 */ + { L"ScrollBar" }, /* 0x84 */ + { L"ComboBox" } /* 0x85 */ + }; + p++; + id = (WORD)*(p); + if ((id >= 0x80) && (id <= 0x85)) + info->className = (LPCSTR)HEAP_strdupW(GetProcessHeap(),0,class_names[id - 0x80]); + else + info->className = NULL; + + p++; + } + else + { + info->className = (LPCWSTR)p; + p += lstrlenW( (LPCWSTR)p ) + 1; + } + + if (*p == 0xffff) /* Is it an integer id? */ + { + p++; + info->windowName = (LPCWSTR)(WORD)*(p); + p++; + } + else + { + + info->windowName = (LPCWSTR)p; + p += lstrlenW( (LPCWSTR)p ) + 1; + } + + + + if (*p) { + + p++; + info->data = (LPVOID)(p); + p += *p / sizeof(WORD); + } + else { + info->data = NULL; + p++; + } + + /* Next control is on dword boundary */ + return (LPCDLGITEMTEMPLATE)((((int)p) + 3) & ~3); } @@ -272,302 +473,95 @@ static const WORD *DIALOG_GetControl32( const WORD *p, DLG_CONTROL_INFO *info, * * Create the control windows for a dialog. */ -static WINBOOL DIALOG_CreateControls( WND *pWnd, LPCSTR template, - const DLG_TEMPLATE *dlgTemplate, - HINSTANCE32 hInst, WINBOOL win32 ) +WINBOOL DIALOG_CreateControls( HANDLE hWndDialog, DIALOGINFO *dlgInfo , + void *template, INT items, + HINSTANCE hInst, WINBOOL bDialogEx) { - DIALOGINFO *dlgInfo = (DIALOGINFO *)pWnd->wExtra; DLG_CONTROL_INFO info; - HWND32 hwndCtrl, hwndDefButton = 0; - INT32 items = dlgTemplate->nbItems; - - TRACE(dialog, " BEGIN\n" ); + HWND hwndCtrl, hwndDefButton = 0; + while (items--) { - if (!win32) - { - HINSTANCE16 instance; - template = DIALOG_GetControl16( template, &info ); - if (HIWORD(info.className) && !strcmp( info.className, "EDIT") && - ((pWnd->dwStyle & DS_LOCALEDIT) != DS_LOCALEDIT)) - { - if (!dlgInfo->hDialogHeap) - { - dlgInfo->hDialogHeap = GlobalAlloc16(GMEM_FIXED, 0x10000); - if (!dlgInfo->hDialogHeap) - { - ERR(dialog, "Insufficient memory to create heap for edit control\n" ); - continue; - } - LocalInit(dlgInfo->hDialogHeap, 0, 0xffff); - } - instance = dlgInfo->hDialogHeap; - } - else instance = (HINSTANCE16)hInst; + + if ( bDialogEx) + template = (void *)DIALOG_GetControlEx( (LPDLGITEMTEMPLATEEX)template, &info ); + else + template = (void *)DIALOG_GetControl( (LPDLGITEMTEMPLATE)template, &info ); - hwndCtrl = CreateWindowEx16( info.exStyle | WS_EX_NOPARENTNOTIFY, - info.className, info.windowName, - info.style | WS_CHILD, - info.x * dlgInfo->xBaseUnit / 4, - info.y * dlgInfo->yBaseUnit / 8, - info.cx * dlgInfo->xBaseUnit / 4, - info.cy * dlgInfo->yBaseUnit / 8, - pWnd->hwndSelf, (HMENU16)info.id, - instance, info.data ); - } - else - { - template = (LPCSTR)DIALOG_GetControl32( (WORD *)template, &info, - dlgTemplate->dialogEx ); - hwndCtrl = CreateWindowEx32W( info.exStyle | WS_EX_NOPARENTNOTIFY, - (LPCWSTR)info.className, - (LPCWSTR)info.windowName, - info.style | WS_CHILD, - info.x * dlgInfo->xBaseUnit / 4, - info.y * dlgInfo->yBaseUnit / 8, - info.cx * dlgInfo->xBaseUnit / 4, - info.cy * dlgInfo->yBaseUnit / 8, - pWnd->hwndSelf, (HMENU32)info.id, - hInst, info.data ); - } - if (!hwndCtrl) return FALSE; + hwndCtrl = CreateWindowExW( info.exStyle | WS_EX_NOPARENTNOTIFY, + (LPCWSTR)info.className, + (LPCWSTR)info.windowName, + info.style | WS_CHILD | WS_THICKFRAME | WS_VISIBLE, + info.x * dlgInfo->xBaseUnit / 4, + info.y * dlgInfo->yBaseUnit / 8, + info.cx * dlgInfo->xBaseUnit / 4 , + info.cy * dlgInfo->yBaseUnit / 8, + hWndDialog, (HMENU)info.id, + hInst, info.data ); + + + if (hwndCtrl) { /* Send initialisation messages to the control */ - if (dlgInfo->hUserFont) SendMessage32A( hwndCtrl, WM_SETFONT, - (WPARAM32)dlgInfo->hUserFont, 0 ); - if (SendMessage32A(hwndCtrl, WM_GETDLGCODE, 0, 0) & DLGC_DEFPUSHBUTTON) - { - /* If there's already a default push-button, set it back */ - /* to normal and use this one instead. */ - if (hwndDefButton) - SendMessage32A( hwndDefButton, BM_SETSTYLE32, - BS_PUSHBUTTON,FALSE ); - hwndDefButton = hwndCtrl; - dlgInfo->idResult = GetWindowWord32( hwndCtrl, GWW_ID ); - } + if (dlgInfo->hUserFont) SendMessage( hwndCtrl, WM_SETFONT, + (WPARAM)dlgInfo->hUserFont, 0 ); + if (SendMessage(hwndCtrl, WM_GETDLGCODE, 0, 0) & DLGC_DEFPUSHBUTTON) + { + /* If there's already a default push-button, set it back */ + /* to normal and use this one instead. */ + if (hwndDefButton) + SendMessage( hwndDefButton, BM_SETSTYLE, BS_PUSHBUTTON,FALSE ); + hwndDefButton = hwndCtrl; + dlgInfo->idResult = GetWindowLong( hwndCtrl, GWL_ID ); + } + } } - TRACE(dialog, " END\n" ); return TRUE; } -/*********************************************************************** - * DIALOG_ParseTemplate16 - * - * Fill a DLG_TEMPLATE structure from the dialog template, and return - * a pointer to the first control. - */ -static LPCSTR DIALOG_ParseTemplate16( LPCSTR p, DLG_TEMPLATE * result ) -{ - result->style = GET_DWORD(p); p += sizeof(DWORD); - result->exStyle = 0; - result->nbItems = *p++; - result->x = GET_WORD(p); p += sizeof(WORD); - result->y = GET_WORD(p); p += sizeof(WORD); - result->cx = GET_WORD(p); p += sizeof(WORD); - result->cy = GET_WORD(p); p += sizeof(WORD); - TRACE(dialog, "DIALOG %d, %d, %d, %d\n", - result->x, result->y, result->cx, result->cy ); - TRACE(dialog, " STYLE %08lx\n", result->style ); - /* Get the menu name */ - - switch( (BYTE)*p ) - { - case 0: - result->menuName = 0; - p++; - break; - case 0xff: - result->menuName = (LPCSTR)(UINT32)GET_WORD( p + 1 ); - p += 3; - TRACE(dialog, " MENU %04x\n", LOWORD(result->menuName) ); - break; - default: - result->menuName = p; - TRACE(dialog, " MENU '%s'\n", p ); - p += strlen(p) + 1; - break; - } - - /* Get the class name */ - - if (*p) - { - result->className = p; - TRACE(dialog, " CLASS '%s'\n", result->className ); - } - else result->className = DIALOG_CLASS_ATOM; - p += strlen(p) + 1; - - /* Get the window caption */ - - result->caption = p; - p += strlen(p) + 1; - TRACE(dialog, " CAPTION '%s'\n", result->caption ); - - /* Get the font name */ - - if (result->style & DS_SETFONT) - { - result->pointSize = GET_WORD(p); - p += sizeof(WORD); - result->faceName = p; - p += strlen(p) + 1; - TRACE(dialog, " FONT %d,'%s'\n", - result->pointSize, result->faceName ); - } - return p; -} - - -/*********************************************************************** - * DIALOG_ParseTemplate32 - * - * Fill a DLG_TEMPLATE structure from the dialog template, and return - * a pointer to the first control. - */ -static LPCSTR DIALOG_ParseTemplate32( LPCSTR template, DLG_TEMPLATE * result ) -{ - const WORD *p = (const WORD *)template; - - result->style = GET_DWORD(p); p += 2; - if (result->style == 0xffff0001) /* DIALOGEX resource */ - { - result->dialogEx = TRUE; - result->helpId = GET_DWORD(p); p += 2; - result->exStyle = GET_DWORD(p); p += 2; - result->style = GET_DWORD(p); p += 2; - } - else - { - result->dialogEx = FALSE; - result->helpId = 0; - result->exStyle = GET_DWORD(p); p += 2; - } - result->nbItems = GET_WORD(p); p++; - result->x = GET_WORD(p); p++; - result->y = GET_WORD(p); p++; - result->cx = GET_WORD(p); p++; - result->cy = GET_WORD(p); p++; - TRACE( dialog, "DIALOG%s %d, %d, %d, %d, %ld\n", - result->dialogEx ? "EX" : "", result->x, result->y, - result->cx, result->cy, result->helpId ); - TRACE( dialog, " STYLE 0x%08lx\n", result->style ); - TRACE( dialog, " EXSTYLE 0x%08lx\n", result->exStyle ); - - /* Get the menu name */ - - switch(GET_WORD(p)) - { - case 0x0000: - result->menuName = NULL; - p++; - break; - case 0xffff: - result->menuName = (LPCSTR)(UINT32)GET_WORD( p + 1 ); - p += 2; - TRACE(dialog, " MENU %04x\n", LOWORD(result->menuName) ); - break; - default: - result->menuName = (LPCSTR)p; - TRACE(dialog, " MENU %s\n", debugstr_w( (LPCWSTR)p )); - p += lstrlen32W( (LPCWSTR)p ) + 1; - break; - } - - /* Get the class name */ - - switch(GET_WORD(p)) - { - case 0x0000: - result->className = DIALOG_CLASS_ATOM; - p++; - break; - case 0xffff: - result->className = (LPCSTR)(UINT32)GET_WORD( p + 1 ); - p += 2; - TRACE(dialog, " CLASS %04x\n", LOWORD(result->className) ); - break; - default: - result->className = (LPCSTR)p; - TRACE(dialog, " CLASS %s\n", debugstr_w( (LPCWSTR)p )); - p += lstrlen32W( (LPCWSTR)p ) + 1; - break; - } - - /* Get the window caption */ - - result->caption = (LPCSTR)p; - p += lstrlen32W( (LPCWSTR)p ) + 1; - TRACE(dialog, " CAPTION %s\n", debugstr_w( (LPCWSTR)result->caption ) ); - - /* Get the font name */ - - if (result->style & DS_SETFONT) - { - result->pointSize = GET_WORD(p); - p++; - if (result->dialogEx) - { - result->weight = GET_WORD(p); p++; - result->italic = LOBYTE(GET_WORD(p)); p++; - } - else - { - result->weight = FW_DONTCARE; - result->italic = FALSE; - } - result->faceName = (LPCSTR)p; - p += lstrlen32W( (LPCWSTR)p ) + 1; - TRACE(dialog, " FONT %d, %s, %d, %s\n", - result->pointSize, debugstr_w( (LPCWSTR)result->faceName ), - result->weight, result->italic ? "TRUE" : "FALSE" ); - } - - /* First control is on dword boundary */ - return (LPCSTR)((((int)p) + 3) & ~3); -} /*********************************************************************** * DIALOG_CreateIndirect */ -HWND32 DIALOG_CreateIndirect( HINSTANCE32 hInst, LPCSTR dlgTemplate, - WINBOOL win32Template, HWND32 owner, - DLGPROC16 dlgProc, LPARAM param, - WINDOWPROCTYPE procType ) +HWND DIALOG_CreateIndirect( HINSTANCE hInst, void *dlgTemplate, HWND owner, + DLGPROC dlgProc, LPARAM param, + WINBOOL bUnicode ) { - HMENU16 hMenu = 0; - HFONT16 hFont = 0; - HWND32 hwnd; - RECT32 rect; + HMENU hMenu = 0; + HFONT hFont = 0; + HWND hwnd; + RECT rect; WND * wndPtr; DLG_TEMPLATE template; DIALOGINFO * dlgInfo; WORD xUnit = xBaseUnit; WORD yUnit = yBaseUnit; + void *dlgItemTemplate; + + + + if ( xBaseUnit == 0 ) + DIALOG_Init(); + + xUnit = xBaseUnit; + yUnit = yBaseUnit; /* Parse dialog template */ - if (!dlgTemplate) return 0; - if (win32Template) - dlgTemplate = DIALOG_ParseTemplate32( dlgTemplate, &template ); - else - dlgTemplate = DIALOG_ParseTemplate16( dlgTemplate, &template ); + + if (((LPDLGTEMPLATEEX)dlgTemplate)->signature != 0xffff) /* DIALOGEX resource */ + dlgItemTemplate = (void *)DIALOG_ParseTemplate((LPCDLGTEMPLATE) dlgTemplate, &template, bUnicode ); + else + dlgItemTemplate = (void *)DIALOG_ParseTemplateEx( (LPCDLGTEMPLATEEX)dlgTemplate, &template, bUnicode ); + /* Load menu */ - if (template.menuName) - { - if (!win32Template) - { - LPSTR str = SEGPTR_STRDUP( template.menuName ); - hMenu = LoadMenu16( hInst, SEGPTR_GET(str) ); - SEGPTR_FREE( str ); - } - else hMenu = LoadMenu32W( hInst, (LPCWSTR)template.menuName ); - } + hMenu = LoadMenuW( hInst, (LPCWSTR)template.menuName ); + /* Create custom font if needed */ @@ -576,33 +570,31 @@ HWND32 DIALOG_CreateIndirect( HINSTANCE32 hInst, LPCSTR dlgTemplate, /* The font height must be negative as it is a point size */ /* (see CreateFont() documentation in the Windows SDK). */ - if (win32Template) - hFont = CreateFont32W( -template.pointSize, 0, 0, 0, + + hFont = CreateFontW( -template.pointSize, 0, 0, 0, template.weight, template.italic, FALSE, FALSE, DEFAULT_CHARSET, 0, 0, PROOF_QUALITY, FF_DONTCARE, (LPCWSTR)template.faceName ); - else - hFont = CreateFont16( -template.pointSize, 0, 0, 0, FW_DONTCARE, - FALSE, FALSE, FALSE, DEFAULT_CHARSET, 0, 0, - PROOF_QUALITY, FF_DONTCARE, - template.faceName ); + if (hFont) { - TEXTMETRIC16 tm; - HFONT16 oldFont; + TEXTMETRIC tm; + HFONT oldFont; - HDC32 hdc = GetDC32(0); - oldFont = SelectObject32( hdc, hFont ); - GetTextMetrics16( hdc, &tm ); - SelectObject32( hdc, oldFont ); - ReleaseDC32( 0, hdc ); + HDC hdc = GetDC(0); + oldFont = SelectObject( hdc, hFont ); + GetTextMetrics( hdc, &tm ); + SelectObject( hdc, oldFont ); + ReleaseDC( 0, hdc ); xUnit = tm.tmAveCharWidth; yUnit = tm.tmHeight; if (!(tm.tmPitchAndFamily & TMPF_FIXED_PITCH)) xBaseUnit = xBaseUnit * 5 / 4; /* See DIALOG_Init() */ + } } - + + /* Create dialog main window */ rect.left = rect.top = 0; @@ -610,15 +602,14 @@ HWND32 DIALOG_CreateIndirect( HINSTANCE32 hInst, LPCSTR dlgTemplate, rect.bottom = template.cy * yUnit / 8; if (template.style & DS_MODALFRAME) template.exStyle |= WS_EX_DLGMODALFRAME; - AdjustWindowRectEx32( &rect, template.style, + AdjustWindowRectEx( &rect, template.style, hMenu ? TRUE : FALSE , template.exStyle ); rect.right -= rect.left; rect.bottom -= rect.top; - if ((INT16)template.x == CW_USEDEFAULT16) + if ((INT)template.x == CW_USEDEFAULT) { - rect.left = rect.top = (procType == WIN_PROC_16) ? CW_USEDEFAULT16 - : CW_USEDEFAULT32; + rect.left = rect.top = CW_USEDEFAULT; } else { @@ -634,48 +625,50 @@ HWND32 DIALOG_CreateIndirect( HINSTANCE32 hInst, LPCSTR dlgTemplate, } if ( !(template.style & WS_CHILD) ) { - INT16 dX, dY; + INT dX, dY; if( !(template.style & DS_ABSALIGN) ) - ClientToScreen32( owner, (POINT32 *)&rect ); + ClientToScreen( owner, (POINT *)&rect ); /* try to fit it into the desktop */ - if( (dX = rect.left + rect.right + SYSMETRICS_CXDLGFRAME - - SYSMETRICS_CXSCREEN) > 0 ) rect.left -= dX; - if( (dY = rect.top + rect.bottom + SYSMETRICS_CYDLGFRAME - - SYSMETRICS_CYSCREEN) > 0 ) rect.top -= dY; + if( (dX = rect.left + rect.right + SYSMETRICS_CXDLGFRAME - SYSMETRICS_CXSCREEN) > 0 ) + rect.left -= dX; + if( (dY = rect.top + rect.bottom + SYSMETRICS_CYDLGFRAME - SYSMETRICS_CYSCREEN) > 0 ) + rect.top -= dY; if( rect.left < 0 ) rect.left = 0; if( rect.top < 0 ) rect.top = 0; } } - if (procType == WIN_PROC_16) - hwnd = CreateWindowEx16(template.exStyle, template.className, - template.caption, template.style & ~WS_VISIBLE, - rect.left, rect.top, rect.right, rect.bottom, - owner, hMenu, hInst, NULL ); - else - hwnd = CreateWindowEx32W(template.exStyle, (LPCWSTR)template.className, + +// template.style & ~WS_VISIBLE + +template.style |= WS_VISIBLE; +template.style |= WS_THICKFRAME; + hwnd = CreateWindowExW(template.exStyle, (LPCWSTR)template.className, (LPCWSTR)template.caption, - template.style & ~WS_VISIBLE, - rect.left, rect.top, rect.right, rect.bottom, + template.style , + rect.left, rect.top, rect.right, rect.bottom , owner, hMenu, hInst, NULL ); + + if (!hwnd) { - if (hFont) DeleteObject32( hFont ); - if (hMenu) DestroyMenu32( hMenu ); + if (hFont) DeleteObject( hFont ); + if (hMenu) DestroyMenu( hMenu ); return 0; } wndPtr = WIN_FindWndPtr( hwnd ); wndPtr->flags |= WIN_ISDIALOG; wndPtr->helpContext = template.helpId; + wndPtr->winproc = dlgProc; /* Initialise dialog extra data */ dlgInfo = (DIALOGINFO *)wndPtr->wExtra; - WINPROC_SetProc( &dlgInfo->dlgProc, dlgProc, procType, WIN_PROC_WINDOW ); + dlgInfo->dlgProc = dlgProc; dlgInfo->hUserFont = hFont; dlgInfo->hMenu = hMenu; dlgInfo->xBaseUnit = xUnit; @@ -686,220 +679,246 @@ HWND32 DIALOG_CreateIndirect( HINSTANCE32 hInst, LPCSTR dlgTemplate, dlgInfo->hDialogHeap = 0; if (dlgInfo->hUserFont) - SendMessage32A( hwnd, WM_SETFONT, (WPARAM32)dlgInfo->hUserFont, 0 ); + MSG_SendMessage( wndPtr, WM_SETFONT, (WPARAM)dlgInfo->hUserFont, 0L); /* Create controls */ - if (DIALOG_CreateControls( wndPtr, dlgTemplate, &template, - hInst, win32Template )) + + + if (!DIALOG_CreateControls( hwnd, dlgInfo, dlgItemTemplate, template.nbItems, hInst , template.dialogEx)) { + DestroyWindow( hwnd ); + if (hFont) DeleteObject( hFont ); + if (hMenu) DestroyMenu( hMenu ); + return 0; + } + + /* Send initialisation messages and set focus */ - dlgInfo->hwndFocus = GetNextDlgTabItem32( hwnd, 0, FALSE ); + dlgInfo->hwndFocus = GetNextDlgTabItem( hwnd, 0, FALSE ); - if (SendMessage32A( hwnd, WM_INITDIALOG, (WPARAM32)dlgInfo->hwndFocus, param )) - SetFocus32( dlgInfo->hwndFocus ); + if (MSG_SendMessage( wndPtr, WM_INITDIALOG, (WPARAM)dlgInfo->hwndFocus, param)) + SetFocus( dlgInfo->hwndFocus ); - if (template.style & WS_VISIBLE && !(wndPtr->dwStyle & WS_VISIBLE)) - { - ShowWindow32( hwnd, SW_SHOWNORMAL ); /* SW_SHOW doesn't always work */ - UpdateWindow32( hwnd ); - } - return hwnd; - } - if( IsWindow32(hwnd) ) DestroyWindow32( hwnd ); - return 0; + //if (template.style & WS_VISIBLE && !(wndPtr->dwStyle & WS_VISIBLE)) + //{ + ShowWindow( hwnd, SW_SHOWNORMAL ); /* SW_SHOW doesn't always work */ + UpdateWindow( hwnd ); + // } + + + PAINT_RedrawWindow( wndPtr->hwndSelf, NULL, 0, + RDW_INVALIDATE | RDW_ALLCHILDREN | + RDW_FRAME | RDW_ERASENOW | RDW_ERASE, 0 ); + return hwnd; + } -/********************************************************************** - * DIALOG_DlgDirSelect - * - * Helper function for DlgDirSelect* + + + +/*********************************************************************** + * DIALOG_IsAccelerator */ -static WINBOOL DIALOG_DlgDirSelect( HWND32 hwnd, LPSTR str, INT32 len, - INT32 id, WINBOOL win32, WINBOOL unicode, - WINBOOL combo ) +WINBOOL DIALOG_IsAccelerator( HWND hwnd, HWND hwndDlg, WPARAM vKey ) { - char *buffer, *ptr; - INT32 item, size; - WINBOOL ret; - HWND32 listbox = GetDlgItem32( hwnd, id ); + HWND hwndControl = hwnd; + HWND hwndNext; + WND *wndPtr; + WINBOOL RetVal = FALSE; + INT dlgCode; - TRACE(dialog, "%04x '%s' %d\n", hwnd, str, id ); - if (!listbox) return FALSE; - if (win32) + if (vKey == VK_SPACE) { - item = SendMessage32A(listbox, combo ? CB_GETCURSEL32 - : LB_GETCURSEL32, 0, 0 ); - if (item == LB_ERR) return FALSE; - size = SendMessage32A(listbox, combo ? CB_GETLBTEXTLEN32 - : LB_GETTEXTLEN32, 0, 0 ); - if (size == LB_ERR) return FALSE; + dlgCode = SendMessage( hwndControl, WM_GETDLGCODE, 0, 0 ); + if (dlgCode & DLGC_BUTTON) + { + SendMessage( hwndControl, WM_LBUTTONDOWN, 0, 0); + SendMessage( hwndControl, WM_LBUTTONUP, 0, 0); + RetVal = TRUE; + } } else { - item = SendMessage32A(listbox, combo ? CB_GETCURSEL16 - : LB_GETCURSEL16, 0, 0 ); - if (item == LB_ERR) return FALSE; - size = SendMessage32A(listbox, combo ? CB_GETLBTEXTLEN16 - : LB_GETTEXTLEN16, 0, 0 ); - if (size == LB_ERR) return FALSE; - } - - if (!(buffer = SEGPTR_ALLOC( size+1 ))) return FALSE; - - if (win32) - SendMessage32A( listbox, combo ? CB_GETLBTEXT32 : LB_GETTEXT32, - item, (LPARAM)buffer ); - else - SendMessage16( listbox, combo ? CB_GETLBTEXT16 : LB_GETTEXT16, - item, (LPARAM)SEGPTR_GET(buffer) ); - - if ((ret = (buffer[0] == '['))) /* drive or directory */ - { - if (buffer[1] == '-') /* drive */ + do { - buffer[3] = ':'; - buffer[4] = 0; - ptr = buffer + 2; - } - else - { - buffer[strlen(buffer)-1] = '\\'; - ptr = buffer + 1; - } - } - else ptr = buffer; + wndPtr = WIN_FindWndPtr( hwndControl ); + if (wndPtr != NULL && wndPtr->text != NULL && + (wndPtr->dwStyle & (WS_VISIBLE | WS_DISABLED)) == WS_VISIBLE) + { + dlgCode = SendMessage( hwndControl, WM_GETDLGCODE, 0, 0 ); + if (dlgCode & (DLGC_BUTTON | DLGC_STATIC)) + { + /* find the accelerator key */ + LPSTR p = wndPtr->text - 2; + do + { + p = strchr( p + 2, '&' ); + } + while (p != NULL && p[1] == '&'); - if (unicode) lstrcpynAtoW( (LPWSTR)str, ptr, len ); - else lstrcpyn32A( str, ptr, len ); - SEGPTR_FREE( buffer ); - TRACE(dialog, "Returning %d '%s'\n", ret, str ); - return ret; + /* and check if it's the one we're looking for */ + if (p != NULL && toupper( p[1] ) == toupper( vKey ) ) + { + if ((dlgCode & DLGC_STATIC) || + (wndPtr->dwStyle & 0x0f) == BS_GROUPBOX ) + { + /* set focus to the control */ + SendMessage( hwndDlg, WM_NEXTDLGCTL, + hwndControl, 1); + /* and bump it on to next */ + SendMessage( hwndDlg, WM_NEXTDLGCTL, 0, 0); + } + else if (dlgCode & + (DLGC_DEFPUSHBUTTON | DLGC_UNDEFPUSHBUTTON)) + { + /* send command message as from the control */ + SendMessage( hwndDlg, WM_COMMAND, + MAKEWPARAM( LOWORD(wndPtr->wIDmenu), + BN_CLICKED ), + (LPARAM)hwndControl ); + } + else + { + /* click the control */ + SendMessage( hwndControl, WM_LBUTTONDOWN, (WPARAM) 0, (LPARAM)0); + SendMessage( hwndControl, WM_LBUTTONUP, (WPARAM)0, (LPARAM)0); + } + RetVal = TRUE; + break; + } + } + } + hwndNext = GetWindow( hwndControl, GW_CHILD ); + if (!hwndNext) + { + hwndNext = GetWindow( hwndControl, GW_HWNDNEXT ); + } + while (!hwndNext) + { + hwndControl = GetParent( hwndControl ); + if (hwndControl == hwndDlg) + { + hwndNext = GetWindow( hwndDlg, GW_CHILD ); + } + else + { + hwndNext = GetWindow( hwndControl, GW_HWNDNEXT ); + } + } + hwndControl = hwndNext; + } + while (hwndControl != hwnd); + } + return RetVal; } + - -/********************************************************************** - * DIALOG_DlgDirList - * - * Helper function for DlgDirList* +/*********************************************************************** + * DIALOG_IsDialogMessage */ -static INT32 DIALOG_DlgDirList( HWND32 hDlg, LPSTR spec, INT32 idLBox, - INT32 idStatic, UINT32 attrib, WINBOOL combo ) +WINBOOL DIALOG_IsDialogMessage( HWND hwnd, HWND hwndDlg, + UINT message, WPARAM wParam, + LPARAM lParam, WINBOOL *translate, + WINBOOL *dispatch, INT dlgCode ) { - int drive; - HWND32 hwnd; - LPSTR orig_spec = spec; + *translate = *dispatch = FALSE; -#define SENDMSG(msg,wparam,lparam) \ - ((attrib & DDL_POSTMSGS) ? PostMessage32A( hwnd, msg, wparam, lparam ) \ - : SendMessage32A( hwnd, msg, wparam, lparam )) - - TRACE(dialog, "%04x '%s' %d %d %04x\n", - hDlg, spec ? spec : "NULL", idLBox, idStatic, attrib ); - - if (spec && spec[0] && (spec[1] == ':')) + if (message == WM_PAINT) { - drive = toupper( spec[0] ) - 'A'; - spec += 2; - if (!DRIVE_SetCurrentDrive( drive )) return FALSE; + /* Apparently, we have to handle this one as well */ + *dispatch = TRUE; + return TRUE; } - else drive = DRIVE_GetCurrentDrive(); - /* If the path exists and is a directory, chdir to it */ - if (!spec || !spec[0] || DRIVE_Chdir( drive, spec )) spec = "*.*"; - else + /* Only the key messages get special processing */ + if ((message != WM_KEYDOWN) && + (message != WM_SYSCHAR) && + (message != WM_CHAR)) + return FALSE; + + if (dlgCode & DLGC_WANTMESSAGE) { - char *p, *p2; - p = spec; - if ((p2 = strrchr( p, '\\' ))) p = p2; - if ((p2 = strrchr( p, '/' ))) p = p2; - if (p != spec) + *translate = *dispatch = TRUE; + return TRUE; + } + + switch(message) + { + case WM_KEYDOWN: + switch(wParam) { - char sep = *p; - *p = 0; - if (!DRIVE_Chdir( drive, spec )) + case VK_TAB: + if (!(dlgCode & DLGC_WANTTAB)) { - *p = sep; /* Restore the original spec */ - return FALSE; + SendMessageA( hwndDlg, WM_NEXTDLGCTL, + (GetKeyState(VK_SHIFT) & 0x8000), 0 ); + return TRUE; } - spec = p + 1; - } - } - - TRACE(dialog, "path=%c:\\%s mask=%s\n", - 'A' + drive, DRIVE_GetDosCwd(drive), spec ); - - if (idLBox && ((hwnd = GetDlgItem32( hDlg, idLBox )) != 0)) - { - SENDMSG( combo ? CB_RESETCONTENT32 : LB_RESETCONTENT32, 0, 0 ); - if (attrib & DDL_DIRECTORY) - { - if (!(attrib & DDL_EXCLUSIVE)) + break; + + case VK_RIGHT: + case VK_DOWN: + case VK_LEFT: + case VK_UP: + if (!(dlgCode & DLGC_WANTARROWS)) { - if (SENDMSG( combo ? CB_DIR32 : LB_DIR32, - attrib & ~(DDL_DIRECTORY | DDL_DRIVES), - (LPARAM)spec ) == LB_ERR) - return FALSE; + WINBOOL fPrevious = (wParam == VK_LEFT || wParam == VK_UP); + HWND hwndNext = + GetNextDlgGroupItem (hwndDlg, GetFocus(), fPrevious ); + SendMessageA( hwndDlg, WM_NEXTDLGCTL, hwndNext, 1 ); + return TRUE; } - if (SENDMSG( combo ? CB_DIR32 : LB_DIR32, - (attrib & (DDL_DIRECTORY | DDL_DRIVES)) | DDL_EXCLUSIVE, - (LPARAM)"*.*" ) == LB_ERR) - return FALSE; + break; + + case VK_ESCAPE: + SendMessageA( hwndDlg, WM_COMMAND, IDCANCEL, + (LPARAM)GetDlgItem( hwndDlg, IDCANCEL ) ); + return TRUE; + + case VK_RETURN: + { + DWORD dw = SendMessage( hwndDlg, DM_GETDEFID, 0, 0 ); + if (HIWORD(dw) == DC_HASDEFID) + { + SendMessageA( hwndDlg, WM_COMMAND, + MAKEWPARAM( LOWORD(dw), BN_CLICKED ), + (LPARAM)GetDlgItem(hwndDlg, LOWORD(dw))); + } + else + { + SendMessageA( hwndDlg, WM_COMMAND, IDOK, + (LPARAM)GetDlgItem( hwndDlg, IDOK ) ); + + } + } + return TRUE; } - else + *translate = TRUE; + break; /* case WM_KEYDOWN */ + + case WM_CHAR: + if (dlgCode & DLGC_WANTCHARS) break; + /* drop through */ + + case WM_SYSCHAR: + if (DIALOG_IsAccelerator( hwnd, hwndDlg, wParam )) { - if (SENDMSG( combo ? CB_DIR32 : LB_DIR32, attrib, - (LPARAM)spec ) == LB_ERR) - return FALSE; + /* don't translate or dispatch */ + return TRUE; } + break; } - if (idStatic && ((hwnd = GetDlgItem32( hDlg, idStatic )) != 0)) - { - char temp[512]; - int drive = DRIVE_GetCurrentDrive(); - strcpy( temp, "A:\\" ); - temp[0] += drive; - lstrcpyn32A( temp + 3, DRIVE_GetDosCwd(drive), sizeof(temp)-3 ); - CharLower32A( temp ); - /* Can't use PostMessage() here, because the string is on the stack */ - SetDlgItemText32A( hDlg, idStatic, temp ); - } - - if (orig_spec && (spec != orig_spec)) - { - /* Update the original file spec */ - char *p = spec; - while ((*orig_spec++ = *p++)); - } - + /* If we get here, the message has not been treated specially */ + /* and can be sent to its destination window. */ + *dispatch = TRUE; return TRUE; -#undef SENDMSG } -/********************************************************************** - * DIALOG_DlgDirListW - * - * Helper function for DlgDirList*32W - */ -static INT32 DIALOG_DlgDirListW( HWND32 hDlg, LPWSTR spec, INT32 idLBox, - INT32 idStatic, UINT32 attrib, WINBOOL combo ) -{ - if (spec) - { - LPSTR specA = HEAP_strdupWtoA( GetProcessHeap(), 0, spec ); - INT32 ret = DIALOG_DlgDirList( hDlg, specA, idLBox, idStatic, - attrib, combo ); - lstrcpyAtoW( spec, specA ); - HeapFree( GetProcessHeap(), 0, specA ); - return ret; - } - return DIALOG_DlgDirList( hDlg, NULL, idLBox, idStatic, attrib, combo ); -} - diff --git a/reactos/lib/user32/internal/heapdup.c b/reactos/lib/user32/internal/heapdup.c index 9f0bf6ceacb..86838c27074 100644 --- a/reactos/lib/user32/internal/heapdup.c +++ b/reactos/lib/user32/internal/heapdup.c @@ -72,6 +72,7 @@ int lpstrncpyA( LPSTR ptr1,LPSTR ptr2, int n) if ( ptr1[i] == 0 ) break; } + return i; } int lpstrncpyW( LPWSTR ptr1,LPWSTR ptr2, int n) { @@ -81,6 +82,7 @@ int lpstrncpyW( LPWSTR ptr1,LPWSTR ptr2, int n) if ( ptr1[i] == 0 ) break; } + return i; } LPSTR HEAP_strdupA(HANDLE hHeap,DWORD dwFlags,LPCSTR ptr) @@ -100,4 +102,14 @@ LPWSTR HEAP_strdupW(HANDLE hHeap,DWORD dwFlags,LPCWSTR ptr) lstrcpyW(lpszString,ptr); return lpszString; +} + +int HEAP_memset( void *d,int c ,int count) +{ + return memset(d,c,count); +} + +int HEAP_memcpy( void *d,void *s,int c) +{ + return memcpy(d,s,c); } \ No newline at end of file diff --git a/reactos/lib/user32/internal/menu.c b/reactos/lib/user32/internal/menu.c index 8c6c51c87e9..ab0aefd63d0 100644 --- a/reactos/lib/user32/internal/menu.c +++ b/reactos/lib/user32/internal/menu.c @@ -1,15 +1,16 @@ -#undef WIN32_LEAN_AND_MEAN + #include #include -//#include +#include #include #include +#include #include #include -#include +#include #include -#include +//#include typedef struct tagMDINEXTMENU { @@ -48,9 +49,6 @@ UINT uSubPWndLevel = 0; WINBOOL fEndMenu = FALSE; -#include -#define DPRINT printf - /*********************************************************************** * debug_print_menuitem @@ -684,7 +682,7 @@ void MENU_PopupMenuCalcSize( LPPOPUPMENU lppop, HWND hwndOwner ) * * Calculate the size of the menu bar. */ -static void MENU_MenuBarCalcSize( HDC hdc, LPRECT lprect, +void MENU_MenuBarCalcSize( HDC hdc, LPRECT lprect, LPPOPUPMENU lppop, HWND hwndOwner ) { MENUITEM *lpitem; @@ -1451,7 +1449,7 @@ WINBOOL MENU_PatchResidentPopup( HQUEUE checkQueue, WND* checkWnd ) } menu->items = newItems; menu->nItems++; - memset( &newItems[pos], 0, sizeof(*newItems) ); + HEAP_memset( &newItems[pos], 0, sizeof(*newItems) ); return &newItems[pos]; } diff --git a/reactos/lib/user32/internal/msg.c b/reactos/lib/user32/internal/msg.c index bcb977aa81f..31c0b36fd2a 100644 --- a/reactos/lib/user32/internal/msg.c +++ b/reactos/lib/user32/internal/msg.c @@ -4,10 +4,10 @@ * Copyright 1993, 1994 Alexandre Julliard */ -#include + #include #include -#include +//#include #include #include #include @@ -16,6 +16,7 @@ #include #include #include +#include @@ -158,16 +159,16 @@ DWORD MSG_TranslateMouseMsg( HWND hTopWnd, DWORD filter, if (HOOK_IsHooked( WH_MOUSE )) { - MOUSEHOOKSTRUCT *hook = malloc(sizeof(MOUSEHOOKSTRUCT)); + MOUSEHOOKSTRUCT *hook = HeapAlloc(GetProcessHeap(),0,sizeof(MOUSEHOOKSTRUCT)); if( hook ) { hook->pt = screen_pt; hook->hwnd = hWnd; hook->wHitTestCode = hittest; hook->dwExtraInfo = 0; - ret = HOOK_CallHooksA( WH_MOUSE, remove ? HC_ACTION : HC_NOREMOVE, - message, (LPARAM)(hook) ); - free(hook); + ret = HOOK_CallHooks( WH_MOUSE, remove ? HC_ACTION : HC_NOREMOVE, + message, (LPARAM)(hook), pWnd->class->bUnicode ); + HeapFree(GetProcessHeap(),0,hook); } if( ret ) return MAKELONG((INT)SYSQ_MSG_SKIP, hittest); } @@ -523,24 +524,47 @@ WINBOOL MSG_PeekHardwareMsg( MSG *msg, HWND hwnd, DWORD filter, return FALSE; } + /*********************************************************************** * MSG_SendMessage * * Implementation of an inter-task SendMessage. */ -LRESULT MSG_SendMessage( HQUEUE hDestQueue, HWND hwnd, UINT msg, - WPARAM wParam, LPARAM lParam, WORD flags ) +LRESULT MSG_SendMessageInterTask( HWND hwnd, UINT msg, + WPARAM wParam, LPARAM lParam, WINBOOL bUnicode) { + + WND *wndPtr; + WND **list, **ppWnd; INT prevSMRL = debugSMRL; QSMCTRL qCtrl = { 0, 1}; MESSAGEQUEUE *queue, *destQ; - if (!(queue = (MESSAGEQUEUE*)GlobalLock( GetFastQueue() ))) return 0; - if (!(destQ = (MESSAGEQUEUE*)GlobalLock( hDestQueue ))) return 0; + if (hwnd == HWND_BROADCAST || hwnd == HWND_TOPMOST) + { + if (!(list = WIN_BuildWinArray( WIN_GetDesktop(), 0, NULL ))) + return TRUE; + for (ppWnd = list; *ppWnd; ppWnd++) + { + wndPtr = *ppWnd; + //if (!WIN_IsWindow(wndPtr)) + //continue; + if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION) + MSG_SendMessageInterTask( wndPtr->hwndSelf, msg, wParam, lParam, bUnicode ); + } + HeapFree( GetProcessHeap(), 0, list ); + return TRUE; + } - if ( + +// should turn queue and destQ around + + if (!(queue = (MESSAGEQUEUE*)GlobalLock( GetFastQueue() ))) return 0; + if (!(destQ = (MESSAGEQUEUE*)GlobalLock( wndPtr->hmemTaskQ ))) return 0; + + //if ( //IsTaskLocked() || - !IsWindow(hwnd)) return 0; + //!IsWindow(hwnd)) return 0; debugSMRL+=4; DPRINT("%*sSM: %s [%04x] (%04x -> %04x)\n", @@ -552,6 +576,9 @@ LRESULT MSG_SendMessage( HQUEUE hDestQueue, HWND hwnd, UINT msg, QUEUE_WaitBits( QS_SMPARAMSFREE ); } + + + /* resume sending */ queue->hWnd = hwnd; @@ -563,7 +590,7 @@ LRESULT MSG_SendMessage( HQUEUE hDestQueue, HWND hwnd, UINT msg, destQ->hSendingTask = GetFastQueue(); QUEUE_ClearWakeBit( queue, QS_SMPARAMSFREE ); - queue->flags = (queue->flags & ~(QUEUE_SM_ASCII|QUEUE_SM_UNICODE)) | flags; +// queue->flags = (queue->flags & ~(QUEUE_SM_ASCII|QUEUE_SM_UNICODE)) | flags; DPRINT("%*ssm: smResultInit = %08x\n", prevSMRL, "", (unsigned)&qCtrl); @@ -610,6 +637,52 @@ LRESULT MSG_SendMessage( HQUEUE hDestQueue, HWND hwnd, UINT msg, WINBOOL MSG_PeekMessage( LPMSG msg, HWND hwnd, WORD first, WORD last, WORD flags, WINBOOL peek ) { +#if 0 + case MOUSE_EVENT: + MouseEvent = &Buffer.Event; + if ( MouseEvent->dwEventFlags == MOUSE_MOVED ) { + msg->hwnd = hwnd; + msg->message = WM_MOUSEMOVE; + msg->wParam = MouseEvent->dwControlKeyState; + msg->lParam = + MAKELONG(MouseEvent->dwMousePosition.X,MouseEvent->dwMousePosition.Y); + } + else if ( MouseEvent->dwEventFlags == DOUBLE_CLICK ) { + msg->hwnd = hwnd; + msg->message = WM_MBUTTONDBLCLK; + msg->wParam = MouseEvent->dwControlKeyState; + msg->lParam = + MAKELONG(MouseEvent->dwMousePosition.X,MouseEvent->dwMousePosition.Y); + + } + else { + if (MouseEvent->dwButtonState == FROM_LEFT_1ST_BUTTON_PRESSED ) { + msg->hwnd = hwnd; + msg->message = WM_MBUTTONDOWN ; + msg->wParam = MouseEvent->dwControlKeyState; + msg->lParam = + MAKELONG(MouseEvent->dwMousePosition.X,MouseEvent->dwMousePosition.Y); + } + else { + msg->hwnd = hwnd; + msg->message = WM_MBUTTONUP ; + msg->wParam = MouseEvent->dwControlKeyState; + msg->lParam = + MAKELONG(MouseEvent->dwMousePosition.X,MouseEvent->dwMousePosition.Y); + } + } + break; + #endif + + +msg->hwnd = hwnd; +msg->message = WM_MBUTTONDBLCLK; +msg->wParam = 0; +msg->lParam = MAKELONG(200,200); + +return TRUE; + +#if 0 int pos, mask; MESSAGEQUEUE *msgQueue; HQUEUE hQueue; @@ -769,6 +842,9 @@ WINBOOL MSG_PeekMessage( LPMSG msg, HWND hwnd, WORD first, WORD last, } if (peek) return TRUE; else return (msg->message != WM_QUIT); + + #endif + } /*********************************************************************** @@ -1040,6 +1116,29 @@ WINBOOL MSG_DoTranslateMessage( UINT message, HWND hwnd, } +LRESULT MSG_SendMessage( WND *wndPtr, UINT msg, WPARAM wParam, LPARAM lParam ) +{ + + LRESULT ret; + + if ( wndPtr == NULL ) + return 0; + + // if (QUEUE_IsExitingQueue(wndPtr->hmemTaskQ)) + // return 0; /* Don't send anything if the task is dying */ + + + + if ( wndPtr->class->bUnicode ) + ret = CallWindowProcW( (WNDPROC)wndPtr->winproc, + wndPtr->hwndSelf, msg, wParam, lParam ); + else + ret = CallWindowProcA( (WNDPROC)wndPtr->winproc, + wndPtr->hwndSelf, msg, wParam, lParam ); + + return ret; +} + HTASK GetCurrentTask(void) { return (HTASK)-2; @@ -1054,7 +1153,7 @@ HQUEUE GetThreadQueue( DWORD thread ) { if ( init == 0 ) { init = 1; - memset(&Queue,0,sizeof(MESSAGEQUEUE)); + HEAP_memset(&Queue,0,sizeof(MESSAGEQUEUE)); } return hThreadQ; } diff --git a/reactos/lib/user32/internal/nc.c b/reactos/lib/user32/internal/nc.c index 25bda936cd6..d63c977ba2f 100644 --- a/reactos/lib/user32/internal/nc.c +++ b/reactos/lib/user32/internal/nc.c @@ -1,8 +1,11 @@ #include #include #include +#include #include +// GetBitmapDimensionEx in NC_DrawMaxButton95 returns TRUE on invalid bitmap + static HBITMAP hbitmapClose = 0; static HBITMAP hbitmapCloseD = 0; static HBITMAP hbitmapMinimize = 0; @@ -126,6 +129,7 @@ NC_AdjustRectOuter95 (LPRECT rect, DWORD style, WINBOOL menu, DWORD exStyle) /* Decide if the window will be managed (see CreateWindowEx) */ // Options.managed && + if (!( !(style & WS_CHILD) && ((style & (WS_DLGFRAME | WS_THICKFRAME)) || (exStyle & WS_EX_DLGMODALFRAME)))) @@ -136,10 +140,10 @@ NC_AdjustRectOuter95 (LPRECT rect, DWORD style, WINBOOL menu, DWORD exStyle) { if (HAS_SIZEFRAME(style)) InflateRect( rect, SYSMETRICS_CXFRAME, SYSMETRICS_CYFRAME ); -#if 0 + if (style & WS_BORDER) InflateRect( rect, SYSMETRICS_CXBORDER, SYSMETRICS_CYBORDER); -#endif + } if ((style & WS_CAPTION) == WS_CAPTION) @@ -151,10 +155,12 @@ NC_AdjustRectOuter95 (LPRECT rect, DWORD style, WINBOOL menu, DWORD exStyle) } } else { - + if (HAS_SIZEFRAME(style)) + InflateRect( rect, SYSMETRICS_CXFRAME, SYSMETRICS_CYFRAME ); +#if 0 if (style & WS_BORDER) InflateRect( rect, SYSMETRICS_CXBORDER, SYSMETRICS_CYBORDER); - +#endif if ((style & WS_CAPTION) == WS_CAPTION) { @@ -326,13 +332,13 @@ NC_GetInsideRect95 (HWND hwnd, RECT *rect) InflateRect( rect, -SYSMETRICS_CXBORDER, -SYSMETRICS_CYBORDER );*/ } - if (wndPtr->dwStyle & WS_CHILD) { +// if (wndPtr->dwStyle & WS_CHILD) { if (wndPtr->dwExStyle & WS_EX_CLIENTEDGE) InflateRect(rect, -SYSMETRICS_CXEDGE, -SYSMETRICS_CYEDGE); if (wndPtr->dwExStyle & WS_EX_STATICEDGE) InflateRect(rect, -SYSMETRICS_CXBORDER, -SYSMETRICS_CYBORDER); - } + // } return; } @@ -827,13 +833,22 @@ static void NC_DrawMaxButton95( WND *wndPtr = WIN_FindWndPtr( hwnd ); SIZE bmsz; HBITMAP bm; + BITMAP bmp; HDC hdcMem; - if( !(wndPtr->flags & WIN_MANAGED) && + + if( !(wndPtr->flags & WIN_MANAGED) ) { GetBitmapDimensionEx((bm = IsZoomed(hwnd) ? - (down ? hbitmapRestoreD : hbitmapRestore ) : - (down ? hbitmapMaximizeD : hbitmapMaximize)), - &bmsz)) { + (down ? hbitmapRestoreD : hbitmapRestore ) : + (down ? hbitmapMaximizeD : hbitmapMaximize)), + &bmsz); + + if ( bmsz.cx == 0 || bmsz.cy == 0 ) { + GetObject(bm, sizeof(BITMAP), &bmp); + bmsz.cx = bmp.bmWidth; + bmsz.cy = bmp.bmHeight; + DPRINT("WARN GetBitmapDimensionEx returned 0 size "); + } NC_GetInsideRect95( hwnd, &rect ); @@ -1169,7 +1184,7 @@ static void NC_DrawCaption( HDC hdc, RECT *rect, HWND hwnd, * *****************************************************************************/ -static void NC_DrawCaption95( +void NC_DrawCaption95( HDC hdc, RECT *rect, HWND hwnd, @@ -1181,6 +1196,7 @@ static void NC_DrawCaption95( WND *wndPtr = WIN_FindWndPtr( hwnd ); char buffer[256]; HPEN hPrevPen; + int txt; if (wndPtr->flags & WIN_MANAGED) return; @@ -1188,7 +1204,7 @@ static void NC_DrawCaption95( MoveToEx( hdc, r.left, r.bottom - 1, NULL ); LineTo( hdc, r.right, r.bottom - 1 ); SelectObject( hdc, hPrevPen ); - r.bottom-2; + // r.bottom - 2; FillRect( hdc, &r, GetSysColorBrush(active ? COLOR_ACTIVECAPTION : @@ -1221,8 +1237,14 @@ static void NC_DrawCaption95( NC_DrawMinButton95( hwnd, hdc, FALSE ); r.right -= SYSMETRICS_CXSIZE + 1; } + + if ( wndPtr->class->bUnicode ) + txt = GetWindowTextW( hwnd, buffer, sizeof(buffer) ); + else + txt = GetWindowTextA( hwnd, buffer, sizeof(buffer) ); - if (GetWindowTextA( hwnd, buffer, sizeof(buffer) )) { + + if (txt) { NONCLIENTMETRICS nclm; HFONT hFont, hOldFont; nclm.cbSize = sizeof(NONCLIENTMETRICS); @@ -1236,7 +1258,11 @@ static void NC_DrawCaption95( else SetTextColor( hdc, GetSysColor( COLOR_INACTIVECAPTIONTEXT ) ); SetBkMode( hdc, TRANSPARENT ); r.left += 2; - DrawTextA( hdc, buffer, -1, &r, + if ( wndPtr->class->bUnicode ) + DrawTextW( hdc, buffer, -1, &r, + DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT ); + else + DrawTextA( hdc, buffer, -1, &r, DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT ); DeleteObject(SelectObject (hdc, hOldFont)); } @@ -1378,10 +1404,10 @@ void NC_DoNCPaint95( if (!(hdc = GetDCEx( hwnd, 0, DCX_USESTYLE | DCX_WINDOW ))) return; - if (ExcludeVisRect( hdc, wndPtr->rectClient.left-wndPtr->rectWindow.left, - wndPtr->rectClient.top-wndPtr->rectWindow.top, - wndPtr->rectClient.right-wndPtr->rectWindow.left, - wndPtr->rectClient.bottom-wndPtr->rectWindow.top ) + if (ExcludeVisRect( hdc, wndPtr->rectClient.left -wndPtr->rectWindow.left, + wndPtr->rectClient.top -wndPtr->rectWindow.top, + wndPtr->rectClient.right -wndPtr->rectWindow.left, + wndPtr->rectClient.bottom -wndPtr->rectWindow.top ) == NULLREGION) { ReleaseDC( hwnd, hdc ); @@ -1495,10 +1521,10 @@ LONG NC_HandleNCActivate( WND *wndPtr, WPARAM wParam ) { WORD wStateChange; - if( wParam ) wStateChange = !(wndPtr->flags & WIN_NCACTIVATED); - else wStateChange = wndPtr->flags & WIN_NCACTIVATED; +// if( wParam ) wStateChange = !(wndPtr->flags & WIN_NCACTIVATED); +// else wStateChange = wndPtr->flags & WIN_NCACTIVATED; - if( wStateChange ) +// if( wStateChange ) { if (wParam) wndPtr->flags |= WIN_NCACTIVATED; else wndPtr->flags &= ~WIN_NCACTIVATED; diff --git a/reactos/lib/user32/internal/paint.c b/reactos/lib/user32/internal/paint.c index ac3a7d01046..2cb97fbdb68 100644 --- a/reactos/lib/user32/internal/paint.c +++ b/reactos/lib/user32/internal/paint.c @@ -15,6 +15,7 @@ /* Last CTLCOLOR id */ //#define CTLCOLOR_MAX CTLCOLOR_STATIC +HBRUSH DEFWND_ControlColor( HDC hDC, UINT ctlType ); /*********************************************************************** @@ -45,28 +46,21 @@ WINBOOL PAINT_RedrawWindow( HWND hwnd, const RECT *rectUpdate, if (!hwnd) hwnd = GetDesktopWindow(); if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE; + +#ifdef OPTIMIZE if (!WIN_IsWindowDrawable( wndPtr, !(flags & RDW_FRAME) ) ) return TRUE; /* No redraw needed */ +#endif bIcon = (wndPtr->dwStyle & WS_MINIMIZE && wndPtr->class->hIcon); - if (rectUpdate) - { - DPRINT( "%04x %d,%d-%d,%d %04x flags=%04x\n", - hwnd, rectUpdate->left, rectUpdate->top, - rectUpdate->right, rectUpdate->bottom, hrgnUpdate, flags ); - } - else - { - DPRINT( "%04x NULL %04x flags=%04x\n", hwnd, hrgnUpdate, flags); - } - + GetClientRect( hwnd, &rectClient ); if (flags & RDW_INVALIDATE) /* Invalidate */ { int rgnNotEmpty = COMPLEXREGION; - if (wndPtr->hrgnUpdate > 1) /* Is there already an update region? */ + if (wndPtr->hrgnUpdate > (HRGN)1) /* Is there already an update region? */ { if ((hrgn = hrgnUpdate) == 0) hrgn = CreateRectRgnIndirect( rectUpdate ? rectUpdate : @@ -116,7 +110,7 @@ WINBOOL PAINT_RedrawWindow( HWND hwnd, const RECT *rectUpdate, else if (flags & RDW_VALIDATE) /* Validate */ { /* We need an update region in order to validate anything */ - if (wndPtr->hrgnUpdate > 1) + if (wndPtr->hrgnUpdate > (HRGN)1) { if (!hrgnUpdate && !rectUpdate) { @@ -148,13 +142,13 @@ WINBOOL PAINT_RedrawWindow( HWND hwnd, const RECT *rectUpdate, if (flags & RDW_INTERNALPAINT) { - if ( wndPtr->hrgnUpdate <= 1 && !(wndPtr->flags & WIN_INTERNAL_PAINT)) + if ( wndPtr->hrgnUpdate <= (HRGN)1 && !(wndPtr->flags & WIN_INTERNAL_PAINT)) QUEUE_IncPaintCount( wndPtr->hmemTaskQ ); wndPtr->flags |= WIN_INTERNAL_PAINT; } else if (flags & RDW_NOINTERNALPAINT) { - if ( wndPtr->hrgnUpdate <= 1 && (wndPtr->flags & WIN_INTERNAL_PAINT)) + if ( wndPtr->hrgnUpdate <= (HRGN)1 && (wndPtr->flags & WIN_INTERNAL_PAINT)) QUEUE_DecPaintCount( wndPtr->hmemTaskQ ); wndPtr->flags &= ~WIN_INTERNAL_PAINT; } @@ -168,10 +162,10 @@ WINBOOL PAINT_RedrawWindow( HWND hwnd, const RECT *rectUpdate, } else if (flags & RDW_ERASENOW) { - if (wndPtr->flags & WIN_NEEDS_NCPAINT) + //if (wndPtr->flags & WIN_NEEDS_NCPAINT) WIN_UpdateNCArea( wndPtr, FALSE); - if (wndPtr->flags & WIN_NEEDS_ERASEBKGND) + //if (wndPtr->flags & WIN_NEEDS_ERASEBKGND) { HDC hdc = GetDCEx( hwnd, wndPtr->hrgnUpdate, DCX_INTERSECTRGN | DCX_USESTYLE | @@ -249,3 +243,36 @@ WINBOOL PAINT_RedrawWindow( HWND hwnd, const RECT *rectUpdate, return TRUE; } +/*********************************************************************** + * GetControlBrush Not A Win32 API + */ +HBRUSH GetControlBrush( HWND hwnd, HDC hdc, UINT ctlType ) +{ + WND* wndPtr = WIN_FindWndPtr( hwnd ); + + if((ctlType <= CTLCOLOR_MAX) && wndPtr ) + { + WND* parent; + if( wndPtr->dwStyle & WS_POPUP ) parent = wndPtr->owner; + else parent = wndPtr->parent; + if( !parent ) parent = wndPtr; + return (HBRUSH)PAINT_GetControlBrush( parent->hwndSelf, hwnd, hdc, ctlType ); + } + return (HBRUSH)0; +} + +/*********************************************************************** + * PAINT_GetControlBrush + */ +HBRUSH PAINT_GetControlBrush( HWND hParent, HWND hWnd, HDC hDC, UINT ctlType ) +{ + LOGBRUSH LogBrush; + HBRUSH bkgBrush = (HBRUSH)SendMessageA( hParent, WM_CTLCOLORMSGBOX + ctlType, + (WPARAM)hDC, (LPARAM)hWnd ); + if( !GetObject(bkgBrush,sizeof(LOGBRUSH),&LogBrush) ) + bkgBrush = DEFWND_ControlColor( hDC, ctlType ); + return bkgBrush; +} + + + diff --git a/reactos/lib/user32/internal/scroll.c b/reactos/lib/user32/internal/scroll.c index 15354332450..a4e660a0a26 100644 --- a/reactos/lib/user32/internal/scroll.c +++ b/reactos/lib/user32/internal/scroll.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #define MAKEINTRESOURCEA(x) "x" @@ -1065,4 +1066,33 @@ done: /* Return current position */ return infoPtr->CurVal; +} + +/************************************************************************* + * SCROLL_FixCaret + */ +WINBOOL SCROLL_FixCaret(HWND hWnd, LPRECT lprc, UINT flags) +{ + HWND hCaret = CARET_GetHwnd(); + + if( hCaret ) + { + RECT rc; + CARET_GetRect( &rc ); + if( hCaret == hWnd || + (flags & SW_SCROLLCHILDREN && IsChild(hWnd, hCaret)) ) + { + POINT pt; + + pt.x = rc.left; pt.y = rc.top; + MapWindowPoints( hCaret, hWnd, (LPPOINT)&rc, 2 ); + if( IntersectRect(lprc, lprc, &rc) ) + { + HideCaret(0); + lprc->left = pt.x; lprc->top = pt.y; + return TRUE; + } + } + } + return FALSE; } \ No newline at end of file diff --git a/reactos/lib/user32/internal/uitools.c b/reactos/lib/user32/internal/uitools.c index ef53f5eed2d..427de6f01b6 100644 --- a/reactos/lib/user32/internal/uitools.c +++ b/reactos/lib/user32/internal/uitools.c @@ -6,9 +6,9 @@ */ #include +#include #include -HPEN STDCALL GetSysColorPen( INT index ); static const WORD wPattern_AA55[8] = { 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555 }; @@ -18,11 +18,7 @@ static const WORD wPattern_AA55[8] = { 0xaaaa, 0x5555, 0xaaaa, 0x5555, * UITOOLS_DrawRectEdge() */ -/* DrawEdge() flags */ -#define BDR_RAISEDOUTER 0x0001 -#define BDR_SUNKENOUTER 0x0002 -#define BDR_RAISEDINNER 0x0004 -#define BDR_SUNKENINNER 0x0008 + #define BDR_OUTER 0x0003 #define BDR_INNER 0x000c diff --git a/reactos/lib/user32/internal/win.c b/reactos/lib/user32/internal/win.c index 904debabf1a..191ef9d079e 100644 --- a/reactos/lib/user32/internal/win.c +++ b/reactos/lib/user32/internal/win.c @@ -9,6 +9,8 @@ #include #include #include +#include +#include WND *rootWnd; ////////////////////////////////////////////////////////////////////////////////// @@ -93,7 +95,7 @@ HANDLE WIN_CreateWindowEx( CREATESTRUCTW *cs, ATOM classAtom) ? MENU_GetSysMenu( hWnd, 0 ) : 0; if (classPtr->cbWndExtra) - memset( wndPtr->wExtra, 0, classPtr->cbWndExtra); + HEAP_memset( wndPtr->wExtra, 0, classPtr->cbWndExtra); /* Call the WH_CBT hook */ @@ -107,7 +109,7 @@ HANDLE WIN_CreateWindowEx( CREATESTRUCTW *cs, ATOM classAtom) cbtc.lpcs = cs; cbtc.hwndInsertAfter = hWndLinkAfter; - ret = HOOK_CallHooksW(WH_CBT, HCBT_CREATEWND, hWnd, (LPARAM)&cbtc); + ret = HOOK_CallHooks(WH_CBT, HCBT_CREATEWND, (INT)hWnd, (LPARAM)&cbtc, classPtr->bUnicode); if (ret) { @@ -232,21 +234,14 @@ HANDLE WIN_CreateWindowEx( CREATESTRUCTW *cs, ATOM classAtom) maxPos.x = wndPtr->rectWindow.left; maxPos.y = wndPtr->rectWindow.top; - if ( classPtr->bUnicode == TRUE ) { - if( SendMessageW( hWnd, WM_NCCREATE, 0, (LPARAM)cs) == 0) - { + + if( MSG_SendMessage( wndPtr, WM_NCCREATE, 0, (LPARAM)cs) == 0) + { /* Abort window creation */ - WIN_DestroyWindow( wndPtr ); - return NULL; - } - } else { - if( SendMessageA( hWnd, WM_NCCREATE, 0, (LPARAM)cs) == 0) - { - /* Abort window creation */ - WIN_DestroyWindow( wndPtr ); - return NULL; - } + WIN_DestroyWindow( wndPtr ); + return NULL; } + /* Insert the window in the linked list */ @@ -258,7 +253,7 @@ HANDLE WIN_CreateWindowEx( CREATESTRUCTW *cs, ATOM classAtom) maxPos.y - wndPtr->rectWindow.top); - if( (SendMessageA( hWnd, WM_CREATE, 0, (LPARAM)cs )) == -1 ) + if( (MSG_SendMessage( wndPtr, WM_CREATE, 0, (LPARAM)cs)) == -1 ) { WIN_UnlinkWindow( hWnd ); WIN_DestroyWindow( wndPtr ); @@ -272,12 +267,12 @@ HANDLE WIN_CreateWindowEx( CREATESTRUCTW *cs, ATOM classAtom) if (((wndPtr->rectClient.right-wndPtr->rectClient.left) <0) ||((wndPtr->rectClient.bottom-wndPtr->rectClient.top)<0)) - SendMessageA( hWnd, WM_SIZE, SIZE_RESTORED, + MSG_SendMessage( wndPtr, WM_SIZE, SIZE_RESTORED, MAKELONG(wndPtr->rectClient.right-wndPtr->rectClient.left, wndPtr->rectClient.bottom-wndPtr->rectClient.top)); - SendMessageA( hWnd, WM_MOVE, 0, + MSG_SendMessage( wndPtr, WM_MOVE, 0, MAKELONG( wndPtr->rectClient.left, - wndPtr->rectClient.top ) ); + wndPtr->rectClient.top) ); } /* Show the window, maximizing or minimizing if needed */ @@ -299,7 +294,7 @@ HANDLE WIN_CreateWindowEx( CREATESTRUCTW *cs, ATOM classAtom) { /* Notify the parent window only */ - SendMessageA( wndPtr->parent->hwndSelf, WM_PARENTNOTIFY, + MSG_SendMessage( wndPtr->parent, WM_PARENTNOTIFY, MAKEWPARAM(WM_CREATE, wndPtr->wIDmenu), (LPARAM)hWnd ); if( !IsWindow(hWnd) ) return 0; } @@ -310,7 +305,7 @@ HANDLE WIN_CreateWindowEx( CREATESTRUCTW *cs, ATOM classAtom) /* Call WH_SHELL hook */ if (!(wndPtr->dwStyle & WS_CHILD) && !wndPtr->owner) - HOOK_CallHooksW( WH_SHELL, HSHELL_WINDOWCREATED, hWnd, 0L ); + HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWCREATED, (INT)hWnd, 0L, classPtr->bUnicode); return hWnd; @@ -318,6 +313,12 @@ HANDLE WIN_CreateWindowEx( CREATESTRUCTW *cs, ATOM classAtom) } +WINBOOL WIN_IsWindow(HANDLE hWnd) +{ + if (WIN_FindWndPtr( hWnd ) == NULL) return FALSE; + return TRUE; +} + /*********************************************************************** * WIN_FindWinToRepaint * @@ -446,7 +447,7 @@ LONG WIN_SetWindowLong( HWND hwnd, INT offset, LONG newval ) /* Special case for dialog window procedure */ if ((offset == DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG)) { - retval = ptr; + retval = (LONG)ptr; *ptr = newval; return (LONG)retval; } @@ -454,12 +455,12 @@ LONG WIN_SetWindowLong( HWND hwnd, INT offset, LONG newval ) else switch(offset) { case GWL_ID: - ptr = (DWORD*)&wndPtr->wIDmenu; + ptr = (LONG*)&wndPtr->wIDmenu; break; case GWL_HINSTANCE: - return SetWindowWord( hwnd, offset, newval ); + return (LONG)SetWindowWord( hwnd, offset, newval ); case GWL_WNDPROC: - retval = wndPtr->winproc; + retval = (LONG)wndPtr->winproc; wndPtr->winproc = (WNDPROC)newval; return retval; case GWL_STYLE: @@ -467,24 +468,22 @@ LONG WIN_SetWindowLong( HWND hwnd, INT offset, LONG newval ) newval &= ~(WS_VISIBLE | WS_CHILD); /* Some bits can't be changed this way */ style.styleNew = newval | (style.styleOld & (WS_VISIBLE | WS_CHILD)); - //if (wndPtr->flags & WIN_ISWIN32) - SendMessageA(hwnd,WM_STYLECHANGING,GWL_STYLE,(LPARAM)&style); + + MSG_SendMessage(wndPtr,WM_STYLECHANGING,GWL_STYLE,(LPARAM)&style); wndPtr->dwStyle = style.styleNew; - //if (wndPtr->flags & WIN_ISWIN32) - SendMessageA(hwnd,WM_STYLECHANGED,GWL_STYLE,(LPARAM)&style); + + MSG_SendMessage(wndPtr,WM_STYLECHANGED,GWL_STYLE,(LPARAM)&style); return style.styleOld; case GWL_USERDATA: - ptr = &wndPtr->userdata; + ptr = (LONG *)&wndPtr->userdata; break; case GWL_EXSTYLE: style.styleOld = wndPtr->dwExStyle; style.styleNew = newval; - //if (wndPtr->flags & WIN_ISWIN32) - SendMessageA(hwnd,WM_STYLECHANGING,GWL_EXSTYLE,(LPARAM)&style); - wndPtr->dwExStyle = newval; - //if (wndPtr->flags & WIN_ISWIN32) - SendMessageA(hwnd,WM_STYLECHANGED,GWL_EXSTYLE,(LPARAM)&style); + MSG_SendMessage(wndPtr,WM_STYLECHANGING,GWL_EXSTYLE,(LPARAM)&style); + wndPtr->dwExStyle = newval; + MSG_SendMessage(wndPtr,WM_STYLECHANGED,GWL_EXSTYLE,(LPARAM)&style); return style.styleOld; default: @@ -511,19 +510,20 @@ WINBOOL WIN_DestroyWindow( WND* wndPtr ) HWND hWnd; WND *pWnd; + if ( wndPtr == NULL ) + return FALSE; + hWnd = wndPtr->hwndSelf; -#ifdef CONFIG_IPC - if (main_block) - DDE_DestroyWindow(wndPtr->hwndSelf); -#endif /* CONFIG_IPC */ + /* free child windows */ while ((pWnd = wndPtr->child)) - wndPtr->child = WIN_DestroyWindow( pWnd ); + if ( !WIN_DestroyWindow( pWnd ) ) + break; - SendMessageA( wndPtr->hwndSelf, WM_NCDESTROY, 0, 0); + MSG_SendMessage( wndPtr, WM_NCDESTROY, 0, 0); /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */ @@ -570,9 +570,9 @@ WINBOOL WIN_DestroyWindow( WND* wndPtr ) if (!(wndPtr->dwStyle & WS_CHILD)) if (wndPtr->wIDmenu) DestroyMenu( (HMENU)wndPtr->wIDmenu ); if (wndPtr->hSysMenu) DestroyMenu( wndPtr->hSysMenu ); - //wndPtr->pDriver->pDestroyWindow( wndPtr ); + - //DeleteDC(wndPtr->dc) /* Always do this to catch orphaned DCs */ + // DeleteDC(wndPtr->dc) /* Always do this to catch orphaned DCs */ wndPtr->winproc = NULL; wndPtr->hwndSelf = NULL; @@ -779,10 +779,7 @@ WINBOOL WIN_LinkWindow( HWND hWnd, HWND hWndInsertAfter ) void WIN_UpdateNCArea(WND* wnd, BOOL bUpdate) { POINT pt = {0, 0}; - HRGN hClip = 1; - - DPRINT("hwnd %04x, hrgnUpdate %04x\n", - wnd->hwndSelf, wnd->hrgnUpdate ); + HRGN hClip = (HRGN)1; /* desktop window doesn't have nonclient area */ if(wnd == WIN_GetDesktop()) @@ -791,7 +788,7 @@ void WIN_UpdateNCArea(WND* wnd, BOOL bUpdate) return; } - if( wnd->hrgnUpdate > 1 ) + if( wnd->hrgnUpdate > (HRGN)1 ) { ClientToScreen(wnd->hwndSelf, &pt); @@ -799,7 +796,7 @@ void WIN_UpdateNCArea(WND* wnd, BOOL bUpdate) if (!CombineRgn( hClip, wnd->hrgnUpdate, 0, RGN_COPY )) { DeleteObject(hClip); - hClip = 1; + hClip = (HRGN)1; } else OffsetRgn( hClip, pt.x, pt.y ); @@ -815,7 +812,7 @@ void WIN_UpdateNCArea(WND* wnd, BOOL bUpdate) hrgn, RGN_AND) == NULLREGION)) { DeleteObject( wnd->hrgnUpdate ); - wnd->hrgnUpdate = 1; + wnd->hrgnUpdate = (HRGN)1; } DeleteObject( hrgn ); @@ -824,17 +821,19 @@ void WIN_UpdateNCArea(WND* wnd, BOOL bUpdate) wnd->flags &= ~WIN_NEEDS_NCPAINT; +#ifdef OPTIMIZE if ((wnd->hwndSelf == GetActiveWindow()) && !(wnd->flags & WIN_NCACTIVATED)) { wnd->flags |= WIN_NCACTIVATED; - if( hClip > 1) DeleteObject( hClip ); - hClip = 1; + if( hClip > (HRGN)1) DeleteObject( hClip ); + hClip = (HRGN)1; } +#endif - if (hClip) SendMessage( wnd->hwndSelf, WM_NCPAINT, hClip, 0L ); + if (hClip) MSG_SendMessage( wnd, WM_NCPAINT, (WPARAM)hClip, 0L ); - if (hClip > 1) DeleteObject( hClip ); + if (hClip > (HRGN)1) DeleteObject( hClip ); } /*********************************************************************** @@ -888,9 +887,9 @@ void WIN_SendDestroyMsg( WND* pWnd ) WIN_CheckFocus(pWnd); if( CARET_GetHwnd() == pWnd->hwndSelf ) DestroyCaret(); -// CLIPBOARD_GetDriver()->pResetOwner( pWnd, TRUE ); + - SendMessageA( pWnd->hwndSelf, WM_DESTROY, 0, 0); + MSG_SendMessage( pWnd, WM_DESTROY, 0, 0); if( IsWindow(pWnd->hwndSelf) ) { @@ -907,6 +906,26 @@ void WIN_SendDestroyMsg( WND* pWnd ) } +/*********************************************************************** + * IsDialogMessage (USER32.90) + */ +WINBOOL STDCALL WIN_IsDialogMessage( HWND hwndDlg, LPMSG msg ) +{ + + WINBOOL ret, translate, dispatch; + INT dlgCode; + + if ((hwndDlg != msg->hwnd) && !IsChild( hwndDlg, msg->hwnd )) + return FALSE; + + dlgCode = SendMessage( msg->hwnd, WM_GETDLGCODE, 0, (LPARAM)msg); + ret = DIALOG_IsDialogMessage( msg->hwnd, hwndDlg, msg->message, + msg->wParam, msg->lParam, + &translate, &dispatch, dlgCode ); + if (translate) TranslateMessage( msg ); + if (dispatch) DispatchMessage( msg ); + return ret; +} diff --git a/reactos/lib/user32/makefile.main b/reactos/lib/user32/makefile.main index 1bfeeb50191..3f0c10f2467 100644 --- a/reactos/lib/user32/makefile.main +++ b/reactos/lib/user32/makefile.main @@ -1,25 +1,36 @@ all: user32.exe INTERNAL_OBJECTS = internal/property.o internal/menu.o internal/heapdup.o internal/nc.o\ - internal/scroll.o internal/win.o internal/dce.o internal/msg.o internal/queue.o\ + internal/win.o internal/dce.o internal/msg.o internal/queue.o\ internal/signal.o internal/event.o internal/timer.o internal/region.o\ - internal/text.o internal/defwnd.o internal/paint.o internal/uitools.o + internal/text.o internal/defwnd.o internal/paint.o internal/uitools.o\ + internal/dialog.o MISC_OBJECTS = misc/sprintf.o misc/dllmain.o misc/string.o misc/sysmetr.o\ misc/main.o misc/bitmap.o misc/cursor.o misc/vk.o WINDOWS_OBJECTS = windows/wndproc.o windows/win.o windows/hook.o windows/spy.o\ - windows/queue.o windows/winpos.o windows/class.o windows/menu.o windows/dc.o\ + windows/queue.o windows/winpos.o windows/class.o windows/dc.o\ windows/timer.o windows/rect.o windows/msg.o windows/input.o windows/property.o\ - windows/focus.o windows/paint.o + windows/focus.o windows/paint.o windows/msgbox.o windows/dialog.o\ + windows/scroll.o windows/defdlg.o GRAPHICS_OBJECTS = graphics/rect.o graphics/caret.o graphics/text.o graphics/syscol.o graphics/fill.o\ graphics/draw.o graphics/icon.o -RESOURCE_OBJECTS = resources/sysres.o +CONTROLS_OBJECTS = controls/button.o controls/combo.o controls/edit.o controls/icontitle.o controls/listbox.o\ + controls/widgets.o controls/menu.o controls/scroll.o controls/static.o -OBJECTS = $(MISC_OBJECTS) $(INTERNAL_OBJECTS) $(GRAPHICS_OBJECTS) $(RESOURCE_OBJECTS) $(WINDOWS_OBJECTS) +RESOURCE_OBJECTS = resources/sysres.o + +RESOURCE_OBJECT = user32.coff + +OBJECTS = $(MISC_OBJECTS) $(INTERNAL_OBJECTS) $(GRAPHICS_OBJECTS) $(RESOURCE_OBJECTS) $(RESOURCE_OBJECT)\ + $(CONTROLS_OBJECTS) $(WINDOWS_OBJECTS) + +user32.coff: user32.rc ../../include/reactos/resource.h + windres user32.rc user32.coff user32.exe: $(OBJECTS) $(LD) $(OBJECTS) F:/gnu/cygnus/cygwin-b20/H-i586-cygwin32/i586-cygwin32/lib/crt1.o ./libgdi32.a ./libkernel32.a ./libcrtdll.a -o user32.exe diff --git a/reactos/lib/user32/misc/bitmap.c b/reactos/lib/user32/misc/bitmap.c index 99fbed8ec63..1473443334d 100644 --- a/reactos/lib/user32/misc/bitmap.c +++ b/reactos/lib/user32/misc/bitmap.c @@ -84,3 +84,6 @@ HBITMAP BITMAP_LoadBitmapW(HINSTANCE instance,LPCWSTR name, return hbitmap; #endif } + + + diff --git a/reactos/lib/user32/misc/main.c b/reactos/lib/user32/misc/main.c index 33452c2c47e..50b6bc00bc3 100644 --- a/reactos/lib/user32/misc/main.c +++ b/reactos/lib/user32/misc/main.c @@ -1,9 +1,12 @@ #include +#include + LRESULT CALLBACK WindowFunc(HWND,UINT,WPARAM, LPARAM); char szName[] = "Hallo"; + int _CRT_fmode = 0; int _CRT_glob = 0; @@ -13,24 +16,34 @@ int __main(int argc, char **argv) } +int i; + + + int main(int argc, char **argv) { + WIDGETS_Init(); +#if 0 HWND hwnd; + HWND User32hWnd; HMENU hmenu; MSG msg; WNDCLASSEX wc1; HINSTANCE hInst = 0; int nWinMode = SW_SHOW; + unsigned short *test; - RECT rect; + + HANDLE hMod, hrsrc; + RECT rect, cl; wc1.hInstance = hInst; wc1.lpszClassName = szName; wc1.lpfnWndProc = WindowFunc; wc1.style = 0; wc1.cbSize = sizeof(WNDCLASSEX); - wc1.hIcon = NULL; - wc1.hIconSm = NULL; + wc1.hIcon = LoadIcon(NULL,IDI_APPLICATION); + wc1.hIconSm = LoadIcon(NULL,IDI_WINLOGO);; wc1.hCursor = NULL; wc1.lpszMenuName = NULL; @@ -38,21 +51,30 @@ int main(int argc, char **argv) wc1.cbClsExtra = 0; wc1.cbWndExtra = 0; - wc1.hbrBackground = NULL; + wc1.hbrBackground = GetStockObject(WHITE_BRUSH); + if ( !RegisterClassEx(&wc1)) return 0; - hmenu = CreateMenu(); - hwnd = CreateWindowEx(0, szName, "test", WS_OVERLAPPEDWINDOW, + hwnd = CreateWindowEx + (0, szName, "test2", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT, - NULL,hmenu,hInst, NULL); + NULL,NULL,hInst, NULL); + + + MessageBox(NULL,"Hallo","Hallo",MB_OK); - ShowWindow(hwnd,nWinMode); UpdateWindow(hwnd); +#endif + MessageBox(NULL,"xxx","yyyy",MB_OK); +#if 0 + GetWindowRect(hwnd,&rect); + GetClientRect(hwnd,&cl); - SetWindowText(hwnd,"Hallo"); + printf("%d\n",(rect.left - rect.right) - (cl.left - cl.right)); + SetWindowText(hwnd,"Hallo3"); DrawMenuBar(hwnd); // SendMessage( hwnd, WM_MOVE, 0,MAKELONG(0,0)); @@ -64,10 +86,11 @@ int main(int argc, char **argv) } Sleep(10000); return msg.wParam; +#endif } - //printf("hallo\n"); + diff --git a/reactos/lib/user32/resources/sysres.c b/reactos/lib/user32/resources/sysres.c index de94d6046d8..61db5f30be1 100644 --- a/reactos/lib/user32/resources/sysres.c +++ b/reactos/lib/user32/resources/sysres.c @@ -9,5 +9,7 @@ LPCVOID SYSRES_GetResPtr( int id ) { // return SYSRES_Resources[Options.language][id]->data; + + return NULL; } \ No newline at end of file diff --git a/reactos/lib/user32/user32.rc b/reactos/lib/user32/user32.rc index 35761f3deb5..d31d64f0faf 100644 --- a/reactos/lib/user32/user32.rc +++ b/reactos/lib/user32/user32.rc @@ -4,8 +4,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US VS_VERSION_INFO VERSIONINFO - FILEVERSION RES_UINT_FV_MAJOR,RES_UINT_FV_MINOR,RES_UINT_FV_REVISION,RES_UINT_FV_BUILD - PRODUCTVERSION RES_UINT_PV_MAJOR,RES_UINT_PV_MINOR,RES_UINT_PV_REVISION,RES_UINT_PV_BUILD + FILEVERSION 0,0,13,RES_UINT_FILE_VERSION + PRODUCTVERSION 0,0,13,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -22,7 +22,7 @@ BEGIN BEGIN VALUE "CompanyName", RES_STR_COMPANY_NAME VALUE "FileDescription", "ReactOS User API Client Dll\0" - VALUE "FileVersion", RES_STR_FILE_VERSION + VALUE "FileVersion", "post 0.0.13\0" VALUE "InternalName", "user32\0" VALUE "LegalCopyright", RES_STR_LEGAL_COPYRIGHT VALUE "OriginalFilename", "user32.dll\0" @@ -36,3 +36,23 @@ BEGIN END END +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +MSGBOX DIALOG DISCARDABLE 100, 80, 216, 168 +STYLE DS_SYSMODAL | DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | + WS_SYSMENU +FONT 8, "MS Sans Serif" +BEGIN + ICON "", 1088, 9, 20, 16, 16, WS_CHILD | WS_VISIBLE + LTEXT "", 100, 32, 4, 176, 48, WS_CHILD | WS_VISIBLE | WS_GROUP + PUSHBUTTON "&OK", 1, 16, 56, 40, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP + PUSHBUTTON "&Cancel", 2, 64, 56, 40, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP + PUSHBUTTON "&Abort", 3, 112, 56, 40, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP + PUSHBUTTON "&Retry", 4, 160, 56, 40, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP + PUSHBUTTON "&Ignore", 5, 208, 56, 40, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP + PUSHBUTTON "&Yes", 6, 256, 56, 40, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP + PUSHBUTTON "&No", 7, 304, 56, 40, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP +END \ No newline at end of file diff --git a/reactos/lib/user32/windows/class.c b/reactos/lib/user32/windows/class.c index d3ceefd90c1..c0fc57990fc 100644 --- a/reactos/lib/user32/windows/class.c +++ b/reactos/lib/user32/windows/class.c @@ -1,10 +1,19 @@ - +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS system libraries + * FILE: lib/user32/windows/class.c + * PURPOSE: Registers a window class + * PROGRAMER: Boudewijn Dekker + * UPDATE HISTORY: + * 28/05/99: Created + */ #include #include #include #include #include + CLASS *rootClass; ATOM STDCALL RegisterClassA(const WNDCLASS* wc) @@ -80,7 +89,7 @@ ATOM STDCALL RegisterClassExA(const WNDCLASSEX* wc) if (classExtra) - memset( classPtr->wExtra, 0, classExtra ); + HEAP_memset( classPtr->wExtra, 0, classExtra ); if (!classPtr) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); @@ -136,7 +145,7 @@ ATOM STDCALL RegisterClassExW( const WNDCLASSEX* wc ) CLASS *classPtr; INT classExtra, winExtra; - int i, len; + int len; if ( wc == NULL || wc->cbSize != sizeof(WNDCLASSEX)) { SetLastError(ERROR_INVALID_DATA); return FALSE; @@ -165,7 +174,7 @@ ATOM STDCALL RegisterClassExW( const WNDCLASSEX* wc ) if (classExtra) - memset( classPtr->wExtra, 0, classExtra ); + HEAP_memset( classPtr->wExtra, 0, classExtra ); if (!classPtr) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); @@ -189,13 +198,17 @@ ATOM STDCALL RegisterClassExW( const WNDCLASSEX* wc ) classPtr->dce = (wc->style & CS_CLASSDC) ? CreateDC( "DISPLAY", NULL,NULL,NULL ) : NULL; - len = lstrlenW((LPWSTR)wc->lpszMenuName); - classPtr->menuName = HeapAlloc(GetProcessHeap(),0,(len+1)*2); - lstrcpyW((LPWSTR)classPtr->menuName, (LPWSTR)wc->lpszMenuName); + if ( wc->lpszMenuName != NULL ) { + len = lstrlenW(wc->lpszMenuName); + classPtr->menuName = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(len+1)); + lstrcpyW(classPtr->menuName,wc->lpszMenuName); + } + else + classPtr->menuName = NULL; len = lstrlenW((LPWSTR)wc->lpszClassName); - classPtr->className = HeapAlloc(GetProcessHeap(),0,(len+1)*2); + classPtr->className = HeapAlloc(GetProcessHeap(),0,(len+1)*sizeof(WCHAR)); lstrcpyW((LPWSTR)classPtr->className,(LPWSTR) wc->lpszClassName ); classPtr->next = rootClass; @@ -283,7 +296,7 @@ WINBOOL GetClassInfoExW( HINSTANCE hInstance, LPCWSTR lpClassName, LPWNDCLASSE if ( HIWORD(lpClassName) != 0 ) a = FindAtomW(lpClassName); else - a = lpClassName; + a = (ATOM)lpClassName; classPtr = CLASS_FindClassByAtom( a, hInstance ); if ( classPtr == NULL ) @@ -408,7 +421,7 @@ WORD STDCALL GetClassWord( HWND hWnd, INT nIndex ) if (nIndex >= 0) { if (nIndex <= wndPtr->class->cbClsExtra - sizeof(WORD)) - return (WORD)((char *)wndPtr->class->wExtra) + nIndex; + return (WORD)(wndPtr->class->wExtra + nIndex); } else switch(nIndex) { diff --git a/reactos/lib/user32/windows/defdlg.c b/reactos/lib/user32/windows/defdlg.c new file mode 100644 index 00000000000..46cbfe896fb --- /dev/null +++ b/reactos/lib/user32/windows/defdlg.c @@ -0,0 +1,374 @@ +/* + * Default dialog procedure + * + * Copyright 1993, 1996 Alexandre Julliard + * + */ + +#include +#include +#include +#include + + + +/*********************************************************************** + * DEFDLG_SetFocus + * + * Set the focus to a control of the dialog, selecting the text if + * the control is an edit dialog. + */ +static void DEFDLG_SetFocus( HWND hwndDlg, HWND hwndCtrl ) +{ + HWND hwndPrev = GetFocus(); + + if (IsChild( hwndDlg, hwndPrev )) + { + if (SendMessage( hwndPrev, WM_GETDLGCODE, 0, 0 ) & DLGC_HASSETSEL) + SendMessage( hwndPrev, EM_SETSEL, TRUE, MAKELONG( -1, 0 ) ); + } + if (SendMessage( hwndCtrl, WM_GETDLGCODE, 0, 0 ) & DLGC_HASSETSEL) + SendMessage( hwndCtrl, EM_SETSEL, FALSE, MAKELONG( 0, -1 ) ); + SetFocus( hwndCtrl ); +} + + +/*********************************************************************** + * DEFDLG_SaveFocus + */ +static BOOL DEFDLG_SaveFocus( HWND hwnd, DIALOGINFO *infoPtr ) +{ + HWND hwndFocus = GetFocus(); + + if (!hwndFocus || !IsChild( hwnd, hwndFocus )) return FALSE; + infoPtr->hwndFocus = hwndFocus; + /* Remove default button */ + return TRUE; +} + + +/*********************************************************************** + * DEFDLG_RestoreFocus + */ +static BOOL DEFDLG_RestoreFocus( HWND hwnd, DIALOGINFO *infoPtr ) +{ + if (!infoPtr->hwndFocus || IsIconic(hwnd)) return FALSE; + if (!IsWindow( infoPtr->hwndFocus )) return FALSE; + DEFDLG_SetFocus( hwnd, infoPtr->hwndFocus ); + /* This used to set infoPtr->hwndFocus to NULL for no apparent reason, + sometimes losing focus when receiving WM_SETFOCUS messages. */ + return TRUE; +} + + +/*********************************************************************** + * DEFDLG_FindDefButton + * + * Find the current default push-button. + */ +static HWND DEFDLG_FindDefButton( HWND hwndDlg ) +{ + HWND hwndChild = GetWindow( hwndDlg, GW_CHILD ); + while (hwndChild) + { + if (SendMessage( hwndChild, WM_GETDLGCODE, 0, 0 ) & DLGC_DEFPUSHBUTTON) + break; + hwndChild = GetWindow( hwndChild, GW_HWNDNEXT ); + } + return hwndChild; +} + + +/*********************************************************************** + * DEFDLG_SetDefButton + * + * Set the new default button to be hwndNew. + */ +static BOOL DEFDLG_SetDefButton( HWND hwndDlg, DIALOGINFO *dlgInfo, + HWND hwndNew ) +{ + if (hwndNew && + !(SendMessage(hwndNew, WM_GETDLGCODE, 0, 0 ) & DLGC_UNDEFPUSHBUTTON)) + return FALSE; /* Destination is not a push button */ + + if (dlgInfo->idResult) /* There's already a default pushbutton */ + { + HWND hwndOld = GetDlgItem( hwndDlg, dlgInfo->idResult ); + if (SendMessageA( hwndOld, WM_GETDLGCODE, 0, 0) & DLGC_DEFPUSHBUTTON) + SendMessageA( hwndOld, BM_SETSTYLE, BS_PUSHBUTTON, TRUE ); + } + if (hwndNew) + { + SendMessageA( hwndNew, BM_SETSTYLE, BS_DEFPUSHBUTTON, TRUE ); + dlgInfo->idResult = GetDlgCtrlID( hwndNew ); + } + else dlgInfo->idResult = 0; + return TRUE; +} + + +/*********************************************************************** + * DEFDLG_Proc + * + * Implementation of DefDlgProc(). Only handle messages that need special + * handling for dialogs. + */ +LRESULT DEFDLG_Proc( HWND hwnd, UINT msg, WPARAM wParam, + LPARAM lParam, DIALOGINFO *dlgInfo ) +{ + switch(msg) + { + case WM_ERASEBKGND: + FillWindow( hwnd, hwnd, (HDC)wParam, (HBRUSH)CTLCOLOR_DLG ); + return 1; + + case WM_NCDESTROY: + + /* Free dialog heap (if created) */ + if (dlgInfo->hDialogHeap) + { + GlobalUnlock(dlgInfo->hDialogHeap); + GlobalFree(dlgInfo->hDialogHeap); + dlgInfo->hDialogHeap = 0; + } + + /* Delete font */ + if (dlgInfo->hUserFont) + { + DeleteObject( dlgInfo->hUserFont ); + dlgInfo->hUserFont = 0; + } + + /* Delete menu */ + if (dlgInfo->hMenu) + { + DestroyMenu( dlgInfo->hMenu ); + dlgInfo->hMenu = 0; + } + + /* Delete window procedure */ + //WINPROC_FreeProc( dlgInfo->dlgProc, WIN_PROC_WINDOW ); + dlgInfo->dlgProc = NULL; + dlgInfo->flags |= DF_END; /* just in case */ + + /* Window clean-up */ + return DefWindowProcA( hwnd, msg, wParam, lParam ); + + case WM_SHOWWINDOW: + if (!wParam) DEFDLG_SaveFocus( hwnd, dlgInfo ); + return DefWindowProcA( hwnd, msg, wParam, lParam ); + + case WM_ACTIVATE: + if (wParam) DEFDLG_RestoreFocus( hwnd, dlgInfo ); + else DEFDLG_SaveFocus( hwnd, dlgInfo ); + return 0; + + case WM_SETFOCUS: + DEFDLG_RestoreFocus( hwnd, dlgInfo ); + return 0; + + case DM_SETDEFID: + if (dlgInfo->flags & DF_END) return 1; + DEFDLG_SetDefButton( hwnd, dlgInfo, + wParam ? GetDlgItem( hwnd, wParam ) : 0 ); + return 1; + + case DM_GETDEFID: + { + HWND hwndDefId; + if (dlgInfo->flags & DF_END) return 0; + if (dlgInfo->idResult) + return MAKELONG( dlgInfo->idResult, DC_HASDEFID ); + if ((hwndDefId = DEFDLG_FindDefButton( hwnd ))) + return MAKELONG( GetDlgCtrlID( hwndDefId ), DC_HASDEFID); + } + return 0; + + case WM_NEXTDLGCTL: + { + HWND hwndDest = (HWND)wParam; + if (!lParam) + hwndDest = GetNextDlgTabItem(hwnd, GetFocus(), wParam); + if (hwndDest) DEFDLG_SetFocus( hwnd, hwndDest ); + DEFDLG_SetDefButton( hwnd, dlgInfo, hwndDest ); + } + return 0; + + case WM_ENTERMENULOOP: + case WM_LBUTTONDOWN: + case WM_NCLBUTTONDOWN: + { + HWND hwndFocus = GetFocus(); + if (hwndFocus) + { + WND *wnd = WIN_FindWndPtr( hwndFocus ); + + if( wnd ) + { + /* always make combo box hide its listbox control */ + + if( WIDGETS_IsControl( wnd, BIC_COMBO ) ) + SendMessageA( hwndFocus, CB_SHOWDROPDOWN, + FALSE, 0 ); + else if( WIDGETS_IsControl( wnd, BIC_EDIT ) && + WIDGETS_IsControl( wnd->parent, + BIC_COMBO )) + SendMessageA( wnd->parent->hwndSelf, + CB_SHOWDROPDOWN, FALSE, 0 ); + } + } + } + return DefWindowProcA( hwnd, msg, wParam, lParam ); + + case WM_GETFONT: + return dlgInfo->hUserFont; + + case WM_CLOSE: + PostMessageA( hwnd, WM_COMMAND, IDCANCEL, + (LPARAM)GetDlgItem( hwnd, IDCANCEL ) ); + return 0; + } + return 0; +} + +/*********************************************************************** + * DEFDLG_Epilog + */ +LRESULT DEFDLG_Epilog(DIALOGINFO* dlgInfo, UINT msg, BOOL fResult) +{ + /* see SDK 3.1 */ + + if ((msg >= WM_CTLCOLORMSGBOX && msg <= WM_CTLCOLORSTATIC) || + msg == WM_CTLCOLOR || msg == WM_COMPAREITEM || + msg == WM_VKEYTOITEM || msg == WM_CHARTOITEM || + msg == WM_QUERYDRAGICON || msg == WM_INITDIALOG) + return fResult; + + return dlgInfo->msgResult; +} + + + + +/*********************************************************************** + * DefDlgProcA (USER.120) + */ +LRESULT WINAPI DefDlgProcA( HWND hwnd, UINT msg, + WPARAM wParam, LPARAM lParam ) +{ + + DIALOGINFO * dlgInfo; + BOOL result = FALSE; + WND * wndPtr = WIN_FindWndPtr( hwnd ); + + if (!wndPtr) return 0; + dlgInfo = (DIALOGINFO *)wndPtr->wExtra; + dlgInfo->msgResult = 0; + + if (dlgInfo->dlgProc) { /* Call dialog procedure */ + result = CallWindowProcA( (WNDPROC)dlgInfo->dlgProc, + hwnd, msg, wParam, lParam ); + + /* Check if window was destroyed by dialog procedure */ + if (dlgInfo->flags & DF_END && !(dlgInfo->flags & DF_ENDING)) { + dlgInfo->flags |= DF_ENDING; + DestroyWindow( hwnd ); + } + } + + if (!result && IsWindow(hwnd)) + { + /* callback didn't process this message */ + + switch(msg) + { + case WM_ERASEBKGND: + case WM_SHOWWINDOW: + case WM_ACTIVATE: + case WM_SETFOCUS: + case DM_SETDEFID: + case DM_GETDEFID: + case WM_NEXTDLGCTL: + case WM_GETFONT: + case WM_CLOSE: + case WM_NCDESTROY: + case WM_ENTERMENULOOP: + case WM_LBUTTONDOWN: + case WM_NCLBUTTONDOWN: + return DEFDLG_Proc( (HWND)hwnd, msg, + (WPARAM)wParam, lParam, dlgInfo ); + case WM_INITDIALOG: + case WM_VKEYTOITEM: + case WM_COMPAREITEM: + case WM_CHARTOITEM: + break; + + default: + return DefWindowProcA( hwnd, msg, wParam, lParam ); + } + } + + return DEFDLG_Epilog(dlgInfo, msg, result); + + +} + + +/*********************************************************************** + * DefDlgProcW (USER.121) + */ +LRESULT WINAPI DefDlgProcW( HWND hwnd, UINT msg, WPARAM wParam, + LPARAM lParam ) +{ + DIALOGINFO * dlgInfo; + BOOL result = FALSE; + WND * wndPtr = WIN_FindWndPtr( hwnd ); + + if (!wndPtr) return 0; + dlgInfo = (DIALOGINFO *)wndPtr->wExtra; + dlgInfo->msgResult = 0; + + if (dlgInfo->dlgProc) { /* Call dialog procedure */ + result = CallWindowProcW( (WNDPROC)dlgInfo->dlgProc, + hwnd, msg, wParam, lParam ); + + /* Check if window was destroyed by dialog procedure */ + if (dlgInfo->flags & DF_END && !(dlgInfo->flags & DF_ENDING)) { + dlgInfo->flags |= DF_ENDING; + DestroyWindow( hwnd ); + } + } + + if (!result && IsWindow(hwnd)) + { + /* callback didn't process this message */ + + switch(msg) + { + case WM_ERASEBKGND: + case WM_SHOWWINDOW: + case WM_ACTIVATE: + case WM_SETFOCUS: + case DM_SETDEFID: + case DM_GETDEFID: + case WM_NEXTDLGCTL: + case WM_GETFONT: + case WM_CLOSE: + case WM_NCDESTROY: + case WM_ENTERMENULOOP: + case WM_LBUTTONDOWN: + case WM_NCLBUTTONDOWN: + return DEFDLG_Proc( (HWND)hwnd, msg, + (WPARAM)wParam, lParam, dlgInfo ); + case WM_INITDIALOG: + case WM_VKEYTOITEM: + case WM_COMPAREITEM: + case WM_CHARTOITEM: + break; + + default: + return DefWindowProcW( hwnd, msg, wParam, lParam ); + } + } + return DEFDLG_Epilog(dlgInfo, msg, result); +} diff --git a/reactos/lib/user32/windows/dialog.c b/reactos/lib/user32/windows/dialog.c index 1cd4513cbaf..956deb0f6dc 100644 --- a/reactos/lib/user32/windows/dialog.c +++ b/reactos/lib/user32/windows/dialog.c @@ -1,247 +1,184 @@ +#include +#include +#include +#include /*********************************************************************** - * CreateDialog16 (USER.89) + * CreateDialog (USER32.89) */ -HWND16 WINAPI CreateDialog16( HINSTANCE16 hInst, SEGPTR dlgTemplate, - HWND16 owner, DLGPROC16 dlgProc ) +#undef CreateDialogA +HWND STDCALL CreateDialogA( HINSTANCE hInst, LPCSTR dlgTemplate, + HWND owner, DLGPROC dlgProc ) { - return CreateDialogParam16( hInst, dlgTemplate, owner, dlgProc, 0 ); -} - - -/*********************************************************************** - * CreateDialogParam16 (USER.241) - */ -HWND16 WINAPI CreateDialogParam16( HINSTANCE16 hInst, SEGPTR dlgTemplate, - HWND16 owner, DLGPROC16 dlgProc, - LPARAM param ) -{ - HWND16 hwnd = 0; - HRSRC16 hRsrc; - HGLOBAL16 hmem; - LPCVOID data; - - TRACE(dialog, "%04x,%08lx,%04x,%08lx,%ld\n", - hInst, (DWORD)dlgTemplate, owner, (DWORD)dlgProc, param ); - - if (!(hRsrc = FindResource16( hInst, dlgTemplate, RT_DIALOG16 ))) return 0; - if (!(hmem = LoadResource16( hInst, hRsrc ))) return 0; - if (!(data = LockResource16( hmem ))) hwnd = 0; - else hwnd = CreateDialogIndirectParam16( hInst, data, owner, - dlgProc, param ); - FreeResource16( hmem ); - return hwnd; + return CreateDialogParamA( hInst, dlgTemplate, owner, dlgProc, 0 ); } /*********************************************************************** - * CreateDialogParam32A (USER32.73) + * CreateDialog (USER32.89) */ -HWND32 WINAPI CreateDialogParam32A( HINSTANCE32 hInst, LPCSTR name, - HWND32 owner, DLGPROC32 dlgProc, + +#undef CreateDialogW +HWND STDCALL CreateDialogW( HINSTANCE hInst, LPCWSTR dlgTemplate, + HWND owner, DLGPROC dlgProc ) +{ + return CreateDialogParamW( hInst, dlgTemplate, owner, dlgProc, 0 ); +} + + + +/*********************************************************************** + * CreateDialogParamA (USER32.73) + */ +HWND STDCALL CreateDialogParamA( HINSTANCE hInst, LPCSTR name, + HWND owner, DLGPROC dlgProc, LPARAM param ) { - if (HIWORD(name)) - { - LPWSTR str = HEAP_strdupAtoW( GetProcessHeap(), 0, name ); - HWND32 hwnd = CreateDialogParam32W( hInst, str, owner, dlgProc, param); - HeapFree( GetProcessHeap(), 0, str ); - return hwnd; - } - return CreateDialogParam32W( hInst, (LPCWSTR)name, owner, dlgProc, param ); -} - - -/*********************************************************************** - * CreateDialogParam32W (USER32.74) - */ -HWND32 WINAPI CreateDialogParam32W( HINSTANCE32 hInst, LPCWSTR name, - HWND32 owner, DLGPROC32 dlgProc, - LPARAM param ) -{ - HANDLE32 hrsrc = FindResource32W( hInst, name, RT_DIALOG32W ); + HANDLE hrsrc = FindResourceA( hInst, name, RT_DIALOG ); if (!hrsrc) return 0; - return CreateDialogIndirectParam32W( hInst, - (LPVOID)LoadResource32(hInst, hrsrc), + return CreateDialogIndirectParamA( hInst, + (LPVOID)LoadResource(hInst, hrsrc), owner, dlgProc, param ); } /*********************************************************************** - * CreateDialogIndirect16 (USER.219) + * CreateDialogParamW (USER32.74) */ -HWND16 WINAPI CreateDialogIndirect16( HINSTANCE16 hInst, LPCVOID dlgTemplate, - HWND16 owner, DLGPROC16 dlgProc ) +HWND STDCALL CreateDialogParamW( HINSTANCE hInst, LPCWSTR name, + HWND owner, DLGPROC dlgProc, + LPARAM param ) { - return CreateDialogIndirectParam16( hInst, dlgTemplate, owner, dlgProc, 0); + HANDLE hrsrc = FindResourceW( hInst, name, (LPCWSTR)RT_DIALOG ); + if (!hrsrc) return 0; + return CreateDialogIndirectParamW( hInst, + (LPVOID)LoadResource(hInst, hrsrc), + owner, dlgProc, param ); } /*********************************************************************** - * CreateDialogIndirectParam16 (USER.242) + * CreateDialogIndirect (USER32.219) */ -HWND16 WINAPI CreateDialogIndirectParam16( HINSTANCE16 hInst, - LPCVOID dlgTemplate, - HWND16 owner, DLGPROC16 dlgProc, - LPARAM param ) +#undef CreateDialogIndirectA +HWND STDCALL CreateDialogIndirectA( HINSTANCE hInst, LPCDLGTEMPLATE dlgTemplate, + HWND owner, DLGPROC dlgProc ) { - return DIALOG_CreateIndirect( hInst, dlgTemplate, FALSE, owner, - dlgProc, param, WIN_PROC_16 ); + return CreateDialogIndirectParamA( hInst, dlgTemplate, owner, dlgProc, 0); +} + +/*********************************************************************** + * CreateDialogIndirect (USER32.219) + */ +#undef CreateDialogIndirectW +HWND STDCALL CreateDialogIndirectW( HINSTANCE hInst, LPCDLGTEMPLATE dlgTemplate, + HWND owner, DLGPROC dlgProc ) +{ + return CreateDialogIndirectParamW( hInst, dlgTemplate, owner, dlgProc, 0); } /*********************************************************************** - * CreateDialogIndirectParam32A (USER32.69) + * CreateDialogIndirectParamA (USER32.69) */ -HWND32 WINAPI CreateDialogIndirectParam32A( HINSTANCE32 hInst, - LPCVOID dlgTemplate, - HWND32 owner, DLGPROC32 dlgProc, +HWND STDCALL CreateDialogIndirectParamA( HINSTANCE hInst, + LPCDLGTEMPLATE dlgTemplate, + HWND owner, DLGPROC dlgProc, LPARAM param ) { - return DIALOG_CreateIndirect( hInst, dlgTemplate, TRUE, owner, - (DLGPROC16)dlgProc, param, WIN_PROC_32A ); + return DIALOG_CreateIndirect( hInst, dlgTemplate, owner, + (DLGPROC)dlgProc, param, FALSE ); } -/*********************************************************************** - * CreateDialogIndirectParam32AorW (USER32.71) - */ -HWND32 WINAPI CreateDialogIndirectParam32AorW( HINSTANCE32 hInst, - LPCVOID dlgTemplate, - HWND32 owner, DLGPROC32 dlgProc, - LPARAM param ) -{ FIXME(dialog,"assume WIN_PROC_32W\n"); - return DIALOG_CreateIndirect( hInst, dlgTemplate, TRUE, owner, - (DLGPROC16)dlgProc, param, WIN_PROC_32W ); -} /*********************************************************************** - * CreateDialogIndirectParam32W (USER32.72) + * CreateDialogIndirectParamW (USER32.72) */ -HWND32 WINAPI CreateDialogIndirectParam32W( HINSTANCE32 hInst, - LPCVOID dlgTemplate, - HWND32 owner, DLGPROC32 dlgProc, +HWND STDCALL CreateDialogIndirectParamW( HINSTANCE hInst, + LPCDLGTEMPLATE dlgTemplate, + HWND owner, DLGPROC dlgProc, LPARAM param ) { - return DIALOG_CreateIndirect( hInst, dlgTemplate, TRUE, owner, - (DLGPROC16)dlgProc, param, WIN_PROC_32W ); + return DIALOG_CreateIndirect( hInst, dlgTemplate, owner, + (DLGPROC)dlgProc, param, TRUE ); } /*********************************************************************** - * DIALOG_DoDialogBox + * DialogBox (USER32.87) */ -INT32 DIALOG_DoDialogBox( HWND32 hwnd, HWND32 owner ) + +#undef DialogBoxA +INT STDCALL DialogBoxA( HINSTANCE hInst, LPCSTR dlgTemplate, + HWND owner, DLGPROC dlgProc ) { - WND * wndPtr; - DIALOGINFO * dlgInfo; - MSG16 msg; - INT32 retval; + return DialogBoxParamA( hInst, dlgTemplate, owner, dlgProc, 0 ); +} - /* Owner must be a top-level window */ - owner = WIN_GetTopParent( owner ); - if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return -1; - dlgInfo = (DIALOGINFO *)wndPtr->wExtra; - EnableWindow32( owner, FALSE ); - ShowWindow32( hwnd, SW_SHOW ); - - while (MSG_InternalGetMessage(&msg, hwnd, owner, MSGF_DIALOGBOX, PM_REMOVE, - !(wndPtr->dwStyle & DS_NOIDLEMSG) )) - { - if (!IsDialogMessage16( hwnd, &msg)) - { - TranslateMessage16( &msg ); - DispatchMessage16( &msg ); - } - if (dlgInfo->flags & DF_END) break; - } - retval = dlgInfo->idResult; - EnableWindow32( owner, TRUE ); - dlgInfo->flags |= DF_ENDING; /* try to stop it being destroyed twice */ - DestroyWindow32( hwnd ); - return retval; +/*********************************************************************** + * DialogBox (USER32.87) + */ +#undef DialogBoxW +INT STDCALL DialogBoxW( HINSTANCE hInst, LPCWSTR dlgTemplate, + HWND owner, DLGPROC dlgProc ) +{ + return DialogBoxParamW( hInst, dlgTemplate, owner, dlgProc, 0 ); } -/*********************************************************************** - * DialogBox16 (USER.87) - */ -INT16 WINAPI DialogBox16( HINSTANCE16 hInst, SEGPTR dlgTemplate, - HWND16 owner, DLGPROC16 dlgProc ) -{ - return DialogBoxParam16( hInst, dlgTemplate, owner, dlgProc, 0 ); -} /*********************************************************************** - * DialogBoxParam16 (USER.239) + * DialogBoxParamA (USER32.139) */ -INT16 WINAPI DialogBoxParam16( HINSTANCE16 hInst, SEGPTR template, - HWND16 owner, DLGPROC16 dlgProc, LPARAM param ) +INT STDCALL DialogBoxParamA( HINSTANCE hInst, LPCSTR name, + HWND owner, DLGPROC dlgProc, LPARAM param ) { - HWND16 hwnd = CreateDialogParam16( hInst, template, owner, dlgProc, param); - if (hwnd) return (INT16)DIALOG_DoDialogBox( hwnd, owner ); - return -1; -} - - -/*********************************************************************** - * DialogBoxParam32A (USER32.139) - */ -INT32 WINAPI DialogBoxParam32A( HINSTANCE32 hInst, LPCSTR name, - HWND32 owner, DLGPROC32 dlgProc, LPARAM param ) -{ - HWND32 hwnd = CreateDialogParam32A( hInst, name, owner, dlgProc, param ); + HWND hwnd = CreateDialogParamA( hInst, name, owner, dlgProc, param ); if (hwnd) return DIALOG_DoDialogBox( hwnd, owner ); return -1; } /*********************************************************************** - * DialogBoxParam32W (USER32.140) + * DialogBoxParamW (USER32.140) */ -INT32 WINAPI DialogBoxParam32W( HINSTANCE32 hInst, LPCWSTR name, - HWND32 owner, DLGPROC32 dlgProc, LPARAM param ) +INT STDCALL DialogBoxParamW( HINSTANCE hInst, LPCWSTR name, + HWND owner, DLGPROC dlgProc, LPARAM param ) { - HWND32 hwnd = CreateDialogParam32W( hInst, name, owner, dlgProc, param ); + HWND hwnd = CreateDialogParamW( hInst, name, owner, dlgProc, param ); if (hwnd) return DIALOG_DoDialogBox( hwnd, owner ); return -1; } /*********************************************************************** - * DialogBoxIndirect16 (USER.218) + * DialogBoxIndirect (USER32.218) */ -INT16 WINAPI DialogBoxIndirect16( HINSTANCE16 hInst, HANDLE16 dlgTemplate, - HWND16 owner, DLGPROC16 dlgProc ) +#undef DialogBoxIndirectA +INT STDCALL DialogBoxIndirectA( HINSTANCE hInst, LPCDLGTEMPLATE dlgTemplate, + HWND owner, DLGPROC dlgProc ) { - return DialogBoxIndirectParam16( hInst, dlgTemplate, owner, dlgProc, 0 ); + return DialogBoxIndirectParamA( hInst, dlgTemplate, owner, dlgProc, 0 ); +} + +/*********************************************************************** + * DialogBoxIndirect (USER32.218) + */ +#undef DialogBoxIndirectW +INT STDCALL DialogBoxIndirectW( HINSTANCE hInst, LPCDLGTEMPLATE dlgTemplate, + HWND owner, DLGPROC dlgProc ) +{ + return DialogBoxIndirectParam( hInst, dlgTemplate, owner, dlgProc, 0 ); } /*********************************************************************** - * DialogBoxIndirectParam16 (USER.240) + * DialogBoxIndirectParamA (USER32.136) */ -INT16 WINAPI DialogBoxIndirectParam16( HINSTANCE16 hInst, HANDLE16 dlgTemplate, - HWND16 owner, DLGPROC16 dlgProc, +INT STDCALL DialogBoxIndirectParamA(HINSTANCE hInstance, LPCDLGTEMPLATE template, + HWND owner, DLGPROC dlgProc, LPARAM param ) { - HWND16 hwnd; - LPCVOID ptr; - - if (!(ptr = GlobalLock16( dlgTemplate ))) return -1; - hwnd = CreateDialogIndirectParam16( hInst, ptr, owner, dlgProc, param ); - GlobalUnlock16( dlgTemplate ); - if (hwnd) return (INT16)DIALOG_DoDialogBox( hwnd, owner ); - return -1; -} - - -/*********************************************************************** - * DialogBoxIndirectParam32A (USER32.136) - */ -INT32 WINAPI DialogBoxIndirectParam32A(HINSTANCE32 hInstance, LPCVOID template, - HWND32 owner, DLGPROC32 dlgProc, - LPARAM param ) -{ - HWND32 hwnd = CreateDialogIndirectParam32A( hInstance, template, + HWND hwnd = CreateDialogIndirectParamA( hInstance, template, owner, dlgProc, param ); if (hwnd) return DIALOG_DoDialogBox( hwnd, owner ); return -1; @@ -249,13 +186,13 @@ INT32 WINAPI DialogBoxIndirectParam32A(HINSTANCE32 hInstance, LPCVOID template, /*********************************************************************** - * DialogBoxIndirectParam32W (USER32.138) + * DialogBoxIndirectParamW (USER32.138) */ -INT32 WINAPI DialogBoxIndirectParam32W(HINSTANCE32 hInstance, LPCVOID template, - HWND32 owner, DLGPROC32 dlgProc, +INT STDCALL DialogBoxIndirectParamW(HINSTANCE hInstance, LPCDLGTEMPLATE template, + HWND owner, DLGPROC dlgProc, LPARAM param ) { - HWND32 hwnd = CreateDialogIndirectParam32W( hInstance, template, + HWND hwnd = CreateDialogIndirectParamW( hInstance, template, owner, dlgProc, param ); if (hwnd) return DIALOG_DoDialogBox( hwnd, owner ); return -1; @@ -263,23 +200,14 @@ INT32 WINAPI DialogBoxIndirectParam32W(HINSTANCE32 hInstance, LPCVOID template, /*********************************************************************** - * EndDialog16 (USER32.173) + * EndDialog (USER32.88) */ -BOOL16 WINAPI EndDialog16( HWND16 hwnd, INT16 retval ) -{ - return EndDialog32( hwnd, retval ); -} - - -/*********************************************************************** - * EndDialog32 (USER.88) - */ -WINBOOL WINAPI EndDialog32( HWND32 hwnd, INT32 retval ) +WINBOOL STDCALL EndDialog( HWND hwnd, INT retval ) { WND * wndPtr = WIN_FindWndPtr( hwnd ); DIALOGINFO * dlgInfo = (DIALOGINFO *)wndPtr->wExtra; - TRACE(dialog, "%04x %d\n", hwnd, retval ); + DPRINT( "%04x %d\n", hwnd, retval ); if( dlgInfo ) { @@ -291,475 +219,153 @@ WINBOOL WINAPI EndDialog32( HWND32 hwnd, INT32 retval ) /*********************************************************************** - * DIALOG_IsAccelerator + * IsDialogMessageA (USER32.342) */ -static WINBOOL DIALOG_IsAccelerator( HWND32 hwnd, HWND32 hwndDlg, WPARAM32 vKey ) +WINBOOL STDCALL IsDialogMessageA( HWND hwndDlg, LPMSG msg ) { - HWND32 hwndControl = hwnd; - HWND32 hwndNext; - WND *wndPtr; - WINBOOL RetVal = FALSE; - INT32 dlgCode; + WINBOOL ret, translate, dispatch; + INT dlgCode; - if (vKey == VK_SPACE) - { - dlgCode = SendMessage32A( hwndControl, WM_GETDLGCODE, 0, 0 ); - if (dlgCode & DLGC_BUTTON) - { - SendMessage32A( hwndControl, WM_LBUTTONDOWN, 0, 0); - SendMessage32A( hwndControl, WM_LBUTTONUP, 0, 0); - RetVal = TRUE; - } - } - else - { - do - { - wndPtr = WIN_FindWndPtr( hwndControl ); - if (wndPtr != NULL && wndPtr->text != NULL && - (wndPtr->dwStyle & (WS_VISIBLE | WS_DISABLED)) == WS_VISIBLE) - { - dlgCode = SendMessage32A( hwndControl, WM_GETDLGCODE, 0, 0 ); - if (dlgCode & (DLGC_BUTTON | DLGC_STATIC)) - { - /* find the accelerator key */ - LPSTR p = wndPtr->text - 2; - do - { - p = strchr( p + 2, '&' ); - } - while (p != NULL && p[1] == '&'); + if ((hwndDlg != msg->hwnd) && !IsChild( hwndDlg, msg->hwnd )) + return FALSE; - /* and check if it's the one we're looking for */ - if (p != NULL && toupper( p[1] ) == toupper( vKey ) ) - { - if ((dlgCode & DLGC_STATIC) || - (wndPtr->dwStyle & 0x0f) == BS_GROUPBOX ) - { - /* set focus to the control */ - SendMessage32A( hwndDlg, WM_NEXTDLGCTL, - hwndControl, 1); - /* and bump it on to next */ - SendMessage32A( hwndDlg, WM_NEXTDLGCTL, 0, 0); - } - else if (dlgCode & - (DLGC_DEFPUSHBUTTON | DLGC_UNDEFPUSHBUTTON)) - { - /* send command message as from the control */ - SendMessage32A( hwndDlg, WM_COMMAND, - MAKEWPARAM( LOWORD(wndPtr->wIDmenu), - BN_CLICKED ), - (LPARAM)hwndControl ); - } - else - { - /* click the control */ - SendMessage32A( hwndControl, WM_LBUTTONDOWN, 0, 0); - SendMessage32A( hwndControl, WM_LBUTTONUP, 0, 0); - } - RetVal = TRUE; - break; - } - } - } - hwndNext = GetWindow32( hwndControl, GW_CHILD ); - if (!hwndNext) - { - hwndNext = GetWindow32( hwndControl, GW_HWNDNEXT ); - } - while (!hwndNext) - { - hwndControl = GetParent32( hwndControl ); - if (hwndControl == hwndDlg) - { - hwndNext = GetWindow32( hwndDlg, GW_CHILD ); - } - else - { - hwndNext = GetWindow32( hwndControl, GW_HWNDNEXT ); - } - } - hwndControl = hwndNext; - } - while (hwndControl != hwnd); - } - return RetVal; + dlgCode = SendMessageA( msg->hwnd, WM_GETDLGCODE, 0, (LPARAM)msg); + ret = DIALOG_IsDialogMessage( msg->hwnd, hwndDlg, msg->message, + msg->wParam, msg->lParam, + &translate, &dispatch, dlgCode ); + if (translate) TranslateMessage( msg ); + if (dispatch) DispatchMessageA( msg ); + return ret; } + + +/*********************************************************************** + * IsDialogMessageW (USER32.343) + */ +WINBOOL STDCALL IsDialogMessageW( HWND hwndDlg, LPMSG msg ) +{ + WINBOOL ret, translate, dispatch; + INT dlgCode; + + if ((hwndDlg != msg->hwnd) && !IsChild( hwndDlg, msg->hwnd )) + return FALSE; + + dlgCode = SendMessageW( msg->hwnd, WM_GETDLGCODE, 0, (LPARAM)msg); + ret = DIALOG_IsDialogMessage( msg->hwnd, hwndDlg, msg->message, + msg->wParam, msg->lParam, + &translate, &dispatch, dlgCode ); + if (translate) TranslateMessage( msg ); + if (dispatch) DispatchMessageW( msg ); + return ret; +} + + -/*********************************************************************** - * DIALOG_IsDialogMessage - */ -static WINBOOL DIALOG_IsDialogMessage( HWND32 hwnd, HWND32 hwndDlg, - UINT32 message, WPARAM32 wParam, - LPARAM lParam, WINBOOL *translate, - WINBOOL *dispatch, INT32 dlgCode ) -{ - *translate = *dispatch = FALSE; - - if (message == WM_PAINT) - { - /* Apparently, we have to handle this one as well */ - *dispatch = TRUE; - return TRUE; - } - - /* Only the key messages get special processing */ - if ((message != WM_KEYDOWN) && - (message != WM_SYSCHAR) && - (message != WM_CHAR)) - return FALSE; - - if (dlgCode & DLGC_WANTMESSAGE) - { - *translate = *dispatch = TRUE; - return TRUE; - } - - switch(message) - { - case WM_KEYDOWN: - switch(wParam) - { - case VK_TAB: - if (!(dlgCode & DLGC_WANTTAB)) - { - SendMessage32A( hwndDlg, WM_NEXTDLGCTL, - (GetKeyState32(VK_SHIFT) & 0x8000), 0 ); - return TRUE; - } - break; - - case VK_RIGHT: - case VK_DOWN: - case VK_LEFT: - case VK_UP: - if (!(dlgCode & DLGC_WANTARROWS)) - { - WINBOOL fPrevious = (wParam == VK_LEFT || wParam == VK_UP); - HWND32 hwndNext = - GetNextDlgGroupItem32 (hwndDlg, GetFocus32(), fPrevious ); - SendMessage32A( hwndDlg, WM_NEXTDLGCTL, hwndNext, 1 ); - return TRUE; - } - break; - - case VK_ESCAPE: - SendMessage32A( hwndDlg, WM_COMMAND, IDCANCEL, - (LPARAM)GetDlgItem32( hwndDlg, IDCANCEL ) ); - return TRUE; - - case VK_RETURN: - { - DWORD dw = SendMessage16( hwndDlg, DM_GETDEFID, 0, 0 ); - if (HIWORD(dw) == DC_HASDEFID) - { - SendMessage32A( hwndDlg, WM_COMMAND, - MAKEWPARAM( LOWORD(dw), BN_CLICKED ), - (LPARAM)GetDlgItem32(hwndDlg, LOWORD(dw))); - } - else - { - SendMessage32A( hwndDlg, WM_COMMAND, IDOK, - (LPARAM)GetDlgItem32( hwndDlg, IDOK ) ); - - } - } - return TRUE; - } - *translate = TRUE; - break; /* case WM_KEYDOWN */ - - case WM_CHAR: - if (dlgCode & DLGC_WANTCHARS) break; - /* drop through */ - - case WM_SYSCHAR: - if (DIALOG_IsAccelerator( hwnd, hwndDlg, wParam )) - { - /* don't translate or dispatch */ - return TRUE; - } - break; - } - - /* If we get here, the message has not been treated specially */ - /* and can be sent to its destination window. */ - *dispatch = TRUE; - return TRUE; -} - - -/*********************************************************************** - * IsDialogMessage16 (USER.90) - */ -BOOL16 WINAPI WIN16_IsDialogMessage16( HWND16 hwndDlg, SEGPTR msg16 ) -{ - LPMSG16 msg = PTR_SEG_TO_LIN(msg16); - WINBOOL ret, translate, dispatch; - INT32 dlgCode; - - if ((hwndDlg != msg->hwnd) && !IsChild16( hwndDlg, msg->hwnd )) - return FALSE; - - dlgCode = SendMessage16( msg->hwnd, WM_GETDLGCODE, 0, (LPARAM)msg16); - ret = DIALOG_IsDialogMessage( msg->hwnd, hwndDlg, msg->message, - msg->wParam, msg->lParam, - &translate, &dispatch, dlgCode ); - if (translate) TranslateMessage16( msg ); - if (dispatch) DispatchMessage16( msg ); - return ret; -} - - -BOOL16 WINAPI IsDialogMessage16( HWND16 hwndDlg, LPMSG16 msg ) -{ - LPMSG16 msg16 = SEGPTR_NEW(MSG16); - WINBOOL ret; - - *msg16 = *msg; - ret = WIN16_IsDialogMessage16( hwndDlg, SEGPTR_GET(msg16) ); - SEGPTR_FREE(msg16); - return ret; -} - -/*********************************************************************** - * IsDialogMessage32A (USER32.342) - */ -WINBOOL WINAPI IsDialogMessage32A( HWND32 hwndDlg, LPMSG32 msg ) -{ - WINBOOL ret, translate, dispatch; - INT32 dlgCode; - - if ((hwndDlg != msg->hwnd) && !IsChild32( hwndDlg, msg->hwnd )) - return FALSE; - - dlgCode = SendMessage32A( msg->hwnd, WM_GETDLGCODE, 0, (LPARAM)msg); - ret = DIALOG_IsDialogMessage( msg->hwnd, hwndDlg, msg->message, - msg->wParam, msg->lParam, - &translate, &dispatch, dlgCode ); - if (translate) TranslateMessage32( msg ); - if (dispatch) DispatchMessage32A( msg ); - return ret; -} - - -/*********************************************************************** - * IsDialogMessage32W (USER32.343) - */ -WINBOOL WINAPI IsDialogMessage32W( HWND32 hwndDlg, LPMSG32 msg ) -{ - WINBOOL ret, translate, dispatch; - INT32 dlgCode; - - if ((hwndDlg != msg->hwnd) && !IsChild32( hwndDlg, msg->hwnd )) - return FALSE; - - dlgCode = SendMessage32W( msg->hwnd, WM_GETDLGCODE, 0, (LPARAM)msg); - ret = DIALOG_IsDialogMessage( msg->hwnd, hwndDlg, msg->message, - msg->wParam, msg->lParam, - &translate, &dispatch, dlgCode ); - if (translate) TranslateMessage32( msg ); - if (dispatch) DispatchMessage32W( msg ); - return ret; -} - - /**************************************************************** - * GetDlgCtrlID16 (USER.277) + * GetDlgCtrlID (USER32.234) */ -INT16 WINAPI GetDlgCtrlID16( HWND16 hwnd ) +INT STDCALL GetDlgCtrlID( HWND hwnd ) { WND *wndPtr = WIN_FindWndPtr(hwnd); if (wndPtr) return wndPtr->wIDmenu; else return 0; } - -/**************************************************************** - * GetDlgCtrlID32 (USER32.234) - */ -INT32 WINAPI GetDlgCtrlID32( HWND32 hwnd ) +HWND STDCALL GetDlgItem(HWND hDlg, int nIDDlgItem ) { - WND *wndPtr = WIN_FindWndPtr(hwnd); - if (wndPtr) return wndPtr->wIDmenu; - else return 0; -} - - -/*********************************************************************** - * GetDlgItem16 (USER.91) - */ -HWND16 WINAPI GetDlgItem16( HWND16 hwndDlg, INT16 id ) -{ - WND *pWnd; - - if (!(pWnd = WIN_FindWndPtr( hwndDlg ))) return 0; - for (pWnd = pWnd->child; pWnd; pWnd = pWnd->next) - if (pWnd->wIDmenu == (UINT16)id) return pWnd->hwndSelf; - return 0; } -/*********************************************************************** - * GetDlgItem32 (USER32.235) - */ -HWND32 WINAPI GetDlgItem32( HWND32 hwndDlg, INT32 id ) -{ - WND *pWnd; - - if (!(pWnd = WIN_FindWndPtr( hwndDlg ))) return 0; - for (pWnd = pWnd->child; pWnd; pWnd = pWnd->next) - if (pWnd->wIDmenu == (UINT16)id) return pWnd->hwndSelf; - return 0; -} /******************************************************************* - * SendDlgItemMessage16 (USER.101) + * SendDlgItemMessageA (USER32.452) */ -LRESULT WINAPI SendDlgItemMessage16( HWND16 hwnd, INT16 id, UINT16 msg, - WPARAM16 wParam, LPARAM lParam ) +LRESULT STDCALL SendDlgItemMessageA( HWND hwnd, INT id, UINT msg, + WPARAM wParam, LPARAM lParam ) { - HWND16 hwndCtrl = GetDlgItem16( hwnd, id ); - if (hwndCtrl) return SendMessage16( hwndCtrl, msg, wParam, lParam ); + HWND hwndCtrl = GetDlgItem( hwnd, id ); + if (hwndCtrl) return SendMessageA( hwndCtrl, msg, wParam, lParam ); else return 0; } /******************************************************************* - * SendDlgItemMessage32A (USER32.452) + * SendDlgItemMessageW (USER32.453) */ -LRESULT WINAPI SendDlgItemMessage32A( HWND32 hwnd, INT32 id, UINT32 msg, - WPARAM32 wParam, LPARAM lParam ) +LRESULT STDCALL SendDlgItemMessageW( HWND hwnd, INT id, UINT msg, + WPARAM wParam, LPARAM lParam ) { - HWND32 hwndCtrl = GetDlgItem32( hwnd, id ); - if (hwndCtrl) return SendMessage32A( hwndCtrl, msg, wParam, lParam ); + HWND hwndCtrl = GetDlgItem( hwnd, id ); + if (hwndCtrl) return SendMessageW( hwndCtrl, msg, wParam, lParam ); else return 0; } + /******************************************************************* - * SendDlgItemMessage32W (USER32.453) + * SetDlgItemTextA (USER32.478) */ -LRESULT WINAPI SendDlgItemMessage32W( HWND32 hwnd, INT32 id, UINT32 msg, - WPARAM32 wParam, LPARAM lParam ) +WINBOOL STDCALL SetDlgItemTextA( HWND hwnd, INT id, LPCSTR lpString ) { - HWND32 hwndCtrl = GetDlgItem32( hwnd, id ); - if (hwndCtrl) return SendMessage32W( hwndCtrl, msg, wParam, lParam ); - else return 0; + return SendDlgItemMessageA( hwnd, id, WM_SETTEXT, 0, (LPARAM)lpString ); } /******************************************************************* - * SetDlgItemText16 (USER.92) + * SetDlgItemTextW (USER32.479) */ -void WINAPI SetDlgItemText16( HWND16 hwnd, INT16 id, SEGPTR lpString ) +WINBOOL STDCALL SetDlgItemTextW( HWND hwnd, INT id, LPCWSTR lpString ) { - SendDlgItemMessage16( hwnd, id, WM_SETTEXT, 0, (LPARAM)lpString ); + return SendDlgItemMessageW( hwnd, id, WM_SETTEXT, 0, (LPARAM)lpString ); } -/******************************************************************* - * SetDlgItemText32A (USER32.478) - */ -WINBOOL WINAPI SetDlgItemText32A( HWND32 hwnd, INT32 id, LPCSTR lpString ) -{ - return SendDlgItemMessage32A( hwnd, id, WM_SETTEXT, 0, (LPARAM)lpString ); -} - - -/******************************************************************* - * SetDlgItemText32W (USER32.479) - */ -WINBOOL WINAPI SetDlgItemText32W( HWND32 hwnd, INT32 id, LPCWSTR lpString ) -{ - return SendDlgItemMessage32W( hwnd, id, WM_SETTEXT, 0, (LPARAM)lpString ); -} /*********************************************************************** - * GetDlgItemText16 (USER.93) + * GetDlgItemTextA (USER32.237) */ -INT16 WINAPI GetDlgItemText16( HWND16 hwnd, INT16 id, SEGPTR str, UINT16 len ) +UINT STDCALL GetDlgItemTextA( HWND hwnd, INT id, LPSTR str, INT len ) { - return (INT16)SendDlgItemMessage16( hwnd, id, WM_GETTEXT, - len, (LPARAM)str ); -} - - -/*********************************************************************** - * GetDlgItemText32A (USER32.237) - */ -INT32 WINAPI GetDlgItemText32A( HWND32 hwnd, INT32 id, LPSTR str, UINT32 len ) -{ - return (INT32)SendDlgItemMessage32A( hwnd, id, WM_GETTEXT, + return (UINT)SendDlgItemMessageA( hwnd, id, WM_GETTEXT, len, (LPARAM)str ); } /*********************************************************************** - * GetDlgItemText32W (USER32.238) + * GetDlgItemTextW (USER32.238) */ -INT32 WINAPI GetDlgItemText32W( HWND32 hwnd, INT32 id, LPWSTR str, UINT32 len ) +UINT STDCALL GetDlgItemTextW( HWND hwnd, INT id, LPWSTR str, INT len ) { - return (INT32)SendDlgItemMessage32W( hwnd, id, WM_GETTEXT, + return (UINT)SendDlgItemMessageW( hwnd, id, WM_GETTEXT, len, (LPARAM)str ); } -/******************************************************************* - * SetDlgItemInt16 (USER.94) - */ -void WINAPI SetDlgItemInt16( HWND16 hwnd, INT16 id, UINT16 value, BOOL16 fSigned ) -{ - return SetDlgItemInt32( hwnd, (UINT32)(UINT16)id, value, fSigned ); -} /******************************************************************* - * SetDlgItemInt32 (USER32.477) + * SetDlgItemInt (USER32.477) */ -void WINAPI SetDlgItemInt32( HWND32 hwnd, INT32 id, UINT32 value, +WINBOOL STDCALL SetDlgItemInt( HWND hwnd, INT id, UINT value, WINBOOL fSigned ) { char str[20]; - if (fSigned) sprintf( str, "%d", (INT32)value ); + if (fSigned) sprintf( str, "%d", (INT)value ); else sprintf( str, "%u", value ); - SendDlgItemMessage32A( hwnd, id, WM_SETTEXT, 0, (LPARAM)str ); + SendDlgItemMessageA( hwnd, id, WM_SETTEXT, 0, (LPARAM)str ); } -/*********************************************************************** - * GetDlgItemInt16 (USER.95) - */ -UINT16 WINAPI GetDlgItemInt16( HWND16 hwnd, INT16 id, BOOL16 *translated, - BOOL16 fSigned ) -{ - UINT32 result; - WINBOOL ok; - - if (translated) *translated = FALSE; - result = GetDlgItemInt32( hwnd, (UINT32)(UINT16)id, &ok, fSigned ); - if (!ok) return 0; - if (fSigned) - { - if (((INT32)result < -32767) || ((INT32)result > 32767)) return 0; - } - else - { - if (result > 65535) return 0; - } - if (translated) *translated = TRUE; - return (UINT16)result; -} /*********************************************************************** - * GetDlgItemInt32 (USER32.236) + * GetDlgItemInt (USER32.236) */ -UINT32 WINAPI GetDlgItemInt32( HWND32 hwnd, INT32 id, WINBOOL *translated, +UINT STDCALL GetDlgItemInt( HWND hwnd, INT id, WINBOOL *translated, WINBOOL fSigned ) { char str[30]; @@ -767,81 +373,62 @@ UINT32 WINAPI GetDlgItemInt32( HWND32 hwnd, INT32 id, WINBOOL *translated, long result = 0; if (translated) *translated = FALSE; - if (!SendDlgItemMessage32A(hwnd, id, WM_GETTEXT, sizeof(str), (LPARAM)str)) + if (!SendDlgItemMessageA(hwnd, id, WM_GETTEXT, sizeof(str), (LPARAM)str)) return 0; if (fSigned) { result = strtol( str, &endptr, 10 ); if (!endptr || (endptr == str)) /* Conversion was unsuccessful */ return 0; - if (((result == LONG_MIN) || (result == LONG_MAX)) && (errno==ERANGE)) + if (((result == LONG_MIN) || (result == LONG_MAX)) ) { + // errno == ERANGE return 0; + } } else { result = strtoul( str, &endptr, 10 ); if (!endptr || (endptr == str)) /* Conversion was unsuccessful */ return 0; - if ((result == ULONG_MAX) && (errno == ERANGE)) return 0; + if ((result == ULONG_MAX) ) { + // && (errno == ERANGE) + return 0; + } } if (translated) *translated = TRUE; - return (UINT32)result; + return (UINT)result; } /*********************************************************************** - * CheckDlgButton16 (USER.97) + * CheckDlgButton (USER32.97) */ -BOOL16 WINAPI CheckDlgButton16( HWND16 hwnd, INT16 id, UINT16 check ) +BOOL STDCALL CheckDlgButton( HWND hwnd, INT id, UINT check ) { - SendDlgItemMessage32A( hwnd, id, BM_SETCHECK32, check, 0 ); + SendDlgItemMessageW( hwnd, id, BM_SETCHECK, check, 0 ); return TRUE; } + + + /*********************************************************************** - * CheckDlgButton32 (USER32.45) + * IsDlgButtonChecked (USER32.98) */ -WINBOOL WINAPI CheckDlgButton32( HWND32 hwnd, INT32 id, UINT32 check ) +UINT STDCALL IsDlgButtonChecked( HWND hwnd, INT id ) { - SendDlgItemMessage32A( hwnd, id, BM_SETCHECK32, check, 0 ); - return TRUE; + return (UINT)SendDlgItemMessageA( hwnd, id, BM_GETCHECK, 0, 0 ); } -/*********************************************************************** - * IsDlgButtonChecked16 (USER.98) - */ -UINT16 WINAPI IsDlgButtonChecked16( HWND16 hwnd, UINT16 id ) -{ - return (UINT16)SendDlgItemMessage32A( hwnd, id, BM_GETCHECK32, 0, 0 ); -} /*********************************************************************** - * IsDlgButtonChecked32 (USER32.344) + * CheckRadioButton (USER32.48) */ -UINT32 WINAPI IsDlgButtonChecked32( HWND32 hwnd, UINT32 id ) -{ - return (UINT32)SendDlgItemMessage32A( hwnd, id, BM_GETCHECK32, 0, 0 ); -} - - -/*********************************************************************** - * CheckRadioButton16 (USER.96) - */ -BOOL16 WINAPI CheckRadioButton16( HWND16 hwndDlg, UINT16 firstID, - UINT16 lastID, UINT16 checkID ) -{ - return CheckRadioButton32( hwndDlg, firstID, lastID, checkID ); -} - - -/*********************************************************************** - * CheckRadioButton32 (USER32.48) - */ -WINBOOL WINAPI CheckRadioButton32( HWND32 hwndDlg, UINT32 firstID, - UINT32 lastID, UINT32 checkID ) +WINBOOL STDCALL CheckRadioButton( HWND hwndDlg, INT firstID, + INT lastID, INT checkID ) { WND *pWnd = WIN_FindWndPtr( hwndDlg ); if (!pWnd) return FALSE; @@ -854,7 +441,7 @@ WINBOOL WINAPI CheckRadioButton32( HWND32 hwndDlg, UINT32 firstID, lastID = firstID; /* Buttons are in reverse order */ while (pWnd) { - SendMessage32A( pWnd->hwndSelf, BM_SETCHECK32, + SendMessageA( pWnd->hwndSelf, BM_SETCHECK, (pWnd->wIDmenu == checkID), 0 ); if (pWnd->wIDmenu == lastID) break; pWnd = pWnd->next; @@ -864,60 +451,41 @@ WINBOOL WINAPI CheckRadioButton32( HWND32 hwndDlg, UINT32 firstID, /*********************************************************************** - * GetDialogBaseUnits (USER.243) (USER32.233) + * GetDialogBaseUnits (USER32.243) (USER32.233) */ -DWORD WINAPI GetDialogBaseUnits(void) +LONG STDCALL GetDialogBaseUnits(void) { return MAKELONG( xBaseUnit, yBaseUnit ); } /*********************************************************************** - * MapDialogRect16 (USER.103) + * MapDialogRect (USER32.103) */ -void WINAPI MapDialogRect16( HWND16 hwnd, LPRECT16 rect ) +WINBOOL STDCALL MapDialogRect( HWND hwnd, LPRECT rect ) { DIALOGINFO * dlgInfo; WND * wndPtr = WIN_FindWndPtr( hwnd ); - if (!wndPtr) return; + if (!wndPtr) return FALSE; dlgInfo = (DIALOGINFO *)wndPtr->wExtra; rect->left = (rect->left * dlgInfo->xBaseUnit) / 4; rect->right = (rect->right * dlgInfo->xBaseUnit) / 4; rect->top = (rect->top * dlgInfo->yBaseUnit) / 8; rect->bottom = (rect->bottom * dlgInfo->yBaseUnit) / 8; + return TRUE; } -/*********************************************************************** - * MapDialogRect32 (USER32.382) - */ -void WINAPI MapDialogRect32( HWND32 hwnd, LPRECT32 rect ) -{ - DIALOGINFO * dlgInfo; - WND * wndPtr = WIN_FindWndPtr( hwnd ); - if (!wndPtr) return; - dlgInfo = (DIALOGINFO *)wndPtr->wExtra; - rect->left = (rect->left * dlgInfo->xBaseUnit) / 4; - rect->right = (rect->right * dlgInfo->xBaseUnit) / 4; - rect->top = (rect->top * dlgInfo->yBaseUnit) / 8; - rect->bottom = (rect->bottom * dlgInfo->yBaseUnit) / 8; -} + + + + /*********************************************************************** - * GetNextDlgGroupItem16 (USER.227) + * GetNextDlgGroupItem (USER32.275) */ -HWND16 WINAPI GetNextDlgGroupItem16( HWND16 hwndDlg, HWND16 hwndCtrl, - BOOL16 fPrevious ) -{ - return (HWND16)GetNextDlgGroupItem32( hwndDlg, hwndCtrl, fPrevious ); -} - - -/*********************************************************************** - * GetNextDlgGroupItem32 (USER32.275) - */ -HWND32 WINAPI GetNextDlgGroupItem32( HWND32 hwndDlg, HWND32 hwndCtrl, +HWND STDCALL GetNextDlgGroupItem( HWND hwndDlg, HWND hwndCtrl, WINBOOL fPrevious ) { WND *pWnd, *pWndLast, *pWndCtrl, *pWndDlg; @@ -965,20 +533,13 @@ HWND32 WINAPI GetNextDlgGroupItem32( HWND32 hwndDlg, HWND32 hwndCtrl, } -/*********************************************************************** - * GetNextDlgTabItem16 (USER.228) - */ -HWND16 WINAPI GetNextDlgTabItem16( HWND16 hwndDlg, HWND16 hwndCtrl, - BOOL16 fPrevious ) -{ - return (HWND16)GetNextDlgTabItem32( hwndDlg, hwndCtrl, fPrevious ); -} + /*********************************************************************** - * GetNextDlgTabItem32 (USER32.276) + * GetNextDlgTabItem (USER32.276) */ -HWND32 WINAPI GetNextDlgTabItem32( HWND32 hwndDlg, HWND32 hwndCtrl, +HWND STDCALL GetNextDlgTabItem( HWND hwndDlg, HWND hwndCtrl, WINBOOL fPrevious ) { WND *pWnd, *pWndLast, *pWndCtrl, *pWndDlg; diff --git a/reactos/lib/user32/windows/hook.c b/reactos/lib/user32/windows/hook.c index 9606a492311..7e2266611fe 100644 --- a/reactos/lib/user32/windows/hook.c +++ b/reactos/lib/user32/windows/hook.c @@ -287,12 +287,12 @@ LRESULT HOOK_CallHook( HHOOK hook, INT fromtype, INT code, WPARAM wParam, LPARAM lParam ) { // MESSAGEQUEUE *queue; - HANDLE prevHook; + //HANDLE prevHook; HOOKDATA *data = (HOOKDATA *)(hook); LRESULT ret; - WPARAM wParamOrig = wParam; - LPARAM lParamOrig = lParam; + //WPARAM wParamOrig = wParam; + //LPARAM lParamOrig = lParam; // HOOK_MapFunc MapFunc; // HOOK_UnMapFunc UnMapFunc; @@ -337,7 +337,16 @@ WINBOOL HOOK_IsHooked( INT id ) return HOOK_GetHook( id, GetThreadQueue(0) ) != 0; } +LRESULT HOOK_CallHooks( INT id, INT code, WPARAM wParam, + LPARAM lParam ,WINBOOL bUnicode) +{ + if ( bUnicode == TRUE ) + return HOOK_CallHooksW( id, code, wParam,lParam ); + else + return HOOK_CallHooksA( id, code, wParam,lParam ); + return 0; +} /*********************************************************************** * HOOK_CallHooksA diff --git a/reactos/lib/user32/windows/msg.c b/reactos/lib/user32/windows/msg.c index 8dd616a346e..56d52d2da8b 100644 --- a/reactos/lib/user32/windows/msg.c +++ b/reactos/lib/user32/windows/msg.c @@ -251,101 +251,51 @@ WINBOOL STDCALL PostMessageW( HWND hwnd, UINT message, WPARAM wParam, LRESULT STDCALL SendMessageA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ) { - WND * wndPtr; - WND **list, **ppWnd; - LRESULT ret; + WND *wndPtr; if (hwnd == HWND_BROADCAST || hwnd == HWND_TOPMOST) { - if (!(list = WIN_BuildWinArray( WIN_GetDesktop(), 0, NULL ))) - return TRUE; - for (ppWnd = list; *ppWnd; ppWnd++) - { - wndPtr = *ppWnd; - if (!IsWindow(wndPtr->hwndSelf)) continue; - if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION) - SendMessageA( wndPtr->hwndSelf, msg, wParam, lParam ); - } - HeapFree( GetProcessHeap(), 0, list ); - return TRUE; + return MSG_SendMessageInterTask(hwnd,msg,wParam,lParam,FALSE); + } + + + if (!(wndPtr = WIN_FindWndPtr( hwnd ))) + { + DPRINT( "invalid hwnd %08x\n", hwnd ); + return 0; } if (HOOK_IsHooked( WH_CALLWNDPROC )) MSG_CallWndProcHook( (LPMSG)&hwnd, FALSE); - if (!(wndPtr = WIN_FindWndPtr( hwnd ))) - { - DPRINT( "invalid hwnd %08x\n", hwnd ); - return 0; - } - - if (QUEUE_IsExitingQueue(wndPtr->hmemTaskQ)) - return 0; /* Don't send anything if the task is dying */ - - SPY_EnterMessage( SPY_SENDMESSAGE, hwnd, msg, wParam, lParam ); - - if (wndPtr->hmemTaskQ != GetFastQueue()) - ret = MSG_SendMessage( wndPtr->hmemTaskQ, hwnd, msg, wParam, lParam, - QUEUE_SM_ASCII ); - else - ret = CallWindowProcA( (WNDPROC)wndPtr->winproc, - hwnd, msg, wParam, lParam ); - - SPY_ExitMessage( SPY_RESULT_OK, hwnd, msg, ret ); - return ret; + + return MSG_SendMessage(wndPtr,msg,wParam,lParam,FALSE); } -LRESULT STDCALL SendMessageW( - HWND hwnd, /* Window to send message to. If HWND_BROADCAST, - the message will be sent to all top-level windows. */ - - UINT msg, /* message */ - WPARAM wParam, /* message parameter */ - LPARAM lParam /* additional message parameter */ -) { - WND * wndPtr; - WND **list, **ppWnd; - LRESULT ret; +LRESULT STDCALL SendMessageW( HWND hwnd, UINT msg, WPARAM wParam, + LPARAM lParam ) +{ + WND *wndPtr; if (hwnd == HWND_BROADCAST || hwnd == HWND_TOPMOST) { - if (!(list = WIN_BuildWinArray( WIN_GetDesktop(), 0, NULL ))) - return TRUE; - for (ppWnd = list; *ppWnd; ppWnd++) - { - wndPtr = *ppWnd; - if (!IsWindow(wndPtr->hwndSelf)) continue; - if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION) - SendMessageW( wndPtr->hwndSelf, msg, wParam, lParam ); - } - HeapFree( GetProcessHeap(), 0, list ); - return TRUE; + return MSG_SendMessageInterTask(hwnd,msg,wParam,lParam,TRUE); } - if (HOOK_IsHooked( WH_CALLWNDPROC )) - MSG_CallWndProcHook( (LPMSG)&hwnd, TRUE); if (!(wndPtr = WIN_FindWndPtr( hwnd ))) { DPRINT( "invalid hwnd %08x\n", hwnd ); return 0; } - if (QUEUE_IsExitingQueue(wndPtr->hmemTaskQ)) - return 0; /* Don't send anything if the task is dying */ - SPY_EnterMessage( SPY_SENDMESSAGE, hwnd, msg, wParam, lParam ); + if (HOOK_IsHooked( WH_CALLWNDPROC )) + MSG_CallWndProcHook( (LPMSG)&hwnd, FALSE); - if (wndPtr->hmemTaskQ != GetFastQueue()) - ret = MSG_SendMessage( wndPtr->hmemTaskQ, hwnd, msg, wParam, lParam, - QUEUE_SM_ASCII | QUEUE_SM_UNICODE ); - else - ret = CallWindowProcW( (WNDPROC)wndPtr->winproc, - hwnd, msg, wParam, lParam ); - - SPY_ExitMessage( SPY_RESULT_OK, hwnd, msg, ret ); - return ret; + + return MSG_SendMessage(wndPtr,msg,wParam,lParam,TRUE); } /*********************************************************************** diff --git a/reactos/lib/user32/windows/msgbox.c b/reactos/lib/user32/windows/msgbox.c index 3a752edd99b..94865416d73 100644 --- a/reactos/lib/user32/windows/msgbox.c +++ b/reactos/lib/user32/windows/msgbox.c @@ -1,6 +1,7 @@ #define UNICODE #include #include +#include #include @@ -9,8 +10,12 @@ #define MB_DEFMASK 0x00000F00 LRESULT CALLBACK MSGBOX_DlgProc( HWND hwnd, UINT message, - WPARAM wParam, LPARAM lParam ); + WPARAM wParam, LPARAM lParam, WINBOOL bUnicode ); +LRESULT CALLBACK MSGBOX_DlgProcA( HWND hwnd, UINT message, + WPARAM wParam, LPARAM lParam ); +LRESULT CALLBACK MSGBOX_DlgProcW( HWND hwnd, UINT message, + WPARAM wParam, LPARAM lParam ); // FIXME ????????? /* Static text */ @@ -47,7 +52,8 @@ INT STDCALL MessageBoxExA( HWND hWnd, LPCSTR text, LPCSTR title, UINT type, WORD langid ) { MSGBOXPARAMS mbox; - + HANDLE hrsrc; + HANDLE hDlgTemplate; if (title == NULL) title="Error"; if (text == NULL) @@ -56,9 +62,13 @@ INT STDCALL MessageBoxExA( HWND hWnd, LPCSTR text, LPCSTR title, mbox.lpszCaption = title; mbox.lpszText = text; mbox.dwStyle = type; - return DialogBoxIndirectParamA( WIN_GetWindowInstance(hWnd), - SYSRES_GetResPtr( SYSRES_DIALOG_MSGBOX ), - hWnd, MSGBOX_DlgProc, (LPARAM)&mbox ); + + hrsrc = FindResourceA( NULL, "MSGBOX", RT_DIALOG ); + if (!hrsrc) return 0; + + hDlgTemplate = LockResource(LoadResource(NULL,hrsrc)); + return DialogBoxIndirectParamA( NULL, hDlgTemplate, + hWnd, MSGBOX_DlgProcA, (LPARAM)&mbox ); } /************************************************************************** @@ -68,7 +78,8 @@ INT STDCALL MessageBoxExW( HWND hWnd, LPCWSTR text, LPCWSTR title, UINT type, WORD langid ) { MSGBOXPARAMS mbox; - + HANDLE hrsrc; + HANDLE hDlgTemplate; if (title == NULL) title=L"Error"; if (text == NULL) @@ -77,9 +88,14 @@ INT STDCALL MessageBoxExW( HWND hWnd, LPCWSTR text, LPCWSTR title, mbox.lpszCaption = title; mbox.lpszText = text; mbox.dwStyle = type; - return DialogBoxIndirectParamW( WIN_GetWindowInstance(hWnd), - SYSRES_GetResPtr( SYSRES_DIALOG_MSGBOX ), - hWnd, MSGBOX_DlgProc, (LPARAM)&mbox ); + + hrsrc = FindResourceW( NULL, L"MSGBOX", RT_DIALOG ); + if (!hrsrc) return 0; + + hDlgTemplate = LockResource(LoadResource(NULL,hrsrc)); + return DialogBoxIndirectParamW( NULL, + hDlgTemplate, + hWnd, MSGBOX_DlgProcW, (LPARAM)&mbox ); } @@ -89,10 +105,13 @@ INT STDCALL MessageBoxExW( HWND hWnd, LPCWSTR text, LPCWSTR title, */ INT STDCALL MessageBoxIndirectA( LPMSGBOXPARAMS msgbox ) { - + HANDLE hrsrc = FindResourceA( NULL, "MSGBOX", RT_DIALOG ); + HANDLE hDlgTemplate; + if (!hrsrc) return 0; + hDlgTemplate = LockResource(LoadResource(NULL,hrsrc)); return DialogBoxIndirectParamA( msgbox->hInstance, - SYSRES_GetResPtr( SYSRES_DIALOG_MSGBOX ), - msgbox->hwndOwner, MSGBOX_DlgProc, + hDlgTemplate, + msgbox->hwndOwner, MSGBOX_DlgProcA, (LPARAM)msgbox ); } @@ -102,9 +121,13 @@ INT STDCALL MessageBoxIndirectA( LPMSGBOXPARAMS msgbox ) INT STDCALL MessageBoxIndirectW( LPMSGBOXPARAMS msgbox ) { + HANDLE hrsrc = FindResourceW( NULL, L"MSGBOX", RT_DIALOG ); + HANDLE hDlgTemplate; + if (!hrsrc) return 0; + hDlgTemplate = LockResource(LoadResource(NULL,hrsrc)); return DialogBoxIndirectParamW( msgbox->hInstance, - SYSRES_GetResPtr( SYSRES_DIALOG_MSGBOX ), - msgbox->hwndOwner, MSGBOX_DlgProc, + hDlgTemplate, + msgbox->hwndOwner, MSGBOX_DlgProcW, (LPARAM)msgbox ); } @@ -113,8 +136,19 @@ INT STDCALL MessageBoxIndirectW( LPMSGBOXPARAMS msgbox ) * * Dialog procedure for message boxes. */ -LRESULT CALLBACK MSGBOX_DlgProc( HWND hwnd, UINT message, +LRESULT CALLBACK MSGBOX_DlgProcA( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ) +{ + return MSGBOX_DlgProc(hwnd,message,wParam,lParam,FALSE); +} + +LRESULT CALLBACK MSGBOX_DlgProcW( HWND hwnd, UINT message, + WPARAM wParam, LPARAM lParam ) +{ + return MSGBOX_DlgProc(hwnd,message,wParam,lParam,TRUE); +} + +LRESULT CALLBACK MSGBOX_DlgProc( HWND hwnd, UINT message,WPARAM wParam, LPARAM lParam, WINBOOL bUnicode ) { static HFONT hFont = 0; LPMSGBOXPARAMS lpmb; @@ -126,144 +160,162 @@ LRESULT CALLBACK MSGBOX_DlgProc( HWND hwnd, UINT message, int i, buttons, bwidth, bheight, theight, wwidth, bpos; int borheight, iheight, tiheight; - NONCLIENTMETRICS nclm; switch(message) { case WM_INITDIALOG: lpmb = (LPMSGBOXPARAMS)lParam; - nclm.cbSize = sizeof(NONCLIENTMETRICS); - SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0); - hFont = CreateFontIndirect(&nclm.lfMessageFont); - /* set button font */ - for (i=1; i < 8; i++) - SendDlgItemMessageW (hwnd, i, WM_SETFONT, (WPARAM)hFont, 0); - /* set text font */ - SendDlgItemMessageW (hwnd, 100, WM_SETFONT, (WPARAM)hFont, 0); + if (TWEAK_WineLook >= WIN95_LOOK) { + NONCLIENTMETRICS nclm; + INT i; + nclm.cbSize = sizeof(NONCLIENTMETRICS); + SystemParametersInfoA(SPI_GETNONCLIENTMETRICS, 0, &nclm, 0); + hFont = CreateFontIndirect (&nclm.lfMessageFont); + /* set button font */ + for (i=1; i < 8; i++) + SendDlgItemMessage (hwnd, i, WM_SETFONT, (WPARAM)hFont, 0); + /* set text font */ + SendDlgItemMessage (hwnd, 100, WM_SETFONT, (WPARAM)hFont, 0); + } + + + - if (lpmb->lpszCaption) - SetWindowTextW(hwnd, lpmb->lpszCaption); - SetWindowTextW(GetDlgItem(hwnd, 100), lpmb->lpszText); + if ( bUnicode == TRUE ) { + if (lpmb->lpszCaption) + SetWindowTextW(hwnd, (LPCWSTR)lpmb->lpszCaption); + SetWindowTextW(GetDlgItem(hwnd, 100),(LPWSTR) lpmb->lpszText); + } else { + if (lpmb->lpszCaption) + SetWindowTextA(hwnd, lpmb->lpszCaption); + SetWindowTextA(GetDlgItem(hwnd, 100), lpmb->lpszText); + } /* Hide not selected buttons */ switch(lpmb->dwStyle & MB_TYPEMASK) { - case MB_OK: - ShowWindow(GetDlgItem(hwnd, 2), SW_HIDE); - /* fall through */ - case MB_OKCANCEL: - ShowWindow(GetDlgItem(hwnd, 3), SW_HIDE); - ShowWindow(GetDlgItem(hwnd, 4), SW_HIDE); - ShowWindow(GetDlgItem(hwnd, 5), SW_HIDE); - ShowWindow(GetDlgItem(hwnd, 6), SW_HIDE); - ShowWindow(GetDlgItem(hwnd, 7), SW_HIDE); - break; - case MB_ABORTRETRYIGNORE: - ShowWindow(GetDlgItem(hwnd, 1), SW_HIDE); - ShowWindow(GetDlgItem(hwnd, 2), SW_HIDE); - ShowWindow(GetDlgItem(hwnd, 6), SW_HIDE); - ShowWindow(GetDlgItem(hwnd, 7), SW_HIDE); - break; - case MB_YESNO: - ShowWindow(GetDlgItem(hwnd, 2), SW_HIDE); - /* fall through */ - case MB_YESNOCANCEL: - ShowWindow(GetDlgItem(hwnd, 1), SW_HIDE); - ShowWindow(GetDlgItem(hwnd, 3), SW_HIDE); - ShowWindow(GetDlgItem(hwnd, 4), SW_HIDE); - ShowWindow(GetDlgItem(hwnd, 5), SW_HIDE); - break; - } - /* Set the icon */ - switch(lpmb->dwStyle & MB_ICONMASK) { - case MB_ICONEXCLAMATION: - SendDlgItemMessage(hwnd, stc1, STM_SETICON, - (WPARAM)LoadIcon(0, IDI_EXCLAMATION), 0); - break; - case MB_ICONQUESTION: - SendDlgItemMessage(hwnd, stc1, STM_SETICON, + case MB_OK: + ShowWindow(GetDlgItem(hwnd, 2), SW_HIDE); + /* fall through */ + case MB_OKCANCEL: + ShowWindow(GetDlgItem(hwnd, 3), SW_HIDE); + ShowWindow(GetDlgItem(hwnd, 4), SW_HIDE); + ShowWindow(GetDlgItem(hwnd, 5), SW_HIDE); + ShowWindow(GetDlgItem(hwnd, 6), SW_HIDE); + ShowWindow(GetDlgItem(hwnd, 7), SW_HIDE); + break; + case MB_ABORTRETRYIGNORE: + ShowWindow(GetDlgItem(hwnd, 1), SW_HIDE); + ShowWindow(GetDlgItem(hwnd, 2), SW_HIDE); + ShowWindow(GetDlgItem(hwnd, 6), SW_HIDE); + ShowWindow(GetDlgItem(hwnd, 7), SW_HIDE); + break; + case MB_YESNO: + ShowWindow(GetDlgItem(hwnd, 2), SW_HIDE); + /* fall through */ + case MB_YESNOCANCEL: + ShowWindow(GetDlgItem(hwnd, 1), SW_HIDE); + ShowWindow(GetDlgItem(hwnd, 3), SW_HIDE); + ShowWindow(GetDlgItem(hwnd, 4), SW_HIDE); + ShowWindow(GetDlgItem(hwnd, 5), SW_HIDE); + break; + } + /* Set the icon */ + switch(lpmb->dwStyle & MB_ICONMASK) { + case MB_ICONEXCLAMATION: + SendDlgItemMessage(hwnd, stc1, STM_SETICON, + (WPARAM)LoadIcon(0, IDI_EXCLAMATION), 0); + break; + case MB_ICONQUESTION: + SendDlgItemMessage(hwnd, stc1, STM_SETICON, (WPARAM)LoadIcon(0, IDI_QUESTION), 0); - break; - case MB_ICONASTERISK: - SendDlgItemMessage(hwnd, stc1, STM_SETICON, + break; + case MB_ICONASTERISK: + SendDlgItemMessage(hwnd, stc1, STM_SETICON, (WPARAM)LoadIcon(0, IDI_ASTERISK), 0); - break; - case MB_ICONHAND: - default: - SendDlgItemMessage(hwnd, stc1, STM_SETICON, + break; + case MB_ICONHAND: + default: + SendDlgItemMessage(hwnd, stc1, STM_SETICON, (WPARAM)LoadIcon(0, IDI_HAND), 0); - break; - } + break; + } - /* Position everything */ - GetWindowRect(hwnd, &rect); - borheight = rect.bottom - rect.top; - wwidth = rect.right - rect.left; - GetClientRect(hwnd, &rect); - borheight -= rect.bottom - rect.top; + /* Position everything */ + GetWindowRect(hwnd, &rect); + borheight = rect.bottom - rect.top; + wwidth = rect.right - rect.left; + GetClientRect(hwnd, &rect); + borheight -= rect.bottom - rect.top; - /* Get the icon height */ - GetWindowRect(GetDlgItem(hwnd, 1088), &rect); - iheight = rect.bottom - rect.top; + /* Get the icon height */ + GetWindowRect(GetDlgItem(hwnd, 1088), &rect); + iheight = rect.bottom - rect.top; - /* Get the number of visible buttons and their width */ - GetWindowRect(GetDlgItem(hwnd, 2), &rect); - bheight = rect.bottom - rect.top; - bwidth = rect.left; - GetWindowRect(GetDlgItem(hwnd, 1), &rect); - bwidth -= rect.left; - for (buttons = 0, i = 1; i < 8; i++) - { - hItem = GetDlgItem(hwnd, i); - if (GetWindowLongW(hItem, GWL_STYLE) & WS_VISIBLE) - buttons++; - } + /* Get the number of visible buttons and their width */ + GetWindowRect(GetDlgItem(hwnd, 2), &rect); + bheight = rect.bottom - rect.top; + bwidth = rect.left; + GetWindowRect(GetDlgItem(hwnd, 1), &rect); + bwidth -= rect.left; + for (buttons = 0, i = 1; i < 8; i++) + { + hItem = GetDlgItem(hwnd, i); + if (GetWindowLong(hItem, GWL_STYLE) & WS_VISIBLE) + buttons++; + } - /* Get the text size */ - hItem = GetDlgItem(hwnd, 100); - GetWindowRect(hItem, &textrect); - MapWindowPoints(0, hwnd, (LPPOINT)&textrect, 2); + /* Get the text size */ + hItem = GetDlgItem(hwnd, 100); + GetWindowRect(hItem, &textrect); + MapWindowPoints(0, hwnd, (LPPOINT)&textrect, 2); - GetClientRect(hItem, &rect); - hdc = GetDC(hItem); - lRet = DrawTextW( hdc, lpmb->lpszText, -1, &rect, + GetClientRect(hItem, &rect); + hdc = GetDC(hItem); + + + if ( bUnicode ) + lRet = DrawTextW( hdc, (LPCWSTR)lpmb->lpszText, -1, &rect, DT_LEFT | DT_EXPANDTABS | DT_WORDBREAK | DT_CALCRECT); - theight = rect.bottom - rect.top; - tiheight = 16 + max(iheight, theight); - ReleaseDC(hItem, hdc); + else + lRet = DrawTextA( hdc, lpmb->lpszText, -1, &rect, + DT_LEFT | DT_EXPANDTABS | DT_WORDBREAK | DT_CALCRECT); + theight = rect.bottom - rect.top; + tiheight = 16 + max(iheight, theight); + ReleaseDC(hItem, hdc); - /* Position the text */ - SetWindowPos(hItem, 0, textrect.left, (tiheight - theight) / 2, + /* Position the text */ + SetWindowPos(hItem, 0, textrect.left, (tiheight - theight) / 2, rect.right - rect.left, theight, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW); - /* Position the icon */ - hItem = GetDlgItem(hwnd, 1088); - GetWindowRect(hItem, &rect); - MapWindowPoints(0, hwnd, (LPPOINT)&rect, 2); - SetWindowPos(hItem, 0, rect.left, (tiheight - iheight) / 2, 0, 0, + /* Position the icon */ + hItem = GetDlgItem(hwnd, 1088); + GetWindowRect(hItem, &rect); + MapWindowPoints(0, hwnd, (LPPOINT)&rect, 2); + SetWindowPos(hItem, 0, rect.left, (tiheight - iheight) / 2, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW); /* Resize the window */ - SetWindowPos(hwnd, 0, 0, 0, wwidth, 8 + tiheight + bheight + borheight, + SetWindowPos(hwnd, 0, 0, 0, wwidth, 8 + tiheight + bheight + borheight, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW); /* Position the buttons */ - bpos = (wwidth - bwidth * buttons) / 2; - GetWindowRect(GetDlgItem(hwnd, 1), &rect); - for (buttons = i = 0; i < 7; i++) { - /* some arithmetic to get the right order for YesNoCancel windows */ - hItem = GetDlgItem(hwnd, (i + 5) % 7 + 1); - if (GetWindowLongW(hItem, GWL_STYLE) & WS_VISIBLE) { - if (buttons++ == ((lpmb->dwStyle & MB_DEFMASK) >> 8)) { - SetFocus(hItem); - SendMessageW( hItem, BM_SETSTYLE, BS_DEFPUSHBUTTON, TRUE ); - } - SetWindowPos(hItem, 0, bpos, tiheight, 0, 0, - SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOREDRAW); - bpos += bwidth; - } - } - return 0; - break; + bpos = (wwidth - bwidth * buttons) / 2; + GetWindowRect(GetDlgItem(hwnd, 1), &rect); + for (buttons = i = 0; i < 7; i++) { + /* some arithmetic to get the right order for YesNoCancel windows */ + hItem = GetDlgItem(hwnd, (i + 5) % 7 + 1); + if (GetWindowLong(hItem, GWL_STYLE) & WS_VISIBLE) { + if (buttons++ == ((lpmb->dwStyle & MB_DEFMASK) >> 8)) { + SetFocus(hItem); + SendMessage( hItem, BM_SETSTYLE, BS_DEFPUSHBUTTON, TRUE ); + } + SetWindowPos(hItem, 0, bpos, tiheight, 0, 0, + SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOREDRAW); + bpos += bwidth; + } + } + return 0; + break; case WM_COMMAND: switch (wParam) diff --git a/reactos/lib/user32/windows/scroll.c b/reactos/lib/user32/windows/scroll.c new file mode 100644 index 00000000000..62f2366ccd0 --- /dev/null +++ b/reactos/lib/user32/windows/scroll.c @@ -0,0 +1,312 @@ +/* + * Scroll windows and DCs + * + * Copyright David W. Metcalfe, 1993 + * Alex Korobka 1995,1996 + * + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + + + +/************************************************************************* + * ScrollWindow (USER.450) + * + * FIXME: verify clipping region calculations + */ +WINBOOL STDCALL ScrollWindow( HWND hwnd, INT dx, INT dy, + const RECT *rect, const RECT *clipRect ) +{ + HDC hdc; + HRGN hrgnUpdate,hrgnClip; + RECT rc, cliprc; + HWND hCaretWnd = CARET_GetHwnd(); + WND* wndScroll = WIN_FindWndPtr( hwnd ); + + + if ( !wndScroll || !WIN_IsWindowDrawable( wndScroll, TRUE ) ) return TRUE; + + if ( !rect ) /* do not clip children */ + { + GetClientRect(hwnd, &rc); + hrgnClip = CreateRectRgnIndirect( &rc ); + + if ((hCaretWnd == hwnd) || IsChild(hwnd,hCaretWnd)) + HideCaret(hCaretWnd); + else hCaretWnd = 0; + + hdc = GetDCEx(hwnd, hrgnClip, DCX_CACHE | DCX_CLIPSIBLINGS); + DeleteObject( hrgnClip ); + } + else /* clip children */ + { + CopyRect(&rc, rect); + + if (hCaretWnd == hwnd) HideCaret(hCaretWnd); + else hCaretWnd = 0; + + hdc = GetDCEx( hwnd, 0, DCX_CACHE | DCX_USESTYLE ); + } + + if (clipRect == NULL) + GetClientRect(hwnd, &cliprc); + else + CopyRect(&cliprc, clipRect); + + hrgnUpdate = CreateRectRgn( 0, 0, 0, 0 ); + ScrollDC( hdc, dx, dy, &rc, &cliprc, hrgnUpdate, NULL ); + ReleaseDC(hwnd, hdc); + + if( !rect ) /* move child windows and update region */ + { + WND* wndPtr; + + if( wndScroll->hrgnUpdate > 1 ) + OffsetRgn( wndScroll->hrgnUpdate, dx, dy ); + + for (wndPtr = wndScroll->child; wndPtr; wndPtr = wndPtr->next) + SetWindowPos(wndPtr->hwndSelf, 0, wndPtr->rectWindow.left + dx, + wndPtr->rectWindow.top + dy, 0,0, SWP_NOZORDER | + SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOREDRAW | + SWP_DEFERERASE ); + } + + PAINT_RedrawWindow( hwnd, NULL, hrgnUpdate, RDW_ALLCHILDREN | + RDW_INVALIDATE | RDW_ERASE | RDW_ERASENOW, RDW_C_USEHRGN ); + + DeleteObject( hrgnUpdate ); + if( hCaretWnd ) + { + POINT pt; + GetCaretPos(&pt); + pt.x += dx; pt.y += dy; + SetCaretPos(pt.x, pt.y); + ShowCaret(hCaretWnd); + } + return TRUE; +} + + + + + +/************************************************************************* + * ScrollDC (USER.449) + * + * Both 'rc' and 'prLClip' are in logical units but update info is + * returned in device coordinates. + */ +WINBOOL STDCALL ScrollDC( HDC hdc, INT dx, INT dy, const RECT *rc, + const RECT *prLClip, HRGN hrgnUpdate, + LPRECT rcUpdate ) +{ +#if 0 + RECT rClip; + POINT src, dest; + INT ldx, ldy; + + + if (!hdc ) return FALSE; + + + /* compute device clipping region */ + + if ( rc ) + rClip = *rc; + else /* maybe we should just return FALSE? */ + GetClipBox( hdc, &rClip ); + + if (prLClip) + IntersectRect(&rClip,&rClip,prLClip); + + if( rClip.left >= rClip.right || rClip.top >= rClip.bottom ) + { + return FALSE; + } + + SaveVisRgn( hdc ); + IntersectVisRect( hdc, rClip.left, rClip.top, + rClip.right, rClip.bottom ); + + + /* translate coordinates */ + + ldx = dx * dc->wndExtX / dc->vportExtX; + ldy = dy * dc->wndExtY / dc->vportExtY; + + if (dx > 0) + dest.x = (src.x = rClip.left) + ldx; + else + src.x = (dest.x = rClip.left) - ldx; + + if (dy > 0) + dest.y = (src.y = rClip.top) + ldy; + else + src.y = (dest.y = rClip.top) - ldy; + + /* copy bits */ + + if( rClip.right - rClip.left > ldx && + rClip.bottom - rClip.top > ldy ) + { + ldx = rClip.right - rClip.left - ldx; + ldy = rClip.bottom - rClip.top - ldy; + + if (!BitBlt( hdc, dest.x, dest.y, ldx, ldy, + hdc, src.x, src.y, SRCCOPY)) + { + return FALSE; + } + } + + /* restore clipping region */ + + RestoreVisRgn( hdc ); + + + /* compute update areas */ + + if ( (hrgnUpdate || rcUpdate) && dc->w.hVisRgn ) + { + HRGN hrgn = (hrgnUpdate) ? hrgnUpdate : CreateRectRgn( 0,0,0,0 ); + HRGN hrgnClip; + + LPtoDP( hdc, (LPPOINT)&rClip, 2 ); + OffsetRect( &rClip, dc->w.DCOrgX, dc->w.DCOrgY ); + hrgnClip = CreateRectRgnIndirect( &rClip ); + + CombineRgn( hrgn, dc->w.hVisRgn, hrgnClip, RGN_AND ); + OffsetRgn( hrgn, dx, dy ); + CombineRgn( hrgn, dc->w.hVisRgn, hrgn, RGN_DIFF ); + CombineRgn( hrgn, hrgn, hrgnClip, RGN_AND ); + OffsetRgn( hrgn, -dc->w.DCOrgX, -dc->w.DCOrgY ); + + if( rcUpdate ) GetRgnBox( hrgnUpdate, rcUpdate ); + + if (!hrgnUpdate) DeleteObject( hrgn ); + DeleteObject( hrgnClip ); + } +#endif + return TRUE; +} + + + + + +/************************************************************************* + * ScrollWindowEx (USER.451) + * + * NOTE: Use this function instead of ScrollWindow + */ +INT STDCALL ScrollWindowEx( HWND hwnd, INT dx, INT dy, + const RECT *rect, const RECT *clipRect, + HRGN hrgnUpdate, LPRECT rcUpdate, + UINT flags ) +{ + INT retVal = NULLREGION; + WINBOOL bCaret = FALSE, bOwnRgn = TRUE; + RECT rc, cliprc; + WND* wnd = WIN_FindWndPtr( hwnd ); + + if( !wnd || !WIN_IsWindowDrawable( wnd, TRUE )) return ERROR; + + if (rect == NULL) GetClientRect(hwnd, &rc); + else rc = *rect; + + if (clipRect) IntersectRect(&cliprc,&rc,clipRect); + else cliprc = rc; + + if (!IsRectEmpty(&cliprc) && (dx || dy)) + { + + HDC hDC; + WINBOOL bUpdate = (rcUpdate || hrgnUpdate || flags & (SW_INVALIDATE | SW_ERASE)); + HRGN hrgnClip = CreateRectRgnIndirect(&cliprc); + + + rc = cliprc; + bCaret = SCROLL_FixCaret(hwnd, &rc, flags); + + if( hrgnUpdate ) bOwnRgn = FALSE; + else if( bUpdate ) hrgnUpdate = CreateRectRgn( 0, 0, 0, 0 ); + + hDC = GetDCEx( hwnd, hrgnClip, DCX_CACHE | DCX_USESTYLE | + ((flags & SW_SCROLLCHILDREN) ? DCX_NOCLIPCHILDREN : 0) ); + if( hDC != NULL) + { + +#if 0 + if( dc->w.hVisRgn && bUpdate ) + { + OffsetRgn( hrgnClip, dc->w.DCOrgX, dc->w.DCOrgY ); + CombineRgn( hrgnUpdate, dc->w.hVisRgn, hrgnClip, RGN_AND ); + OffsetRgn( hrgnUpdate, dx, dy ); + CombineRgn( hrgnUpdate, dc->w.hVisRgn, hrgnUpdate, RGN_DIFF ); + CombineRgn( hrgnUpdate, hrgnUpdate, hrgnClip, RGN_AND ); + OffsetRgn( hrgnUpdate, -dc->w.DCOrgX, -dc->w.DCOrgY ); + + if( rcUpdate ) GetRgnBox( hrgnUpdate, rcUpdate ); + } +#endif + ReleaseDC(hwnd, hDC); + + } + + if( wnd->hrgnUpdate > 1 ) + { + if( rect || clipRect ) + { + if( (CombineRgn( hrgnClip, hrgnClip, + wnd->hrgnUpdate, RGN_AND ) != NULLREGION) ) + { + CombineRgn( wnd->hrgnUpdate, wnd->hrgnUpdate, hrgnClip, RGN_DIFF ); + OffsetRgn( hrgnClip, dx, dy ); + CombineRgn( wnd->hrgnUpdate, wnd->hrgnUpdate, hrgnClip, RGN_OR ); + } + } + else + OffsetRgn( wnd->hrgnUpdate, dx, dy ); + } + + if( flags & SW_SCROLLCHILDREN ) + { + RECT r; + WND* w; + for( w = wnd->child; w; w = w->next ) + { + + if( !clipRect || IntersectRect(&w->rectWindow, &r, &cliprc) ) + SetWindowPos(w->hwndSelf, 0, w->rectWindow.left + dx, + w->rectWindow.top + dy, 0,0, SWP_NOZORDER | + SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOREDRAW | + SWP_DEFERERASE ); + } + } + + if( flags & (SW_INVALIDATE | SW_ERASE) ) + PAINT_RedrawWindow( hwnd, NULL, hrgnUpdate, RDW_INVALIDATE | RDW_ERASE | + ((flags & SW_ERASE) ? RDW_ERASENOW : 0) | ((flags & SW_SCROLLCHILDREN) ? RDW_ALLCHILDREN : 0 ), 0 ); + + if( bCaret ) + { + SetCaretPos( rc.left + dx, rc.top + dy ); + ShowCaret(0); + } + + if( bOwnRgn && hrgnUpdate ) DeleteObject( hrgnUpdate ); + DeleteObject( hrgnClip ); + } + return retVal; +} + + diff --git a/reactos/lib/user32/windows/win.c b/reactos/lib/user32/windows/win.c index 269f36646b6..feb1ffafa62 100644 --- a/reactos/lib/user32/windows/win.c +++ b/reactos/lib/user32/windows/win.c @@ -5,9 +5,11 @@ #include #include #include +#include #include +// change style on WS_OVERLAPPEDWINDOW #undef CreateWindowA HWND STDCALL CreateWindowA(LPCSTR lpClassName, LPCSTR lpWindowName, @@ -51,17 +53,11 @@ HWND STDCALL CreateWindowExA( DWORD exStyle, LPCSTR lpClassName, //if(exStyle & WS_EX_MDICHILD) // return MDI_CreateMDIWindowA(className, windowName, style, x, y, width, height, parent, instance, data); -#if 0 - while ((*lpWindowName)!=0 && i < MAX_PATH) - { - WindowNameW[i] = *lpWindowName; - lpWindowName++; - i++; - } - WindowNameW[i] = 0; -#endif + + if ( style == WS_OVERLAPPEDWINDOW ) + style |= (WS_OVERLAPPED| WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX |WS_MAXIMIZEBOX ); /* Create the window */ @@ -91,8 +87,6 @@ HWND STDCALL CreateWindowExW( DWORD exStyle, LPCWSTR lpClassName, HWND parent, HMENU menu, HINSTANCE hInstance, LPVOID data ) { -// WCHAR WindowNameW[MAX_PATH]; -// WCHAR ClassNameW[MAX_PATH]; CLASS *p; DWORD status; CREATESTRUCTW cs; @@ -103,7 +97,8 @@ HWND STDCALL CreateWindowExW( DWORD exStyle, LPCWSTR lpClassName, if ( p == NULL ) return NULL; - + if ( style == WS_OVERLAPPEDWINDOW ) + style |= (WS_OVERLAPPED| WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX |WS_MAXIMIZEBOX ); /* Create the window */ @@ -133,22 +128,25 @@ WINBOOL STDCALL DestroyWindow( HWND hwnd ) { WND * wndPtr; - DPRINT( "(%04x)\n", hwnd); - /* Initialization */ if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE; //if (wndPtr == pWndDesktop) return FALSE; /* Can't destroy desktop */ + + if ( hwnd == NULL ) + return FALSE; + + /* Call hooks */ - if( HOOK_CallHooksA( WH_CBT, HCBT_DESTROYWND, hwnd, 0L) ) + if( HOOK_CallHooks( WH_CBT, HCBT_DESTROYWND, hwnd, 0L, wndPtr->class->bUnicode ) ) return FALSE; if (!(wndPtr->dwStyle & WS_CHILD) && !wndPtr->owner) { - HOOK_CallHooksA( WH_SHELL, HSHELL_WINDOWDESTROYED, hwnd, 0L ); + HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, hwnd, 0L, wndPtr->class->bUnicode ); /* FIXME: clean up palette - see "Internals" p.352 */ } @@ -156,12 +154,13 @@ WINBOOL STDCALL DestroyWindow( HWND hwnd ) if( wndPtr->dwStyle & WS_CHILD && !(wndPtr->dwExStyle & WS_EX_NOPARENTNOTIFY) ) { /* Notify the parent window only */ - SendMessageA( wndPtr->parent->hwndSelf, WM_PARENTNOTIFY, + if ( wndPtr->parent != NULL ) + SendMessageA( wndPtr->parent->hwndSelf, WM_PARENTNOTIFY, MAKEWPARAM(WM_DESTROY, wndPtr->wIDmenu), (LPARAM)hwnd ); if( !IsWindow(hwnd) ) return TRUE; } - // CLIPBOARD_GetDriver()->pResetOwner( wndPtr, FALSE ); /* before the window is unmapped */ + /* Hide the window */ @@ -182,7 +181,10 @@ WINBOOL STDCALL DestroyWindow( HWND hwnd ) for (;;) { - WND *siblingPtr = wndPtr->parent->child; /* First sibling */ + + WND *siblingPtr = NULL; + if ( wndPtr->parent != NULL ) + siblingPtr = wndPtr->parent->child; /* First sibling */ while (siblingPtr) { if (siblingPtr->owner == wndPtr) @@ -571,20 +573,22 @@ WINBOOL STDCALL IsWindowVisible( HWND hwnd ) /*********************************************************************** - * ShowWindow32 (USER32.534) + * ShowWindow (USER32.534) */ WINBOOL STDCALL ShowWindow( HWND hwnd, INT cmd ) { WND* wndPtr = WIN_FindWndPtr( hwnd ); - WINBOOL wasVisible, showFlag; + WINBOOL wasVisible = FALSE, showFlag; RECT newPos = {0, 0, 0, 0}; int swp = 0; if (!wndPtr) return FALSE; // DPRINT("hwnd=%04x, cmd=%d\n", hwnd, cmd); +#ifdef OPTIMIZATION wasVisible = (wndPtr->dwStyle & WS_VISIBLE) != 0; +#endif switch(cmd) { @@ -680,6 +684,51 @@ WINBOOL STDCALL ShowWindow( HWND hwnd, INT cmd ) // SendMessage(hwnd, WM_NCACTIVATE,TRUE,0); // SendMessage(hwnd, WM_NCPAINT,CreateRectRgn(100,100,100, 100) ,0); + + return wasVisible; } + +/******************************************************************* + * FlashWindow (USER32.202) + */ +WINBOOL STDCALL FlashWindow( HWND hWnd, WINBOOL bInvert ) +{ + WND *wndPtr = WIN_FindWndPtr(hWnd); + + + if (!wndPtr) return FALSE; + + if (wndPtr->dwStyle & WS_MINIMIZE) + { + if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED)) + { + HDC hDC = GetDC(hWnd); + + if (!SendMessage( hWnd, WM_ERASEBKGND, (WPARAM)hDC, 0 )) + wndPtr->flags |= WIN_NEEDS_ERASEBKGND; + + ReleaseDC( hWnd, hDC ); + wndPtr->flags |= WIN_NCACTIVATED; + } + else + { + PAINT_RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | + RDW_UPDATENOW | RDW_FRAME, 0 ); + wndPtr->flags &= ~WIN_NCACTIVATED; + } + return TRUE; + } + else + { + WPARAM wparam; + if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED); + else wparam = (hWnd == GetActiveWindow()); + + SendMessage( hWnd, WM_NCACTIVATE, wparam, (LPARAM)0 ); + return wparam; + } +} + + diff --git a/reactos/lib/user32/windows/winpos.c b/reactos/lib/user32/windows/winpos.c index d76fcdebf78..453dbfcbd45 100644 --- a/reactos/lib/user32/windows/winpos.c +++ b/reactos/lib/user32/windows/winpos.c @@ -175,15 +175,13 @@ HWND SetActiveWindow(HWND hWnd ) WINBOOL STDCALL SetWindowPos( - HWND hWnd, - HWND hWndInsertAfter , - int X, - int Y, - int cx, - int cy, + HWND hWnd, HWND hWndInsertAfter , + int X, int Y, + int cx, int cy, UINT flags) { - WINDOWPOS winpos; + + WINDOWPOS winpos; WND * wndPtr; RECT newWindowRect, newClientRect, oldWindowRect; HRGN visRgn = 0; @@ -192,13 +190,22 @@ SetWindowPos( UINT uFlags; WINBOOL resync = FALSE; - DPRINT("hwnd %04x, (%i,%i)-(%i,%i) flags %08x\n", - hWnd, X, Y, X+cx, Y+cy, flags); + /* Check window handle */ if (hWnd == GetDesktopWindow()) return FALSE; + + if (hWnd == GetActiveWindow() ) flags |= SWP_NOACTIVATE; /* Already active */ + + + /* Check dimensions */ + + if (cx <= 0) cx = 1; + if (cy <= 0) cy = 1; + if (!(wndPtr = WIN_FindWndPtr( hWnd ))) return FALSE; +#if OPTIMIZATION if(wndPtr->dwStyle & WS_VISIBLE) flags &= ~SWP_SHOWWINDOW; else @@ -208,38 +215,30 @@ SetWindowPos( if (!(flags & SWP_SHOWWINDOW)) flags |= SWP_NOREDRAW; } -/* Check for windows that may not be resized - FIXME: this should be done only for Windows 3.0 programs - if (flags & (SWP_SHOWWINDOW | SWP_HIDEWINDOW ) ) - flags |= SWP_NOSIZE | SWP_NOMOVE; -*/ - /* Check dimensions */ - if (cx <= 0) cx = 1; - if (cy <= 0) cy = 1; /* Check flags */ - if (hWnd == hwndActive) flags |= SWP_NOACTIVATE; /* Already active */ if ((wndPtr->rectWindow.right - wndPtr->rectWindow.left == cx) && (wndPtr->rectWindow.bottom - wndPtr->rectWindow.top == cy)) flags |= SWP_NOSIZE; /* Already the right size */ if ((wndPtr->rectWindow.left == X) && (wndPtr->rectWindow.top == Y)) flags |= SWP_NOMOVE; /* Already the right position */ +#endif /* Check hWndInsertAfter */ if (!(flags & (SWP_NOZORDER | SWP_NOACTIVATE))) { /* Ignore TOPMOST flags when activating a window */ /* _and_ moving it in Z order. */ - if ((hWndInsertAfter == HWND_TOPMOST) || - (hWndInsertAfter == HWND_NOTOPMOST)) + + if ((hWndInsertAfter == HWND_TOPMOST) || (hWndInsertAfter == HWND_NOTOPMOST)) hWndInsertAfter = HWND_TOP; } /* TOPMOST not supported yet */ - if ((hWndInsertAfter == HWND_TOPMOST) || - (hWndInsertAfter == HWND_NOTOPMOST)) hWndInsertAfter = HWND_TOP; + if ((hWndInsertAfter == HWND_TOPMOST) || (hWndInsertAfter == HWND_NOTOPMOST)) + hWndInsertAfter = HWND_TOP; /* hWndInsertAfter must be a sibling of the window */ if ((hWndInsertAfter != HWND_TOP) && (hWndInsertAfter != HWND_BOTTOM)) @@ -274,7 +273,7 @@ SetWindowPos( /* Send WM_WINDOWPOSCHANGING message */ if (!(winpos.flags & SWP_NOSENDCHANGING)) - SendMessageA( hWnd, WM_WINDOWPOSCHANGING, 0, (LPARAM)&winpos ); + MSG_SendMessage( wndPtr, WM_WINDOWPOSCHANGING, 0, (LPARAM)&winpos ); /* Calculate new position and size */ @@ -414,10 +413,11 @@ SetWindowPos( - if (!(flags & SWP_NOREDRAW)) + if (!(flags & SWP_NOREDRAW) && wndPtr->parent != NULL ) PAINT_RedrawWindow( wndPtr->parent->hwndSelf, &oldWindowRect, 0, RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_ERASE | RDW_ERASENOW, 0 ); + uFlags |= SMC_NOPARENTERASE; @@ -468,6 +468,7 @@ SetWindowPos( + /*********************************************************************** * WINPOS_CreateInternalPosAtom */ @@ -491,14 +492,14 @@ void WINPOS_CheckInternalPos( HWND hwnd ) if( hwnd == hwndActive ) { hwndActive = 0; - //WARN(win, "\tattempt to activate destroyed window!\n"); + DPRINT("\tattempt to activate destroyed window!\n"); } if( lpPos ) { - if( IsWindow(lpPos->hwndIconTitle) ) - DestroyWindow( lpPos->hwndIconTitle ); - HeapFree( GetProcessHeap(), 0, lpPos ); + //if( IsWindow(lpPos->hwndIconTitle) ) + // DestroyWindow( lpPos->hwndIconTitle ); + //HeapFree( GetProcessHeap(), 0, lpPos ); } } @@ -512,7 +513,18 @@ static POINT WINPOS_FindIconPos( WND* wndPtr, POINT pt ) RECT rectParent; short x, y, xspacing, yspacing; - GetClientRect( wndPtr->parent->hwndSelf, &rectParent ); + if ( wndPtr->parent != NULL ) { + GetClientRect( wndPtr->parent->hwndSelf, &rectParent ); + } + else { + + rectParent.left = 0; + rectParent.right = SYSMETRICS_CXFULLSCREEN; + + rectParent.top = 0; + rectParent.right = SYSMETRICS_CYFULLSCREEN; + } + if ((pt.x >= rectParent.left) && (pt.x + SYSMETRICS_CXICON < rectParent.right) && (pt.y >= rectParent.top) && (pt.y + SYSMETRICS_CYICON < rectParent.bottom)) return pt; /* The icon already has a suitable position */ @@ -526,7 +538,9 @@ static POINT WINPOS_FindIconPos( WND* wndPtr, POINT pt ) for (x = rectParent.left; x <= rectParent.right-xspacing; x += xspacing) { /* Check if another icon already occupies this spot */ - WND *childPtr = wndPtr->parent->child; + WND *childPtr = NULL; + if ( wndPtr->parent ) + childPtr = wndPtr->parent->child; while (childPtr) { if ((childPtr->dwStyle & WS_MINIMIZE) && (childPtr != wndPtr)) @@ -712,6 +726,7 @@ LPINTERNALPOS WINPOS_InitInternalPos( WND* wnd, POINT pt, *(UINT*)&lpPos->ptIconPos = *(UINT*)&lpPos->ptMaxPos = 0xFFFFFFFF; } + if( wnd->dwStyle & WS_MINIMIZE ) memcpy( &lpPos->ptIconPos, &pt,sizeof(POINT) ); else if( wnd->dwStyle & WS_MAXIMIZE ) @@ -824,7 +839,7 @@ void WINPOS_GetMinMaxInfo( WND *wndPtr, POINT *maxSize, POINT *maxPos, MinMax.ptMaxPosition.y = -yinc; } - SendMessageA( wndPtr->hwndSelf, WM_GETMINMAXINFO, 0, (LPARAM)&MinMax ); + MSG_SendMessage( wndPtr, WM_GETMINMAXINFO, 0, (LPARAM)&MinMax ); /* Some sanity checks */ @@ -857,25 +872,19 @@ UINT WINPOS_MinMaximize( WND* wndPtr, UINT cmd, LPRECT lpRect ) //DPRINT("0x%04x %u\n", wndPtr->hwndSelf, cmd ); - if ( wndPtr->class->bUnicode ) { - if (HOOK_CallHooksW(WH_CBT, HCBT_MINMAX, (INT)wndPtr->hwndSelf, cmd)) { - swpFlags |= SWP_NOSIZE | SWP_NOMOVE; - return swpFlags; - } - } - else { - if (HOOK_CallHooksA(WH_CBT, HCBT_MINMAX, (INT)wndPtr->hwndSelf, cmd)) { - swpFlags |= SWP_NOSIZE | SWP_NOMOVE; - return swpFlags; - } + + if (HOOK_CallHooks(WH_CBT, HCBT_MINMAX, (INT)wndPtr->hwndSelf, cmd, wndPtr->class->bUnicode )) { + swpFlags |= SWP_NOSIZE | SWP_NOMOVE; + return swpFlags; } + if (lpPos) { if( wndPtr->dwStyle & WS_MINIMIZE ) { - if( !SendMessageA( wndPtr->hwndSelf, WM_QUERYOPEN, 0, 0L ) ) + if( !MSG_SendMessage( wndPtr->hwndSelf, WM_QUERYOPEN, 0, 0L ) ) return (SWP_NOSIZE | SWP_NOMOVE); swpFlags |= SWP_NOCOPYBITS; } @@ -1000,7 +1009,156 @@ WINBOOL WINPOS_SetPlacement( HWND hwnd, const WINDOWPLACEMENT *wndpl, */ WINBOOL WINPOS_SetActiveWindow( HWND hWnd, WINBOOL fMouse, WINBOOL fChangeFocus) { - return FALSE; + CBTACTIVATESTRUCT* cbtStruct; + WND* wndPtr, *wndTemp; + //HQUEUE hOldActiveQueue, hNewActiveQueue; + WORD wIconized = 0; + + /* paranoid checks */ + if( hWnd == GetDesktopWindow || hWnd == hwndActive ) return 0; + +/* if (wndPtr && (GetFastQueue() != wndPtr->hmemTaskQ)) + * return 0; + */ + wndPtr = WIN_FindWndPtr(hWnd); + //hOldActiveQueue = (pActiveQueue)?pActiveQueue->self : 0; + + if( (wndTemp = WIN_FindWndPtr(hwndActive)) ) + wIconized = HIWORD(wndTemp->dwStyle & WS_MINIMIZE); + + +#if 0 + /* call CBT hook chain */ + if ((cbtStruct = SEGPTR_NEW(CBTACTIVATESTRUCT16))) + { + LRESULT wRet; + cbtStruct->fMouse = fMouse; + cbtStruct->hWndActive = hwndActive; + wRet = HOOK_CallHooks16( WH_CBT, HCBT_ACTIVATE, (WPARAM16)hWnd, + (LPARAM)SEGPTR_GET(cbtStruct) ); + SEGPTR_FREE(cbtStruct); + if (wRet) return wRet; + } +#endif + + /* set prev active wnd to current active wnd and send notification */ + if ((hwndPrevActive = hwndActive) && IsWindow(hwndPrevActive)) + { + if (!SendMessageA( hwndPrevActive, WM_NCACTIVATE, FALSE, 0 )) + { + //if (GetSysModalWindow16() != hWnd) return 0; + /* disregard refusal if hWnd is sysmodal */ + } + + + SendMessageA( hwndPrevActive, WM_ACTIVATE, + MAKEWPARAM( WA_INACTIVE, wIconized ), + (LPARAM)hWnd ); + + + /* check if something happened during message processing */ + if( hwndPrevActive != hwndActive ) return 0; + } + + /* set active wnd */ + hwndActive = hWnd; + + /* send palette messages */ + if (hWnd && SendMessage( hWnd, WM_QUERYNEWPALETTE, 0, 0L)) + SendMessage((HWND)-1, WM_PALETTEISCHANGING, (WPARAM)hWnd, 0L ); + + /* if prev wnd is minimized redraw icon title */ + if( IsIconic( hwndPrevActive ) ) WINPOS_RedrawIconTitle(hwndPrevActive); + +#if DESKTOP + /* managed windows will get ConfigureNotify event */ + if (wndPtr && !(wndPtr->dwStyle & WS_CHILD) && !(wndPtr->flags & WIN_MANAGED)) + { + /* check Z-order and bring hWnd to the top */ + for (wndTemp = WIN_GetDesktop()->child; wndTemp; wndTemp = wndTemp->next) + if (wndTemp->dwStyle & WS_VISIBLE) break; + + if( wndTemp != wndPtr ) + SetWindowPos(hWnd, HWND_TOP, 0,0,0,0, + SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE ); + if (!IsWindow(hWnd)) return 0; + } + +#endif + +#if 0 + hNewActiveQueue = wndPtr ? wndPtr->hmemTaskQ : 0; + + /* send WM_ACTIVATEAPP if necessary */ + if (hOldActiveQueue != hNewActiveQueue) + { + WND **list, **ppWnd; + + if ((list = WIN_BuildWinArray( WIN_GetDesktop(), 0, NULL ))) + { + for (ppWnd = list; *ppWnd; ppWnd++) + { + if (!IsWindow( (*ppWnd)->hwndSelf )) continue; + + if ((*ppWnd)->hmemTaskQ == hOldActiveQueue) + SendMessage16( (*ppWnd)->hwndSelf, WM_ACTIVATEAPP, + 0, QUEUE_GetQueueTask(hNewActiveQueue) ); + } + HeapFree( SystemHeap, 0, list ); + } + + pActiveQueue = (hNewActiveQueue) + ? (MESSAGEQUEUE*) GlobalLock16(hNewActiveQueue) : NULL; + + if ((list = WIN_BuildWinArray( WIN_GetDesktop(), 0, NULL ))) + { + for (ppWnd = list; *ppWnd; ppWnd++) + { + if (!IsWindow( (*ppWnd)->hwndSelf )) continue; + + if ((*ppWnd)->hmemTaskQ == hNewActiveQueue) + SendMessage( (*ppWnd)->hwndSelf, WM_ACTIVATEAPP, + 1, QUEUE_GetQueueTask( hOldActiveQueue ) ); + } + HeapFree( SystemHeap, 0, list ); + } + if (!IsWindow(hWnd)) return 0; + } + +#endif + if (hWnd) + { + /* walk up to the first unowned window */ + wndTemp = wndPtr; + while (wndTemp->owner) wndTemp = wndTemp->owner; + /* and set last active owned popup */ + wndTemp->hwndLastActive = hWnd; + + wIconized = HIWORD(wndTemp->dwStyle & WS_MINIMIZE); + SendMessageA( hWnd, WM_NCACTIVATE, TRUE, 0 ); + + SendMessageA( hWnd, WM_ACTIVATE, + MAKEWPARAM( (fMouse) ? WA_CLICKACTIVE : WA_ACTIVE, wIconized), + (LPARAM)hwndPrevActive ); + + + if( !IsWindow(hWnd) ) return 0; + } +#if 0 + /* change focus if possible */ + if( fChangeFocus && GetFocus() ) + if( WIN_GetTopParent(GetFocus()) != hwndActive ) + FOCUS_SwitchFocus( GetFocus(), + (wndPtr && (wndPtr->dwStyle & WS_MINIMIZE))? + 0: + hwndActive + ); +#endif + + /* if active wnd is minimized redraw icon title */ + if( IsIconic(hwndActive) ) WINPOS_RedrawIconTitle(hwndActive); + + return (hWnd == hwndActive); } /******************************************************************* @@ -1060,7 +1218,7 @@ WINBOOL WINPOS_ChangeActiveWindow( HWND hWnd, WINBOOL mouseMsg ) /* child windows get WM_CHILDACTIVATE message */ if( (wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) == WS_CHILD ) - return SendMessageA(hWnd, WM_CHILDACTIVATE, 0, 0L); + return MSG_SendMessage(wndPtr, WM_CHILDACTIVATE, 0, 0L); /* owned popups imply owner activation - not sure */ if ((wndPtr->dwStyle & WS_POPUP) && wndPtr->owner && @@ -1076,10 +1234,11 @@ WINBOOL WINPOS_ChangeActiveWindow( HWND hWnd, WINBOOL mouseMsg ) if( !WINPOS_SetActiveWindow(hWnd ,mouseMsg ,TRUE) ) return FALSE; +#if DESKTOP /* switch desktop queue to current active */ if( wndPtr->parent == WIN_GetDesktop()) WIN_GetDesktop()->hmemTaskQ = wndPtr->hmemTaskQ; - +#endif return TRUE; } @@ -1397,8 +1556,7 @@ UINT WINPOS_SizeMoveClean( WND* Wnd, HRGN oldVisRgn, // REMOVED DCX_KEEPCLIPRGN hDC = GetDCEx( Wnd->parent->hwndSelf, oldVisRgn, - DCX_INTERSECTRGN | - DCX_CACHE | DCX_CLIPSIBLINGS); + DCX_INTERSECTRGN | DCX_CACHE | DCX_CLIPSIBLINGS); BitBlt( hDC, xto, yto, width, height, hDC, xfrom, yfrom, SRCCOPY ); ReleaseDC( Wnd->parent->hwndSelf, hDC); @@ -1422,3 +1580,15 @@ UINT WINPOS_SizeMoveClean( WND* Wnd, HRGN oldVisRgn, return uFlags; } +/*********************************************************************** + * MoveWindow (USER32.399) + */ +WINBOOL STDCALL MoveWindow( HWND hwnd, INT x, INT y, INT cx, INT cy, + WINBOOL repaint ) +{ + int flags = SWP_NOZORDER | SWP_NOACTIVATE; + if (!repaint) flags |= SWP_NOREDRAW; + + return SetWindowPos( hwnd, 0, x, y, cx, cy, flags ); +} +