From e13eb18455e032a36aede58331aff46220f0d9d6 Mon Sep 17 00:00:00 2001 From: Joseph Lenox Date: Tue, 26 Jun 2018 20:20:27 -0500 Subject: [PATCH] Implemented UI_SpinCtrl and refactored common components to UI_Window. Added tests. Replaced click tests in UI_Checkbox with event pushes. --- src/CMakeLists.txt | 1 + src/GUI/OptionsGroup/Field.hpp | 126 +++++++++++++---- src/test/GUI/test_field_checkbox.cpp | 204 ++++++++------------------- src/test/GUI/test_field_spinctrl.cpp | 156 ++++++++++++++++++++ xs/src/libslic3r/Log.hpp | 4 + 5 files changed, 317 insertions(+), 174 deletions(-) create mode 100644 src/test/GUI/test_field_spinctrl.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4bc65a525..8e179f05b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -177,6 +177,7 @@ set(UI_TEST_SOURCES ${GUI_TESTDIR}/testableframe.cpp ${GUI_TESTDIR}/test_harness_gui.cpp ${GUI_TESTDIR}/test_field_checkbox.cpp + ${GUI_TESTDIR}/test_field_spinctrl.cpp ) set(SLIC3R_TEST_SOURCES ${TESTDIR}/test_harness.cpp diff --git a/src/GUI/OptionsGroup/Field.hpp b/src/GUI/OptionsGroup/Field.hpp index 6397a02a5..726aa8caa 100644 --- a/src/GUI/OptionsGroup/Field.hpp +++ b/src/GUI/OptionsGroup/Field.hpp @@ -2,16 +2,65 @@ #define SLIC3R_FIELD_HPP #include +#include +#include #include #include "ConfigBase.hpp" +#include "Log.hpp" + +#include "wx/spinctrl.h" namespace Slic3r { namespace GUI { -class UI_Checkbox { +using namespace std::string_literals; + +class UI_Window { public: - UI_Checkbox(wxWindow* parent, Slic3r::ConfigOptionDef _opt, wxWindowID checkid = wxID_ANY) : parent(parent), opt(_opt) { - ui_window = new wxCheckBox(parent, checkid, ""); - _check = dynamic_cast(ui_window); + UI_Window(wxWindow* _parent, Slic3r::ConfigOptionDef _opt) : parent(_parent), opt(_opt) {}; + virtual ~UI_Window() = default; + + /// Don't trigger on_change when this is true. + bool disable_change_event {false}; + + /// Set the underlying control to the value (cast it and throw bad_any_cast if there are problems). + virtual void set_value(boost::any value) = 0; + + /// Enables the underlying UI widget. + void enable() { this->window->Enable(); } + + /// Disables the underlying UI widget. + void disable() { this->window->Disable(); } + + /// Set the underlying widget to either enabled or disabled. + void toggle(bool enable = true) { enable ? this->enable() : this->disable(); } + + /// Getter functions for UI_Window items. + virtual bool get_bool() { Slic3r::Log::warn(this->LogChannel(), "get_bool does not exist"s); return false; } //< return false all the time if this is not implemented. + virtual int get_int() { Slic3r::Log::warn(this->LogChannel(), "get_int does not exist"s); return 0; } //< return 0 all the time if this is not implemented. + + /// Function to call when the contents of this change. + std::function on_change {nullptr}; + std::function on_kill_focus {nullptr}; + +protected: + wxWindow* parent {nullptr}; + wxWindow* window {nullptr}; //< Pointer copy of the derived classes + + const Slic3r::ConfigOptionDef opt; //< Reference to the UI-specific bits of this option + + virtual std::string LogChannel() { return "UI_Window"s; } + + virtual void _on_change(std::string opt_id) = 0; + + /// Define a default size for derived classes. + wxSize _default_size() { return wxSize((opt.width >= 0 ? opt.width : 60), (opt.height != -1 ? opt.height : -1)); } +}; + +class UI_Checkbox : public UI_Window { +public: + UI_Checkbox(wxWindow* parent, Slic3r::ConfigOptionDef _opt, wxWindowID checkid = wxID_ANY) : UI_Window(parent, _opt) { + _check = new wxCheckBox(parent, checkid, ""); + this->window = _check; // Set some defaults. if (this->opt.readonly) { this->_check->Disable(); } @@ -21,43 +70,68 @@ public: _check->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent& e) { this->_on_change(""); e.Skip(); }); _check->Bind(wxEVT_KILL_FOCUS, [this](wxFocusEvent& e) { if (this->on_kill_focus != nullptr) {this->on_kill_focus("");} e.Skip(); }); } - ~UI_Checkbox() { wxDELETE(_check); ui_window = _check = nullptr; } - /// Function to call when the contents of this change. - std::function on_change {nullptr}; - std::function on_kill_focus {nullptr}; - /// Don't trigger on_change when this is true. - bool disable_change_event {false}; - - /// Enables the underlying UI widget. - void enable() { this->_check->Enable(); } - - /// Disables the underlying UI widget. - void disable() { this->ui_window->Disable(); } - - /// Set the underlying widget to either enabled or disabled. - void toggle(bool enable = true) { enable ? this->enable() : this->disable(); } + ~UI_Checkbox() = default; + /// Returns a bare pointer to the underlying checkbox, usually for test interface wxCheckBox* check() { return _check; } /// Returns the value of the enclosed checkbox. /// Implements get_bool - bool get_bool() { return _check->GetValue();} + virtual bool get_bool() override { return _check->GetValue();} /// Casts the containing value to boolean and sets the built-in checkbox appropriately. /// implements set_value - void set_value(boost::any value) { this->_check->SetValue(boost::any_cast(value)); } -private: - wxWindow* parent {nullptr}; - wxWindow* ui_window {nullptr}; + virtual void set_value(boost::any value) override { this->_check->SetValue(boost::any_cast(value)); } + +protected: wxCheckBox* _check {nullptr}; - const Slic3r::ConfigOptionDef opt; //< Reference to the UI-specific bits of this option + + virtual std::string LogChannel() override { return "UI_Checkbox"s; } void _on_change(std::string opt_id) { - if (!this->disable_change_event && this->on_change != nullptr) { + if (!this->disable_change_event && this->window->IsEnabled() && this->on_change != nullptr) { this->on_change(opt_id, this->get_bool()); } } + +}; + +class UI_SpinCtrl : public UI_Window { +public: + UI_SpinCtrl(wxWindow* parent, Slic3r::ConfigOptionDef _opt, wxWindowID spinid = wxID_ANY) : UI_Window(parent, _opt) { + + /// Initialize and set defaults, if available. + _spin = new wxSpinCtrl(parent, spinid, "", wxDefaultPosition, _default_size(), 0, + (opt.min > 0 ? opt.min : 0), + (opt.max > 0 ? opt.max : std::numeric_limits::max()), + (opt.default_value != NULL ? opt.default_value->getInt() : 0)); + + window = _spin; + + // Set up event handlers + _spin->Bind(wxEVT_SPINCTRL, [this](wxCommandEvent& e) { this->_on_change(""); e.Skip(); }); + _spin->Bind(wxEVT_KILL_FOCUS, [this](wxFocusEvent& e) { if (this->on_kill_focus != nullptr) {this->on_kill_focus("");} e.Skip(); }); + } + ~UI_SpinCtrl() = default; + int get_int() { return this->_spin->GetValue(); } + void set_value(boost::any value) { this->_spin->SetValue(boost::any_cast(value)); } + + /// Access method for the underlying SpinCtrl + wxSpinCtrl* spinctrl() { return _spin; } + +protected: + virtual std::string LogChannel() { return "UI_SpinCtrl"s; } + + void _on_change(std::string opt_id) { + if (!this->disable_change_event && this->window->IsEnabled() && this->on_change != nullptr) { + this->on_change(opt_id, this->get_int()); + } + } + +private: + wxSpinCtrl* _spin {nullptr}; + int _tmp {0}; }; } } // Namespace Slic3r::GUI diff --git a/src/test/GUI/test_field_checkbox.cpp b/src/test/GUI/test_field_checkbox.cpp index 42cea2eb7..5a71c7a0d 100644 --- a/src/test/GUI/test_field_checkbox.cpp +++ b/src/test/GUI/test_field_checkbox.cpp @@ -22,23 +22,23 @@ SCENARIO( "GUI Checkbox option items fire their on_kill_focus when focus leaves wxMilliSleep(500); GIVEN( "A checkbox field item exists on a window") { auto exec_counter {0}; - auto* test_field {new Slic3r::GUI::UI_Checkbox(wxTheApp->GetTopWindow(), Slic3r::ConfigOptionDef())}; + auto test_field {Slic3r::GUI::UI_Checkbox(wxTheApp->GetTopWindow(), Slic3r::ConfigOptionDef())}; auto killfunc {[&exec_counter](const std::string& opt_id) { exec_counter += 1; }}; - test_field->on_kill_focus = killfunc; + test_field.on_kill_focus = killfunc; wxTheApp->GetTopWindow()->Show(); wxTheApp->GetTopWindow()->Fit(); WHEN ( "focus leaves the checkbox") { exec_counter = 0; - test_field->check()->SetFocus(); + test_field.check()->SetFocus(); wxMilliSleep(500); - auto ev {wxFocusEvent(wxEVT_KILL_FOCUS, test_field->check()->GetId())}; - ev.SetEventObject(test_field->check()); - test_field->check()->ProcessWindowEvent(ev); + auto ev {wxFocusEvent(wxEVT_KILL_FOCUS, test_field.check()->GetId())}; + ev.SetEventObject(test_field.check()); + test_field.check()->ProcessWindowEvent(ev); wxYield(); wxMilliSleep(500); THEN( "on_focus_kill is executed.") { @@ -47,15 +47,15 @@ SCENARIO( "GUI Checkbox option items fire their on_kill_focus when focus leaves } WHEN ( "focus leaves the checkbox and no callback is assigned") { - test_field->on_kill_focus = nullptr; + test_field.on_kill_focus = nullptr; exec_counter = 0; - test_field->check()->SetFocus(); + test_field.check()->SetFocus(); wxMilliSleep(500); - auto ev {wxFocusEvent(wxEVT_KILL_FOCUS, test_field->check()->GetId())}; - ev.SetEventObject(test_field->check()); - test_field->check()->ProcessWindowEvent(ev); + auto ev {wxFocusEvent(wxEVT_KILL_FOCUS, test_field.check()->GetId())}; + ev.SetEventObject(test_field.check()); + test_field.check()->ProcessWindowEvent(ev); wxYield(); wxMilliSleep(500); THEN( "on_focus_kill doesn't try to execute nullptr") { @@ -63,7 +63,6 @@ SCENARIO( "GUI Checkbox option items fire their on_kill_focus when focus leaves REQUIRE(exec_counter == 0); } } - delete test_field; } } SCENARIO( "GUI Checkbox set_value and get_bool work as expected." ) { @@ -72,41 +71,38 @@ SCENARIO( "GUI Checkbox set_value and get_bool work as expected." ) { wxTheApp->SetTopWindow(new wxTestableFrame()); wxMilliSleep(500); - auto* test_field {new Slic3r::GUI::UI_Checkbox(wxTheApp->GetTopWindow(), Slic3r::ConfigOptionDef())}; + auto test_field {Slic3r::GUI::UI_Checkbox(wxTheApp->GetTopWindow(), Slic3r::ConfigOptionDef())}; GIVEN( "A checkbox field item exists on a window") { WHEN ( "set_value is an bool and true") { - test_field->set_value(true); + test_field.set_value(true); THEN( " Result is converted correctly.") { - REQUIRE( test_field->get_bool() == true); + REQUIRE( test_field.get_bool() == true); } } WHEN ( "set_value is an bool and false") { - test_field->set_value(false); + test_field.set_value(false); THEN( " Result is converted correctly.") { - REQUIRE( test_field->get_bool() == false); + REQUIRE( test_field.get_bool() == false); } } WHEN ( "set_value is a floating point number > 0") { - test_field->set_value(true); + test_field.set_value(true); try { - test_field->set_value(10.2); + test_field.set_value(10.2); } catch (boost::bad_any_cast &e) { THEN( " Nothing happens; exception was thrown (and caught).") { REQUIRE(true); } } THEN( " Value did not change.") { - REQUIRE( test_field->get_bool() == true); + REQUIRE( test_field.get_bool() == true); } } } - - delete test_field; - } -SCENARIO( "GUI Checkbox option items fire their on_change event when clicked and appropriate." ) { +SCENARIO( "GUI Checkbox option respond to EVT_CHECKBOX when appropriate." ) { wxUIActionSimulator sim; wxTestableFrame* old = dynamic_cast(wxTheApp->GetTopWindow()); old->Destroy(); @@ -118,82 +114,46 @@ SCENARIO( "GUI Checkbox option items fire their on_change event when clicked and auto exec_counter {0}; auto changefunc {[&exec_counter](const std::string& opt_id, bool value) { exec_counter += 1; }}; - auto* test_field {new Slic3r::GUI::UI_Checkbox(wxTheApp->GetTopWindow(), Slic3r::ConfigOptionDef())}; + auto test_field {Slic3r::GUI::UI_Checkbox(wxTheApp->GetTopWindow(), Slic3r::ConfigOptionDef())}; - test_field->disable_change_event = false; - test_field->on_change = changefunc; + test_field.disable_change_event = false; + test_field.on_change = changefunc; wxTheApp->GetTopWindow()->Show(); wxTheApp->GetTopWindow()->Fit(); - WHEN ( "the box is checked") { + WHEN ( "CHECKBOX event is received") { exec_counter = 0; - sim.MouseMove(test_field->check()->GetScreenPosition() + wxPoint(10, 10)); - wxYield(); - sim.MouseMove(test_field->check()->GetScreenPosition() + wxPoint(10, 10)); - wxYield(); - sim.MouseClick(wxMOUSE_BTN_LEFT); - wxYield(); - sim.MouseClick(wxMOUSE_BTN_LEFT); + auto ev {wxCommandEvent(wxEVT_CHECKBOX, test_field.check()->GetId())}; + ev.SetEventObject(test_field.check()); + test_field.check()->ProcessWindowEvent(ev); wxYield(); + wxMilliSleep(250); THEN ( "on_change is executed.") { REQUIRE(exec_counter == 1); } } - WHEN ( "the box is unchecked") { - exec_counter = 0; - sim.MouseMove(test_field->check()->GetScreenPosition() + wxPoint(10, 10)); - wxYield(); - sim.MouseMove(test_field->check()->GetScreenPosition() + wxPoint(10, 10)); - wxYield(); - sim.MouseClick(wxMOUSE_BTN_LEFT); - wxYield(); - sim.MouseClick(wxMOUSE_BTN_LEFT); - wxYield(); - THEN ( "on_change is executed.") { - REQUIRE(exec_counter == 1); - } - } - delete test_field; } GIVEN( "A checkbox field item and disable_change = true") { auto exec_counter {0}; auto changefunc {[&exec_counter] (const std::string& opt_id, bool value) { exec_counter++; }}; - auto* test_field {new Slic3r::GUI::UI_Checkbox(wxTheApp->GetTopWindow(), Slic3r::ConfigOptionDef())}; + auto test_field {Slic3r::GUI::UI_Checkbox(wxTheApp->GetTopWindow(), Slic3r::ConfigOptionDef())}; wxTheApp->GetTopWindow()->Show(); wxTheApp->GetTopWindow()->Fit(); - test_field->disable_change_event = true; - test_field->on_change = changefunc; + test_field.disable_change_event = true; + test_field.on_change = changefunc; - WHEN ( "the box is checked") { + WHEN ( "CHECKBOX event is received") { exec_counter = 0; - sim.MouseMove(test_field->check()->GetScreenPosition() + wxPoint(10, 10)); - wxYield(); - sim.MouseMove(test_field->check()->GetScreenPosition() + wxPoint(10, 10)); - wxYield(); - sim.MouseClick(wxMOUSE_BTN_LEFT); - wxYield(); - sim.MouseClick(wxMOUSE_BTN_LEFT); + auto ev {wxCommandEvent(wxEVT_CHECKBOX, test_field.check()->GetId())}; + ev.SetEventObject(test_field.check()); + test_field.check()->ProcessWindowEvent(ev); wxYield(); + wxMilliSleep(250); THEN ( "on_change is not executed.") { REQUIRE(exec_counter == 0); } } - WHEN ( "the box is unchecked") { - exec_counter = 0; - sim.MouseMove(test_field->check()->GetScreenPosition() + wxPoint(10, 10)); - wxYield(); - sim.MouseMove(test_field->check()->GetScreenPosition() + wxPoint(10, 10)); - wxYield(); - sim.MouseClick(wxMOUSE_BTN_LEFT); - wxYield(); - sim.MouseClick(wxMOUSE_BTN_LEFT); - wxYield(); - THEN ( "on_change is not executed.") { - REQUIRE(exec_counter == 0); - } - } - delete test_field; } GIVEN( "A checkbox field item and readonly") { @@ -209,77 +169,31 @@ SCENARIO( "GUI Checkbox option items fire their on_change event when clicked and test_field->disable_change_event = false; // don't disable :D test_field->on_change = changefunc; - WHEN ( "the box is clicked and readonly") { + WHEN ( "CHECKBOX event is received") { exec_counter = 0; test_field->set_value(false); - sim.MouseMove(test_field->check()->GetScreenPosition() + wxPoint(10, 10)); - wxYield(); - sim.MouseMove(test_field->check()->GetScreenPosition() + wxPoint(10, 10)); - wxYield(); - sim.MouseClick(wxMOUSE_BTN_LEFT); - wxYield(); - sim.MouseClick(wxMOUSE_BTN_LEFT); + auto ev {wxCommandEvent(wxEVT_CHECKBOX, test_field->check()->GetId())}; + ev.SetEventObject(test_field->check()); + test_field->check()->ProcessWindowEvent(ev); wxYield(); + wxMilliSleep(250); THEN ( "on_change is not executed.") { REQUIRE(exec_counter == 0); } - THEN ( "Box is not checked.") { - REQUIRE(test_field->get_bool() == false); - } - } - WHEN ( "the box is clicked and readonly") { - exec_counter = 0; - test_field->set_value(true); - sim.MouseMove(test_field->check()->GetScreenPosition() + wxPoint(10, 10)); - wxYield(); - sim.MouseMove(test_field->check()->GetScreenPosition() + wxPoint(10, 10)); - wxYield(); - sim.MouseClick(wxMOUSE_BTN_LEFT); - wxYield(); - sim.MouseClick(wxMOUSE_BTN_LEFT); - wxYield(); - THEN ( "on_change is not executed.") { - REQUIRE(exec_counter == 0); - } - THEN ( "Box is checked.") { - REQUIRE(test_field->get_bool() == true); - } } WHEN ( "the box is clicked and enabled") { exec_counter = 0; test_field->enable(); test_field->set_value(true); - wxMilliSleep(500); - sim.MouseMove(test_field->check()->GetScreenPosition() + wxPoint(10, 10)); - wxYield(); - sim.MouseMove(test_field->check()->GetScreenPosition() + wxPoint(10, 10)); - wxYield(); - sim.MouseClick(wxMOUSE_BTN_LEFT); - wxYield(); - sim.MouseClick(wxMOUSE_BTN_LEFT); + + auto ev {wxCommandEvent(wxEVT_CHECKBOX, test_field->check()->GetId())}; + ev.SetEventObject(test_field->check()); + test_field->check()->ProcessWindowEvent(ev); wxYield(); + wxMilliSleep(250); THEN ( "on_change is executed.") { REQUIRE(exec_counter == 1); } - THEN ( "Box is not checked.") { - REQUIRE(test_field->get_bool() == false); - } - } - WHEN ( "the box is clicked and disabled") { - exec_counter = 0; - test_field->set_value(true); - test_field->disable(); - sim.MouseMove(test_field->check()->GetScreenPosition() + wxPoint(10, 10)); - wxYield(); - sim.MouseMove(test_field->check()->GetScreenPosition() + wxPoint(10, 10)); - wxYield(); - sim.MouseClick(wxMOUSE_BTN_LEFT); - wxYield(); - sim.MouseClick(wxMOUSE_BTN_LEFT); - wxYield(); - THEN ( "on_change is not executed.") { - REQUIRE(exec_counter == 0); - } THEN ( "Box is checked.") { REQUIRE(test_field->get_bool() == true); } @@ -288,33 +202,27 @@ SCENARIO( "GUI Checkbox option items fire their on_change event when clicked and exec_counter = 0; test_field->set_value(true); test_field->toggle(true); - sim.MouseMove(test_field->check()->GetScreenPosition() + wxPoint(10, 10)); - wxYield(); - sim.MouseMove(test_field->check()->GetScreenPosition() + wxPoint(10, 10)); - wxYield(); - sim.MouseClick(wxMOUSE_BTN_LEFT); - wxYield(); - sim.MouseClick(wxMOUSE_BTN_LEFT); + auto ev {wxCommandEvent(wxEVT_CHECKBOX, test_field->check()->GetId())}; + ev.SetEventObject(test_field->check()); + test_field->check()->ProcessWindowEvent(ev); wxYield(); + wxMilliSleep(250); THEN ( "on_change is executed.") { REQUIRE(exec_counter == 1); } - THEN ( "Box is not checked.") { - REQUIRE(test_field->get_bool() == false); + THEN ( "Box is checked.") { + REQUIRE(test_field->get_bool() == true); } } WHEN ( "the box is clicked and toggled false") { exec_counter = 0; test_field->set_value(true); test_field->toggle(false); - sim.MouseMove(test_field->check()->GetScreenPosition() + wxPoint(10, 10)); - wxYield(); - sim.MouseMove(test_field->check()->GetScreenPosition() + wxPoint(10, 10)); - wxYield(); - sim.MouseClick(wxMOUSE_BTN_LEFT); - wxYield(); - sim.MouseClick(wxMOUSE_BTN_LEFT); + auto ev {wxCommandEvent(wxEVT_CHECKBOX, test_field->check()->GetId())}; + ev.SetEventObject(test_field->check()); + test_field->check()->ProcessWindowEvent(ev); wxYield(); + wxMilliSleep(250); THEN ( "on_change is not executed.") { REQUIRE(exec_counter == 0); } diff --git a/src/test/GUI/test_field_spinctrl.cpp b/src/test/GUI/test_field_spinctrl.cpp new file mode 100644 index 000000000..fc2b92b27 --- /dev/null +++ b/src/test/GUI/test_field_spinctrl.cpp @@ -0,0 +1,156 @@ +#include + +#ifndef WX_PRECOMP + #include "wx/app.h" + #include "wx/sizer.h" + #include "wx/checkbox.h" + #include "wx/uiaction.h" +#endif // WX_PRECOMP +#include +#include "testableframe.h" +#include "OptionsGroup/Field.hpp" +#include "ConfigBase.hpp" + +using namespace Slic3r::GUI; +SCENARIO( "Spinctrl initializes with default value if available.") { + wxTestableFrame* old = dynamic_cast(wxTheApp->GetTopWindow()); + + old->Destroy(); + wxTheApp->SetTopWindow(new wxTestableFrame()); + wxMilliSleep(250); + + Slic3r::ConfigOptionDef simple_option; + simple_option.type = coInt; + auto* intopt { new Slic3r::ConfigOptionInt(7) }; + simple_option.default_value = intopt; // no delete, it's taken care of by ConfigOptionDef + GIVEN ( "A UI Spinctrl") { + auto test_field {Slic3r::GUI::UI_SpinCtrl(wxTheApp->GetTopWindow(), simple_option)}; + + wxTheApp->GetTopWindow()->Show(); + wxTheApp->GetTopWindow()->Fit(); + + REQUIRE(test_field.get_int() == 7); + } +} + +SCENARIO( "Receiving a Spinctrl event") { + wxTestableFrame* old = dynamic_cast(wxTheApp->GetTopWindow()); + old->Destroy(); + wxTheApp->SetTopWindow(new wxTestableFrame()); + wxMilliSleep(250); + GIVEN ( "A UI Spinctrl") { + auto exec_counter {0}; + auto changefunc {[&exec_counter] (const std::string& opt_id, bool value) { exec_counter++; }}; + auto test_field {Slic3r::GUI::UI_SpinCtrl(wxTheApp->GetTopWindow(), Slic3r::ConfigOptionDef())}; + + test_field.on_change = changefunc; + + wxTheApp->GetTopWindow()->Show(); + wxTheApp->GetTopWindow()->Fit(); + WHEN( "A spin event occurs") { + exec_counter = 0; + auto ev {wxSpinEvent(wxEVT_SPINCTRL, test_field.spinctrl()->GetId())}; + ev.SetEventObject(test_field.spinctrl()); + test_field.spinctrl()->ProcessWindowEvent(ev); + wxYield(); + wxMilliSleep(250); + THEN( "on_change is executed.") { + REQUIRE(exec_counter == 1); + } + } + WHEN( "A spin event occurs and change event is disabled") { + exec_counter = 0; + test_field.disable_change_event = false; + auto ev {wxSpinEvent(wxEVT_SPINCTRL, test_field.spinctrl()->GetId())}; + ev.SetEventObject(test_field.spinctrl()); + test_field.spinctrl()->ProcessWindowEvent(ev); + wxYield(); + wxMilliSleep(250); + THEN( "on_change is not executed.") { + REQUIRE(exec_counter == 1); + } + } + } +} + +SCENARIO( "Changing the text via entry works on pressing enter") { + wxTestableFrame* old = dynamic_cast(wxTheApp->GetTopWindow()); + old->Destroy(); + wxTheApp->SetTopWindow(new wxTestableFrame()); + wxUIActionSimulator sim; + wxMilliSleep(500); + GIVEN ( "A UI Spinctrl") { + auto exec_counter {0}; + auto changefunc {[&exec_counter] (const std::string& opt_id, bool value) { exec_counter++; }}; + auto test_field {Slic3r::GUI::UI_SpinCtrl(wxTheApp->GetTopWindow(), Slic3r::ConfigOptionDef())}; + + test_field.on_change = changefunc; + + wxTheApp->GetTopWindow()->Show(); + wxTheApp->GetTopWindow()->Fit(); + WHEN( "A number is entered followed by enter key") { + exec_counter = 0; + test_field.spinctrl()->SetFocus(); + wxYield(); + wxMilliSleep(250); + sim.Char('3'); + wxMilliSleep(250); + sim.Char(WXK_RETURN); + wxMilliSleep(250); + wxYield(); + THEN( "on_change is executed.") { + REQUIRE(exec_counter == 1); + } + THEN( "get_int returns entered value.") { + REQUIRE(test_field.get_int() == 3); + } + } + WHEN( "A number is entered followed by enter key and change event is disabled") { + exec_counter = 0; + test_field.disable_change_event = true; + test_field.spinctrl()->SetFocus(); + wxYield(); + wxMilliSleep(250); + sim.Char('3'); + wxMilliSleep(250); + sim.Char(WXK_RETURN); + wxMilliSleep(250); + wxYield(); + THEN( "on_change is not executed.") { + REQUIRE(exec_counter == 0); + } + THEN( "get_int returns entered value.") { + REQUIRE(test_field.get_int() == 3); + } + } + WHEN( "A number is entered and focus is lost") { + auto killfunc {[&exec_counter](const std::string& opt_id) { exec_counter += 1; }}; + test_field.on_kill_focus = killfunc; + + auto ev {wxFocusEvent(wxEVT_KILL_FOCUS, test_field.spinctrl()->GetId())}; + ev.SetEventObject(test_field.spinctrl()); + + exec_counter = 0; + test_field.spinctrl()->SetValue(3); + test_field.spinctrl()->SetFocus(); + wxYield(); + wxMilliSleep(250); + sim.Char('7'); + wxYield(); + wxMilliSleep(250); + test_field.spinctrl()->ProcessWindowEvent(ev); + wxMilliSleep(250); + wxYield(); + THEN( "on_kill_focus is executed and on_change are both executed.") { + REQUIRE(exec_counter == 2); + } + THEN( "get_int returns updated value.") { + REQUIRE(test_field.get_int() == 7); + } + THEN( "get_bool returns 0.") { + REQUIRE(test_field.get_bool() == 0); + } + } + } +} + diff --git a/xs/src/libslic3r/Log.hpp b/xs/src/libslic3r/Log.hpp index 70e8616fc..0593aa695 100644 --- a/xs/src/libslic3r/Log.hpp +++ b/xs/src/libslic3r/Log.hpp @@ -37,6 +37,10 @@ public: std::cerr << topic << " WARN" << ": "; std::wcerr << message << std::endl; } + static void warn(std::string topic, std::string message) { + std::cerr << topic << " WARN" << ": "; + std::cerr << message << std::endl; + } };