diff --git a/reactos/dll/win32/user32/CMakeLists.txt b/reactos/dll/win32/user32/CMakeLists.txt index b1ace098fb5..e1b0657ed80 100644 --- a/reactos/dll/win32/user32/CMakeLists.txt +++ b/reactos/dll/win32/user32/CMakeLists.txt @@ -72,7 +72,7 @@ target_link_libraries(user32 win32ksys ${PSEH_LIB}) -add_delay_importlibs(user32 imm32) +add_delay_importlibs(user32 imm32 usp10) add_importlibs(user32 gdi32 advapi32 msvcrt kernel32 ntdll) add_pch(user32 include/user32.h) add_cd_file(TARGET user32 DESTINATION reactos/system32 FOR all) diff --git a/reactos/dll/win32/user32/controls/button.c b/reactos/dll/win32/user32/controls/button.c index af205c5dd8e..49c34d7e1ff 100644 --- a/reactos/dll/win32/user32/controls/button.c +++ b/reactos/dll/win32/user32/controls/button.c @@ -31,7 +31,6 @@ * Styles * - BS_NOTIFY: is it complete? * - BS_RIGHTBUTTON: same as BS_LEFTTEXT - * - BS_TYPEMASK * * Messages * - WM_CHAR: Checks a (manual or automatic) check box on '+' or '=', clears it on '-' key. @@ -75,14 +74,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(button); #define UISTATE_GWL_OFFSET (HIMAGE_GWL_OFFSET+sizeof(HFONT)) #define NB_EXTRA_BYTES (UISTATE_GWL_OFFSET+sizeof(LONG)) - /* Button state values */ -#define BUTTON_UNCHECKED 0x00 -#define BUTTON_CHECKED 0x01 -#define BUTTON_3STATE 0x02 -#define BUTTON_HIGHLIGHTED 0x04 -#define BUTTON_HASFOCUS 0x08 -#define BUTTON_NSTATES 0x0F /* undocumented flags */ +#define BUTTON_NSTATES 0x0F #define BUTTON_BTNPRESSED 0x40 #define BUTTON_UNKNOWN2 0x20 #define BUTTON_UNKNOWN3 0x10 @@ -103,22 +96,22 @@ static void UB_Paint( HWND hwnd, HDC hDC, UINT action ); static void OB_Paint( HWND hwnd, HDC hDC, UINT action ); static void BUTTON_CheckAutoRadioButton( HWND hwnd ); -#define MAX_BTN_TYPE 12 +#define MAX_BTN_TYPE 16 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 */ + BST_UNCHECKED, /* BS_PUSHBUTTON */ + BST_UNCHECKED, /* BS_DEFPUSHBUTTON */ + BST_CHECKED, /* BS_CHECKBOX */ + BST_CHECKED, /* BS_AUTOCHECKBOX */ + BST_CHECKED, /* BS_RADIOBUTTON */ + BST_INDETERMINATE, /* BS_3STATE */ + BST_INDETERMINATE, /* BS_AUTO3STATE */ + BST_UNCHECKED, /* BS_GROUPBOX */ + BST_UNCHECKED, /* BS_USERBUTTON */ + BST_CHECKED, /* BS_AUTORADIOBUTTON */ + BST_UNCHECKED, /* BS_PUSHBOX */ + BST_UNCHECKED /* BS_OWNERDRAW */ }; typedef void (*pfPaint)( HWND hwnd, HDC hdc, UINT action ); @@ -135,7 +128,7 @@ static const pfPaint btnPaintFunc[MAX_BTN_TYPE] = GB_Paint, /* BS_GROUPBOX */ UB_Paint, /* BS_USERBUTTON */ CB_Paint, /* BS_AUTORADIOBUTTON */ - NULL, /* Not defined */ + NULL, /* BS_PUSHBOX */ OB_Paint /* BS_OWNERDRAW */ }; @@ -191,7 +184,7 @@ static inline void set_button_font( HWND hwnd, HFONT font ) static inline UINT get_button_type( LONG window_style ) { - return (window_style & 0x0f); + return (window_style & BS_TYPEMASK); } /* paint a button of any type */ @@ -214,15 +207,6 @@ static inline WCHAR *get_button_text( HWND hwnd ) return buffer; } -static void setup_clipping( HWND hwnd, HDC hdc ) -{ - RECT rc; - - GetClientRect( hwnd, &rc ); - DPtoLP( hdc, (POINT *)&rc, 2 ); - IntersectClipRect( hdc, rc.left, rc.top, rc.right, rc.bottom ); -} - /* Retrieve the UI state for the control */ static BOOL button_update_uistate(HWND hwnd, BOOL unicode) { @@ -313,10 +297,15 @@ LRESULT WINAPI ButtonWndProc_common(HWND hWnd, UINT uMsg, /* XP turns a BS_USERBUTTON into BS_PUSHBUTTON */ if (btn_type == BS_USERBUTTON ) { - style = (style & ~0x0f) | BS_PUSHBUTTON; +#ifdef __REACTOS__ + style = (style & ~BS_TYPEMASK) | BS_PUSHBUTTON; SetWindowLongPtrW( hWnd, GWL_STYLE, style ); +#else + style = (style & ~BS_TYPEMASK) | BS_PUSHBUTTON; + WIN_SetStyle( hWnd, style, BS_TYPEMASK & ~style ); +#endif } - set_button_state( hWnd, BUTTON_UNCHECKED ); + set_button_state( hWnd, BST_UNCHECKED ); button_update_uistate( hWnd, unicode ); return 0; @@ -389,7 +378,7 @@ LRESULT WINAPI ButtonWndProc_common(HWND hWnd, UINT uMsg, if (!(state & BUTTON_BTNPRESSED)) break; state &= BUTTON_NSTATES; set_button_state( hWnd, state ); - if (!(state & BUTTON_HIGHLIGHTED)) + if (!(state & BST_PUSHED)) { ReleaseCapture(); break; @@ -403,14 +392,14 @@ LRESULT WINAPI ButtonWndProc_common(HWND hWnd, UINT uMsg, switch(btn_type) { case BS_AUTOCHECKBOX: - SendMessageW( hWnd, BM_SETCHECK, !(state & BUTTON_CHECKED), 0 ); + SendMessageW( hWnd, BM_SETCHECK, !(state & BST_CHECKED), 0 ); break; case BS_AUTORADIOBUTTON: SendMessageW( hWnd, BM_SETCHECK, TRUE, 0 ); break; case BS_AUTO3STATE: SendMessageW( hWnd, BM_SETCHECK, - (state & BUTTON_3STATE) ? 0 : ((state & 3) + 1), 0 ); + (state & BST_INDETERMINATE) ? 0 : ((state & 3) + 1), 0 ); break; } BUTTON_NOTIFY_PARENT(hWnd, BN_CLICKED); @@ -424,7 +413,7 @@ LRESULT WINAPI ButtonWndProc_common(HWND hWnd, UINT uMsg, { state &= BUTTON_NSTATES; set_button_state( hWnd, state ); - if (state & BUTTON_HIGHLIGHTED) SendMessageW( hWnd, BM_SETSTATE, FALSE, 0 ); + if (state & BST_PUSHED) SendMessageW( hWnd, BM_SETSTATE, FALSE, 0 ); } break; @@ -490,7 +479,7 @@ LRESULT WINAPI ButtonWndProc_common(HWND hWnd, UINT uMsg, case WM_SETFOCUS: TRACE("WM_SETFOCUS %p\n",hWnd); - set_button_state( hWnd, get_button_state(hWnd) | BUTTON_HASFOCUS ); + set_button_state( hWnd, get_button_state(hWnd) | BST_FOCUS ); paint_button( hWnd, btn_type, ODA_FOCUS ); if (style & BS_NOTIFY) BUTTON_NOTIFY_PARENT(hWnd, BN_SETFOCUS); @@ -499,7 +488,7 @@ LRESULT WINAPI ButtonWndProc_common(HWND hWnd, UINT uMsg, case WM_KILLFOCUS: TRACE("WM_KILLFOCUS %p\n",hWnd); state = get_button_state( hWnd ); - set_button_state( hWnd, state & ~BUTTON_HASFOCUS ); + set_button_state( hWnd, state & ~BST_FOCUS ); paint_button( hWnd, btn_type, ODA_FOCUS ); if ((state & BUTTON_BTNPRESSED) && GetCapture() == hWnd) @@ -515,10 +504,11 @@ LRESULT WINAPI ButtonWndProc_common(HWND hWnd, UINT uMsg, break; case BM_SETSTYLE: - if ((wParam & 0x0f) >= MAX_BTN_TYPE) break; - btn_type = wParam & 0x0f; - style = (style & ~0x0f) | btn_type; + if ((wParam & BS_TYPEMASK) >= MAX_BTN_TYPE) break; + btn_type = wParam & BS_TYPEMASK; + style = (style & ~BS_TYPEMASK) | btn_type; SetWindowLongPtrW( hWnd, GWL_STYLE, style ); + //WIN_SetStyle( hWnd, style, BS_TYPEMASK & ~style ); /* Only redraw if lParam flag is set.*/ if (lParam) @@ -559,16 +549,21 @@ LRESULT WINAPI ButtonWndProc_common(HWND hWnd, UINT uMsg, state = get_button_state( hWnd ); if ((btn_type == BS_RADIOBUTTON) || (btn_type == BS_AUTORADIOBUTTON)) { +#ifdef __REACTOS__ if (wParam) style |= WS_TABSTOP; else style &= ~WS_TABSTOP; SetWindowLongPtrW( hWnd, GWL_STYLE, style ); +#else + if (wParam) WIN_SetStyle( hWnd, WS_TABSTOP, 0 ); + else WIN_SetStyle( hWnd, 0, WS_TABSTOP ); +#endif } if ((state & 3) != wParam) { set_button_state( hWnd, (state & ~3) | wParam ); paint_button( hWnd, btn_type, ODA_SELECT ); } - if ((btn_type == BS_AUTORADIOBUTTON) && (wParam == BUTTON_CHECKED) && (style & WS_CHILD)) + if ((btn_type == BS_AUTORADIOBUTTON) && (wParam == BST_CHECKED) && (style & WS_CHILD)) BUTTON_CheckAutoRadioButton( hWnd ); break; @@ -578,15 +573,10 @@ LRESULT WINAPI ButtonWndProc_common(HWND hWnd, UINT uMsg, case BM_SETSTATE: state = get_button_state( hWnd ); if (wParam) - { - if (state & BUTTON_HIGHLIGHTED) break; - set_button_state( hWnd, state | BUTTON_HIGHLIGHTED ); - } + set_button_state( hWnd, state | BST_PUSHED ); else - { - if (!(state & BUTTON_HIGHLIGHTED)) break; - set_button_state( hWnd, state & ~BUTTON_HIGHLIGHTED ); - } + set_button_state( hWnd, state & ~BST_PUSHED ); + paint_button( hWnd, btn_type, ODA_SELECT ); break; @@ -642,7 +632,7 @@ static UINT BUTTON_BStoDT( DWORD style, DWORD ex_style ) /* "Convert" pushlike buttons to pushbuttons */ if (style & BS_PUSHLIKE) - style &= ~0x0F; + style &= ~BS_TYPEMASK; if (!(style & BS_MULTILINE)) dtStyle |= DT_SINGLELINE; @@ -821,7 +811,7 @@ static void BUTTON_DrawLabel(HWND hwnd, HDC hdc, UINT dtFlags, const RECT *rc) * I don't have Win31 on hand to verify that, so I leave it as is. */ - if ((style & BS_PUSHLIKE) && (state & BUTTON_3STATE)) + if ((style & BS_PUSHLIKE) && (state & BST_INDETERMINATE)) { hbr = GetSysColorBrush(COLOR_GRAYTEXT); flags |= DSS_MONO; @@ -873,8 +863,9 @@ static void PB_Paint( HWND hwnd, HDC hDC, UINT action ) HFONT hFont; LONG state = get_button_state( hwnd ); LONG style = GetWindowLongPtrW( hwnd, GWL_STYLE ); - BOOL pushedState = (state & BUTTON_HIGHLIGHTED); + BOOL pushedState = (state & BST_PUSHED); HWND parent; + HRGN hrgn; GetClientRect( hwnd, &rc ); @@ -884,7 +875,7 @@ static void PB_Paint( HWND hwnd, HDC hDC, UINT action ) if (!parent) parent = hwnd; GetControlColor( parent, hwnd, hDC, WM_CTLCOLORBTN); - setup_clipping( hwnd, hDC ); + hrgn = set_control_clipping( hDC, &rc ); #ifdef __REACTOS__ hOldPen = SelectObject(hDC, GetStockObject(DC_PEN)); SetDCPenColor(hDC, GetSysColor(COLOR_WINDOWFRAME)); @@ -916,7 +907,7 @@ static void PB_Paint( HWND hwnd, HDC hDC, UINT action ) uState |= DFCS_PUSHED; } - if (state & (BUTTON_CHECKED | BUTTON_3STATE)) + if (state & (BST_CHECKED | BST_INDETERMINATE)) uState |= DFCS_CHECKED; DrawFrameControl( hDC, &rc, DFC_BUTTON, uState ); @@ -938,8 +929,7 @@ static void PB_Paint( HWND hwnd, HDC hDC, UINT action ) SetTextColor( hDC, oldTxtColor ); draw_focus: - if ((action == ODA_FOCUS) || - ((action == ODA_DRAWENTIRE) && (state & BUTTON_HASFOCUS))) + if (action == ODA_FOCUS || (state & BST_FOCUS)) { if (!(get_ui_state(hwnd) & UISF_HIDEFOCUS)) { @@ -952,6 +942,8 @@ draw_focus: SelectObject( hDC, hOldPen ); SelectObject( hDC, hOldBrush ); SetBkMode(hDC, oldBkMode); + SelectClipRgn( hDC, hrgn ); + if (hrgn) DeleteObject( hrgn ); } /********************************************************************** @@ -968,6 +960,7 @@ static void CB_Paint( HWND hwnd, HDC hDC, UINT action ) LONG state = get_button_state( hwnd ); LONG style = GetWindowLongPtrW( hwnd, GWL_STYLE ); HWND parent; + HRGN hrgn; if (style & BS_PUSHLIKE) { @@ -983,7 +976,7 @@ static void CB_Paint( HWND hwnd, HDC hDC, UINT action ) parent = GetParent(hwnd); if (!parent) parent = hwnd; hBrush = GetControlColor( parent, hwnd, hDC, WM_CTLCOLORSTATIC); - setup_clipping( hwnd, hDC ); + hrgn = set_control_clipping( hDC, &client ); if (style & BS_LEFTTEXT) { @@ -1020,11 +1013,11 @@ static void CB_Paint( HWND hwnd, HDC hDC, UINT action ) if ((get_button_type(style) == BS_RADIOBUTTON) || (get_button_type(style) == BS_AUTORADIOBUTTON)) flags = DFCS_BUTTONRADIO; - else if (state & BUTTON_3STATE) flags = DFCS_BUTTON3STATE; + else if (state & BST_INDETERMINATE) flags = DFCS_BUTTON3STATE; else flags = DFCS_BUTTONCHECK; - if (state & (BUTTON_CHECKED | BUTTON_3STATE)) flags |= DFCS_CHECKED; - if (state & BUTTON_HIGHLIGHTED) flags |= DFCS_PUSHED; + if (state & (BST_CHECKED | BST_INDETERMINATE)) flags |= DFCS_CHECKED; + if (state & BST_PUSHED) flags |= DFCS_PUSHED; if (style & WS_DISABLED) flags |= DFCS_INACTIVE; @@ -1067,8 +1060,7 @@ static void CB_Paint( HWND hwnd, HDC hDC, UINT action ) BUTTON_DrawLabel(hwnd, hDC, dtFlags, &rtext); /* ... and focus */ - if ((action == ODA_FOCUS) || - ((action == ODA_DRAWENTIRE) && (state & BUTTON_HASFOCUS))) + if (action == ODA_FOCUS || (state & BST_FOCUS)) { if (!(get_ui_state(hwnd) & UISF_HIDEFOCUS)) { @@ -1078,6 +1070,8 @@ static void CB_Paint( HWND hwnd, HDC hDC, UINT action ) DrawFocusRect( hDC, &rtext ); } } + SelectClipRgn( hDC, hrgn ); + if (hrgn) DeleteObject( hrgn ); } @@ -1097,8 +1091,8 @@ static void BUTTON_CheckAutoRadioButton( HWND hwnd ) { if (!sibling) break; if ((hwnd != sibling) && - ((GetWindowLongPtrW( sibling, GWL_STYLE) & 0x0f) == BS_AUTORADIOBUTTON)) - SendMessageW( sibling, BM_SETCHECK, BUTTON_UNCHECKED, 0 ); + ((GetWindowLongPtrW( sibling, GWL_STYLE) & BS_TYPEMASK) == BS_AUTORADIOBUTTON)) + SendMessageW( sibling, BM_SETCHECK, BST_UNCHECKED, 0 ); sibling = GetNextDlgGroupItem( parent, sibling, FALSE ); } while (sibling != start); } @@ -1117,16 +1111,17 @@ static void GB_Paint( HWND hwnd, HDC hDC, UINT action ) TEXTMETRICW tm; LONG style = GetWindowLongPtrW( hwnd, GWL_STYLE ); HWND parent; + HRGN hrgn; if ((hFont = get_button_font( hwnd ))) SelectObject( hDC, hFont ); /* GroupBox acts like static control, so it sends CTLCOLORSTATIC */ parent = GetParent(hwnd); if (!parent) parent = hwnd; hbr = GetControlColor( parent, hwnd, hDC, WM_CTLCOLORSTATIC); - setup_clipping( hwnd, hDC ); - + GetClientRect( hwnd, &rc); rcFrame = rc; + hrgn = set_control_clipping( hDC, &rc ); GetTextMetricsW (hDC, &tm); rcFrame.top += (tm.tmHeight / 2) - 1; @@ -1135,20 +1130,22 @@ static void GB_Paint( HWND hwnd, HDC hDC, UINT action ) InflateRect(&rc, -7, 1); dtFlags = BUTTON_CalcLabelRect(hwnd, hDC, &rc); - if (dtFlags == (UINT)-1L) - return; + if (dtFlags != (UINT)-1L) + { + /* Because buttons have CS_PARENTDC class style, there is a chance + * that label will be drawn out of client rect. + * But Windows doesn't clip label's rect, so do I. + */ - /* Because buttons have CS_PARENTDC class style, there is a chance - * that label will be drawn out of client rect. - * But Windows doesn't clip label's rect, so do I. - */ + /* There is 1-pixel margin at the left, right, and bottom */ + rc.left--; rc.right++; rc.bottom++; + FillRect(hDC, &rc, hbr); + rc.left++; rc.right--; rc.bottom--; - /* There is 1-pixel margin at the left, right, and bottom */ - rc.left--; rc.right++; rc.bottom++; - FillRect(hDC, &rc, hbr); - rc.left++; rc.right--; rc.bottom--; - - BUTTON_DrawLabel(hwnd, hDC, dtFlags, &rc); + BUTTON_DrawLabel(hwnd, hDC, dtFlags, &rc); + } + SelectClipRgn( hDC, hrgn ); + if (hrgn) DeleteObject( hrgn ); } @@ -1164,8 +1161,6 @@ static void UB_Paint( HWND hwnd, HDC hDC, UINT action ) LONG state = get_button_state( hwnd ); HWND parent; - if (action == ODA_SELECT) return; - GetClientRect( hwnd, &rc); if ((hFont = get_button_font( hwnd ))) SelectObject( hDC, hFont ); @@ -1175,14 +1170,26 @@ static void UB_Paint( HWND hwnd, HDC hDC, UINT action ) hBrush = GetControlColor( parent, hwnd, hDC, WM_CTLCOLORBTN); FillRect( hDC, &rc, hBrush ); - if ((action == ODA_FOCUS) || - ((action == ODA_DRAWENTIRE) && (state & BUTTON_HASFOCUS))) + if (action == ODA_FOCUS || (state & BST_FOCUS)) { if (!(get_ui_state(hwnd) & UISF_HIDEFOCUS)) DrawFocusRect( hDC, &rc ); } - BUTTON_NOTIFY_PARENT( hwnd, BN_PAINT ); + switch (action) + { + case ODA_FOCUS: + BUTTON_NOTIFY_PARENT( hwnd, (state & BST_FOCUS) ? BN_SETFOCUS : BN_KILLFOCUS ); + break; + + case ODA_SELECT: + BUTTON_NOTIFY_PARENT( hwnd, (state & BST_PUSHED) ? BN_HILITE : BN_UNHILITE ); + break; + + default: + BUTTON_NOTIFY_PARENT( hwnd, BN_PAINT ); + break; + } } @@ -1197,13 +1204,14 @@ static void OB_Paint( HWND hwnd, HDC hDC, UINT action ) LONG_PTR id = GetWindowLongPtrW( hwnd, GWLP_ID ); HWND parent; HFONT hFont, hPrevFont = 0; + HRGN hrgn; dis.CtlType = ODT_BUTTON; dis.CtlID = id; dis.itemID = 0; dis.itemAction = action; - dis.itemState = ((state & BUTTON_HASFOCUS) ? ODS_FOCUS : 0) | - ((state & BUTTON_HIGHLIGHTED) ? ODS_SELECTED : 0) | + dis.itemState = ((state & BST_FOCUS) ? ODS_FOCUS : 0) | + ((state & BST_PUSHED) ? ODS_SELECTED : 0) | (IsWindowEnabled(hwnd) ? 0: ODS_DISABLED); dis.hwndItem = hwnd; dis.hDC = hDC; @@ -1215,8 +1223,10 @@ static void OB_Paint( HWND hwnd, HDC hDC, UINT action ) if (!parent) parent = hwnd; GetControlColor( parent, hwnd, hDC, WM_CTLCOLORBTN); - setup_clipping( hwnd, hDC ); + hrgn = set_control_clipping( hDC, &dis.rcItem ); SendMessageW( GetParent(hwnd), WM_DRAWITEM, id, (LPARAM)&dis ); if (hPrevFont) SelectObject(hDC, hPrevFont); + SelectClipRgn( hDC, hrgn ); + if (hrgn) DeleteObject( hrgn ); } diff --git a/reactos/dll/win32/user32/controls/combo.c b/reactos/dll/win32/user32/controls/combo.c index 6d053f5a58d..0edcbf73945 100644 --- a/reactos/dll/win32/user32/controls/combo.c +++ b/reactos/dll/win32/user32/controls/combo.c @@ -751,19 +751,6 @@ static void CBPaintText( !(lphc->wState & CBF_DROPPED) ) itemState |= ODS_SELECTED | ODS_FOCUS; - /* - * Save the current clip region. - * To retrieve the clip region, we need to create one "dummy" - * clip region. - */ - clipRegion = CreateRectRgnIndirect(&rectEdit); - - if (GetClipRgn(hdc, clipRegion)!=1) - { - DeleteObject(clipRegion); - clipRegion=NULL; - } - if (!IsWindowEnabled(lphc->self)) itemState |= ODS_DISABLED; dis.CtlType = ODT_COMBOBOX; @@ -774,22 +761,17 @@ static void CBPaintText( dis.itemState = itemState; dis.hDC = hdc; dis.rcItem = rectEdit; - dis.itemData = SendMessageW(lphc->hWndLBox, LB_GETITEMDATA, - (WPARAM)id, 0 ); + dis.itemData = SendMessageW(lphc->hWndLBox, LB_GETITEMDATA, id, 0 ); /* * Clip the DC and have the parent draw the item. */ - IntersectClipRect(hdc, - rectEdit.left, rectEdit.top, - rectEdit.right, rectEdit.bottom); + clipRegion = set_control_clipping( hdc, &rectEdit ); SendMessageW(lphc->owner, WM_DRAWITEM, ctlid, (LPARAM)&dis ); - /* - * Reset the clipping region. - */ - SelectClipRgn(hdc, clipRegion); + SelectClipRgn( hdc, clipRegion); + if (clipRegion) DeleteObject( clipRegion ); } else { @@ -2153,14 +2135,24 @@ LRESULT WINAPI ComboWndProc_common( HWND hwnd, UINT message, return SendMessageW(lphc->hWndLBox, LB_GETLOCALE, 0, 0); case CB_SETLOCALE: return SendMessageW(lphc->hWndLBox, LB_SETLOCALE, wParam, 0); + case CB_SETDROPPEDWIDTH: + if( (CB_GETTYPE(lphc) == CBS_SIMPLE) || + (INT)wParam >= 32768 ) + return CB_ERR; + /* new value must be higher than combobox width */ + if((INT)wParam >= lphc->droppedRect.right - lphc->droppedRect.left) + lphc->droppedWidth = wParam; + else if(wParam) + lphc->droppedWidth = 0; + + /* recalculate the combobox area */ + CBCalcPlacement(hwnd, lphc, &lphc->textRect, &lphc->buttonRect, &lphc->droppedRect ); + + /* fall through */ case CB_GETDROPPEDWIDTH: if( lphc->droppedWidth ) return lphc->droppedWidth; return lphc->droppedRect.right - lphc->droppedRect.left; - case CB_SETDROPPEDWIDTH: - if( (CB_GETTYPE(lphc) != CBS_SIMPLE) && - (INT)wParam < 32768 ) lphc->droppedWidth = (INT)wParam; - return CB_ERR; case CB_GETDROPPEDCONTROLRECT: if( lParam ) CBGetDroppedControlRect(lphc, (LPRECT)lParam ); return CB_OKAY; @@ -2233,7 +2225,7 @@ LRESULT WINAPI ComboWndProc_common( HWND hwnd, UINT message, case CB_LIMITTEXT: if( lphc->wState & CBF_EDIT ) return SendMessageW(lphc->hWndEdit, EM_LIMITTEXT, wParam, lParam); - break; // ReactOS!!! removed at revision 38715 + return TRUE; case WM_UPDATEUISTATE: if (unicode) diff --git a/reactos/dll/win32/user32/controls/edit.c b/reactos/dll/win32/user32/controls/edit.c index 3fd65ef8883..8401b22c980 100644 --- a/reactos/dll/win32/user32/controls/edit.c +++ b/reactos/dll/win32/user32/controls/edit.c @@ -85,6 +85,7 @@ typedef struct tagLINEDEF { LINE_END ending; INT width; /* width of the line in pixels */ INT index; /* line index into the buffer */ + SCRIPT_STRING_ANALYSIS ssa; /* Uniscribe Data */ struct tagLINEDEF *next; } LINEDEF; @@ -141,6 +142,11 @@ typedef struct */ UINT composition_len; /* length of composition, 0 == no composition */ int composition_start; /* the character position for the composition */ + /* + * Uniscribe Data + */ + SCRIPT_LOGATTR *logAttr; + SCRIPT_STRING_ANALYSIS ssa; /* Uniscribe Data for single line controls */ } EDITSTATE; @@ -158,6 +164,7 @@ typedef struct } while(0) static const WCHAR empty_stringW[] = {0}; +static LRESULT EDIT_EM_PosFromChar(EDITSTATE *es, INT index, BOOL after_wrap); /********************************************************************* * @@ -233,6 +240,14 @@ static HBRUSH EDIT_NotifyCtlColor(EDITSTATE *es, HDC hdc) } +static inline UINT get_text_length(EDITSTATE *es) +{ + if(es->text_length == (UINT)-1) + es->text_length = strlenW(es->text); + return es->text_length; +} + + /********************************************************************* * * EDIT_WordBreakProc @@ -242,61 +257,51 @@ static HBRUSH EDIT_NotifyCtlColor(EDITSTATE *es, HDC hdc) * allows to be called without linebreaks between s[0] up to * s[count - 1]. Remember it is only called * internally, so we can decide this for ourselves. + * Additional we will always be breaking the full string. * */ -static INT EDIT_WordBreakProc(LPWSTR s, INT index, INT count, INT action) +static INT EDIT_WordBreakProc(EDITSTATE *es, LPWSTR s, INT index, INT count, INT action) { - INT ret = 0; + INT ret = 0; - TRACE("s=%p, index=%d, count=%d, action=%d\n", s, index, count, action); + TRACE("s=%p, index=%d, count=%d, action=%d\n", s, index, count, action); - if(!s) return 0; + if(!s) return 0; - 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: - ERR("unknown action code, please report !\n"); - break; - } - return ret; + if (!es->logAttr) + { + SCRIPT_ANALYSIS psa; + + memset(&psa,0,sizeof(SCRIPT_ANALYSIS)); + psa.eScript = SCRIPT_UNDEFINED; + + es->logAttr = HeapAlloc(GetProcessHeap(), 0, sizeof(SCRIPT_LOGATTR) * get_text_length(es)); + ScriptBreak(es->text, get_text_length(es), &psa, es->logAttr); + } + + switch (action) { + case WB_LEFT: + if (index) + index--; + while (index && !es->logAttr[index].fSoftBreak) + index--; + ret = index; + break; + case WB_RIGHT: + if (!count) + break; + while (s[index] && index < count && !es->logAttr[index].fSoftBreak) + index++; + ret = index; + break; + case WB_ISDELIMITER: + ret = es->logAttr[index].fWhiteSpace; + break; + default: + ERR("unknown action code, please report !\n"); + break; + } + return ret; } @@ -344,11 +349,110 @@ static INT EDIT_CallWordBreakProc(EDITSTATE *es, INT start, INT index, INT count } } else - ret = EDIT_WordBreakProc(es->text + start, index, count, action); + ret = EDIT_WordBreakProc(es, es->text, index+start, count+start, action) - start; return ret; } +static inline void EDIT_InvalidateUniscribeData_linedef(LINEDEF *line_def) +{ + if (line_def->ssa) + { + ScriptStringFree(&line_def->ssa); + line_def->ssa = NULL; + } +} + +static inline void EDIT_InvalidateUniscribeData(EDITSTATE *es) +{ + LINEDEF *line_def = es->first_line_def; + while (line_def) + { + EDIT_InvalidateUniscribeData_linedef(line_def); + line_def = line_def->next; + } + if (es->ssa) + { + ScriptStringFree(&es->ssa); + es->ssa = NULL; + } +} + +static SCRIPT_STRING_ANALYSIS EDIT_UpdateUniscribeData_linedef(EDITSTATE *es, HDC dc, LINEDEF *line_def) +{ + if (!line_def) + return NULL; + + if (line_def->net_length && !line_def->ssa) + { + int index = line_def->index; + HFONT old_font = NULL; + HDC udc = dc; + SCRIPT_TABDEF tabdef; + + if (!udc) + udc = GetDC(es->hwndSelf); + if (es->font) + old_font = SelectObject(udc, es->font); + + tabdef.cTabStops = es->tabs_count; + tabdef.iScale = 0; + tabdef.pTabStops = es->tabs; + tabdef.iTabOrigin = 0; + + ScriptStringAnalyse(udc, &es->text[index], line_def->net_length, (1.5*line_def->net_length+16), -1, SSA_LINK|SSA_FALLBACK|SSA_GLYPHS|SSA_TAB, -1, NULL, NULL, NULL, &tabdef, NULL, &line_def->ssa); + + if (es->font) + SelectObject(udc, old_font); + if (udc != dc) + ReleaseDC(es->hwndSelf, udc); + } + + return line_def->ssa; +} + +static SCRIPT_STRING_ANALYSIS EDIT_UpdateUniscribeData(EDITSTATE *es, HDC dc, INT line) +{ + LINEDEF *line_def; + + if (!(es->style & ES_MULTILINE)) + { + if (!es->ssa) + { + INT length = get_text_length(es); + HFONT old_font = NULL; + HDC udc = dc; + + if (!udc) + udc = GetDC(es->hwndSelf); + if (es->font) + old_font = SelectObject(udc, es->font); + + if (es->style & ES_PASSWORD) + ScriptStringAnalyse(udc, &es->password_char, length, (1.5*length+16), -1, SSA_LINK|SSA_FALLBACK|SSA_GLYPHS|SSA_PASSWORD, -1, NULL, NULL, NULL, NULL, NULL, &es->ssa); + else + ScriptStringAnalyse(udc, es->text, length, (1.5*length+16), -1, SSA_LINK|SSA_FALLBACK|SSA_GLYPHS, -1, NULL, NULL, NULL, NULL, NULL, &es->ssa); + + if (es->font) + SelectObject(udc, old_font); + if (udc != dc) + ReleaseDC(es->hwndSelf, udc); + } + return es->ssa; + } + else + { + line_def = es->first_line_def; + while (line_def && line) + { + line_def = line_def->next; + line--; + } + + return EDIT_UpdateUniscribeData_linedef(es,dc,line_def); + } +} + /********************************************************************* * * EDIT_BuildLineDefs_ML @@ -360,8 +464,6 @@ static INT EDIT_CallWordBreakProc(EDITSTATE *es, INT start, INT index, INT count */ static void EDIT_BuildLineDefs_ML(EDITSTATE *es, INT istart, INT iend, INT delta, HRGN hrgn) { - HDC dc; - HFONT old_font = 0; LPWSTR current_position, cp; INT fw; LINEDEF *current_line; @@ -375,10 +477,6 @@ static void EDIT_BuildLineDefs_ML(EDITSTATE *es, INT istart, INT iend, INT delta if (istart == iend && delta == 0) return; - dc = GetDC(es->hwndSelf); - if (es->font) - old_font = SelectObject(dc, es->font); - previous_line = NULL; current_line = es->first_line_def; @@ -397,7 +495,6 @@ static void EDIT_BuildLineDefs_ML(EDITSTATE *es, INT istart, INT iend, INT delta if (!current_line) /* Error occurred start is not inside previous buffer */ { FIXME(" modification occurred outside buffer\n"); - ReleaseDC(es->hwndSelf, dc); return; } @@ -423,9 +520,9 @@ static void EDIT_BuildLineDefs_ML(EDITSTATE *es, INT istart, INT iend, INT delta { /* The buffer has been expanded, create a new line and insert it into the link list */ - LINEDEF *new_line = HeapAlloc(GetProcessHeap(), 0, sizeof(LINEDEF)); - if (new_line == NULL) // reactos r33509 - break; // reactos r33509 + LINEDEF *new_line = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LINEDEF)); + if (new_line == NULL) // reactos r33509 + break; // reactos r33509 new_line->next = previous_line->next; previous_line->next = new_line; current_line = new_line; @@ -475,33 +572,69 @@ static void EDIT_BuildLineDefs_ML(EDITSTATE *es, INT istart, INT iend, INT delta current_line->net_length = cp - current_position; } - /* Calculate line width */ - current_line->width = (INT)LOWORD(GetTabbedTextExtentW(dc, - current_position, current_line->net_length, - es->tabs_count, es->tabs)); + if (current_line->net_length) + { + const SIZE *sz; + EDIT_InvalidateUniscribeData_linedef(current_line); + EDIT_UpdateUniscribeData_linedef(es, NULL, current_line); + sz = ScriptString_pSize(current_line->ssa); + /* Calculate line width */ + current_line->width = sz->cx; + } + else current_line->width = 0; /* FIXME: check here for lines that are too wide even in AUTOHSCROLL (> 32767 ???) */ + +/* Line breaks just look back from the end and find the next break and try that. */ + if (!(es->style & ES_AUTOHSCROLL)) { - if (current_line->width > fw) { - INT next = 0; - INT prev; + if (current_line->width > fw && fw > es->char_width) { + + INT prev, next; + int w; + const SIZE *sz; + float d; + + prev = current_line->net_length - 1; + w = current_line->net_length; + d = (float)current_line->width/(float)fw; + if (d > 1.2) d -= 0.2; + next = prev/d; + if (next >= prev) next = prev-1; do { - prev = next; - next = EDIT_CallWordBreakProc(es, current_position - es->text, - prev + 1, current_line->net_length, WB_RIGHT); - current_line->width = (INT)LOWORD(GetTabbedTextExtentW(dc, - current_position, next, es->tabs_count, es->tabs)); - } while (current_line->width <= fw); - if (!prev) { /* Didn't find a line break so force a break */ - next = 0; + prev = EDIT_CallWordBreakProc(es, current_position - es->text, + next, current_line->net_length, WB_LEFT); + current_line->net_length = prev; + EDIT_InvalidateUniscribeData_linedef(current_line); + EDIT_UpdateUniscribeData_linedef(es, NULL, current_line); + sz = ScriptString_pSize(current_line->ssa); + if (sz) + current_line->width = sz->cx; + else + prev = 0; + next = prev - 1; + } while (prev && current_line->width > fw); + current_line->net_length = w; + + if (prev == 0) { /* Didn't find a line break so force a break */ + INT *piDx; + const INT *count; + + EDIT_InvalidateUniscribeData_linedef(current_line); + EDIT_UpdateUniscribeData_linedef(es, NULL, current_line); + + count = ScriptString_pcOutChars(current_line->ssa); + piDx = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * (*count)); + ScriptStringGetLogicalWidths(current_line->ssa,piDx); + + prev = current_line->net_length-1; do { - prev = next; - next++; - current_line->width = (INT)LOWORD(GetTabbedTextExtentW(dc, - current_position, next, es->tabs_count, es->tabs)); - } while (current_line->width <= fw); - if (!prev) + current_line->width -= piDx[prev]; + prev--; + } while ( prev > 0 && current_line->width > fw); + if (prev<=0) prev = 1; + HeapFree(GetProcessHeap(),0,piDx); } /* If the first line we are calculating, wrapped before istart, we must @@ -522,8 +655,14 @@ static void EDIT_BuildLineDefs_ML(EDITSTATE *es, INT istart, INT iend, INT delta current_line->net_length = prev; current_line->ending = END_WRAP; - current_line->width = (INT)LOWORD(GetTabbedTextExtentW(dc, current_position, - current_line->net_length, es->tabs_count, es->tabs)); + + if (current_line->net_length > 0) + { + EDIT_UpdateUniscribeData_linedef(es, NULL, current_line); + sz = ScriptString_pSize(current_line->ssa); + current_line->width = sz->cx; + } + else current_line->width = 0; } else if (current_line == start_line && current_line->index != nstart_index && @@ -570,6 +709,7 @@ static void EDIT_BuildLineDefs_ML(EDITSTATE *es, INT istart, INT iend, INT delta while (current_line) { pnext = current_line->next; + EDIT_InvalidateUniscribeData_linedef(current_line); HeapFree(GetProcessHeap(), 0, current_line); current_line = pnext; es->line_count--; @@ -599,9 +739,7 @@ static void EDIT_BuildLineDefs_ML(EDITSTATE *es, INT istart, INT iend, INT delta if ((es->style & ES_CENTER) || (es->style & ES_RIGHT)) rc.left = es->format_rect.left; else - rc.left = es->format_rect.left + (INT)LOWORD(GetTabbedTextExtentW(dc, - es->text + nstart_index, istart - nstart_index, - es->tabs_count, es->tabs)) - es->x_offset; /* Adjust for horz scroll */ + rc.left = LOWORD(EDIT_EM_PosFromChar(es, nstart_index, FALSE)); rc.right = es->format_rect.right; SetRectRgn(hrgn, rc.left, rc.top, rc.right, rc.bottom); @@ -624,40 +762,6 @@ static void EDIT_BuildLineDefs_ML(EDITSTATE *es, INT istart, INT iend, INT delta CombineRgn(hrgn, hrgn, tmphrgn, RGN_OR); DeleteObject(tmphrgn); } - - if (es->font) - SelectObject(dc, old_font); - - ReleaseDC(es->hwndSelf, dc); -} - - -static inline UINT get_text_length(EDITSTATE *es) -{ - if(es->text_length == (UINT)-1) - es->text_length = strlenW(es->text); - return es->text_length; -} - -/********************************************************************* - * - * EDIT_GetPasswordPointer_SL - * - * note: caller should free the (optionally) allocated buffer - * - */ -static LPWSTR EDIT_GetPasswordPointer_SL(EDITSTATE *es) -{ - if (es->style & ES_PASSWORD) { - INT len = get_text_length(es); - LPWSTR text = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR)); - if (text == NULL) - return NULL; - text[len] = '\0'; - while(len) text[--len] = es->password_char; - return text; - } else - return es->text; } @@ -668,27 +772,15 @@ static LPWSTR EDIT_GetPasswordPointer_SL(EDITSTATE *es) */ static void EDIT_CalcLineWidth_SL(EDITSTATE *es) { - SIZE size; - LPWSTR text; - HDC dc; - HFONT old_font = 0; - - text = EDIT_GetPasswordPointer_SL(es); - - dc = GetDC(es->hwndSelf); - if (es->font) - old_font = SelectObject(dc, es->font); - - GetTextExtentPoint32W(dc, text, strlenW(text), &size); - - if (es->font) - SelectObject(dc, old_font); - ReleaseDC(es->hwndSelf, dc); - - if (es->style & ES_PASSWORD) - HeapFree(GetProcessHeap(), 0, text); - - es->text_width = size.cx; + EDIT_UpdateUniscribeData(es, NULL, 0); + if (es->ssa) + { + const SIZE *size; + size = ScriptString_pSize(es->ssa); + es->text_width = size->cx; + } + else + es->text_width = 0; } /********************************************************************* @@ -704,20 +796,19 @@ static void EDIT_CalcLineWidth_SL(EDITSTATE *es) static INT EDIT_CharFromPos(EDITSTATE *es, INT x, INT y, LPBOOL after_wrap) { INT index; - HDC dc; - HFONT old_font = 0; - INT x_high = 0, x_low = 0; if (es->style & ES_MULTILINE) { + int trailing; 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; + EDIT_UpdateUniscribeData(es, NULL, line); 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 (es->style & ES_RIGHT) x -= (es->format_rect.right - es->format_rect.left) - line_def->width; @@ -728,39 +819,21 @@ static INT EDIT_CharFromPos(EDITSTATE *es, INT x, INT y, LPBOOL after_wrap) *after_wrap = (line_def->ending == END_WRAP); return line_index + line_def->net_length; } - if (x <= 0) { + if (x <= 0 || !line_def->ssa) { if (after_wrap) *after_wrap = FALSE; return line_index; } - dc = GetDC(es->hwndSelf); - if (es->font) - old_font = SelectObject(dc, es->font); - low = line_index; - high = line_index + line_def->net_length + 1; - while (low < high - 1) - { - INT mid = (low + high) / 2; - INT x_now = LOWORD(GetTabbedTextExtentW(dc, es->text + line_index, mid - line_index, es->tabs_count, es->tabs)); - if (x_now > x) { - high = mid; - x_high = x_now; - } else { - low = mid; - x_low = x_now; - } - } - if (abs(x_high - x) + 1 <= abs(x_low - x)) - index = high; - else - index = low; + ScriptStringXtoCP(line_def->ssa, x , &index, &trailing); + if (trailing) index++; + index += line_index; if (after_wrap) *after_wrap = ((index == line_index + line_def->net_length) && (line_def->ending == END_WRAP)); } else { - LPWSTR text; - SIZE size; + INT xoff = 0; + INT trailing; if (after_wrap) *after_wrap = FALSE; x -= es->format_rect.left; @@ -776,60 +849,55 @@ static INT EDIT_CharFromPos(EDITSTATE *es, INT x, INT y, LPBOOL after_wrap) x -= indent / 2; } - text = EDIT_GetPasswordPointer_SL(es); - dc = GetDC(es->hwndSelf); - if (es->font) - old_font = SelectObject(dc, es->font); + EDIT_UpdateUniscribeData(es, NULL, 0); + if (es->x_offset) + { + if (es->ssa) + { + if (es->x_offset>= get_text_length(es)) + { + const SIZE *size; + size = ScriptString_pSize(es->ssa); + xoff = size->cx; + } + ScriptStringCPtoX(es->ssa, es->x_offset, FALSE, &xoff); + } + else + xoff = 0; + } if (x < 0) - { - INT low = 0; - INT high = es->x_offset; - while (low < high - 1) - { - INT mid = (low + high) / 2; - GetTextExtentPoint32W( dc, text + mid, - es->x_offset - mid, &size ); - if (size.cx > -x) { - low = mid; - x_low = size.cx; - } else { - high = mid; - x_high = size.cx; - } - } - if (abs(x_high + x) <= abs(x_low + x) + 1) - index = high; - else - index = low; + { + if (x + xoff > 0 || !es->ssa) + { + ScriptStringXtoCP(es->ssa, x+xoff, &index, &trailing); + if (trailing) index++; + } + else + index = 0; } - else - { - INT low = es->x_offset; - INT high = get_text_length(es) + 1; - while (low < high - 1) - { - INT mid = (low + high) / 2; - GetTextExtentPoint32W( dc, text + es->x_offset, - mid - es->x_offset, &size ); - if (size.cx > x) { - high = mid; - x_high = size.cx; - } else { - low = mid; - x_low = size.cx; - } - } - if (abs(x_high - x) <= abs(x_low - x) + 1) - index = high; - else - index = low; + else + { + if (x) + { + const SIZE *size = NULL; + if (es->ssa) + size = ScriptString_pSize(es->ssa); + if (!size) + index = 0; + else if (x > size->cx) + index = get_text_length(es); + else if (es->ssa) + { + ScriptStringXtoCP(es->ssa, x+xoff, &index, &trailing); + if (trailing) index++; + } + else + index = 0; + } + else + index = es->x_offset; } - if (es->style & ES_PASSWORD) - HeapFree(GetProcessHeap(), 0, text); } - if (es->font) - SelectObject(dc, old_font); - ReleaseDC(es->hwndSelf, dc); return index; } @@ -959,22 +1027,17 @@ static LRESULT EDIT_EM_PosFromChar(EDITSTATE *es, INT index, BOOL after_wrap) INT len = get_text_length(es); INT l; INT li; - INT x; + INT x = 0; INT y = 0; INT w; INT lw = 0; - INT ll = 0; - HDC dc; - HFONT old_font = 0; - SIZE size; LINEDEF *line_def; index = min(index, len); - dc = GetDC(es->hwndSelf); - if (es->font) - old_font = SelectObject(dc, es->font); if (es->style & ES_MULTILINE) { l = EDIT_EM_LineFromChar(es, index); + EDIT_UpdateUniscribeData(es, NULL, l); + y = (l - es->y_offset) * es->line_height; li = EDIT_EM_LineIndex(es, l); if (after_wrap && (li == index) && l) { @@ -995,38 +1058,63 @@ static LRESULT EDIT_EM_PosFromChar(EDITSTATE *es, INT index, BOOL after_wrap) while (line_def->index != li) line_def = line_def->next; - ll = line_def->net_length; + if (!line_def->ssa) + return 0; + lw = line_def->width; - w = es->format_rect.right - es->format_rect.left; - if (es->style & ES_RIGHT) - { - x = LOWORD(GetTabbedTextExtentW(dc, es->text + li + (index - li), ll - (index - li), - es->tabs_count, es->tabs)) - es->x_offset; - x = w - x; - } - else if (es->style & ES_CENTER) - { - x = LOWORD(GetTabbedTextExtentW(dc, es->text + li, index - li, - es->tabs_count, es->tabs)) - es->x_offset; - x += (w - lw) / 2; - } - else /* ES_LEFT */ - { - x = LOWORD(GetTabbedTextExtentW(dc, es->text + li, index - li, - es->tabs_count, es->tabs)) - es->x_offset; - } - } else { - LPWSTR text = EDIT_GetPasswordPointer_SL(es); - if (index < es->x_offset) { - GetTextExtentPoint32W(dc, text + index, - es->x_offset - index, &size); - x = -size.cx; - } else { - GetTextExtentPoint32W(dc, text + es->x_offset, - index - es->x_offset, &size); - x = size.cx; + ScriptStringCPtoX(line_def->ssa, (index - 1) - li, TRUE, &x); + x -= es->x_offset; + if (es->style & ES_RIGHT) + x = w - (lw - x); + else if (es->style & ES_CENTER) + x += (w - lw) / 2; + } else { + INT xoff = 0; + INT xi = 0; + EDIT_UpdateUniscribeData(es, NULL, 0); + if (es->x_offset) + { + if (es->ssa) + { + if (es->x_offset >= get_text_length(es)) + { + if (es->ssa) + { + const SIZE *size; + size = ScriptString_pSize(es->ssa); + xoff = size->cx; + } + else + xoff = 0; + } + ScriptStringCPtoX(es->ssa, es->x_offset, FALSE, &xoff); + } + else + xoff = 0; + } + if (index) + { + if (index >= get_text_length(es)) + { + if (es->ssa) + { + const SIZE *size; + size = ScriptString_pSize(es->ssa); + xi = size->cx; + } + else + xi = 0; + } + else if (es->ssa) + ScriptStringCPtoX(es->ssa, index, FALSE, &xi); + else + xi = 0; + } + x = xi - xoff; + + if (index >= es->x_offset) { if (!es->x_offset && (es->style & (ES_RIGHT | ES_CENTER))) { w = es->format_rect.right - es->format_rect.left; @@ -1040,14 +1128,9 @@ static LRESULT EDIT_EM_PosFromChar(EDITSTATE *es, INT index, BOOL after_wrap) } } y = 0; - if (es->style & ES_PASSWORD) - HeapFree(GetProcessHeap(), 0, text); } x += es->format_rect.left; y += es->format_rect.top; - if (es->font) - SelectObject(dc, old_font); - ReleaseDC(es->hwndSelf, dc); return MAKELONG((INT16)x, (INT16)y); } @@ -1063,20 +1146,27 @@ static LRESULT EDIT_EM_PosFromChar(EDITSTATE *es, INT index, BOOL after_wrap) static void EDIT_GetLineRect(EDITSTATE *es, INT line, INT scol, INT ecol, LPRECT rc) { INT line_index = EDIT_EM_LineIndex(es, line); + INT pt1, pt2; 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 : (short)LOWORD(EDIT_EM_PosFromChar(es, line_index + scol, TRUE)); - rc->right = (ecol == -1) ? es->format_rect.right : (short)LOWORD(EDIT_EM_PosFromChar(es, line_index + ecol, TRUE)); + pt1 = (scol == 0) ? es->format_rect.left : (short)LOWORD(EDIT_EM_PosFromChar(es, line_index + scol, TRUE)); + pt2 = (ecol == -1) ? es->format_rect.right : (short)LOWORD(EDIT_EM_PosFromChar(es, line_index + ecol, TRUE)); + rc->right = max(pt1 , pt2); + rc->left = min(pt1, pt2); } static inline void text_buffer_changed(EDITSTATE *es) { es->text_length = (UINT)-1; + + HeapFree( GetProcessHeap(), 0, es->logAttr ); + es->logAttr = NULL; + EDIT_InvalidateUniscribeData(es); } /********************************************************************* @@ -2035,7 +2125,7 @@ static INT EDIT_PaintText(EDITSTATE *es, HDC dc, INT x, INT y, INT line, INT col ret = (INT)LOWORD(TabbedTextOutW(dc, x, y, es->text + li + col, count, es->tabs_count, es->tabs, es->format_rect.left - es->x_offset)); } else { - LPWSTR text = EDIT_GetPasswordPointer_SL(es); + LPWSTR text = es->text; TextOutW(dc, x, y, text + li + col, count); GetTextExtentPoint32W(dc, text + li + col, count, &size); ret = size.cx; @@ -2068,13 +2158,14 @@ static INT EDIT_PaintText(EDITSTATE *es, HDC dc, INT x, INT y, INT line, INT col */ static void EDIT_PaintLine(EDITSTATE *es, HDC dc, INT line, BOOL rev) { - INT s = es->selection_start; - INT e = es->selection_end; - INT li; - INT ll; + INT s = 0; + INT e = 0; + INT li = 0; + INT ll = 0; INT x; INT y; LRESULT pos; + SCRIPT_STRING_ANALYSIS ssa; if (es->style & ES_MULTILINE) { INT vlc = get_vertical_line_count(es); @@ -2086,16 +2177,49 @@ static void EDIT_PaintLine(EDITSTATE *es, HDC dc, INT line, BOOL rev) TRACE("line=%d\n", line); + ssa = EDIT_UpdateUniscribeData(es, dc, line); pos = EDIT_EM_PosFromChar(es, EDIT_EM_LineIndex(es, line), FALSE); x = (short)LOWORD(pos); y = (short)HIWORD(pos); - li = EDIT_EM_LineIndex(es, line); - ll = EDIT_EM_LineLength(es, li); - s = min(es->selection_start, es->selection_end); - e = max(es->selection_start, es->selection_end); - s = min(li + ll, max(li, s)); - e = min(li + ll, max(li, e)); - if (rev && (s != e) && + + if (es->style & ES_MULTILINE) + { + int line_idx = line; + x = -es->x_offset; + if (es->style & ES_RIGHT || es->style & ES_CENTER) + { + LINEDEF *line_def = es->first_line_def; + int w, lw; + + while (line_def && line_idx) + { + line_def = line_def->next; + line_idx--; + } + w = es->format_rect.right - es->format_rect.left; + lw = line_def->width; + + if (es->style & ES_RIGHT) + x = w - (lw - x); + else if (es->style & ES_CENTER) + x += (w - lw) / 2; + } + x += es->format_rect.left; + } + + if (rev) + { + li = EDIT_EM_LineIndex(es, line); + ll = EDIT_EM_LineLength(es, li); + s = min(es->selection_start, es->selection_end); + e = max(es->selection_start, es->selection_end); + s = min(li + ll, max(li, s)); + e = min(li + ll, max(li, e)); + } + + if (ssa) + ScriptStringOut(ssa, x, y, 0, &es->format_rect, s - li, e - li, FALSE); + else if (rev && (s != e) && ((es->flags & EF_FOCUSED) || (es->style & ES_NOHIDESEL))) { x += EDIT_PaintText(es, dc, x, y, line, 0, s - li, FALSE); x += EDIT_PaintText(es, dc, x, y, line, s - li, e - s, TRUE); @@ -2391,6 +2515,7 @@ static void EDIT_EM_ReplaceSel(EDITSTATE *es, BOOL can_undo, LPCWSTR lpsz_replac s = es->selection_start; e = es->selection_end; + EDIT_InvalidateUniscribeData(es); if ((s == e) && !strl) return; @@ -2466,12 +2591,15 @@ static void EDIT_EM_ReplaceSel(EDITSTATE *es, BOOL can_undo, LPCWSTR lpsz_replac } else { INT fw = es->format_rect.right - es->format_rect.left; + EDIT_InvalidateUniscribeData(es); EDIT_CalcLineWidth_SL(es); /* remove chars that don't fit */ if (honor_limit && !(es->style & ES_AUTOHSCROLL) && (es->text_width > fw)) { while ((es->text_width > fw) && s + strl >= s) { strcpyW(es->text + s + strl - 1, es->text + s + strl); strl--; + es->text_length = -1; + EDIT_InvalidateUniscribeData(es); EDIT_CalcLineWidth_SL(es); } text_buffer_changed(es); @@ -2569,6 +2697,7 @@ static void EDIT_EM_ReplaceSel(EDITSTATE *es, BOOL can_undo, LPCWSTR lpsz_replac es->flags &= ~EF_UPDATE; EDIT_NOTIFY_PARENT(es, EN_CHANGE); } + EDIT_InvalidateUniscribeData(es); } @@ -2769,6 +2898,7 @@ static void EDIT_EM_SetPasswordChar(EDITSTATE *es, WCHAR c) SetWindowLongW( es->hwndSelf, GWL_STYLE, style & ~ES_PASSWORD ); es->style &= ~ES_PASSWORD; } + EDIT_InvalidateUniscribeData(es); EDIT_UpdateText(es, NULL, TRUE); } @@ -2795,6 +2925,7 @@ static BOOL EDIT_EM_SetTabStops(EDITSTATE *es, INT count, const INT *tabs) } // reactos r33503 memcpy(es->tabs, tabs, count * sizeof(INT)); } + EDIT_InvalidateUniscribeData(es); return TRUE; } @@ -3125,6 +3256,7 @@ static void EDIT_WM_ContextMenu(EDITSTATE *es, INT x, INT y) /* Windows places the menu at the edit's center in this case */ GetClientRect(es->hwndSelf, &rc); MapWindowPoints(es->hwndSelf, 0, (POINT *)&rc, 2); + //WIN_GetRectangles( es->hwndSelf, COORDS_SCREEN, NULL, &rc ); x = rc.left + (rc.right - rc.left) / 2; y = rc.top + (rc.bottom - rc.top) / 2; } @@ -3534,6 +3666,9 @@ static void EDIT_WM_Paint(EDITSTATE *es, HDC hdc) (es->style & ES_NOHIDESEL)); dc = hdc ? hdc : BeginPaint(es->hwndSelf, &ps); + /* The dc we use for calcualting may not be the one we paint into. + This is the safest action. */ + EDIT_InvalidateUniscribeData(es); GetClientRect(es->hwndSelf, &rcClient); /* get the background brush */ @@ -3646,6 +3781,7 @@ static void EDIT_WM_SetFont(EDITSTATE *es, HFONT font, BOOL redraw) RECT clientRect; es->font = font; + EDIT_InvalidateUniscribeData(es); dc = GetDC(es->hwndSelf); if (font) old_font = SelectObject(dc, font); @@ -3736,7 +3872,8 @@ static void EDIT_WM_SetText(EDITSTATE *es, LPCWSTR text, BOOL unicode) EDIT_NOTIFY_PARENT(es, EN_CHANGE); } EDIT_EM_ScrollCaret(es); - EDIT_UpdateScrollInfo(es); + EDIT_UpdateScrollInfo(es); + EDIT_InvalidateUniscribeData(es); } @@ -4357,9 +4494,11 @@ static LRESULT EDIT_WM_NCCreate(HWND hwnd, LPCREATESTRUCTW lpcs, BOOL unicode) cleanup: SetWindowLongPtrW(es->hwndSelf, 0, 0); + EDIT_InvalidateUniscribeData(es); HeapFree(GetProcessHeap(), 0, es->first_line_def); HeapFree(GetProcessHeap(), 0, es->undo_text); if (es->hloc32W) LocalFree(es->hloc32W); + HeapFree(GetProcessHeap(), 0, es->logAttr); HeapFree(GetProcessHeap(), 0, es); return FALSE; } diff --git a/reactos/dll/win32/user32/controls/listbox.c b/reactos/dll/win32/user32/controls/listbox.c index 07165d397ee..ed489316013 100644 --- a/reactos/dll/win32/user32/controls/listbox.c +++ b/reactos/dll/win32/user32/controls/listbox.c @@ -540,9 +540,7 @@ static void LISTBOX_PaintItem( LB_DESCR *descr, HDC hdc, const RECT *rect, after they are done, so a region has better to exist else everything ends clipped */ GetClientRect(descr->self, &r); - hrgn = CreateRectRgnIndirect(&r); - SelectClipRgn( hdc, hrgn); - DeleteObject( hrgn ); + hrgn = set_control_clipping( hdc, &r ); dis.CtlType = ODT_LISTBOX; dis.CtlID = GetWindowLongPtrW( descr->self, GWLP_ID ); @@ -562,6 +560,8 @@ static void LISTBOX_PaintItem( LB_DESCR *descr, HDC hdc, const RECT *rect, descr->self, index, item ? debugstr_w(item->str) : "", action, dis.itemState, wine_dbgstr_rect(rect) ); SendMessageW(descr->owner, WM_DRAWITEM, dis.CtlID, (LPARAM)&dis); + SelectClipRgn( hdc, hrgn ); + if (hrgn) DeleteObject( hrgn ); } else { diff --git a/reactos/dll/win32/user32/controls/regcontrol.c b/reactos/dll/win32/user32/controls/regcontrol.c index cf500b371b4..60de50e9004 100644 --- a/reactos/dll/win32/user32/controls/regcontrol.c +++ b/reactos/dll/win32/user32/controls/regcontrol.c @@ -19,12 +19,33 @@ static PFNCLIENT pfnClientA; static PFNCLIENT pfnClientW; static PFNCLIENTWORKER pfnClientWorker; -// -// FIXME! -// These are not "System Classes" but Global Classes that are registered -// every time a process is created, so these can be unregistered as the msdn -// documents states. -// + +/*********************************************************************** + * set_control_clipping + * + * Set clipping for a builtin control that uses CS_PARENTDC. + * Return the previous clip region if any. + */ +HRGN set_control_clipping( HDC hdc, const RECT *rect ) +{ + RECT rc = *rect; + HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 ); + + if (GetClipRgn( hdc, hrgn ) != 1) + { + DeleteObject( hrgn ); + hrgn = 0; + } + DPtoLP( hdc, (POINT *)&rc, 2 ); + if (GetLayout( hdc ) & LAYOUT_RTL) /* compensate for the shifting done by IntersectClipRect */ + { + rc.left++; + rc.right++; + } + IntersectClipRect( hdc, rc.left, rc.top, rc.right, rc.bottom ); + return hrgn; +} + static const struct { const struct builtin_class_descr *desc; diff --git a/reactos/dll/win32/user32/controls/static.c b/reactos/dll/win32/user32/controls/static.c index 3a38820ef1c..fbf8d968bfb 100644 --- a/reactos/dll/win32/user32/controls/static.c +++ b/reactos/dll/win32/user32/controls/static.c @@ -105,34 +105,6 @@ const struct builtin_class_descr STATIC_builtin_class = 0 /* brush */ }; -static void setup_clipping(HWND hwnd, HDC hdc, HRGN *orig) -{ - RECT rc; - HRGN hrgn; - - /* Native control has always a clipping region set (this may be because - * builtin controls uses CS_PARENTDC) and an application depends on it - */ - hrgn = CreateRectRgn(0, 0, 1, 1); - if (GetClipRgn(hdc, hrgn) != 1) - { - DeleteObject(hrgn); - *orig = NULL; - } else - *orig = hrgn; - - GetClientRect(hwnd, &rc); - DPtoLP(hdc, (POINT *)&rc, 2); - IntersectClipRect(hdc, rc.left, rc.top, rc.right, rc.bottom); -} - -static void restore_clipping(HDC hdc, HRGN hrgn) -{ - SelectClipRgn(hdc, hrgn); - if (hrgn != NULL) - DeleteObject(hrgn); -} - /*********************************************************************** * STATIC_SetIcon * @@ -314,12 +286,13 @@ static VOID STATIC_TryPaintFcn(HWND hwnd, LONG full_style) if (!IsRectEmpty(&rc) && IsWindowVisible(hwnd) && staticPaintFunc[style]) { HDC hdc; - HRGN hOrigClipping; + HRGN hrgn; hdc = GetDC( hwnd ); - setup_clipping(hwnd, hdc, &hOrigClipping); + hrgn = set_control_clipping( hdc, &rc ); (staticPaintFunc[style])( hwnd, hdc, full_style ); - restore_clipping(hdc, hOrigClipping); + SelectClipRgn( hdc, hrgn ); + if (hrgn) DeleteObject( hrgn ); ReleaseDC( hwnd, hdc ); } } @@ -426,13 +399,15 @@ LRESULT WINAPI StaticWndProc_common( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM case WM_PAINT: { PAINTSTRUCT ps; + RECT rect; HDC hdc = wParam ? (HDC)wParam : BeginPaint(hwnd, &ps); + GetClientRect( hwnd, &rect ); if (staticPaintFunc[style]) { - HRGN hOrigClipping; - setup_clipping(hwnd, hdc, &hOrigClipping); + HRGN hrgn = set_control_clipping( hdc, &rect ); (staticPaintFunc[style])( hwnd, hdc, full_style ); - restore_clipping(hdc, hOrigClipping); + SelectClipRgn( hdc, hrgn ); + if (hrgn) DeleteObject( hrgn ); } if (!wParam) EndPaint(hwnd, &ps); } diff --git a/reactos/dll/win32/user32/include/controls.h b/reactos/dll/win32/user32/include/controls.h index e1b10562a10..f80b7dc1294 100644 --- a/reactos/dll/win32/user32/include/controls.h +++ b/reactos/dll/win32/user32/include/controls.h @@ -88,6 +88,8 @@ extern BOOL COMBO_FlipListbox( LPHEADCOMBO, BOOL, BOOL ); #define LB_ADDSTRING_UPPER 0x1AC #define LB_ADDSTRING_LOWER 0x1AD +HRGN set_control_clipping( HDC hdc, const RECT *rect ); + LRESULT WINAPI DesktopWndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ); LRESULT WINAPI User32DefWindowProc(HWND,UINT,WPARAM,LPARAM,BOOL); BOOL WINAPI RegisterClientPFN(VOID); diff --git a/reactos/dll/win32/user32/include/user32.h b/reactos/dll/win32/user32/include/user32.h index 9f5472e1a00..4dd40c7ba73 100644 --- a/reactos/dll/win32/user32/include/user32.h +++ b/reactos/dll/win32/user32/include/user32.h @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include diff --git a/reactos/dll/win32/user32/user32.rbuild b/reactos/dll/win32/user32/user32.rbuild index 213e7576d59..f973fc18f4f 100644 --- a/reactos/dll/win32/user32/user32.rbuild +++ b/reactos/dll/win32/user32/user32.rbuild @@ -9,6 +9,7 @@ gdi32 advapi32 imm32 + usp10 win32ksys pseh ntdll diff --git a/reactos/dll/win32/user32/windows/cursoricon.c b/reactos/dll/win32/user32/windows/cursoricon.c index c951766198a..eef5b24db68 100644 --- a/reactos/dll/win32/user32/windows/cursoricon.c +++ b/reactos/dll/win32/user32/windows/cursoricon.c @@ -1453,31 +1453,31 @@ HICON WINAPI CreateIconIndirect(PICONINFO iconinfo) // the size of the mask bitmap always determines the icon size! width = bmpAnd.bmWidth; height = bmpAnd.bmHeight; - if (bmpXor.bmPlanes * bmpXor.bmBitsPixel != 1) + if (bmpXor.bmPlanes * bmpXor.bmBitsPixel != 1 ) { color = CreateBitmap( width, height, bmpXor.bmPlanes, bmpXor.bmBitsPixel, NULL ); - if(!color) - { - ERR("Unable to create color bitmap!\n"); - return NULL; - } + if(!color) + { + ERR("Unable to create color bitmap!\n"); + return NULL; + } mask = CreateBitmap( width, height, 1, 1, NULL ); - if(!mask) - { - ERR("Unable to create mask bitmap!\n"); - DeleteObject(color); - return NULL; - } + if(!mask) + { + ERR("Unable to create mask bitmap!\n"); + DeleteObject(color); + return NULL; + } } else - { - mask = CreateBitmap( width, height * 2, 1, 1, NULL ); - if(!mask) - { - ERR("Unable to create mask bitmap!\n"); - return NULL; - } - } + { + mask = CreateBitmap( width, height * 2, 1, 1, NULL ); + if(!mask) + { + ERR("Unable to create mask bitmap!\n"); + return NULL; + } + } } else { diff --git a/reactos/dll/win32/user32/windows/dialog.c b/reactos/dll/win32/user32/windows/dialog.c index 1d93861303a..414e1780680 100644 --- a/reactos/dll/win32/user32/windows/dialog.c +++ b/reactos/dll/win32/user32/windows/dialog.c @@ -342,7 +342,9 @@ static BOOL DIALOG_CreateControls32( HWND hwnd, LPCSTR template, const DLG_TEMPL { template = (LPCSTR)DIALOG_GetControl32( (const WORD *)template, &info, dlgTemplate->dialogEx ); - /* Is this it? */ + info.style &= ~WS_POPUP; + info.style |= WS_CHILD; + if (info.style & WS_BORDER) { info.style &= ~WS_BORDER; @@ -405,6 +407,8 @@ static BOOL DIALOG_CreateControls32( HWND hwnd, LPCSTR template, const DLG_TEMPL if (!hwndCtrl) { + WARN("control %s %s creation failed\n", debugstr_w(info.className), + debugstr_w(info.windowName)); if (dlgTemplate->style & DS_NOFAILCREATE) continue; return FALSE; } @@ -1013,6 +1017,7 @@ static HWND DIALOG_CreateIndirect( HINSTANCE hInst, LPCVOID dlgTemplate, if (dlgProc) { HWND focus = GetNextDlgTabItem( hwnd, 0, FALSE ); + if (!focus) focus = GetNextDlgGroupItem( hwnd, 0, FALSE ); if (SendMessageW( hwnd, WM_INITDIALOG, (WPARAM)focus, param ) && IsWindow( hwnd ) && ((~template.style & DS_CONTROL) || (template.style & WS_VISIBLE))) { @@ -1020,6 +1025,7 @@ static HWND DIALOG_CreateIndirect( HINSTANCE hInst, LPCVOID dlgTemplate, * WM_INITDIALOG may have changed the tab order, so find the first * tabstop control again. */ dlgInfo->hwndFocus = GetNextDlgTabItem( hwnd, 0, FALSE ); + if (!dlgInfo->hwndFocus) dlgInfo->hwndFocus = GetNextDlgGroupItem( hwnd, 0, FALSE ); if( dlgInfo->hwndFocus ) SetFocus( dlgInfo->hwndFocus ); } @@ -1983,41 +1989,52 @@ DlgDirSelectExW( BOOL WINAPI EndDialog( - HWND hDlg, - INT_PTR nResult) + HWND hwnd, + INT_PTR retval) { BOOL wasEnabled = TRUE; DIALOGINFO * dlgInfo; HWND owner; - if (!(dlgInfo = GETDLGINFO(hDlg))) + TRACE("%p %ld\n", hwnd, retval ); + + if (!(dlgInfo = GETDLGINFO(hwnd))) { - ERR("got invalid window handle (%p); buggy app !?\n", hDlg); + ERR("got invalid window handle (%p); buggy app !?\n", hwnd); return FALSE; } - - dlgInfo->idResult = nResult; + dlgInfo->idResult = retval; dlgInfo->flags |= DF_END; wasEnabled = (dlgInfo->flags & DF_OWNERENABLED); - if (wasEnabled && (owner = GetWindow( hDlg, GW_OWNER ))) + owner = GetWindow( hwnd, GW_OWNER ); + if (wasEnabled && owner) DIALOG_EnableOwner( owner ); /* Windows sets the focus to the dialog itself in EndDialog */ - if (IsChild(hDlg, GetFocus())) - SetFocus( hDlg ); + if (IsChild(hwnd, GetFocus())) + SetFocus( hwnd ); /* Don't have to send a ShowWindow(SW_HIDE), just do SetWindowPos with SWP_HIDEWINDOW as done in Windows */ - SetWindowPos(hDlg, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE + SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW); - if (hDlg == GetActiveWindow()) WinPosActivateOtherWindow( hDlg ); + if (hwnd == GetActiveWindow()) + { + /* If this dialog was given an owner then set the focus to that owner + even when the owner is disabled (normally when a window closes any + disabled windows cannot receive the focus). */ + if (owner) + SetForegroundWindow( owner ); + else + WinPosActivateOtherWindow( hwnd ); + } /* unblock dialog loop */ - PostMessageA(hDlg, WM_NULL, 0, 0); + PostMessageA(hwnd, WM_NULL, 0, 0); return TRUE; }