From e5755015e7cf57e1f6c9a9ed31c21f98f494b74c Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 21 Sep 2014 01:41:17 +0000 Subject: [PATCH] Fix setting layout direction for wxComboBox in wxMSW. The EDIT control used by the native combobox is different from normal EDIT controls and has to be handled specially. We also need to explicitly forward WS_EX_LAYOUTRTL to the dropdown window as it doesn't inherit it from the combobox itself automatically. See #11583. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@77754 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- include/wx/msw/combobox.h | 2 ++ include/wx/msw/private.h | 41 +++++++++++++++++++++++++++++---------- src/msw/combobox.cpp | 34 ++++++++++++++++++++++++++++++++ src/msw/window.cpp | 25 +----------------------- 4 files changed, 68 insertions(+), 34 deletions(-) diff --git a/include/wx/msw/combobox.h b/include/wx/msw/combobox.h index 5fc7cc5cf1..449eb17266 100644 --- a/include/wx/msw/combobox.h +++ b/include/wx/msw/combobox.h @@ -126,6 +126,8 @@ public: virtual bool SetHint(const wxString& hint); #endif // wxUSE_UXTHEME + virtual void SetLayoutDirection(wxLayoutDirection dir) wxOVERRIDE; + protected: #if wxUSE_TOOLTIPS virtual void DoSetToolTip(wxToolTip *tip); diff --git a/include/wx/msw/private.h b/include/wx/msw/private.h index 5632e4e241..de77f43125 100644 --- a/include/wx/msw/private.h +++ b/include/wx/msw/private.h @@ -1013,29 +1013,28 @@ inline long wxSetWindowExStyle(const wxWindowMSW *win, long style) return ::SetWindowLong(GetHwndOf(win), GWL_EXSTYLE, style); } -// Update layout direction flag for an EDIT control. -// -// Returns true if anything changed or false if the direction flag was already -// set to the desired direction (which can't be wxLayout_Default). -inline bool wxUpdateEditLayoutDirection(WXHWND hWnd, wxLayoutDirection dir) +// Common helper of wxUpdate{,Edit}LayoutDirection() below: sets or clears the +// given flag(s) depending on wxLayoutDirection and returns true if the flags +// really changed. +inline bool +wxUpdateExStyleForLayoutDirection(WXHWND hWnd, + wxLayoutDirection dir, + LONG_PTR flagsForRTL) { wxCHECK_MSG( hWnd, false, wxS("Can't set layout direction for invalid window") ); - static const LONG_PTR - EDIT_RTL_EX_FLAGS = WS_EX_RIGHT | WS_EX_RTLREADING | WS_EX_LEFTSCROLLBAR; - const LONG_PTR styleOld = ::GetWindowLongPtr(hWnd, GWL_EXSTYLE); LONG_PTR styleNew = styleOld; switch ( dir ) { case wxLayout_LeftToRight: - styleNew &= ~EDIT_RTL_EX_FLAGS; + styleNew &= ~flagsForRTL; break; case wxLayout_RightToLeft: - styleNew |= EDIT_RTL_EX_FLAGS; + styleNew |= flagsForRTL; break; case wxLayout_Default: @@ -1050,6 +1049,28 @@ inline bool wxUpdateEditLayoutDirection(WXHWND hWnd, wxLayoutDirection dir) return true; } +// Update layout direction flag for a generic window. +// +// See below for the special version that must be used with EDIT controls. +// +// Returns true if the layout direction did change. +inline bool wxUpdateLayoutDirection(WXHWND hWnd, wxLayoutDirection dir) +{ + return wxUpdateExStyleForLayoutDirection(hWnd, dir, WS_EX_LAYOUTRTL); +} + +// Update layout direction flag for an EDIT control. +// +// Returns true if anything changed or false if the direction flag was already +// set to the desired direction (which can't be wxLayout_Default). +inline bool wxUpdateEditLayoutDirection(WXHWND hWnd, wxLayoutDirection dir) +{ + return wxUpdateExStyleForLayoutDirection(hWnd, dir, + WS_EX_RIGHT | + WS_EX_RTLREADING | + WS_EX_LEFTSCROLLBAR); +} + // Companion of the above function checking if an EDIT control uses RTL. inline wxLayoutDirection wxGetEditLayoutDirection(WXHWND hWnd) { diff --git a/src/msw/combobox.cpp b/src/msw/combobox.cpp index 02dfefb82b..f846184d63 100644 --- a/src/msw/combobox.cpp +++ b/src/msw/combobox.cpp @@ -707,4 +707,38 @@ wxWindow *wxComboBox::MSWFindItem(long id, WXHWND hWnd) const return wxChoice::MSWFindItem(id, hWnd); } +void wxComboBox::SetLayoutDirection(wxLayoutDirection dir) +{ +#ifndef __WXWINCE__ + // Edit field and drop-down list must be handled explicitly. + + // Edit field is a special EDIT control (e.g. it always returns null + // extended style flags), so its layout direction should be set using the + // same extended flag as for ordinary window but reset simply with + // alignment flags. + if ( dir == wxLayout_RightToLeft ) + { + wxUpdateLayoutDirection(GetEditHWND(), dir); + } + else + { + LONG_PTR style = ::GetWindowLongPtr(GetEditHWND(), GWL_STYLE); + if ( !(style & ES_CENTER) ) + { + style &= ~ES_RIGHT; + ::SetWindowLongPtr(GetEditHWND(), GWL_STYLE, style); + } + } + + // Layout for the drop-down list also must be set explicitly. + WinStruct info; + if ( ::GetComboBoxInfo(GetHwnd(), &info) ) + { + wxUpdateLayoutDirection(info.hwndList, dir); + } +#endif // !__WXWINCE__ + + wxChoice::SetLayoutDirection(dir); +} + #endif // wxUSE_COMBOBOX diff --git a/src/msw/window.cpp b/src/msw/window.cpp index 3d4dae58fd..ccca4f7a90 100644 --- a/src/msw/window.cpp +++ b/src/msw/window.cpp @@ -1135,31 +1135,8 @@ void wxWindowMSW::SetLayoutDirection(wxLayoutDirection dir) #ifdef __WXWINCE__ wxUnusedVar(dir); #else - wxCHECK_RET( GetHwnd(), - wxT("layout direction must be set after window creation") ); - - LONG styleOld = wxGetWindowExStyle(this); - - LONG styleNew = styleOld; - switch ( dir ) + if ( wxUpdateLayoutDirection(GetHwnd(), dir) ) { - case wxLayout_LeftToRight: - styleNew &= ~WS_EX_LAYOUTRTL; - break; - - case wxLayout_RightToLeft: - styleNew |= WS_EX_LAYOUTRTL; - break; - - default: - wxFAIL_MSG(wxT("unsupported layout direction")); - break; - } - - if ( styleNew != styleOld ) - { - wxSetWindowExStyle(this, styleNew); - // Update layout: whether we have children or are drawing something, we // need to redo it with the new layout. SendSizeEvent();