UI spinbox implementation

This commit is contained in:
Nikita Lisitsa 2021-03-05 23:33:19 +03:00
parent 3faccd1256
commit 27bd390381
6 changed files with 166 additions and 0 deletions

View file

@ -17,6 +17,7 @@ namespace psemek::ui
std::shared_ptr<frame> make_frame() override;
std::shared_ptr<window> make_window(std::string caption) override;
std::shared_ptr<slider> make_slider() override;
std::shared_ptr<spinbox> make_spinbox() override;
// directions:
// 0 - up

View file

@ -10,6 +10,7 @@
#include <psemek/ui/image_view.hpp>
#include <psemek/ui/rich_image_view.hpp>
#include <psemek/ui/slider.hpp>
#include <psemek/ui/spinbox.hpp>
#include <psemek/gfx/texture.hpp>
@ -29,6 +30,7 @@ namespace psemek::ui
virtual std::shared_ptr<image_view> make_image_view(std::shared_ptr<gfx::texture_2d> image);
virtual std::shared_ptr<rich_image_view> make_rich_image_view(std::shared_ptr<gfx::texture_2d> image);
virtual std::shared_ptr<slider> make_slider();
virtual std::shared_ptr<spinbox> make_spinbox();
virtual ~element_factory() {}
};

View file

@ -0,0 +1,39 @@
#pragma once
#include <psemek/ui/element.hpp>
#include <functional>
namespace psemek::ui
{
struct spinbox
: element
{
virtual int value() const { return value_; }
virtual void set_value(int v);
virtual geom::interval<int> value_range() const { return value_range_; }
virtual void set_value_range(geom::interval<int> 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<void(int)>;
virtual void on_value_changed(on_value_changed_callback callback);
protected:
virtual void post_value_changed();
private:
int value_ = 0;
geom::interval<int> value_range_ = geom::interval<int>::full();
bool wrap_ = false;
on_value_changed_callback on_value_changed_;
};
}

View file

@ -476,6 +476,67 @@ namespace psemek::ui
geom::triangle<geom::point<float, 2>> triangle_;
};
struct spinbox_impl
: spinbox
{
spinbox_impl()
{
auto layout = std::make_shared<grid_layout>();
layout->set_row_count(2);
auto inc_button = std::make_shared<arrow_button_impl>(0);
auto dec_button = std::make_shared<arrow_button_impl>(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<float, 2> 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<float, 2> const & box) override
{
child_->reshape(box);
}
void draw(painter &) const override
{}
~spinbox_impl()
{
release_children();
}
private:
std::shared_ptr<element> child_;
element * children_range_[1] {nullptr};
};
}
struct default_element_factory::impl
@ -516,6 +577,11 @@ namespace psemek::ui
return r;
}
std::shared_ptr<spinbox> default_element_factory::make_spinbox()
{
return std::make_shared<spinbox_impl>();
}
std::shared_ptr<slider> default_element_factory::make_slider()
{
return std::make_shared<slider_impl>();

View file

@ -75,4 +75,6 @@ namespace psemek::ui
std::shared_ptr<slider> element_factory::make_slider() { return nullptr; }
std::shared_ptr<spinbox> element_factory::make_spinbox() { return nullptr; }
}

View file

@ -0,0 +1,56 @@
#include <psemek/ui/spinbox.hpp>
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<int> 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); });
}
}