mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-08-11 17:08:59 +08:00
Implemented UI_Choice (a combobox) with tests.
This commit is contained in:
parent
880b17703d
commit
dea6896c8e
@ -179,6 +179,7 @@ set(UI_TEST_SOURCES
|
||||
${GUI_TESTDIR}/test_field_checkbox.cpp
|
||||
${GUI_TESTDIR}/test_field_spinctrl.cpp
|
||||
${GUI_TESTDIR}/test_field_textbox.cpp
|
||||
${GUI_TESTDIR}/test_field_choice.cpp
|
||||
)
|
||||
set(SLIC3R_TEST_SOURCES
|
||||
${TESTDIR}/test_harness.cpp
|
||||
|
@ -11,6 +11,8 @@
|
||||
#include "wx/spinctrl.h"
|
||||
#include "wx/checkbox.h"
|
||||
#include "wx/textctrl.h"
|
||||
#include "wx/combobox.h"
|
||||
#include "wx/arrstr.h"
|
||||
|
||||
namespace Slic3r { namespace GUI {
|
||||
|
||||
@ -90,8 +92,6 @@ public:
|
||||
std::function<void (const std::string&, bool value)> on_change {nullptr};
|
||||
|
||||
protected:
|
||||
wxCheckBox* _check {nullptr};
|
||||
|
||||
virtual std::string LogChannel() override { return "UI_Checkbox"s; }
|
||||
|
||||
void _on_change(std::string opt_id) {
|
||||
@ -99,6 +99,8 @@ protected:
|
||||
this->on_change(opt_id, this->get_bool());
|
||||
}
|
||||
}
|
||||
private:
|
||||
wxCheckBox* _check {nullptr};
|
||||
|
||||
};
|
||||
|
||||
@ -139,7 +141,6 @@ protected:
|
||||
|
||||
private:
|
||||
wxSpinCtrl* _spin {nullptr};
|
||||
int _tmp {0};
|
||||
};
|
||||
|
||||
class UI_TextCtrl : public UI_Window {
|
||||
@ -188,7 +189,62 @@ protected:
|
||||
|
||||
private:
|
||||
wxTextCtrl* _text {nullptr};
|
||||
int _tmp {0};
|
||||
};
|
||||
|
||||
class UI_Choice : public UI_Window {
|
||||
public:
|
||||
UI_Choice(wxWindow* parent, Slic3r::ConfigOptionDef _opt, wxWindowID id = wxID_ANY) : UI_Window(parent, _opt) {
|
||||
int style {0};
|
||||
style |= wxTE_PROCESS_ENTER;
|
||||
if (opt.gui_type.size() > 0 && opt.gui_type.compare("select_open"s)) style |= wxCB_READONLY;
|
||||
|
||||
/// Load the values
|
||||
auto values {wxArrayString()};
|
||||
for (auto v : opt.enum_values) values.Add(wxString(v));
|
||||
|
||||
_choice = new wxComboBox(parent, id,
|
||||
(opt.default_value != nullptr ? opt.default_value->getString() : ""),
|
||||
wxDefaultPosition, _default_size(), values, style);
|
||||
window = _choice;
|
||||
|
||||
_choice->Bind(wxEVT_COMBOBOX, [this](wxCommandEvent& e) { this->_on_change(""); e.Skip(); });
|
||||
_choice->Bind(wxEVT_TEXT_ENTER, [this](wxCommandEvent& e) { this->_on_change(""); e.Skip(); });
|
||||
_choice->Bind(wxEVT_KILL_FOCUS, [this](wxFocusEvent& e) { if (this->on_kill_focus != nullptr) {this->on_kill_focus(""); this->_on_change("");} e.Skip(); });
|
||||
}
|
||||
std::string get_string() override {
|
||||
if (opt.enum_values.size() > 0) {
|
||||
auto idx = this->_choice->GetSelection();
|
||||
if (idx != wxNOT_FOUND) return this->opt.enum_values.at(idx);
|
||||
}
|
||||
return this->_choice->GetValue().ToStdString();
|
||||
}
|
||||
|
||||
|
||||
/// Returns a bare pointer to the underlying combobox, usually for test interface
|
||||
wxComboBox* choice() { return this->_choice; }
|
||||
|
||||
void set_value(boost::any value) override {
|
||||
auto result {std::find(opt.enum_values.cbegin(), opt.enum_values.cend(), boost::any_cast<std::string>(value))};
|
||||
if (result == opt.enum_values.cend()) {
|
||||
this->_choice->SetValue(wxString(boost::any_cast<std::string>(value)));
|
||||
} else {
|
||||
auto idx = std::distance(opt.enum_values.cbegin(), result);
|
||||
this->_choice->SetSelection(idx);
|
||||
}
|
||||
}
|
||||
|
||||
/// Function to call when the contents of this change.
|
||||
std::function<void (const std::string&, std::string value)> on_change {nullptr};
|
||||
protected:
|
||||
virtual std::string LogChannel() override { return "UI_Choice"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_string());
|
||||
}
|
||||
}
|
||||
private:
|
||||
wxComboBox* _choice {nullptr};
|
||||
};
|
||||
|
||||
} } // Namespace Slic3r::GUI
|
||||
|
143
src/test/GUI/test_field_choice.cpp
Normal file
143
src/test/GUI/test_field_choice.cpp
Normal file
@ -0,0 +1,143 @@
|
||||
#include <catch.hpp>
|
||||
|
||||
#ifndef WX_PRECOMP
|
||||
#include "wx/app.h"
|
||||
#include "wx/uiaction.h"
|
||||
#endif // WX_PRECOMP
|
||||
|
||||
#include <iostream>
|
||||
#include "testableframe.h"
|
||||
#include "OptionsGroup/Field.hpp"
|
||||
#include "ConfigBase.hpp"
|
||||
|
||||
using namespace std::string_literals;
|
||||
|
||||
SCENARIO( "UI_Choice: default values from options") {
|
||||
wxTestableFrame* old = dynamic_cast<wxTestableFrame*>(wxTheApp->GetTopWindow());
|
||||
old->Destroy();
|
||||
wxTheApp->SetTopWindow(new wxTestableFrame());
|
||||
wxUIActionSimulator sim;
|
||||
wxMilliSleep(500);
|
||||
|
||||
GIVEN( "I have a UI Choice with 3 options from ConfigOptionDef and a default_value that is not in the enumeration.") {
|
||||
auto simple_option {ConfigOptionDef()};
|
||||
auto* default_string {new ConfigOptionString("A")};
|
||||
|
||||
simple_option.default_value = default_string; // owned by ConfigOptionDef
|
||||
simple_option.enum_values.push_back("B");
|
||||
simple_option.enum_values.push_back("C");
|
||||
simple_option.enum_values.push_back("D");
|
||||
|
||||
auto test_field {Slic3r::GUI::UI_Choice(wxTheApp->GetTopWindow(), simple_option)};
|
||||
WHEN( "I don't explicitly select any option in the drop-down") {
|
||||
THEN( "get_value() returns the the value associuted with the listed default option in the related ConfigOptionDef") {
|
||||
REQUIRE(simple_option.default_value->getString() == test_field.get_string());
|
||||
}
|
||||
}
|
||||
WHEN( "I select the first option in the drop-down") {
|
||||
test_field.choice()->SetSelection(0);
|
||||
THEN( "get_value() returns the the value associuted with the first option in the related ConfigOptionDef") {
|
||||
REQUIRE(simple_option.enum_values[0] == test_field.get_string());
|
||||
}
|
||||
}
|
||||
WHEN( "I select the second option in the drop-down") {
|
||||
test_field.choice()->SetSelection(1);
|
||||
THEN( "get_value() returns the the value associuted with the second option in the related ConfigOptionDef") {
|
||||
REQUIRE(simple_option.enum_values[1] == test_field.get_string());
|
||||
}
|
||||
}
|
||||
WHEN( "I select the third option in the drop-down") {
|
||||
test_field.choice()->SetSelection(2);
|
||||
THEN( "get_value() returns the the value associuted with the third option in the related ConfigOptionDef") {
|
||||
REQUIRE(simple_option.enum_values[2] == test_field.get_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
GIVEN( "I have a UI Choice with 3 options from ConfigOptionDef and a default_value that is in the enumeration.") {
|
||||
auto simple_option {ConfigOptionDef()};
|
||||
auto* default_string {new ConfigOptionString("B"s)};
|
||||
|
||||
simple_option.default_value = default_string; // owned by ConfigOptionDef
|
||||
simple_option.enum_values.push_back("B"s);
|
||||
simple_option.enum_values.push_back("C"s);
|
||||
simple_option.enum_values.push_back("D"s);
|
||||
|
||||
auto test_field {Slic3r::GUI::UI_Choice(wxTheApp->GetTopWindow(), simple_option)};
|
||||
WHEN( "I don't explicitly select any option in the drop-down") {
|
||||
THEN( "get_value() returns the first value in the related ConfigOptionDef") {
|
||||
REQUIRE(simple_option.enum_values[0] == test_field.get_string());
|
||||
REQUIRE(test_field.choice()->FindString(simple_option.enum_values[0]) == 0);
|
||||
}
|
||||
}
|
||||
WHEN( "I set the string value to another item in the enumeration") {
|
||||
test_field.choice()->SetValue("C"s);
|
||||
THEN( "get_string() returns the matching item in ConfigOptionDef") {
|
||||
REQUIRE(test_field.get_string() == "C"s);
|
||||
REQUIRE(test_field.choice()->FindString(simple_option.enum_values[1]) == 1);
|
||||
}
|
||||
}
|
||||
WHEN( "I set the string value to another item that is not in the enumeration") {
|
||||
test_field.choice()->SetValue("F"s);
|
||||
THEN( "get_string() returns the matching item in ConfigOptionDef") {
|
||||
REQUIRE(test_field.get_string() == "F"s);
|
||||
REQUIRE(test_field.choice()->GetSelection() == wxNOT_FOUND);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SCENARIO( "UI_Choice: event handling for on_change and on_kill_focus") {
|
||||
auto event_count {0};
|
||||
auto killfunc {[&event_count](const std::string& opt_id) { event_count += 1; }};
|
||||
auto changefunc {[&event_count](const std::string& opt_id, std::string value) { event_count += 1; }};
|
||||
GIVEN( "I have a UI Choice with 2 options from ConfigOptionDef, no default value, and an on_change handler and on_kill_focus handler.") {
|
||||
auto simple_option {ConfigOptionDef()};
|
||||
auto* default_string {new ConfigOptionString("B")};
|
||||
|
||||
simple_option.default_value = default_string; // owned by ConfigOptionDef
|
||||
simple_option.enum_values.push_back("B");
|
||||
simple_option.enum_values.push_back("C");
|
||||
|
||||
auto test_field {Slic3r::GUI::UI_Choice(wxTheApp->GetTopWindow(), simple_option)};
|
||||
|
||||
test_field.on_kill_focus = killfunc;
|
||||
test_field.on_change = changefunc;
|
||||
|
||||
WHEN( "I receive a wxEVT_COMBOBOX event") {
|
||||
event_count = 0;
|
||||
wxMilliSleep(250);
|
||||
|
||||
auto ev {wxCommandEvent(wxEVT_COMBOBOX, test_field.choice()->GetId())};
|
||||
ev.SetEventObject(test_field.choice());
|
||||
test_field.choice()->ProcessWindowEvent(ev);
|
||||
THEN( "on_change handler is executed.") {
|
||||
REQUIRE(event_count == 1);
|
||||
}
|
||||
}
|
||||
WHEN( "I receive a wxEVT_TEXT_ENTER event") {
|
||||
event_count = 0;
|
||||
wxMilliSleep(250);
|
||||
|
||||
auto ev {wxCommandEvent(wxEVT_TEXT_ENTER, test_field.choice()->GetId())};
|
||||
ev.SetEventObject(test_field.choice());
|
||||
test_field.choice()->ProcessWindowEvent(ev);
|
||||
THEN( "on_change handler is executed.") {
|
||||
REQUIRE(event_count == 1);
|
||||
}
|
||||
}
|
||||
WHEN( "My control loses focus.") {
|
||||
event_count = 0;
|
||||
test_field.choice()->SetFocus();
|
||||
wxMilliSleep(250);
|
||||
|
||||
auto ev {wxFocusEvent(wxEVT_KILL_FOCUS, test_field.choice()->GetId())};
|
||||
ev.SetEventObject(test_field.choice());
|
||||
test_field.choice()->ProcessWindowEvent(ev);
|
||||
|
||||
THEN( "on_change handler is executed and on_kill_focus handler is executed.") {
|
||||
REQUIRE(event_count == 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user