- Sync up with wine controls. See http://www.winehq.org/pipermail/wine-cvs/ for log data.

svn path=/trunk/; revision=54604
This commit is contained in:
James Tabor 2011-12-07 09:23:04 +00:00
parent b069e5d538
commit 0f285fa795
12 changed files with 627 additions and 469 deletions

View file

@ -72,7 +72,7 @@ target_link_libraries(user32
win32ksys win32ksys
${PSEH_LIB}) ${PSEH_LIB})
add_delay_importlibs(user32 imm32) add_delay_importlibs(user32 imm32 usp10)
add_importlibs(user32 gdi32 advapi32 msvcrt kernel32 ntdll) add_importlibs(user32 gdi32 advapi32 msvcrt kernel32 ntdll)
add_pch(user32 include/user32.h) add_pch(user32 include/user32.h)
add_cd_file(TARGET user32 DESTINATION reactos/system32 FOR all) add_cd_file(TARGET user32 DESTINATION reactos/system32 FOR all)

View file

@ -31,7 +31,6 @@
* Styles * Styles
* - BS_NOTIFY: is it complete? * - BS_NOTIFY: is it complete?
* - BS_RIGHTBUTTON: same as BS_LEFTTEXT * - BS_RIGHTBUTTON: same as BS_LEFTTEXT
* - BS_TYPEMASK
* *
* Messages * Messages
* - WM_CHAR: Checks a (manual or automatic) check box on '+' or '=', clears it on '-' key. * - 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 UISTATE_GWL_OFFSET (HIMAGE_GWL_OFFSET+sizeof(HFONT))
#define NB_EXTRA_BYTES (UISTATE_GWL_OFFSET+sizeof(LONG)) #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 */ /* undocumented flags */
#define BUTTON_NSTATES 0x0F
#define BUTTON_BTNPRESSED 0x40 #define BUTTON_BTNPRESSED 0x40
#define BUTTON_UNKNOWN2 0x20 #define BUTTON_UNKNOWN2 0x20
#define BUTTON_UNKNOWN3 0x10 #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 OB_Paint( HWND hwnd, HDC hDC, UINT action );
static void BUTTON_CheckAutoRadioButton( HWND hwnd ); static void BUTTON_CheckAutoRadioButton( HWND hwnd );
#define MAX_BTN_TYPE 12 #define MAX_BTN_TYPE 16
static const WORD maxCheckState[MAX_BTN_TYPE] = static const WORD maxCheckState[MAX_BTN_TYPE] =
{ {
BUTTON_UNCHECKED, /* BS_PUSHBUTTON */ BST_UNCHECKED, /* BS_PUSHBUTTON */
BUTTON_UNCHECKED, /* BS_DEFPUSHBUTTON */ BST_UNCHECKED, /* BS_DEFPUSHBUTTON */
BUTTON_CHECKED, /* BS_CHECKBOX */ BST_CHECKED, /* BS_CHECKBOX */
BUTTON_CHECKED, /* BS_AUTOCHECKBOX */ BST_CHECKED, /* BS_AUTOCHECKBOX */
BUTTON_CHECKED, /* BS_RADIOBUTTON */ BST_CHECKED, /* BS_RADIOBUTTON */
BUTTON_3STATE, /* BS_3STATE */ BST_INDETERMINATE, /* BS_3STATE */
BUTTON_3STATE, /* BS_AUTO3STATE */ BST_INDETERMINATE, /* BS_AUTO3STATE */
BUTTON_UNCHECKED, /* BS_GROUPBOX */ BST_UNCHECKED, /* BS_GROUPBOX */
BUTTON_UNCHECKED, /* BS_USERBUTTON */ BST_UNCHECKED, /* BS_USERBUTTON */
BUTTON_CHECKED, /* BS_AUTORADIOBUTTON */ BST_CHECKED, /* BS_AUTORADIOBUTTON */
BUTTON_UNCHECKED, /* Not defined */ BST_UNCHECKED, /* BS_PUSHBOX */
BUTTON_UNCHECKED /* BS_OWNERDRAW */ BST_UNCHECKED /* BS_OWNERDRAW */
}; };
typedef void (*pfPaint)( HWND hwnd, HDC hdc, UINT action ); typedef void (*pfPaint)( HWND hwnd, HDC hdc, UINT action );
@ -135,7 +128,7 @@ static const pfPaint btnPaintFunc[MAX_BTN_TYPE] =
GB_Paint, /* BS_GROUPBOX */ GB_Paint, /* BS_GROUPBOX */
UB_Paint, /* BS_USERBUTTON */ UB_Paint, /* BS_USERBUTTON */
CB_Paint, /* BS_AUTORADIOBUTTON */ CB_Paint, /* BS_AUTORADIOBUTTON */
NULL, /* Not defined */ NULL, /* BS_PUSHBOX */
OB_Paint /* BS_OWNERDRAW */ 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 ) static inline UINT get_button_type( LONG window_style )
{ {
return (window_style & 0x0f); return (window_style & BS_TYPEMASK);
} }
/* paint a button of any type */ /* paint a button of any type */
@ -214,15 +207,6 @@ static inline WCHAR *get_button_text( HWND hwnd )
return buffer; 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 */ /* Retrieve the UI state for the control */
static BOOL button_update_uistate(HWND hwnd, BOOL unicode) 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 */ /* XP turns a BS_USERBUTTON into BS_PUSHBUTTON */
if (btn_type == BS_USERBUTTON ) if (btn_type == BS_USERBUTTON )
{ {
style = (style & ~0x0f) | BS_PUSHBUTTON; #ifdef __REACTOS__
style = (style & ~BS_TYPEMASK) | BS_PUSHBUTTON;
SetWindowLongPtrW( hWnd, GWL_STYLE, style ); 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 ); button_update_uistate( hWnd, unicode );
return 0; return 0;
@ -389,7 +378,7 @@ LRESULT WINAPI ButtonWndProc_common(HWND hWnd, UINT uMsg,
if (!(state & BUTTON_BTNPRESSED)) break; if (!(state & BUTTON_BTNPRESSED)) break;
state &= BUTTON_NSTATES; state &= BUTTON_NSTATES;
set_button_state( hWnd, state ); set_button_state( hWnd, state );
if (!(state & BUTTON_HIGHLIGHTED)) if (!(state & BST_PUSHED))
{ {
ReleaseCapture(); ReleaseCapture();
break; break;
@ -403,14 +392,14 @@ LRESULT WINAPI ButtonWndProc_common(HWND hWnd, UINT uMsg,
switch(btn_type) switch(btn_type)
{ {
case BS_AUTOCHECKBOX: case BS_AUTOCHECKBOX:
SendMessageW( hWnd, BM_SETCHECK, !(state & BUTTON_CHECKED), 0 ); SendMessageW( hWnd, BM_SETCHECK, !(state & BST_CHECKED), 0 );
break; break;
case BS_AUTORADIOBUTTON: case BS_AUTORADIOBUTTON:
SendMessageW( hWnd, BM_SETCHECK, TRUE, 0 ); SendMessageW( hWnd, BM_SETCHECK, TRUE, 0 );
break; break;
case BS_AUTO3STATE: case BS_AUTO3STATE:
SendMessageW( hWnd, BM_SETCHECK, SendMessageW( hWnd, BM_SETCHECK,
(state & BUTTON_3STATE) ? 0 : ((state & 3) + 1), 0 ); (state & BST_INDETERMINATE) ? 0 : ((state & 3) + 1), 0 );
break; break;
} }
BUTTON_NOTIFY_PARENT(hWnd, BN_CLICKED); BUTTON_NOTIFY_PARENT(hWnd, BN_CLICKED);
@ -424,7 +413,7 @@ LRESULT WINAPI ButtonWndProc_common(HWND hWnd, UINT uMsg,
{ {
state &= BUTTON_NSTATES; state &= BUTTON_NSTATES;
set_button_state( hWnd, state ); 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; break;
@ -490,7 +479,7 @@ LRESULT WINAPI ButtonWndProc_common(HWND hWnd, UINT uMsg,
case WM_SETFOCUS: case WM_SETFOCUS:
TRACE("WM_SETFOCUS %p\n",hWnd); 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 ); paint_button( hWnd, btn_type, ODA_FOCUS );
if (style & BS_NOTIFY) if (style & BS_NOTIFY)
BUTTON_NOTIFY_PARENT(hWnd, BN_SETFOCUS); BUTTON_NOTIFY_PARENT(hWnd, BN_SETFOCUS);
@ -499,7 +488,7 @@ LRESULT WINAPI ButtonWndProc_common(HWND hWnd, UINT uMsg,
case WM_KILLFOCUS: case WM_KILLFOCUS:
TRACE("WM_KILLFOCUS %p\n",hWnd); TRACE("WM_KILLFOCUS %p\n",hWnd);
state = get_button_state( 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 ); paint_button( hWnd, btn_type, ODA_FOCUS );
if ((state & BUTTON_BTNPRESSED) && GetCapture() == hWnd) if ((state & BUTTON_BTNPRESSED) && GetCapture() == hWnd)
@ -515,10 +504,11 @@ LRESULT WINAPI ButtonWndProc_common(HWND hWnd, UINT uMsg,
break; break;
case BM_SETSTYLE: case BM_SETSTYLE:
if ((wParam & 0x0f) >= MAX_BTN_TYPE) break; if ((wParam & BS_TYPEMASK) >= MAX_BTN_TYPE) break;
btn_type = wParam & 0x0f; btn_type = wParam & BS_TYPEMASK;
style = (style & ~0x0f) | btn_type; style = (style & ~BS_TYPEMASK) | btn_type;
SetWindowLongPtrW( hWnd, GWL_STYLE, style ); SetWindowLongPtrW( hWnd, GWL_STYLE, style );
//WIN_SetStyle( hWnd, style, BS_TYPEMASK & ~style );
/* Only redraw if lParam flag is set.*/ /* Only redraw if lParam flag is set.*/
if (lParam) if (lParam)
@ -559,16 +549,21 @@ LRESULT WINAPI ButtonWndProc_common(HWND hWnd, UINT uMsg,
state = get_button_state( hWnd ); state = get_button_state( hWnd );
if ((btn_type == BS_RADIOBUTTON) || (btn_type == BS_AUTORADIOBUTTON)) if ((btn_type == BS_RADIOBUTTON) || (btn_type == BS_AUTORADIOBUTTON))
{ {
#ifdef __REACTOS__
if (wParam) style |= WS_TABSTOP; if (wParam) style |= WS_TABSTOP;
else style &= ~WS_TABSTOP; else style &= ~WS_TABSTOP;
SetWindowLongPtrW( hWnd, GWL_STYLE, style ); 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) if ((state & 3) != wParam)
{ {
set_button_state( hWnd, (state & ~3) | wParam ); set_button_state( hWnd, (state & ~3) | wParam );
paint_button( hWnd, btn_type, ODA_SELECT ); 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 ); BUTTON_CheckAutoRadioButton( hWnd );
break; break;
@ -578,15 +573,10 @@ LRESULT WINAPI ButtonWndProc_common(HWND hWnd, UINT uMsg,
case BM_SETSTATE: case BM_SETSTATE:
state = get_button_state( hWnd ); state = get_button_state( hWnd );
if (wParam) if (wParam)
{ set_button_state( hWnd, state | BST_PUSHED );
if (state & BUTTON_HIGHLIGHTED) break;
set_button_state( hWnd, state | BUTTON_HIGHLIGHTED );
}
else else
{ set_button_state( hWnd, state & ~BST_PUSHED );
if (!(state & BUTTON_HIGHLIGHTED)) break;
set_button_state( hWnd, state & ~BUTTON_HIGHLIGHTED );
}
paint_button( hWnd, btn_type, ODA_SELECT ); paint_button( hWnd, btn_type, ODA_SELECT );
break; break;
@ -642,7 +632,7 @@ static UINT BUTTON_BStoDT( DWORD style, DWORD ex_style )
/* "Convert" pushlike buttons to pushbuttons */ /* "Convert" pushlike buttons to pushbuttons */
if (style & BS_PUSHLIKE) if (style & BS_PUSHLIKE)
style &= ~0x0F; style &= ~BS_TYPEMASK;
if (!(style & BS_MULTILINE)) if (!(style & BS_MULTILINE))
dtStyle |= DT_SINGLELINE; 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. * 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); hbr = GetSysColorBrush(COLOR_GRAYTEXT);
flags |= DSS_MONO; flags |= DSS_MONO;
@ -873,8 +863,9 @@ static void PB_Paint( HWND hwnd, HDC hDC, UINT action )
HFONT hFont; HFONT hFont;
LONG state = get_button_state( hwnd ); LONG state = get_button_state( hwnd );
LONG style = GetWindowLongPtrW( hwnd, GWL_STYLE ); LONG style = GetWindowLongPtrW( hwnd, GWL_STYLE );
BOOL pushedState = (state & BUTTON_HIGHLIGHTED); BOOL pushedState = (state & BST_PUSHED);
HWND parent; HWND parent;
HRGN hrgn;
GetClientRect( hwnd, &rc ); GetClientRect( hwnd, &rc );
@ -884,7 +875,7 @@ static void PB_Paint( HWND hwnd, HDC hDC, UINT action )
if (!parent) parent = hwnd; if (!parent) parent = hwnd;
GetControlColor( parent, hwnd, hDC, WM_CTLCOLORBTN); GetControlColor( parent, hwnd, hDC, WM_CTLCOLORBTN);
setup_clipping( hwnd, hDC ); hrgn = set_control_clipping( hDC, &rc );
#ifdef __REACTOS__ #ifdef __REACTOS__
hOldPen = SelectObject(hDC, GetStockObject(DC_PEN)); hOldPen = SelectObject(hDC, GetStockObject(DC_PEN));
SetDCPenColor(hDC, GetSysColor(COLOR_WINDOWFRAME)); SetDCPenColor(hDC, GetSysColor(COLOR_WINDOWFRAME));
@ -916,7 +907,7 @@ static void PB_Paint( HWND hwnd, HDC hDC, UINT action )
uState |= DFCS_PUSHED; uState |= DFCS_PUSHED;
} }
if (state & (BUTTON_CHECKED | BUTTON_3STATE)) if (state & (BST_CHECKED | BST_INDETERMINATE))
uState |= DFCS_CHECKED; uState |= DFCS_CHECKED;
DrawFrameControl( hDC, &rc, DFC_BUTTON, uState ); DrawFrameControl( hDC, &rc, DFC_BUTTON, uState );
@ -938,8 +929,7 @@ static void PB_Paint( HWND hwnd, HDC hDC, UINT action )
SetTextColor( hDC, oldTxtColor ); SetTextColor( hDC, oldTxtColor );
draw_focus: draw_focus:
if ((action == ODA_FOCUS) || if (action == ODA_FOCUS || (state & BST_FOCUS))
((action == ODA_DRAWENTIRE) && (state & BUTTON_HASFOCUS)))
{ {
if (!(get_ui_state(hwnd) & UISF_HIDEFOCUS)) if (!(get_ui_state(hwnd) & UISF_HIDEFOCUS))
{ {
@ -952,6 +942,8 @@ draw_focus:
SelectObject( hDC, hOldPen ); SelectObject( hDC, hOldPen );
SelectObject( hDC, hOldBrush ); SelectObject( hDC, hOldBrush );
SetBkMode(hDC, oldBkMode); 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 state = get_button_state( hwnd );
LONG style = GetWindowLongPtrW( hwnd, GWL_STYLE ); LONG style = GetWindowLongPtrW( hwnd, GWL_STYLE );
HWND parent; HWND parent;
HRGN hrgn;
if (style & BS_PUSHLIKE) if (style & BS_PUSHLIKE)
{ {
@ -983,7 +976,7 @@ static void CB_Paint( HWND hwnd, HDC hDC, UINT action )
parent = GetParent(hwnd); parent = GetParent(hwnd);
if (!parent) parent = hwnd; if (!parent) parent = hwnd;
hBrush = GetControlColor( parent, hwnd, hDC, WM_CTLCOLORSTATIC); hBrush = GetControlColor( parent, hwnd, hDC, WM_CTLCOLORSTATIC);
setup_clipping( hwnd, hDC ); hrgn = set_control_clipping( hDC, &client );
if (style & BS_LEFTTEXT) 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) || if ((get_button_type(style) == BS_RADIOBUTTON) ||
(get_button_type(style) == BS_AUTORADIOBUTTON)) flags = DFCS_BUTTONRADIO; (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; else flags = DFCS_BUTTONCHECK;
if (state & (BUTTON_CHECKED | BUTTON_3STATE)) flags |= DFCS_CHECKED; if (state & (BST_CHECKED | BST_INDETERMINATE)) flags |= DFCS_CHECKED;
if (state & BUTTON_HIGHLIGHTED) flags |= DFCS_PUSHED; if (state & BST_PUSHED) flags |= DFCS_PUSHED;
if (style & WS_DISABLED) flags |= DFCS_INACTIVE; 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); BUTTON_DrawLabel(hwnd, hDC, dtFlags, &rtext);
/* ... and focus */ /* ... and focus */
if ((action == ODA_FOCUS) || if (action == ODA_FOCUS || (state & BST_FOCUS))
((action == ODA_DRAWENTIRE) && (state & BUTTON_HASFOCUS)))
{ {
if (!(get_ui_state(hwnd) & UISF_HIDEFOCUS)) if (!(get_ui_state(hwnd) & UISF_HIDEFOCUS))
{ {
@ -1078,6 +1070,8 @@ static void CB_Paint( HWND hwnd, HDC hDC, UINT action )
DrawFocusRect( hDC, &rtext ); DrawFocusRect( hDC, &rtext );
} }
} }
SelectClipRgn( hDC, hrgn );
if (hrgn) DeleteObject( hrgn );
} }
@ -1097,8 +1091,8 @@ static void BUTTON_CheckAutoRadioButton( HWND hwnd )
{ {
if (!sibling) break; if (!sibling) break;
if ((hwnd != sibling) && if ((hwnd != sibling) &&
((GetWindowLongPtrW( sibling, GWL_STYLE) & 0x0f) == BS_AUTORADIOBUTTON)) ((GetWindowLongPtrW( sibling, GWL_STYLE) & BS_TYPEMASK) == BS_AUTORADIOBUTTON))
SendMessageW( sibling, BM_SETCHECK, BUTTON_UNCHECKED, 0 ); SendMessageW( sibling, BM_SETCHECK, BST_UNCHECKED, 0 );
sibling = GetNextDlgGroupItem( parent, sibling, FALSE ); sibling = GetNextDlgGroupItem( parent, sibling, FALSE );
} while (sibling != start); } while (sibling != start);
} }
@ -1117,16 +1111,17 @@ static void GB_Paint( HWND hwnd, HDC hDC, UINT action )
TEXTMETRICW tm; TEXTMETRICW tm;
LONG style = GetWindowLongPtrW( hwnd, GWL_STYLE ); LONG style = GetWindowLongPtrW( hwnd, GWL_STYLE );
HWND parent; HWND parent;
HRGN hrgn;
if ((hFont = get_button_font( hwnd ))) SelectObject( hDC, hFont ); if ((hFont = get_button_font( hwnd ))) SelectObject( hDC, hFont );
/* GroupBox acts like static control, so it sends CTLCOLORSTATIC */ /* GroupBox acts like static control, so it sends CTLCOLORSTATIC */
parent = GetParent(hwnd); parent = GetParent(hwnd);
if (!parent) parent = hwnd; if (!parent) parent = hwnd;
hbr = GetControlColor( parent, hwnd, hDC, WM_CTLCOLORSTATIC); hbr = GetControlColor( parent, hwnd, hDC, WM_CTLCOLORSTATIC);
setup_clipping( hwnd, hDC );
GetClientRect( hwnd, &rc); GetClientRect( hwnd, &rc);
rcFrame = rc; rcFrame = rc;
hrgn = set_control_clipping( hDC, &rc );
GetTextMetricsW (hDC, &tm); GetTextMetricsW (hDC, &tm);
rcFrame.top += (tm.tmHeight / 2) - 1; rcFrame.top += (tm.tmHeight / 2) - 1;
@ -1135,20 +1130,22 @@ static void GB_Paint( HWND hwnd, HDC hDC, UINT action )
InflateRect(&rc, -7, 1); InflateRect(&rc, -7, 1);
dtFlags = BUTTON_CalcLabelRect(hwnd, hDC, &rc); dtFlags = BUTTON_CalcLabelRect(hwnd, hDC, &rc);
if (dtFlags == (UINT)-1L) if (dtFlags != (UINT)-1L)
return; {
/* 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 /* There is 1-pixel margin at the left, right, and bottom */
* that label will be drawn out of client rect. rc.left--; rc.right++; rc.bottom++;
* But Windows doesn't clip label's rect, so do I. FillRect(hDC, &rc, hbr);
*/ rc.left++; rc.right--; rc.bottom--;
/* There is 1-pixel margin at the left, right, and bottom */ BUTTON_DrawLabel(hwnd, hDC, dtFlags, &rc);
rc.left--; rc.right++; rc.bottom++; }
FillRect(hDC, &rc, hbr); SelectClipRgn( hDC, hrgn );
rc.left++; rc.right--; rc.bottom--; if (hrgn) DeleteObject( hrgn );
BUTTON_DrawLabel(hwnd, hDC, dtFlags, &rc);
} }
@ -1164,8 +1161,6 @@ static void UB_Paint( HWND hwnd, HDC hDC, UINT action )
LONG state = get_button_state( hwnd ); LONG state = get_button_state( hwnd );
HWND parent; HWND parent;
if (action == ODA_SELECT) return;
GetClientRect( hwnd, &rc); GetClientRect( hwnd, &rc);
if ((hFont = get_button_font( hwnd ))) SelectObject( hDC, hFont ); 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); hBrush = GetControlColor( parent, hwnd, hDC, WM_CTLCOLORBTN);
FillRect( hDC, &rc, hBrush ); FillRect( hDC, &rc, hBrush );
if ((action == ODA_FOCUS) || if (action == ODA_FOCUS || (state & BST_FOCUS))
((action == ODA_DRAWENTIRE) && (state & BUTTON_HASFOCUS)))
{ {
if (!(get_ui_state(hwnd) & UISF_HIDEFOCUS)) if (!(get_ui_state(hwnd) & UISF_HIDEFOCUS))
DrawFocusRect( hDC, &rc ); 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 ); LONG_PTR id = GetWindowLongPtrW( hwnd, GWLP_ID );
HWND parent; HWND parent;
HFONT hFont, hPrevFont = 0; HFONT hFont, hPrevFont = 0;
HRGN hrgn;
dis.CtlType = ODT_BUTTON; dis.CtlType = ODT_BUTTON;
dis.CtlID = id; dis.CtlID = id;
dis.itemID = 0; dis.itemID = 0;
dis.itemAction = action; dis.itemAction = action;
dis.itemState = ((state & BUTTON_HASFOCUS) ? ODS_FOCUS : 0) | dis.itemState = ((state & BST_FOCUS) ? ODS_FOCUS : 0) |
((state & BUTTON_HIGHLIGHTED) ? ODS_SELECTED : 0) | ((state & BST_PUSHED) ? ODS_SELECTED : 0) |
(IsWindowEnabled(hwnd) ? 0: ODS_DISABLED); (IsWindowEnabled(hwnd) ? 0: ODS_DISABLED);
dis.hwndItem = hwnd; dis.hwndItem = hwnd;
dis.hDC = hDC; dis.hDC = hDC;
@ -1215,8 +1223,10 @@ static void OB_Paint( HWND hwnd, HDC hDC, UINT action )
if (!parent) parent = hwnd; if (!parent) parent = hwnd;
GetControlColor( parent, hwnd, hDC, WM_CTLCOLORBTN); 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 ); SendMessageW( GetParent(hwnd), WM_DRAWITEM, id, (LPARAM)&dis );
if (hPrevFont) SelectObject(hDC, hPrevFont); if (hPrevFont) SelectObject(hDC, hPrevFont);
SelectClipRgn( hDC, hrgn );
if (hrgn) DeleteObject( hrgn );
} }

View file

@ -751,19 +751,6 @@ static void CBPaintText(
!(lphc->wState & CBF_DROPPED) ) !(lphc->wState & CBF_DROPPED) )
itemState |= ODS_SELECTED | ODS_FOCUS; 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; if (!IsWindowEnabled(lphc->self)) itemState |= ODS_DISABLED;
dis.CtlType = ODT_COMBOBOX; dis.CtlType = ODT_COMBOBOX;
@ -774,22 +761,17 @@ static void CBPaintText(
dis.itemState = itemState; dis.itemState = itemState;
dis.hDC = hdc; dis.hDC = hdc;
dis.rcItem = rectEdit; dis.rcItem = rectEdit;
dis.itemData = SendMessageW(lphc->hWndLBox, LB_GETITEMDATA, dis.itemData = SendMessageW(lphc->hWndLBox, LB_GETITEMDATA, id, 0 );
(WPARAM)id, 0 );
/* /*
* Clip the DC and have the parent draw the item. * Clip the DC and have the parent draw the item.
*/ */
IntersectClipRect(hdc, clipRegion = set_control_clipping( hdc, &rectEdit );
rectEdit.left, rectEdit.top,
rectEdit.right, rectEdit.bottom);
SendMessageW(lphc->owner, WM_DRAWITEM, ctlid, (LPARAM)&dis ); SendMessageW(lphc->owner, WM_DRAWITEM, ctlid, (LPARAM)&dis );
/* SelectClipRgn( hdc, clipRegion);
* Reset the clipping region. if (clipRegion) DeleteObject( clipRegion );
*/
SelectClipRgn(hdc, clipRegion);
} }
else else
{ {
@ -2153,14 +2135,24 @@ LRESULT WINAPI ComboWndProc_common( HWND hwnd, UINT message,
return SendMessageW(lphc->hWndLBox, LB_GETLOCALE, 0, 0); return SendMessageW(lphc->hWndLBox, LB_GETLOCALE, 0, 0);
case CB_SETLOCALE: case CB_SETLOCALE:
return SendMessageW(lphc->hWndLBox, LB_SETLOCALE, wParam, 0); 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: case CB_GETDROPPEDWIDTH:
if( lphc->droppedWidth ) if( lphc->droppedWidth )
return lphc->droppedWidth; return lphc->droppedWidth;
return lphc->droppedRect.right - lphc->droppedRect.left; 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: case CB_GETDROPPEDCONTROLRECT:
if( lParam ) CBGetDroppedControlRect(lphc, (LPRECT)lParam ); if( lParam ) CBGetDroppedControlRect(lphc, (LPRECT)lParam );
return CB_OKAY; return CB_OKAY;
@ -2233,7 +2225,7 @@ LRESULT WINAPI ComboWndProc_common( HWND hwnd, UINT message,
case CB_LIMITTEXT: case CB_LIMITTEXT:
if( lphc->wState & CBF_EDIT ) if( lphc->wState & CBF_EDIT )
return SendMessageW(lphc->hWndEdit, EM_LIMITTEXT, wParam, lParam); return SendMessageW(lphc->hWndEdit, EM_LIMITTEXT, wParam, lParam);
break; // ReactOS!!! removed at revision 38715 return TRUE;
case WM_UPDATEUISTATE: case WM_UPDATEUISTATE:
if (unicode) if (unicode)

View file

@ -85,6 +85,7 @@ typedef struct tagLINEDEF {
LINE_END ending; LINE_END ending;
INT width; /* width of the line in pixels */ INT width; /* width of the line in pixels */
INT index; /* line index into the buffer */ INT index; /* line index into the buffer */
SCRIPT_STRING_ANALYSIS ssa; /* Uniscribe Data */
struct tagLINEDEF *next; struct tagLINEDEF *next;
} LINEDEF; } LINEDEF;
@ -141,6 +142,11 @@ typedef struct
*/ */
UINT composition_len; /* length of composition, 0 == no composition */ UINT composition_len; /* length of composition, 0 == no composition */
int composition_start; /* the character position for the 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; } EDITSTATE;
@ -158,6 +164,7 @@ typedef struct
} while(0) } while(0)
static const WCHAR empty_stringW[] = {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 * 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 * allows to be called without linebreaks between s[0] up to
* s[count - 1]. Remember it is only called * s[count - 1]. Remember it is only called
* internally, so we can decide this for ourselves. * 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) { if (!es->logAttr)
case WB_LEFT: {
if (!count) SCRIPT_ANALYSIS psa;
break;
if (index) memset(&psa,0,sizeof(SCRIPT_ANALYSIS));
index--; psa.eScript = SCRIPT_UNDEFINED;
if (s[index] == ' ') {
while (index && (s[index] == ' ')) es->logAttr = HeapAlloc(GetProcessHeap(), 0, sizeof(SCRIPT_LOGATTR) * get_text_length(es));
index--; ScriptBreak(es->text, get_text_length(es), &psa, es->logAttr);
if (index) { }
while (index && (s[index] != ' '))
index--; switch (action) {
if (s[index] == ' ') case WB_LEFT:
index++; if (index)
} index--;
} else { while (index && !es->logAttr[index].fSoftBreak)
while (index && (s[index] != ' ')) index--;
index--; ret = index;
if (s[index] == ' ') break;
index++; case WB_RIGHT:
} if (!count)
ret = index; break;
break; while (s[index] && index < count && !es->logAttr[index].fSoftBreak)
case WB_RIGHT: index++;
if (!count) ret = index;
break; break;
if (index) case WB_ISDELIMITER:
index--; ret = es->logAttr[index].fWhiteSpace;
if (s[index] == ' ') break;
while ((index < count) && (s[index] == ' ')) index++; default:
else { ERR("unknown action code, please report !\n");
while (s[index] && (s[index] != ' ') && (index < count)) break;
index++; }
while ((s[index] == ' ') && (index < count)) index++; return ret;
}
ret = index;
break;
case WB_ISDELIMITER:
ret = (s[index] == ' ');
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 else
ret = EDIT_WordBreakProc(es->text + start, index, count, action); ret = EDIT_WordBreakProc(es, es->text, index+start, count+start, action) - start;
return ret; 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 * 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) 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; LPWSTR current_position, cp;
INT fw; INT fw;
LINEDEF *current_line; 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) if (istart == iend && delta == 0)
return; return;
dc = GetDC(es->hwndSelf);
if (es->font)
old_font = SelectObject(dc, es->font);
previous_line = NULL; previous_line = NULL;
current_line = es->first_line_def; 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 */ if (!current_line) /* Error occurred start is not inside previous buffer */
{ {
FIXME(" modification occurred outside buffer\n"); FIXME(" modification occurred outside buffer\n");
ReleaseDC(es->hwndSelf, dc);
return; 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 /* The buffer has been expanded, create a new line and
insert it into the link list */ insert it into the link list */
LINEDEF *new_line = HeapAlloc(GetProcessHeap(), 0, sizeof(LINEDEF)); LINEDEF *new_line = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LINEDEF));
if (new_line == NULL) // reactos r33509 if (new_line == NULL) // reactos r33509
break; // reactos r33509 break; // reactos r33509
new_line->next = previous_line->next; new_line->next = previous_line->next;
previous_line->next = new_line; previous_line->next = new_line;
current_line = 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; current_line->net_length = cp - current_position;
} }
/* Calculate line width */ if (current_line->net_length)
current_line->width = (INT)LOWORD(GetTabbedTextExtentW(dc, {
current_position, current_line->net_length, const SIZE *sz;
es->tabs_count, es->tabs)); 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 ???) */ /* 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 (!(es->style & ES_AUTOHSCROLL)) {
if (current_line->width > fw) { if (current_line->width > fw && fw > es->char_width) {
INT next = 0;
INT prev; 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 { do {
prev = next; prev = EDIT_CallWordBreakProc(es, current_position - es->text,
next = EDIT_CallWordBreakProc(es, current_position - es->text, next, current_line->net_length, WB_LEFT);
prev + 1, current_line->net_length, WB_RIGHT); current_line->net_length = prev;
current_line->width = (INT)LOWORD(GetTabbedTextExtentW(dc, EDIT_InvalidateUniscribeData_linedef(current_line);
current_position, next, es->tabs_count, es->tabs)); EDIT_UpdateUniscribeData_linedef(es, NULL, current_line);
} while (current_line->width <= fw); sz = ScriptString_pSize(current_line->ssa);
if (!prev) { /* Didn't find a line break so force a break */ if (sz)
next = 0; 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 { do {
prev = next; current_line->width -= piDx[prev];
next++; prev--;
current_line->width = (INT)LOWORD(GetTabbedTextExtentW(dc, } while ( prev > 0 && current_line->width > fw);
current_position, next, es->tabs_count, es->tabs)); if (prev<=0)
} while (current_line->width <= fw);
if (!prev)
prev = 1; prev = 1;
HeapFree(GetProcessHeap(),0,piDx);
} }
/* If the first line we are calculating, wrapped before istart, we must /* 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->net_length = prev;
current_line->ending = END_WRAP; 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 && else if (current_line == start_line &&
current_line->index != nstart_index && 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) while (current_line)
{ {
pnext = current_line->next; pnext = current_line->next;
EDIT_InvalidateUniscribeData_linedef(current_line);
HeapFree(GetProcessHeap(), 0, current_line); HeapFree(GetProcessHeap(), 0, current_line);
current_line = pnext; current_line = pnext;
es->line_count--; 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)) if ((es->style & ES_CENTER) || (es->style & ES_RIGHT))
rc.left = es->format_rect.left; rc.left = es->format_rect.left;
else else
rc.left = es->format_rect.left + (INT)LOWORD(GetTabbedTextExtentW(dc, rc.left = LOWORD(EDIT_EM_PosFromChar(es, nstart_index, FALSE));
es->text + nstart_index, istart - nstart_index,
es->tabs_count, es->tabs)) - es->x_offset; /* Adjust for horz scroll */
rc.right = es->format_rect.right; rc.right = es->format_rect.right;
SetRectRgn(hrgn, rc.left, rc.top, rc.right, rc.bottom); 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); CombineRgn(hrgn, hrgn, tmphrgn, RGN_OR);
DeleteObject(tmphrgn); 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) static void EDIT_CalcLineWidth_SL(EDITSTATE *es)
{ {
SIZE size; EDIT_UpdateUniscribeData(es, NULL, 0);
LPWSTR text; if (es->ssa)
HDC dc; {
HFONT old_font = 0; const SIZE *size;
size = ScriptString_pSize(es->ssa);
text = EDIT_GetPasswordPointer_SL(es); es->text_width = size->cx;
}
dc = GetDC(es->hwndSelf); else
if (es->font) es->text_width = 0;
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;
} }
/********************************************************************* /*********************************************************************
@ -704,20 +796,19 @@ static void EDIT_CalcLineWidth_SL(EDITSTATE *es)
static INT EDIT_CharFromPos(EDITSTATE *es, INT x, INT y, LPBOOL after_wrap) static INT EDIT_CharFromPos(EDITSTATE *es, INT x, INT y, LPBOOL after_wrap)
{ {
INT index; INT index;
HDC dc;
HFONT old_font = 0;
INT x_high = 0, x_low = 0;
if (es->style & ES_MULTILINE) { if (es->style & ES_MULTILINE) {
int trailing;
INT line = (y - es->format_rect.top) / es->line_height + es->y_offset; INT line = (y - es->format_rect.top) / es->line_height + es->y_offset;
INT line_index = 0; INT line_index = 0;
LINEDEF *line_def = es->first_line_def; LINEDEF *line_def = es->first_line_def;
INT low, high; EDIT_UpdateUniscribeData(es, NULL, line);
while ((line > 0) && line_def->next) { while ((line > 0) && line_def->next) {
line_index += line_def->length; line_index += line_def->length;
line_def = line_def->next; line_def = line_def->next;
line--; line--;
} }
x += es->x_offset - es->format_rect.left; x += es->x_offset - es->format_rect.left;
if (es->style & ES_RIGHT) if (es->style & ES_RIGHT)
x -= (es->format_rect.right - es->format_rect.left) - line_def->width; 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); *after_wrap = (line_def->ending == END_WRAP);
return line_index + line_def->net_length; return line_index + line_def->net_length;
} }
if (x <= 0) { if (x <= 0 || !line_def->ssa) {
if (after_wrap) if (after_wrap)
*after_wrap = FALSE; *after_wrap = FALSE;
return line_index; 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) if (after_wrap)
*after_wrap = ((index == line_index + line_def->net_length) && *after_wrap = ((index == line_index + line_def->net_length) &&
(line_def->ending == END_WRAP)); (line_def->ending == END_WRAP));
} else { } else {
LPWSTR text; INT xoff = 0;
SIZE size; INT trailing;
if (after_wrap) if (after_wrap)
*after_wrap = FALSE; *after_wrap = FALSE;
x -= es->format_rect.left; 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; x -= indent / 2;
} }
text = EDIT_GetPasswordPointer_SL(es); EDIT_UpdateUniscribeData(es, NULL, 0);
dc = GetDC(es->hwndSelf); if (es->x_offset)
if (es->font) {
old_font = SelectObject(dc, es->font); 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) if (x < 0)
{ {
INT low = 0; if (x + xoff > 0 || !es->ssa)
INT high = es->x_offset; {
while (low < high - 1) ScriptStringXtoCP(es->ssa, x+xoff, &index, &trailing);
{ if (trailing) index++;
INT mid = (low + high) / 2; }
GetTextExtentPoint32W( dc, text + mid, else
es->x_offset - mid, &size ); index = 0;
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;
} }
else else
{ {
INT low = es->x_offset; if (x)
INT high = get_text_length(es) + 1; {
while (low < high - 1) const SIZE *size = NULL;
{ if (es->ssa)
INT mid = (low + high) / 2; size = ScriptString_pSize(es->ssa);
GetTextExtentPoint32W( dc, text + es->x_offset, if (!size)
mid - es->x_offset, &size ); index = 0;
if (size.cx > x) { else if (x > size->cx)
high = mid; index = get_text_length(es);
x_high = size.cx; else if (es->ssa)
} else { {
low = mid; ScriptStringXtoCP(es->ssa, x+xoff, &index, &trailing);
x_low = size.cx; if (trailing) index++;
} }
} else
if (abs(x_high - x) <= abs(x_low - x) + 1) index = 0;
index = high; }
else else
index = low; 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; 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 len = get_text_length(es);
INT l; INT l;
INT li; INT li;
INT x; INT x = 0;
INT y = 0; INT y = 0;
INT w; INT w;
INT lw = 0; INT lw = 0;
INT ll = 0;
HDC dc;
HFONT old_font = 0;
SIZE size;
LINEDEF *line_def; LINEDEF *line_def;
index = min(index, len); index = min(index, len);
dc = GetDC(es->hwndSelf);
if (es->font)
old_font = SelectObject(dc, es->font);
if (es->style & ES_MULTILINE) { if (es->style & ES_MULTILINE) {
l = EDIT_EM_LineFromChar(es, index); l = EDIT_EM_LineFromChar(es, index);
EDIT_UpdateUniscribeData(es, NULL, l);
y = (l - es->y_offset) * es->line_height; y = (l - es->y_offset) * es->line_height;
li = EDIT_EM_LineIndex(es, l); li = EDIT_EM_LineIndex(es, l);
if (after_wrap && (li == index) && 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) while (line_def->index != li)
line_def = line_def->next; line_def = line_def->next;
ll = line_def->net_length; if (!line_def->ssa)
return 0;
lw = line_def->width; lw = line_def->width;
w = es->format_rect.right - es->format_rect.left; w = es->format_rect.right - es->format_rect.left;
if (es->style & ES_RIGHT) ScriptStringCPtoX(line_def->ssa, (index - 1) - li, TRUE, &x);
{ x -= es->x_offset;
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;
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))) if (!es->x_offset && (es->style & (ES_RIGHT | ES_CENTER)))
{ {
w = es->format_rect.right - es->format_rect.left; 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; y = 0;
if (es->style & ES_PASSWORD)
HeapFree(GetProcessHeap(), 0, text);
} }
x += es->format_rect.left; x += es->format_rect.left;
y += es->format_rect.top; y += es->format_rect.top;
if (es->font)
SelectObject(dc, old_font);
ReleaseDC(es->hwndSelf, dc);
return MAKELONG((INT16)x, (INT16)y); 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) static void EDIT_GetLineRect(EDITSTATE *es, INT line, INT scol, INT ecol, LPRECT rc)
{ {
INT line_index = EDIT_EM_LineIndex(es, line); INT line_index = EDIT_EM_LineIndex(es, line);
INT pt1, pt2;
if (es->style & ES_MULTILINE) if (es->style & ES_MULTILINE)
rc->top = es->format_rect.top + (line - es->y_offset) * es->line_height; rc->top = es->format_rect.top + (line - es->y_offset) * es->line_height;
else else
rc->top = es->format_rect.top; rc->top = es->format_rect.top;
rc->bottom = rc->top + es->line_height; 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)); pt1 = (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)); 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) static inline void text_buffer_changed(EDITSTATE *es)
{ {
es->text_length = (UINT)-1; 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, ret = (INT)LOWORD(TabbedTextOutW(dc, x, y, es->text + li + col, count,
es->tabs_count, es->tabs, es->format_rect.left - es->x_offset)); es->tabs_count, es->tabs, es->format_rect.left - es->x_offset));
} else { } else {
LPWSTR text = EDIT_GetPasswordPointer_SL(es); LPWSTR text = es->text;
TextOutW(dc, x, y, text + li + col, count); TextOutW(dc, x, y, text + li + col, count);
GetTextExtentPoint32W(dc, text + li + col, count, &size); GetTextExtentPoint32W(dc, text + li + col, count, &size);
ret = size.cx; 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) static void EDIT_PaintLine(EDITSTATE *es, HDC dc, INT line, BOOL rev)
{ {
INT s = es->selection_start; INT s = 0;
INT e = es->selection_end; INT e = 0;
INT li; INT li = 0;
INT ll; INT ll = 0;
INT x; INT x;
INT y; INT y;
LRESULT pos; LRESULT pos;
SCRIPT_STRING_ANALYSIS ssa;
if (es->style & ES_MULTILINE) { if (es->style & ES_MULTILINE) {
INT vlc = get_vertical_line_count(es); 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); TRACE("line=%d\n", line);
ssa = EDIT_UpdateUniscribeData(es, dc, line);
pos = EDIT_EM_PosFromChar(es, EDIT_EM_LineIndex(es, line), FALSE); pos = EDIT_EM_PosFromChar(es, EDIT_EM_LineIndex(es, line), FALSE);
x = (short)LOWORD(pos); x = (short)LOWORD(pos);
y = (short)HIWORD(pos); y = (short)HIWORD(pos);
li = EDIT_EM_LineIndex(es, line);
ll = EDIT_EM_LineLength(es, li); if (es->style & ES_MULTILINE)
s = min(es->selection_start, es->selection_end); {
e = max(es->selection_start, es->selection_end); int line_idx = line;
s = min(li + ll, max(li, s)); x = -es->x_offset;
e = min(li + ll, max(li, e)); if (es->style & ES_RIGHT || es->style & ES_CENTER)
if (rev && (s != e) && {
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))) { ((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, 0, s - li, FALSE);
x += EDIT_PaintText(es, dc, x, y, line, s - li, e - s, TRUE); 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; s = es->selection_start;
e = es->selection_end; e = es->selection_end;
EDIT_InvalidateUniscribeData(es);
if ((s == e) && !strl) if ((s == e) && !strl)
return; return;
@ -2466,12 +2591,15 @@ static void EDIT_EM_ReplaceSel(EDITSTATE *es, BOOL can_undo, LPCWSTR lpsz_replac
} }
else { else {
INT fw = es->format_rect.right - es->format_rect.left; INT fw = es->format_rect.right - es->format_rect.left;
EDIT_InvalidateUniscribeData(es);
EDIT_CalcLineWidth_SL(es); EDIT_CalcLineWidth_SL(es);
/* remove chars that don't fit */ /* remove chars that don't fit */
if (honor_limit && !(es->style & ES_AUTOHSCROLL) && (es->text_width > fw)) { if (honor_limit && !(es->style & ES_AUTOHSCROLL) && (es->text_width > fw)) {
while ((es->text_width > fw) && s + strl >= s) { while ((es->text_width > fw) && s + strl >= s) {
strcpyW(es->text + s + strl - 1, es->text + s + strl); strcpyW(es->text + s + strl - 1, es->text + s + strl);
strl--; strl--;
es->text_length = -1;
EDIT_InvalidateUniscribeData(es);
EDIT_CalcLineWidth_SL(es); EDIT_CalcLineWidth_SL(es);
} }
text_buffer_changed(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; es->flags &= ~EF_UPDATE;
EDIT_NOTIFY_PARENT(es, EN_CHANGE); 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 ); SetWindowLongW( es->hwndSelf, GWL_STYLE, style & ~ES_PASSWORD );
es->style &= ~ES_PASSWORD; es->style &= ~ES_PASSWORD;
} }
EDIT_InvalidateUniscribeData(es);
EDIT_UpdateText(es, NULL, TRUE); EDIT_UpdateText(es, NULL, TRUE);
} }
@ -2795,6 +2925,7 @@ static BOOL EDIT_EM_SetTabStops(EDITSTATE *es, INT count, const INT *tabs)
} // reactos r33503 } // reactos r33503
memcpy(es->tabs, tabs, count * sizeof(INT)); memcpy(es->tabs, tabs, count * sizeof(INT));
} }
EDIT_InvalidateUniscribeData(es);
return TRUE; 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 */ /* Windows places the menu at the edit's center in this case */
GetClientRect(es->hwndSelf, &rc); GetClientRect(es->hwndSelf, &rc);
MapWindowPoints(es->hwndSelf, 0, (POINT *)&rc, 2); MapWindowPoints(es->hwndSelf, 0, (POINT *)&rc, 2);
//WIN_GetRectangles( es->hwndSelf, COORDS_SCREEN, NULL, &rc );
x = rc.left + (rc.right - rc.left) / 2; x = rc.left + (rc.right - rc.left) / 2;
y = rc.top + (rc.bottom - rc.top) / 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)); (es->style & ES_NOHIDESEL));
dc = hdc ? hdc : BeginPaint(es->hwndSelf, &ps); 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); GetClientRect(es->hwndSelf, &rcClient);
/* get the background brush */ /* get the background brush */
@ -3646,6 +3781,7 @@ static void EDIT_WM_SetFont(EDITSTATE *es, HFONT font, BOOL redraw)
RECT clientRect; RECT clientRect;
es->font = font; es->font = font;
EDIT_InvalidateUniscribeData(es);
dc = GetDC(es->hwndSelf); dc = GetDC(es->hwndSelf);
if (font) if (font)
old_font = SelectObject(dc, font); old_font = SelectObject(dc, font);
@ -3737,6 +3873,7 @@ static void EDIT_WM_SetText(EDITSTATE *es, LPCWSTR text, BOOL unicode)
} }
EDIT_EM_ScrollCaret(es); 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: cleanup:
SetWindowLongPtrW(es->hwndSelf, 0, 0); SetWindowLongPtrW(es->hwndSelf, 0, 0);
EDIT_InvalidateUniscribeData(es);
HeapFree(GetProcessHeap(), 0, es->first_line_def); HeapFree(GetProcessHeap(), 0, es->first_line_def);
HeapFree(GetProcessHeap(), 0, es->undo_text); HeapFree(GetProcessHeap(), 0, es->undo_text);
if (es->hloc32W) LocalFree(es->hloc32W); if (es->hloc32W) LocalFree(es->hloc32W);
HeapFree(GetProcessHeap(), 0, es->logAttr);
HeapFree(GetProcessHeap(), 0, es); HeapFree(GetProcessHeap(), 0, es);
return FALSE; return FALSE;
} }

