From f139198cfc8afd5fbb159c4ab3a7c33234e03d9f Mon Sep 17 00:00:00 2001 From: Richard Powell Date: Sat, 1 Jul 2023 07:56:43 -0700 Subject: [PATCH] Issue #123: Allow binding to multiple events Making it possible to bind to multiple events. Updated Docs. --- LATEST_RELEASE_NOTES.md | 6 +- docs/ProgrammersGuide.md | 46 ++++---- docs/src/docs/ProgrammersGuide.md | 38 +++---- examples/HelloWorld/ExtendedExample.cpp | 32 +++++- examples/HelloWorld/ExtendedExample.h | 14 +++ examples/HelloWorld/HelloWorld.cpp | 4 + include/wxUI/Bitmap.h | 3 +- include/wxUI/BitmapButton.h | 5 +- include/wxUI/BitmapComboBox.h | 5 +- include/wxUI/BitmapToggleButton.h | 5 +- include/wxUI/Button.h | 5 +- include/wxUI/CheckBox.h | 5 +- include/wxUI/Choice.h | 5 +- include/wxUI/ComboBox.h | 5 +- include/wxUI/Hyperlink.h | 6 +- include/wxUI/Line.h | 2 +- include/wxUI/ListBox.h | 5 +- include/wxUI/RadioBox.h | 9 +- include/wxUI/Slider.h | 5 +- include/wxUI/SpinCtrl.h | 5 +- include/wxUI/Text.h | 2 +- include/wxUI/TextCtrl.h | 6 +- include/wxUI/Widget.h | 144 ++++++++++++++++++------ tests/wxUI_ButtonTests.cpp | 1 - 24 files changed, 249 insertions(+), 114 deletions(-) diff --git a/LATEST_RELEASE_NOTES.md b/LATEST_RELEASE_NOTES.md index 7d0d47d..b590ea2 100644 --- a/LATEST_RELEASE_NOTES.md +++ b/LATEST_RELEASE_NOTES.md @@ -1,8 +1,8 @@ -# wxUI release notes for v0.1.3 +# wxUI release notes for v0.1.4 Bugs addressed in this release: -* [#118](../../issues/118) make_unique used without including - Other changes: +* [#123](../../issues/123) Allow binding to multiple events + diff --git a/docs/ProgrammersGuide.md b/docs/ProgrammersGuide.md index c24cf1e..aa031d7 100644 --- a/docs/ProgrammersGuide.md +++ b/docs/ProgrammersGuide.md @@ -46,6 +46,10 @@ Handlers are callable items that handle events. The handler can be declared wit ExtendedExample dialog(this); dialog.ShowModal(); } }, + wxUI::Item { "&MultibindExample...", [this] { + MultibindExample dialog(this); + dialog.ShowModal(); + } }, wxUI::Item { "&Example Item...", [] { wxLogMessage("Hello World!"); } }, @@ -85,6 +89,10 @@ Items { "Name", "Help", Handler } ExtendedExample dialog(this); dialog.ShowModal(); } }, + wxUI::Item { "&MultibindExample...", [this] { + MultibindExample dialog(this); + dialog.ShowModal(); + } }, wxUI::Item { "&Example Item...", [] { wxLogMessage("Hello World!"); } }, @@ -174,7 +182,7 @@ The list of Methods supported by all controllers: #### Bind -Some *Controllers* support "binding" a function call to their event handlers. When the event for that controller is emitted, the function-like object supplied will be called. +*Controllers* support "binding" a function call to their event handlers. When the event for that *controller* is emitted, the function-like object supplied will be called. You can bind multiple events on a single *controller*. For convenience, some *controllers* have default events that will be used if none is supplied. ```cpp Button { wxSizerFlags().Border(wxRIGHT), "Left" } @@ -223,24 +231,24 @@ ExtendedExample::ExtendedExample(wxWindow* parent) The "Controllers" currently supported by `wxUI`: -| wxUI | wxWidget | Proxy | Proxy accessors value | -| :------------------- | :--------------------- | :------------------------ | :-------------- | -| `Bitmap` | `wxStaticBitmap` | `BitmapProxy` | n/a | -| `BitmapButton` | `wxBitmapButton` | `BitmapButtonProxy` | n/a | -| `BitmapComboBox` | `wxBitmapComboBox` | `BitmapComboBoxProxy` | `selection` -> `int`
`value` -> `std::string`
*default*: `value` | -| `BitmapToggleButton` | `wxBitmapToggleButton` | `BitmapToggleButtonProxy` | `value` -> `bool`
*default*: `value` | -| `Button` | `wxButton` | `ButtonProxy` | n/a | -| `CheckBox` | `wxCheckBox` | `CheckBoxProxy` | `value` -> `bool`
*default*: `value` | -| `Choice` | `wxChoice` | `ChoiceProxy` | `selection` -> `int`
*default*: `selection` | -| `ComboBox` | `wxComboBox` | `ComboBoxProxy` | `selection` -> `int`
`value` -> `std::string`
*default*: `value` | -| `Hypertext` | `wxHypertextCtrl` | `HypertextProxy` | n/a | -| `Line` | `wxStaticLine` | `LineProxy` | n/a | -| `ListBox` | `wxListBox` | `ListBoxProxy` | `selection` -> `int`
*default*: `selection` | -| `RadioBox` | `wxRadioBox` | `RadioBoxProxy` | `selection` -> `int`
*default*: `selection` | -| `Slider` | `wxSlider` | `SliderProxy` | `value` -> `int`
*default*: `value` | -| `SpinCtrl` | `wxSpinCtrl` | `SpinCtrlProxy` | `value` -> `int`
*default*: `value` | -| `Text` | `wxStaticText` | `TextProxy` | `label` -> `std::string`
*default*: `label` | -| `TextCtrl` | `wxTextCtrl` | `TextCtrlProxy` | `label` -> `std::string`
*default*: `label` | +| wxUI | wxWidget | Default Event | Proxy | Proxy accessors value | +| :------------------- | :--------------------- | :----------------- | :------------------------ | :-------------- | +| `Bitmap` | `wxStaticBitmap` | n/a | `BitmapProxy` | n/a | +| `BitmapButton` | `wxBitmapButton` | `EVT_BUTTON` | `BitmapButtonProxy` | n/a | +| `BitmapComboBox` | `wxBitmapComboBox` | `EVT_COMBOBOX` | `BitmapComboBoxProxy` | `selection` -> `int`
`value` -> `std::string`
*default*: `value` | +| `BitmapToggleButton` | `wxBitmapToggleButton` | `EVT_TOGGLEBUTTON` | `BitmapToggleButtonProxy` | `value` -> `bool`
*default*: `value` | +| `Button` | `wxButton` | `EVT_BUTTON` | `ButtonProxy` | n/a | +| `CheckBox` | `wxCheckBox` | `EVT_CHECKBOX` | `CheckBoxProxy` | `value` -> `bool`
*default*: `value` | +| `Choice` | `wxChoice` | `EVT_CHOICE` | `ChoiceProxy` | `selection` -> `int`
*default*: `selection` | +| `ComboBox` | `wxComboBox` | `EVT_COMBOBOX` | `ComboBoxProxy` | `selection` -> `int`
`value` -> `std::string`
*default*: `value` | +| `Hypertext` | `wxHypertextCtrl` | n/a | `HypertextProxy` | n/a | +| `Line` | `wxStaticLine` | n/a | `LineProxy` | n/a | +| `ListBox` | `wxListBox` | `EVT_LISTBOX` | `ListBoxProxy` | `selection` -> `int`
*default*: `selection` | +| `RadioBox` | `wxRadioBox` | `EVT_RADIOBOX` | `RadioBoxProxy` | `selection` -> `int`
*default*: `selection` | +| `Slider` | `wxSlider` | `EVT_SLIDER` | `SliderProxy` | `value` -> `int`
*default*: `value` | +| `SpinCtrl` | `wxSpinCtrl` | `EVT_SPINCTRL` | `SpinCtrlProxy` | `value` -> `int`
*default*: `value` | +| `Text` | `wxStaticText` | n/a | `TextProxy` | `label` -> `std::string`
*default*: `label` | +| `TextCtrl` | `wxTextCtrl` | `EVT_TEXT` | `TextCtrlProxy` | `label` -> `std::string`
*default*: `label` | Additional "Contollers" should be easy to add in future updates. diff --git a/docs/src/docs/ProgrammersGuide.md b/docs/src/docs/ProgrammersGuide.md index 89259f0..8b3dc3b 100644 --- a/docs/src/docs/ProgrammersGuide.md +++ b/docs/src/docs/ProgrammersGuide.md @@ -111,7 +111,7 @@ The list of Methods supported by all controllers: #### Bind -Some *Controllers* support "binding" a function call to their event handlers. When the event for that controller is emitted, the function-like object supplied will be called. +*Controllers* support "binding" a function call to their event handlers. When the event for that *controller* is emitted, the function-like object supplied will be called. You can bind multiple events on a single *controller*. For convenience, some *controllers* have default events that will be used if none is supplied. ```cpp {{{ examples/HelloWorld/HelloWorld.cpp wxUIBind " // ..." }}} @@ -157,24 +157,24 @@ ExtendedExample::ExtendedExample(wxWindow* parent) The "Controllers" currently supported by `wxUI`: -| wxUI | wxWidget | Proxy | Proxy accessors value | -| :------------------- | :--------------------- | :------------------------ | :-------------- | -| `Bitmap` | `wxStaticBitmap` | `BitmapProxy` | n/a | -| `BitmapButton` | `wxBitmapButton` | `BitmapButtonProxy` | n/a | -| `BitmapComboBox` | `wxBitmapComboBox` | `BitmapComboBoxProxy` | `selection` -> `int`
`value` -> `std::string`
*default*: `value` | -| `BitmapToggleButton` | `wxBitmapToggleButton` | `BitmapToggleButtonProxy` | `value` -> `bool`
*default*: `value` | -| `Button` | `wxButton` | `ButtonProxy` | n/a | -| `CheckBox` | `wxCheckBox` | `CheckBoxProxy` | `value` -> `bool`
*default*: `value` | -| `Choice` | `wxChoice` | `ChoiceProxy` | `selection` -> `int`
*default*: `selection` | -| `ComboBox` | `wxComboBox` | `ComboBoxProxy` | `selection` -> `int`
`value` -> `std::string`
*default*: `value` | -| `Hypertext` | `wxHypertextCtrl` | `HypertextProxy` | n/a | -| `Line` | `wxStaticLine` | `LineProxy` | n/a | -| `ListBox` | `wxListBox` | `ListBoxProxy` | `selection` -> `int`
*default*: `selection` | -| `RadioBox` | `wxRadioBox` | `RadioBoxProxy` | `selection` -> `int`
*default*: `selection` | -| `Slider` | `wxSlider` | `SliderProxy` | `value` -> `int`
*default*: `value` | -| `SpinCtrl` | `wxSpinCtrl` | `SpinCtrlProxy` | `value` -> `int`
*default*: `value` | -| `Text` | `wxStaticText` | `TextProxy` | `label` -> `std::string`
*default*: `label` | -| `TextCtrl` | `wxTextCtrl` | `TextCtrlProxy` | `label` -> `std::string`
*default*: `label` | +| wxUI | wxWidget | Default Event | Proxy | Proxy accessors value | +| :------------------- | :--------------------- | :----------------- | :------------------------ | :-------------- | +| `Bitmap` | `wxStaticBitmap` | n/a | `BitmapProxy` | n/a | +| `BitmapButton` | `wxBitmapButton` | `EVT_BUTTON` | `BitmapButtonProxy` | n/a | +| `BitmapComboBox` | `wxBitmapComboBox` | `EVT_COMBOBOX` | `BitmapComboBoxProxy` | `selection` -> `int`
`value` -> `std::string`
*default*: `value` | +| `BitmapToggleButton` | `wxBitmapToggleButton` | `EVT_TOGGLEBUTTON` | `BitmapToggleButtonProxy` | `value` -> `bool`
*default*: `value` | +| `Button` | `wxButton` | `EVT_BUTTON` | `ButtonProxy` | n/a | +| `CheckBox` | `wxCheckBox` | `EVT_CHECKBOX` | `CheckBoxProxy` | `value` -> `bool`
*default*: `value` | +| `Choice` | `wxChoice` | `EVT_CHOICE` | `ChoiceProxy` | `selection` -> `int`
*default*: `selection` | +| `ComboBox` | `wxComboBox` | `EVT_COMBOBOX` | `ComboBoxProxy` | `selection` -> `int`
`value` -> `std::string`
*default*: `value` | +| `Hypertext` | `wxHypertextCtrl` | n/a | `HypertextProxy` | n/a | +| `Line` | `wxStaticLine` | n/a | `LineProxy` | n/a | +| `ListBox` | `wxListBox` | `EVT_LISTBOX` | `ListBoxProxy` | `selection` -> `int`
*default*: `selection` | +| `RadioBox` | `wxRadioBox` | `EVT_RADIOBOX` | `RadioBoxProxy` | `selection` -> `int`
*default*: `selection` | +| `Slider` | `wxSlider` | `EVT_SLIDER` | `SliderProxy` | `value` -> `int`
*default*: `value` | +| `SpinCtrl` | `wxSpinCtrl` | `EVT_SPINCTRL` | `SpinCtrlProxy` | `value` -> `int`
*default*: `value` | +| `Text` | `wxStaticText` | n/a | `TextProxy` | `label` -> `std::string`
*default*: `label` | +| `TextCtrl` | `wxTextCtrl` | `EVT_TEXT` | `TextCtrlProxy` | `label` -> `std::string`
*default*: `label` | Additional "Contollers" should be easy to add in future updates. diff --git a/examples/HelloWorld/ExtendedExample.cpp b/examples/HelloWorld/ExtendedExample.cpp index 1ac3425..ccf9476 100644 --- a/examples/HelloWorld/ExtendedExample.cpp +++ b/examples/HelloWorld/ExtendedExample.cpp @@ -26,8 +26,6 @@ SOFTWARE. #include "ExtendedExample.h" #include -wxUI::Text::Proxy textProxy; -wxUI::SpinCtrl::Proxy spinProxy; ExtendedExample::ExtendedExample(wxWindow* parent) : wxDialog(parent, wxID_ANY, "ExtendedExample", wxDefaultPosition, wxDefaultSize, @@ -42,7 +40,7 @@ ExtendedExample::ExtendedExample(wxWindow* parent) }, HSizer { Button { "Incr" } - .bind([]() { + .bind([this]() { *spinProxy = 1 + *spinProxy; }), }, @@ -61,7 +59,7 @@ ExtendedExample::ExtendedExample(wxWindow* parent) }, HSizer { Button { "ReduceText" } - .bind([]() { + .bind([this]() { auto str = textProxy->get(); if (str.size()) { str.pop_back(); @@ -123,3 +121,29 @@ ExtendedExample::ExtendedExample(wxWindow* parent) } .attachTo(this); } + +MultibindExample::MultibindExample(wxWindow* parent) + : wxDialog(parent, wxID_ANY, "MultibindExample", wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) +{ + using namespace wxUI; + VSizer { + wxSizerFlags().Expand().Border(), + HSizer { + TextCtrl {} + .withSize({ 200, -1 }) + .withStyle(wxTE_PROCESS_ENTER) + .bind([this]() { + *timesTyped = std::to_string(stoi(*timesTyped) + 1); + }) + .bind(wxEVT_TEXT_ENTER, [this]() { + *timesEntered = std::to_string(stoi(*timesEntered) + 1); + }), + }, + HSizer { + timesTyped = Text { "0" }, + timesEntered = Text { "0" }, + }, + Generic { CreateStdDialogButtonSizer(wxOK) }, + } + .attachTo(this); +} diff --git a/examples/HelloWorld/ExtendedExample.h b/examples/HelloWorld/ExtendedExample.h index 01fcee0..dcb8999 100644 --- a/examples/HelloWorld/ExtendedExample.h +++ b/examples/HelloWorld/ExtendedExample.h @@ -25,8 +25,22 @@ SOFTWARE. // wxUI Extended Dialog Example #include +#include class ExtendedExample : public wxDialog { public: explicit ExtendedExample(wxWindow* parent); + +private: + wxUI::Text::Proxy textProxy; + wxUI::SpinCtrl::Proxy spinProxy; +}; + +class MultibindExample : public wxDialog { +public: + explicit MultibindExample(wxWindow* parent); + +private: + wxUI::Text::Proxy timesTyped; + wxUI::Text::Proxy timesEntered; }; diff --git a/examples/HelloWorld/HelloWorld.cpp b/examples/HelloWorld/HelloWorld.cpp index 1961b6a..066f0fa 100644 --- a/examples/HelloWorld/HelloWorld.cpp +++ b/examples/HelloWorld/HelloWorld.cpp @@ -125,6 +125,10 @@ HelloWorldFrame::HelloWorldFrame() ExtendedExample dialog(this); dialog.ShowModal(); } }, + wxUI::Item { "&MultibindExample...", [this] { + MultibindExample dialog(this); + dialog.ShowModal(); + } }, wxUI::Item { "&Example Item...", [] { wxLogMessage("Hello World!"); } }, diff --git a/include/wxUI/Bitmap.h b/include/wxUI/Bitmap.h index e21f286..53d18d1 100644 --- a/include/wxUI/Bitmap.h +++ b/include/wxUI/Bitmap.h @@ -68,5 +68,6 @@ struct Bitmap : public details::WidgetDetails { wxBitmap bitmap; }; -static_assert(details::Widget); +WIDGET_STATIC_ASSERT_BOILERPLATE(Bitmap); + } diff --git a/include/wxUI/BitmapButton.h b/include/wxUI/BitmapButton.h index 7221be7..62fb0ab 100644 --- a/include/wxUI/BitmapButton.h +++ b/include/wxUI/BitmapButton.h @@ -69,10 +69,11 @@ struct BitmapButton : public details::WidgetDetails auto bind(Function func) { - return details::BindWidgetToEvent { *this, wxEVT_BUTTON, func }; + return super::bind(wxEVT_BUTTON, func); } struct Proxy : super::WidgetProxy { @@ -85,5 +86,5 @@ struct BitmapButton : public details::WidgetDetails); +WIDGET_STATIC_ASSERT_BOILERPLATE(BitmapButton); } diff --git a/include/wxUI/BitmapComboBox.h b/include/wxUI/BitmapComboBox.h index 6b730bf..b5915be 100644 --- a/include/wxUI/BitmapComboBox.h +++ b/include/wxUI/BitmapComboBox.h @@ -102,10 +102,11 @@ struct BitmapComboBox : public details::WidgetDetails auto bind(Function func) { - return details::BindWidgetToEvent { *this, wxEVT_COMBOBOX, func }; + return super::bind(wxEVT_COMBOBOX, func); } struct Proxy : super::WidgetProxy { @@ -138,5 +139,5 @@ struct BitmapComboBox : public details::WidgetDetails); +WIDGET_STATIC_ASSERT_BOILERPLATE(BitmapComboBox); } diff --git a/include/wxUI/BitmapToggleButton.h b/include/wxUI/BitmapToggleButton.h index 07bd165..e57f283 100644 --- a/include/wxUI/BitmapToggleButton.h +++ b/include/wxUI/BitmapToggleButton.h @@ -66,10 +66,11 @@ struct BitmapToggleButton : public details::WidgetDetails auto bind(Function func) { - return details::BindWidgetToEvent { *this, wxEVT_TOGGLEBUTTON, func }; + return super::bind(wxEVT_TOGGLEBUTTON, func); } struct Proxy : super::WidgetProxy { @@ -93,5 +94,5 @@ struct BitmapToggleButton : public details::WidgetDetails bitmapPressed; }; -static_assert(details::Widget); +WIDGET_STATIC_ASSERT_BOILERPLATE(BitmapToggleButton); } diff --git a/include/wxUI/Button.h b/include/wxUI/Button.h index 24d8bba..aa84a48 100644 --- a/include/wxUI/Button.h +++ b/include/wxUI/Button.h @@ -70,10 +70,11 @@ struct Button : public details::WidgetDetails { return *this; } + using super::bind; template auto bind(Function func) { - return details::BindWidgetToEvent { *this, wxEVT_BUTTON, func }; + return super::bind(wxEVT_BUTTON, func); } struct Proxy : super::WidgetProxy { @@ -86,5 +87,5 @@ struct Button : public details::WidgetDetails { bool isDefault = false; }; -static_assert(details::Widget