From a802083feb47f8e0a67d2f991d173a011de80d42 Mon Sep 17 00:00:00 2001 From: cnjinhao Date: Wed, 28 Jan 2015 07:14:21 +0800 Subject: [PATCH] Add inputbox --- include/nana/gui/msgbox.hpp | 20 ++ include/nana/gui/widgets/spinbox.hpp | 6 + source/gui/msgbox.cpp | 389 +++++++++++++++++++-------- source/gui/widgets/spinbox.cpp | 60 ++++- source/internationalization.cpp | 34 ++- 5 files changed, 370 insertions(+), 139 deletions(-) diff --git a/include/nana/gui/msgbox.hpp b/include/nana/gui/msgbox.hpp index f179c556..6507ef01 100644 --- a/include/nana/gui/msgbox.hpp +++ b/include/nana/gui/msgbox.hpp @@ -91,6 +91,26 @@ namespace nana button_t button_; icon_t icon_; }; + + class inputbox + { + public: + inputbox(window, ::nana::string description, ::nana::string title = ::nana::string(), ::nana::string label = ::nana::string()); + + void set_modal(); + bool valid() const; + int get_int(int value, int begin, int last, int step); + double get_double(double value, double begin, double last, double step); + ::nana::string get_string(); + private: + window owner_; + bool valid_input_; + bool modal_mode_; + + ::nana::string description_; + ::nana::string title_; + ::nana::string label_; + }; }//end namespace nana #endif diff --git a/include/nana/gui/widgets/spinbox.hpp b/include/nana/gui/widgets/spinbox.hpp index 58934dae..29bee2f8 100644 --- a/include/nana/gui/widgets/spinbox.hpp +++ b/include/nana/gui/widgets/spinbox.hpp @@ -49,6 +49,7 @@ namespace nana void mouse_leave(graph_reference, const arg_mouse&) override; void key_press(graph_reference, const arg_keyboard&) override; void key_char(graph_reference, const arg_keyboard&) override; + void resized(graph_reference, const arg_resized&) override; private: implementation * const impl_; }; @@ -80,6 +81,11 @@ namespace nana void range(std::initializer_list steps_utf8); void range(std::initializer_list steps); + /// Gets the spined value + ::nana::string value() const; + int to_int() const; + double to_double() const; + /// Sets a predicator that determines whether accepts the current user input. /// @param pred Predicator to determines the input. void set_accept(std::function pred); diff --git a/source/gui/msgbox.cpp b/source/gui/msgbox.cpp index 1b37d4be..982491eb 100644 --- a/source/gui/msgbox.cpp +++ b/source/gui/msgbox.cpp @@ -9,17 +9,20 @@ * * @file: nana/gui/msgbox.hpp */ -#include -#include + +//#include //deprecated +//#include //deprecated +#include +#include +#include +#include +#include +#include #if defined(NANA_WINDOWS) #include #elif defined(NANA_X11) - #include - #include - #include #include #include - #include #endif namespace nana @@ -107,7 +110,7 @@ namespace nana const unsigned text_pixels = 500 - ico_pixels; text_.create(*this, nana::rectangle(12 + ico_pixels, 25, 1, 1)); - text_.background(0xFFFFFF); + text_.bgcolor(colors::white); text_.caption(text); nana::size ts = text_.measure(text_pixels); @@ -319,146 +322,294 @@ namespace nana }; #endif - //class msgbox - msgbox::msgbox() - : wd_(nullptr), button_(ok), icon_(icon_none) - {} + //class msgbox + msgbox::msgbox() + : wd_(nullptr), button_(ok), icon_(icon_none) + {} - msgbox::msgbox(const msgbox& rhs) - : wd_(rhs.wd_), title_(rhs.title_), button_(rhs.button_), icon_(rhs.icon_) + msgbox::msgbox(const msgbox& rhs) + : wd_(rhs.wd_), title_(rhs.title_), button_(rhs.button_), icon_(rhs.icon_) + { + sstream_<(nana::charset(str)); + sstream_<(nana::charset(str)); #else - sstream_<(nana::charset(str));; + sstream_<(nana::charset(str));; #else - sstream_<(API::root(wd_)), static_cast(nana::charset(sstream_.str())).c_str(), title_.c_str(), type); #else int bt = ::MessageBoxA(reinterpret_cast(API::root(wd_), sstream_.str().c_str(), title_.c_str(), type); #endif - switch(bt) - { - case IDOK: - return pick_ok; - case IDYES: - return pick_yes; - case IDNO: - return pick_no; - case IDCANCEL: - return pick_cancel; - } - - return pick_yes; -#elif defined(NANA_X11) - msgbox_window box(wd_, title_, button_, icon_); - box.prompt(nana::charset(sstream_.str())); - return box.pick(); -#endif + switch(bt) + { + case IDOK: + return pick_ok; + case IDYES: return pick_yes; + case IDNO: + return pick_no; + case IDCANCEL: + return pick_cancel; } - //end class msgbox + return pick_yes; +#elif defined(NANA_X11) + msgbox_window box(wd_, title_, button_, icon_); + box.prompt(nana::charset(sstream_.str())); + return box.pick(); +#endif + return pick_yes; + } + //end class msgbox + + + //class inputbox + + class inputbox_window + : public ::nana::form + { + public: + inputbox_window(window owner, const ::nana::string & desc, const ::nana::string& title, const ::nana::string& label, unsigned input_widget_size) + : form(owner, API::make_center(owner, 500, 300), appear::decorate<>()) + { + desc_.create(*this); + desc_.format(true).caption(desc); + auto desc_extent = desc_.measure(470); + desc_extent.height += 8; + + label_.create(*this); + label_.format(true).caption(label); + label_.text_align(::nana::align::left, ::nana::align_v::center); + auto label_extent = label_.measure(230); + label_extent.height += 8; + + btn_ok_.create(*this); + btn_ok_.i18n(i18n_eval("Nana.OK")); + btn_ok_.events().click([this]{ + close(); + valid_input_ = true; + }); + + btn_cancel_.create(*this); + btn_cancel_.i18n(i18n_eval("Nana.Cancel")); + btn_cancel_.events().click([this]{ + close(); + }); + + place_.bind(*this); + std::stringstream ss; + ss << "margin=10 vert >"; + + place_.div(ss.str().data()); + place_["desc"] << desc_; + place_["label"] << label_; + place_["buttons"] << btn_ok_ << btn_cancel_; + + unsigned height = 20 + desc_extent.height + label_extent.height + 10 + 23; + size({ 500, height }); + caption(title); + } + + void set_input(window handle) + { + place_["input"] << handle; + place_.collocate(); + show(); + } + + bool valid_input() const + { + return valid_input_; + } + private: + ::nana::label desc_; + ::nana::label label_; + ::nana::button btn_ok_; + ::nana::button btn_cancel_; + bool valid_input_{ false }; + ::nana::place place_; + }; + + inputbox::inputbox(window owner, ::nana::string desc, ::nana::string title, ::nana::string label) + : owner_{ owner }, valid_input_{ false }, modal_mode_{false}, + description_(std::move(desc)), + title_(std::move(title)), + label_(std::move(label)) + {} + + void inputbox::set_modal() + { + modal_mode_ = true; + } + + bool inputbox::valid() const + { + return valid_input_; + } + + int inputbox::get_int(int value, int begin, int last, int step) + { + int longest = (std::abs((begin < 0 ? begin * 10 : begin)) < std::abs(last < 0 ? last * 10 : last) ? last : begin); + std::wstringstream ss; + ss << longest; + paint::graphics graph{ ::nana::size{ 10, 10 } }; + auto input_widget_size = graph.text_extent_size(ss.str()).width + 34; + auto t1 = graph.typeface(); + + inputbox_window inp_window(owner_, description_, title_, label_, input_widget_size); + ::nana::spinbox spinbox(inp_window); + spinbox.range(begin, last, step); + spinbox.set_accept_integer(); + inp_window.set_input(spinbox); + auto t2 = spinbox.typeface(); + if (modal_mode_) + inp_window.modality(); + else + API::wait_for(inp_window); + + valid_input_ = inp_window.valid_input(); + return spinbox.to_int(); + } + + double inputbox::get_double(double value, double begin, double last, double step) + { + std::wstring longest; + for (auto i = begin; i < last; i += step) + { + std::wstringstream ss; + ss << i; + auto str = ss.str(); + if (str.size() > longest.size()) + longest = str; + } + + paint::graphics graph{ ::nana::size{ 10, 10 } }; + auto input_widget_size = graph.text_extent_size(longest).width + 34; + + inputbox_window inp_window(owner_, description_, title_, label_, input_widget_size); + ::nana::spinbox spinbox(inp_window); + spinbox.range(begin, last, step); + spinbox.set_accept_real(); + inp_window.set_input(spinbox); + + if (modal_mode_) + inp_window.modality(); + else + API::wait_for(inp_window); + + valid_input_ = inp_window.valid_input(); + return spinbox.to_double(); + } + + ::nana::string inputbox::get_string() + { + return{}; + } + + //end class inputbox } diff --git a/source/gui/widgets/spinbox.cpp b/source/gui/widgets/spinbox.cpp index d1b39b21..c33483c5 100644 --- a/source/gui/widgets/spinbox.cpp +++ b/source/gui/widgets/spinbox.cpp @@ -157,7 +157,7 @@ namespace nana API::eat_tabstop(wd, true); API::effects_edge_nimbus(wd, effects::edge_nimbus::active); API::effects_edge_nimbus(wd, effects::edge_nimbus::over); - _m_reset_text_area(); + reset_text_area(); } void detach() @@ -166,6 +166,11 @@ namespace nana editor_ = nullptr; } + ::nana::string value() const + { + return range_->value(); + } + void set_range(std::unique_ptr ptr) { range_.swap(ptr); @@ -268,6 +273,15 @@ namespace nana return false; } + + void reset_text_area() + { + auto spins_r = _m_spins_area(); + if (spins_r.x == 0) + editor_->text_area({}); + else + editor_->text_area({ 2, 2, graph_->width() - spins_r.width - 2, spins_r.height - 2 }); + } private: void _m_text() { @@ -279,15 +293,6 @@ namespace nana } } - void _m_reset_text_area() - { - auto spins_r = _m_spins_area(); - if (spins_r.x == 0) - editor_->text_area({}); - else - editor_->text_area({ 2, 2, graph_->width() - spins_r.width - 2, spins_r.height - 2 }); - } - ::nana::rectangle _m_spins_area() const { auto size = API::window_size(editor_->window_handle()); @@ -432,6 +437,14 @@ namespace nana API::lazy_refresh(); } } + + void drawer::resized(graph_reference graph, const arg_resized& arg) + { + impl_->reset_text_area(); + impl_->render(); + impl_->editor()->reset_caret(); + API::lazy_refresh(); + } } }//end namespace drawerbase @@ -490,6 +503,33 @@ namespace nana API::refresh_window(handle()); } + ::nana::string spinbox::value() const + { + internal_scope_guard lock; + if (handle()) + return get_drawer_trigger().impl()->value(); + return{}; + } + + int spinbox::to_int() const + { + //std::stoi is not defined by MinGW + std::wstringstream ss; + ss << value(); + int n = 0; + ss >> n; + return n; + } + + double spinbox::to_double() const + { + //std::stod is not defined by MinGW + std::wstringstream ss; + ss << value(); + double d = 0; + ss >> d; + return d; + } void spinbox::set_accept(std::function pred) { diff --git a/source/internationalization.cpp b/source/internationalization.cpp index e36e6312..d070d0cd 100644 --- a/source/internationalization.cpp +++ b/source/internationalization.cpp @@ -144,6 +144,15 @@ namespace nana static std::shared_ptr& get_data_ptr() { static std::shared_ptr data_ptr; + if (!data_ptr) + { + data_ptr = std::make_shared(); + + //Initialize the predefined language text + auto & table = data_ptr->table; + table["Nana.OK"].assign(L"OK"); + table["Nana.Cancel"].assign(L"Cancel"); + } return data_ptr; } @@ -208,6 +217,16 @@ namespace nana impl->table[std::move(msgid)].swap(str); } + //Assign all language texts to the new table. + auto & cur_table = get_data_ptr()->table; + auto & new_table = impl->table; + for (auto & m : cur_table) + { + auto & value = new_table[m.first]; + if (value.empty()) + value = m.second; + } + get_data_ptr().swap(impl); use_eval(); } @@ -288,22 +307,17 @@ namespace nana void internationalization::set(std::string msgid, nana::string msgstr) { auto & ptr = internationalization_parts::get_data_ptr(); - if (!ptr) - ptr = std::make_shared(); ptr->table[msgid].swap(msgstr); } bool internationalization::_m_get(std::string& msgid, nana::string& msgstr) const { - auto impl = internationalization_parts::get_data_ptr(); - if (impl) + auto & impl = internationalization_parts::get_data_ptr(); + auto i = impl->table.find(msgid); + if (i != impl->table.end()) { - auto i = impl->table.find(msgid); - if (i != impl->table.end()) - { - msgstr = i->second; - return true; - } + msgstr = i->second; + return true; } msgstr = nana::charset(std::move(msgid), nana::unicode::utf8);