View file

@ -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 after they are done, so a region has better to exist
else everything ends clipped */ else everything ends clipped */
GetClientRect(descr->self, &r); GetClientRect(descr->self, &r);
hrgn = CreateRectRgnIndirect(&r); hrgn = set_control_clipping( hdc, &r );
SelectClipRgn( hdc, hrgn);
DeleteObject( hrgn );
dis.CtlType = ODT_LISTBOX; dis.CtlType = ODT_LISTBOX;
dis.CtlID = GetWindowLongPtrW( descr->self, GWLP_ID ); 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, descr->self, index, item ? debugstr_w(item->str) : "", action,
dis.itemState, wine_dbgstr_rect(rect) ); dis.itemState, wine_dbgstr_rect(rect) );
SendMessageW(descr->owner, WM_DRAWITEM, dis.CtlID, (LPARAM)&dis); SendMessageW(descr->owner, WM_DRAWITEM, dis.CtlID, (LPARAM)&dis);
SelectClipRgn( hdc, hrgn );
if (hrgn) DeleteObject( hrgn );
} }
else else
{ {

View file

@ -19,12 +19,33 @@ static PFNCLIENT pfnClientA;
static PFNCLIENT pfnClientW; static PFNCLIENT pfnClientW;
static PFNCLIENTWORKER pfnClientWorker; static PFNCLIENTWORKER pfnClientWorker;
//
// FIXME! /***********************************************************************
// These are not "System Classes" but Global Classes that are registered * set_control_clipping
// every time a process is created, so these can be unregistered as the msdn *
// documents states. * 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 static const struct
{ {
const struct builtin_class_descr *desc; const struct builtin_class_descr *desc;

View file

@ -105,34 +105,6 @@ const struct builtin_class_descr STATIC_builtin_class =
0 /* brush */ 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 * STATIC_SetIcon
* *
@ -314,12 +286,13 @@ static VOID STATIC_TryPaintFcn(HWND hwnd, LONG full_style)
if (!IsRectEmpty(&rc) && IsWindowVisible(hwnd) && staticPaintFunc[style]) if (!IsRectEmpty(&rc) && IsWindowVisible(hwnd) && staticPaintFunc[style])
{ {
HDC hdc; HDC hdc;
HRGN hOrigClipping; HRGN hrgn;
hdc = GetDC( hwnd ); hdc = GetDC( hwnd );
setup_clipping(hwnd, hdc, &hOrigClipping); hrgn = set_control_clipping( hdc, &rc );
(staticPaintFunc[style])( hwnd, hdc, full_style ); (staticPaintFunc[style])( hwnd, hdc, full_style );
restore_clipping(hdc, hOrigClipping); SelectClipRgn( hdc, hrgn );
if (hrgn) DeleteObject( hrgn );
ReleaseDC( hwnd, hdc ); ReleaseDC( hwnd, hdc );
} }
} }
@ -426,13 +399,15 @@ LRESULT WINAPI StaticWndProc_common( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM
case WM_PAINT: case WM_PAINT:
{ {
PAINTSTRUCT ps; PAINTSTRUCT ps;
RECT rect;
HDC hdc = wParam ? (HDC)wParam : BeginPaint(hwnd, &ps); HDC hdc = wParam ? (HDC)wParam : BeginPaint(hwnd, &ps);
GetClientRect( hwnd, &rect );
if (staticPaintFunc[style]) if (staticPaintFunc[style])
{ {
HRGN hOrigClipping; HRGN hrgn = set_control_clipping( hdc, &rect );
setup_clipping(hwnd, hdc, &hOrigClipping);
(staticPaintFunc[style])( hwnd, hdc, full_style ); (staticPaintFunc[style])( hwnd, hdc, full_style );
restore_clipping(hdc, hOrigClipping); SelectClipRgn( hdc, hrgn );
if (hrgn) DeleteObject( hrgn );
} }
if (!wParam) EndPaint(hwnd, &ps); if (!wParam) EndPaint(hwnd, &ps);
} }

View file

@ -88,6 +88,8 @@ extern BOOL COMBO_FlipListbox( LPHEADCOMBO, BOOL, BOOL );
#define LB_ADDSTRING_UPPER 0x1AC #define LB_ADDSTRING_UPPER 0x1AC
#define LB_ADDSTRING_LOWER 0x1AD #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 DesktopWndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam );
LRESULT WINAPI User32DefWindowProc(HWND,UINT,WPARAM,LPARAM,BOOL); LRESULT WINAPI User32DefWindowProc(HWND,UINT,WPARAM,LPARAM,BOOL);
BOOL WINAPI RegisterClientPFN(VOID); BOOL WINAPI RegisterClientPFN(VOID);

View file

@ -22,6 +22,7 @@
#include <windowsx.h> #include <windowsx.h>
#include <winnls32.h> #include <winnls32.h>
#include <strsafe.h> #include <strsafe.h>
#include <usp10.h>
#include <ndk/cmfuncs.h> #include <ndk/cmfuncs.h>
#include <ndk/kefuncs.h> #include <ndk/kefuncs.h>
#include <ndk/obfuncs.h> #include <ndk/obfuncs.h>

View file

@ -9,6 +9,7 @@
<library>gdi32</library> <library>gdi32</library>
<library>advapi32</library> <library>advapi32</library>
<library>imm32</library> <library>imm32</library>
<library>usp10</library>
<library>win32ksys</library> <library>win32ksys</library>
<library>pseh</library> <library>pseh</library>
<library>ntdll</library> <library>ntdll</library>

View file

@ -1453,31 +1453,31 @@ HICON WINAPI CreateIconIndirect(PICONINFO iconinfo)
// the size of the mask bitmap always determines the icon size! // the size of the mask bitmap always determines the icon size!
width = bmpAnd.bmWidth; width = bmpAnd.bmWidth;
height = bmpAnd.bmHeight; height = bmpAnd.bmHeight;
if (bmpXor.bmPlanes * bmpXor.bmBitsPixel != 1) if (bmpXor.bmPlanes * bmpXor.bmBitsPixel != 1 )
{ {
color = CreateBitmap( width, height, bmpXor.bmPlanes, bmpXor.bmBitsPixel, NULL ); color = CreateBitmap( width, height, bmpXor.bmPlanes, bmpXor.bmBitsPixel, NULL );
if(!color) if(!color)
{ {
ERR("Unable to create color bitmap!\n"); ERR("Unable to create color bitmap!\n");
return NULL; return NULL;
} }
mask = CreateBitmap( width, height, 1, 1, NULL ); mask = CreateBitmap( width, height, 1, 1, NULL );
if(!mask) if(!mask)
{ {
ERR("Unable to create mask bitmap!\n"); ERR("Unable to create mask bitmap!\n");
DeleteObject(color); DeleteObject(color);
return NULL; return NULL;
} }
} }
else else
{ {
mask = CreateBitmap( width, height * 2, 1, 1, NULL ); mask = CreateBitmap( width, height * 2, 1, 1, NULL );
if(!mask) if(!mask)
{ {
ERR("Unable to create mask bitmap!\n"); ERR("Unable to create mask bitmap!\n");
return NULL; return NULL;
} }
} }
} }
else else
{ {

View file

@ -342,7 +342,9 @@ static BOOL DIALOG_CreateControls32( HWND hwnd, LPCSTR template, const DLG_TEMPL
{ {
template = (LPCSTR)DIALOG_GetControl32( (const WORD *)template, &info, template = (LPCSTR)DIALOG_GetControl32( (const WORD *)template, &info,
dlgTemplate->dialogEx ); dlgTemplate->dialogEx );
/* Is this it? */ info.style &= ~WS_POPUP;
info.style |= WS_CHILD;
if (info.style & WS_BORDER) if (info.style & WS_BORDER)
{ {
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) if (!hwndCtrl)
{ {
WARN("control %s %s creation failed\n", debugstr_w(info.className),
debugstr_w(info.windowName));
if (dlgTemplate->style & DS_NOFAILCREATE) continue; if (dlgTemplate->style & DS_NOFAILCREATE) continue;
return FALSE; return FALSE;
} }
@ -1013,6 +1017,7 @@ static HWND DIALOG_CreateIndirect( HINSTANCE hInst, LPCVOID dlgTemplate,
if (dlgProc) if (dlgProc)
{ {
HWND focus = GetNextDlgTabItem( hwnd, 0, FALSE ); HWND focus = GetNextDlgTabItem( hwnd, 0, FALSE );
if (!focus) focus = GetNextDlgGroupItem( hwnd, 0, FALSE );
if (SendMessageW( hwnd, WM_INITDIALOG, (WPARAM)focus, param ) && IsWindow( hwnd ) && if (SendMessageW( hwnd, WM_INITDIALOG, (WPARAM)focus, param ) && IsWindow( hwnd ) &&
((~template.style & DS_CONTROL) || (template.style & WS_VISIBLE))) ((~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 * WM_INITDIALOG may have changed the tab order, so find the first
* tabstop control again. */ * tabstop control again. */
dlgInfo->hwndFocus = GetNextDlgTabItem( hwnd, 0, FALSE ); dlgInfo->hwndFocus = GetNextDlgTabItem( hwnd, 0, FALSE );
if (!dlgInfo->hwndFocus) dlgInfo->hwndFocus = GetNextDlgGroupItem( hwnd, 0, FALSE );
if( dlgInfo->hwndFocus ) if( dlgInfo->hwndFocus )
SetFocus( dlgInfo->hwndFocus ); SetFocus( dlgInfo->hwndFocus );
} }
@ -1983,41 +1989,52 @@ DlgDirSelectExW(
BOOL BOOL
WINAPI WINAPI
EndDialog( EndDialog(
HWND hDlg, HWND hwnd,
INT_PTR nResult) INT_PTR retval)
{ {
BOOL wasEnabled = TRUE; BOOL wasEnabled = TRUE;
DIALOGINFO * dlgInfo; DIALOGINFO * dlgInfo;
HWND owner; 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; return FALSE;
} }
dlgInfo->idResult = retval;
dlgInfo->idResult = nResult;
dlgInfo->flags |= DF_END; dlgInfo->flags |= DF_END;
wasEnabled = (dlgInfo->flags & DF_OWNERENABLED); wasEnabled = (dlgInfo->flags & DF_OWNERENABLED);
if (wasEnabled && (owner = GetWindow( hDlg, GW_OWNER ))) owner = GetWindow( hwnd, GW_OWNER );
if (wasEnabled && owner)
DIALOG_EnableOwner( owner ); DIALOG_EnableOwner( owner );
/* Windows sets the focus to the dialog itself in EndDialog */ /* Windows sets the focus to the dialog itself in EndDialog */
if (IsChild(hDlg, GetFocus())) if (IsChild(hwnd, GetFocus()))
SetFocus( hDlg ); SetFocus( hwnd );
/* Don't have to send a ShowWindow(SW_HIDE), just do /* Don't have to send a ShowWindow(SW_HIDE), just do
SetWindowPos with SWP_HIDEWINDOW as done in Windows */ 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); | 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 */ /* unblock dialog loop */
PostMessageA(hDlg, WM_NULL, 0, 0); PostMessageA(hwnd, WM_NULL, 0, 0);
return TRUE; return TRUE;
} }