From a818e505c4651f2ac3b77ab6f193fee61690a3c6 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Wed, 5 Oct 2022 19:18:56 +0100 Subject: [PATCH 1/3] Add "Process Enter" checkbox to bitmap combo widgets sample page Allow toggling wxTE_PROCESS_ENTER and even set it by default -- and turn off wxCB_READONLY which was set by default for some reason. --- samples/widgets/bmpcombobox.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/samples/widgets/bmpcombobox.cpp b/samples/widgets/bmpcombobox.cpp index 9391f1ba30..0280d283ff 100644 --- a/samples/widgets/bmpcombobox.cpp +++ b/samples/widgets/bmpcombobox.cpp @@ -169,6 +169,7 @@ protected: // the checkboxes for styles wxCheckBox *m_chkSort, + *m_chkProcessEnter, *m_chkReadonly; // the combobox itself and the sizer it is in @@ -250,6 +251,7 @@ BitmapComboBoxWidgetsPage::BitmapComboBoxWidgetsPage(WidgetsBookCtrl *book, { // init everything m_chkSort = + m_chkProcessEnter = m_chkReadonly = NULL; m_combobox = NULL; @@ -314,6 +316,7 @@ void BitmapComboBoxWidgetsPage::CreateContent() wxSizer *sizerStyle = new wxStaticBoxSizer(box, wxVERTICAL); m_chkSort = CreateCheckBoxAndAddToSizer(sizerStyle, "&Sort items"); + m_chkProcessEnter = CreateCheckBoxAndAddToSizer(sizerStyle, "Process &Enter"); m_chkReadonly = CreateCheckBoxAndAddToSizer(sizerStyle, "&Read only"); wxButton *btn = new wxButton(this, BitmapComboBoxPage_Reset, "&Reset"); @@ -385,7 +388,8 @@ void BitmapComboBoxWidgetsPage::CreateContent() m_combobox->Create(this, BitmapComboBoxPage_Combo, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, - wxCB_READONLY); + // Flags correspond to the checkboxes state in Reset(). + wxTE_PROCESS_ENTER); #if defined(wxGENERIC_BITMAPCOMBOBOX) // This will sure make the list look nicer when larger images are used. @@ -414,7 +418,8 @@ void BitmapComboBoxWidgetsPage::CreateContent() void BitmapComboBoxWidgetsPage::Reset() { m_chkSort->SetValue(false); - m_chkReadonly->SetValue(true); + m_chkProcessEnter->SetValue(true); + m_chkReadonly->SetValue(false); } void BitmapComboBoxWidgetsPage::CreateCombo() @@ -423,6 +428,8 @@ void BitmapComboBoxWidgetsPage::CreateCombo() if ( m_chkSort->GetValue() ) flags |= wxCB_SORT; + if ( m_chkProcessEnter->GetValue() ) + flags |= wxTE_PROCESS_ENTER; if ( m_chkReadonly->GetValue() ) flags |= wxCB_READONLY; @@ -752,7 +759,9 @@ void BitmapComboBoxWidgetsPage::OnButtonAddWidgetIcons(wxCommandEvent& WXUNUSED( void BitmapComboBoxWidgetsPage::OnUpdateUIResetButton(wxUpdateUIEvent& event) { if (m_combobox) - event.Enable( m_chkSort->GetValue() || m_chkReadonly->GetValue() ); + event.Enable( m_chkSort->GetValue() + || !m_chkProcessEnter->GetValue() + || m_chkReadonly->GetValue() ); } void BitmapComboBoxWidgetsPage::OnUpdateUIInsert(wxUpdateUIEvent& event) From 30f30ff9464db4a95fde63e6a848d2bb753d332f Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Wed, 5 Oct 2022 23:47:09 +0100 Subject: [PATCH 2/3] Add wxComboBox::MSWRecreate() and use it from wxBitmapComboBox No real changes, this is just a refactoring moving the code recreating the native MSW combobox into wxComboBox itself, as it seems better to do this in this class itself rather than outside of it. This commit is best viewed with Git --color-moved option. --- include/wx/msw/combobox.h | 6 +++ src/msw/bmpcbox.cpp | 90 +------------------------------------ src/msw/combobox.cpp | 93 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 100 insertions(+), 89 deletions(-) diff --git a/include/wx/msw/combobox.h b/include/wx/msw/combobox.h index 3114d41b0d..0b72ba65ef 100644 --- a/include/wx/msw/combobox.h +++ b/include/wx/msw/combobox.h @@ -154,6 +154,12 @@ protected: m_allowTextEvents = enable; } + // Recreate the native control entirely while preserving its initial + // contents and attributes: this is useful if the height of the items must + // be changed as the native control doesn't seem to support doing this once + // it had been already determined. + void MSWRecreate(); + private: // there are the overridden wxTextEntry methods which should only be called // when we do have an edit control so they assert if this is not the case diff --git a/src/msw/bmpcbox.cpp b/src/msw/bmpcbox.cpp index 011bd4f534..85c23c1ba6 100644 --- a/src/msw/bmpcbox.cpp +++ b/src/msw/bmpcbox.cpp @@ -123,97 +123,9 @@ void wxBitmapComboBox::RecreateControl() // Can't use CBS_OWNERDRAWVARIABLE because it has odd // mouse-wheel behaviour. // - wxString value = GetValue(); - int selection = GetSelection(); - wxPoint pos = GetPosition(); - wxSize size = GetSize(); - size.y = GetBestSize().y; - const wxArrayString strings = GetStrings(); - const unsigned numItems = strings.size(); - unsigned i; - - // Save the client data pointers before clearing the control, if any. - const wxClientDataType clientDataType = GetClientDataType(); - wxVector objectClientData; - wxVector voidClientData; - switch ( clientDataType ) - { - case wxClientData_None: - break; - - case wxClientData_Object: - objectClientData.reserve(numItems); - for ( i = 0; i < numItems; ++i ) - objectClientData.push_back(GetClientObject(i)); - break; - - case wxClientData_Void: - voidClientData.reserve(numItems); - for ( i = 0; i < numItems; ++i ) - voidClientData.push_back(GetClientData(i)); - break; - } - - wxComboBox::DoClear(); - - HWND hwnd = GetHwnd(); - DissociateHandle(); - ::DestroyWindow(hwnd); - - if ( !MSWCreateControl(wxT("COMBOBOX"), wxEmptyString, pos, size) ) - return; - - // initialize the controls contents - for ( i = 0; i < numItems; i++ ) - { - wxComboBox::Append(strings[i]); - - if ( !objectClientData.empty() ) - SetClientObject(i, objectClientData[i]); - else if ( !voidClientData.empty() ) - SetClientData(i, voidClientData[i]); - } - - // and make sure it has the same attributes as before - if ( m_hasFont ) - { - // calling SetFont(m_font) would do nothing as the code would - // notice that the font didn't change, so force it to believe - // that it did - wxFont font = m_font; - m_font = wxNullFont; - SetFont(font); - } - - if ( m_hasFgCol ) - { - wxColour colFg = m_foregroundColour; - m_foregroundColour = wxNullColour; - SetForegroundColour(colFg); - } - - if ( m_hasBgCol ) - { - wxColour colBg = m_backgroundColour; - m_backgroundColour = wxNullColour; - SetBackgroundColour(colBg); - } - else - { - SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); - } + MSWRecreate(); ::SendMessage(GetHwnd(), CB_SETITEMHEIGHT, 0, MeasureItem(0)); - - // Revert the old string value - if ( !HasFlag(wxCB_READONLY) ) - ChangeValue(value); - else if ( selection != wxNOT_FOUND ) - SetSelection(selection); - - // If disabled we'll have to disable it again after re-creating - if ( !IsEnabled() ) - DoEnable(false); } wxBitmapComboBox::~wxBitmapComboBox() diff --git a/src/msw/combobox.cpp b/src/msw/combobox.cpp index 94a9c03385..1e64117342 100644 --- a/src/msw/combobox.cpp +++ b/src/msw/combobox.cpp @@ -440,6 +440,99 @@ wxWindow *wxComboBox::GetEditableWindow() // wxComboBox creation // ---------------------------------------------------------------------------- +void wxComboBox::MSWRecreate() +{ + wxString value = GetValue(); + int selection = GetSelection(); + wxPoint pos = GetPosition(); + wxSize size = GetSize(); + size.y = GetBestSize().y; + const wxArrayString strings = GetStrings(); + const unsigned numItems = strings.size(); + unsigned i; + + // Save the client data pointers before clearing the control, if any. + const wxClientDataType clientDataType = GetClientDataType(); + wxVector objectClientData; + wxVector voidClientData; + switch ( clientDataType ) + { + case wxClientData_None: + break; + + case wxClientData_Object: + objectClientData.reserve(numItems); + for ( i = 0; i < numItems; ++i ) + objectClientData.push_back(GetClientObject(i)); + break; + + case wxClientData_Void: + voidClientData.reserve(numItems); + for ( i = 0; i < numItems; ++i ) + voidClientData.push_back(GetClientData(i)); + break; + } + + wxComboBox::DoClear(); + + HWND hwnd = GetHwnd(); + DissociateHandle(); + ::DestroyWindow(hwnd); + + if ( !MSWCreateControl(wxT("COMBOBOX"), wxEmptyString, pos, size) ) + return; + + // initialize the controls contents + for ( i = 0; i < numItems; i++ ) + { + wxComboBox::Append(strings[i]); + + if ( !objectClientData.empty() ) + SetClientObject(i, objectClientData[i]); + else if ( !voidClientData.empty() ) + SetClientData(i, voidClientData[i]); + } + + // and make sure it has the same attributes as before + if ( m_hasFont ) + { + // calling SetFont(m_font) would do nothing as the code would + // notice that the font didn't change, so force it to believe + // that it did + wxFont font = m_font; + m_font = wxNullFont; + SetFont(font); + } + + if ( m_hasFgCol ) + { + wxColour colFg = m_foregroundColour; + m_foregroundColour = wxNullColour; + SetForegroundColour(colFg); + } + + if ( m_hasBgCol ) + { + wxColour colBg = m_backgroundColour; + m_backgroundColour = wxNullColour; + SetBackgroundColour(colBg); + } + else + { + SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); + } + + // Revert the old string value + if ( !HasFlag(wxCB_READONLY) ) + ChangeValue(value); + else if ( selection != wxNOT_FOUND ) + SetSelection(selection); + + // If disabled we'll have to disable it again after re-creating + if ( !IsEnabled() ) + DoEnable(false); +} + bool wxComboBox::Create(wxWindow *parent, wxWindowID id, const wxString& value, const wxPoint& pos, From 2466acb0daddef73ab28631076606d9e2c0add53 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Wed, 5 Oct 2022 23:55:20 +0100 Subject: [PATCH 3/3] Fix not getting some wxComboBox events after recreating it Subclass the new EDIT control recreated together with the COMBOBOX itself to make sure we still process the messages from it correctly. This notably ensures that we still get wxEVT_TEXT_ENTER events in wxBitmapComboBox under MSW after adding some items with images to it, as this recreates the combobox internally. --- src/msw/combobox.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/msw/combobox.cpp b/src/msw/combobox.cpp index 1e64117342..91db31427b 100644 --- a/src/msw/combobox.cpp +++ b/src/msw/combobox.cpp @@ -482,6 +482,14 @@ void wxComboBox::MSWRecreate() if ( !MSWCreateControl(wxT("COMBOBOX"), wxEmptyString, pos, size) ) return; + if ( !HasFlag(wxCB_READONLY) ) + { + // A new EDIT control was created as well, we need to subclass it just + // as when creating the combobox, see Create(). However we don't need + // to assign to gs_wndprocEdit as it must have been already set. + wxSetWindowProc((HWND)GetEditHWND(), wxComboEditWndProc); + } + // initialize the controls contents for ( i = 0; i < numItems; i++ ) {