From 27bd39038154ca8a2957e15f304396214f0ad345 Mon Sep 17 00:00:00 2001 From: lisyarus Date: Fri, 5 Mar 2021 23:33:19 +0300 Subject: [PATCH] UI spinbox implementation --- .../psemek/ui/default_element_factory.hpp | 1 + libs/ui/include/psemek/ui/element_factory.hpp | 2 + libs/ui/include/psemek/ui/spinbox.hpp | 39 +++++++++++ libs/ui/source/default_element_factory.cpp | 66 +++++++++++++++++++ libs/ui/source/element_factory.cpp | 2 + libs/ui/source/spinbox.cpp | 56 ++++++++++++++++ 6 files changed, 166 insertions(+) create mode 100644 libs/ui/include/psemek/ui/spinbox.hpp create mode 100644 libs/ui/source/spinbox.cpp diff --git a/libs/ui/include/psemek/ui/default_element_factory.hpp b/libs/ui/include/psemek/ui/default_element_factory.hpp index 17e98bf5..8f53a58a 100644 --- a/libs/ui/include/psemek/ui/default_element_factory.hpp +++ b/libs/ui/include/psemek/ui/default_element_factory.hpp @@ -17,6 +17,7 @@ namespace psemek::ui std::shared_ptr make_frame() override; std::shared_ptr make_window(std::string caption) override; std::shared_ptr make_slider() override; + std::shared_ptr make_spinbox() override; // directions: // 0 - up diff --git a/libs/ui/include/psemek/ui/element_factory.hpp b/libs/ui/include/psemek/ui/element_factory.hpp index bb91e888..fa37fad0 100644 --- a/libs/ui/include/psemek/ui/element_factory.hpp +++ b/libs/ui/include/psemek/ui/element_factory.hpp @@ -10,6 +10,7 @@ #include #include #include +#include #include @@ -29,6 +30,7 @@ namespace psemek::ui virtual std::shared_ptr make_image_view(std::shared_ptr image); virtual std::shared_ptr make_rich_image_view(std::shared_ptr image); virtual std::shared_ptr make_slider(); + virtual std::shared_ptr make_spinbox(); virtual ~element_factory() {} }; diff --git a/libs/ui/include/psemek/ui/spinbox.hpp b/libs/ui/include/psemek/ui/spinbox.hpp new file mode 100644 index 00000000..c31a4a2b --- /dev/null +++ b/libs/ui/include/psemek/ui/spinbox.hpp @@ -0,0 +1,39 @@ +#pragma once + +#include + +#include + +namespace psemek::ui +{ + + struct spinbox + : element + { + virtual int value() const { return value_; } + virtual void set_value(int v); + + virtual geom::interval value_range() const { return value_range_; } + virtual void set_value_range(geom::interval i); + + virtual bool wrap() const { return wrap_; } + virtual void set_wrap(bool w); + + virtual void inc(); + virtual void dec(); + + using on_value_changed_callback = std::function; + + virtual void on_value_changed(on_value_changed_callback callback); + + protected: + virtual void post_value_changed(); + + private: + int value_ = 0; + geom::interval value_range_ = geom::interval::full(); + bool wrap_ = false; + on_value_changed_callback on_value_changed_; + }; + +} diff --git a/libs/ui/source/default_element_factory.cpp b/libs/ui/source/default_element_factory.cpp index b44f0a3f..0ac7a7b3 100644 --- a/libs/ui/source/default_element_factory.cpp +++ b/libs/ui/source/default_element_factory.cpp @@ -476,6 +476,67 @@ namespace psemek::ui geom::triangle> triangle_; }; + struct spinbox_impl + : spinbox + { + spinbox_impl() + { + auto layout = std::make_shared(); + layout->set_row_count(2); + + auto inc_button = std::make_shared(0); + auto dec_button = std::make_shared(1); + + inc_button->on_click([this]{ + inc(); + }); + + dec_button->on_click([this]{ + dec(); + }); + + layout->set(0, 0, inc_button); + layout->set(1, 0, dec_button); + layout->set_outer_margin(false); + + child_ = layout; + children_range_[0] = child_.get(); + child_->set_parent(this); + } + + geom::box size_constraints() const override + { + return child_->size_constraints(); + } + + children_range children() const override + { + return {children_range_}; + } + + struct shape const & shape() const override + { + return child_->shape(); + } + + void reshape(geom::box const & box) override + { + child_->reshape(box); + } + + void draw(painter &) const override + {} + + ~spinbox_impl() + { + release_children(); + } + + private: + std::shared_ptr child_; + element * children_range_[1] {nullptr}; + }; + } struct default_element_factory::impl @@ -516,6 +577,11 @@ namespace psemek::ui return r; } + std::shared_ptr default_element_factory::make_spinbox() + { + return std::make_shared(); + } + std::shared_ptr default_element_factory::make_slider() { return std::make_shared(); diff --git a/libs/ui/source/element_factory.cpp b/libs/ui/source/element_factory.cpp index 016ec370..d332912f 100644 --- a/libs/ui/source/element_factory.cpp +++ b/libs/ui/source/element_factory.cpp @@ -75,4 +75,6 @@ namespace psemek::ui std::shared_ptr element_factory::make_slider() { return nullptr; } + std::shared_ptr element_factory::make_spinbox() { return nullptr; } + } diff --git a/libs/ui/source/spinbox.cpp b/libs/ui/source/spinbox.cpp new file mode 100644 index 00000000..f0454009 --- /dev/null +++ b/libs/ui/source/spinbox.cpp @@ -0,0 +1,56 @@ +#include + +namespace psemek::ui +{ + + void spinbox::set_value(int v) + { + v = geom::clamp(v, value_range_); + if (v != value_) + { + value_ = v; + post_value_changed(); + } + } + + void spinbox::set_value_range(geom::interval i) + { + value_range_ = i; + set_value(value_); + } + + void spinbox::set_wrap(bool w) + { + wrap_ = w; + } + + void spinbox::inc() + { + if (wrap_) + set_value(((value_ + 1 - value_range_.min) % (value_range_.length() + 1)) + value_range_.min); + else + set_value(value_ + 1); + } + + void spinbox::dec() + { + int const range = value_range_.length() + 1; + if (wrap_) + set_value(((value_ + range - 1 - value_range_.min) % range) + value_range_.min); + else + set_value(value_ - 1); + } + + void spinbox::on_value_changed(on_value_changed_callback callback) + { + on_value_changed_ = std::move(callback); + post_value_changed(); + } + + void spinbox::post_value_changed() + { + if (on_value_changed_) + post([cb = on_value_changed_, v = value_]{ cb(v); }); + } + +}