Add ui::checkbox interface & default implementation
This commit is contained in:
parent
9f550d7a46
commit
6dd5fd5ee7
6 changed files with 209 additions and 0 deletions
45
libs/ui/include/psemek/ui/checkbox.hpp
Normal file
45
libs/ui/include/psemek/ui/checkbox.hpp
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
#pragma once
|
||||
|
||||
#include <psemek/ui/element.hpp>
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace psemek::ui
|
||||
{
|
||||
|
||||
struct checkbox
|
||||
: element
|
||||
{
|
||||
bool on_event(mouse_move const & e) override;
|
||||
bool on_event(mouse_click const & e) override;
|
||||
|
||||
bool value() const { return value_; }
|
||||
void set_value(bool value) { value_ = value; }
|
||||
|
||||
using on_value_changed_callback = std::function<void(bool)>;
|
||||
|
||||
void on_value_changed(on_value_changed_callback callback)
|
||||
{
|
||||
callback_ = std::move(callback);
|
||||
}
|
||||
|
||||
protected:
|
||||
enum class state_t
|
||||
{
|
||||
normal,
|
||||
mouseover,
|
||||
mousedown,
|
||||
};
|
||||
|
||||
virtual state_t state() const { return state_; }
|
||||
|
||||
virtual void on_state_changed(state_t old);
|
||||
|
||||
private:
|
||||
state_t state_ = state_t::normal;
|
||||
bool value_ = false;
|
||||
|
||||
on_value_changed_callback callback_;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -17,6 +17,7 @@ namespace psemek::ui
|
|||
using element_factory::make_button;
|
||||
std::shared_ptr<frame> make_frame() override;
|
||||
std::shared_ptr<window> make_window(std::string caption) override;
|
||||
std::shared_ptr<checkbox> make_checkbox(bool value) override;
|
||||
std::shared_ptr<slider> make_slider() override;
|
||||
std::shared_ptr<spinbox> make_spinbox() override;
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#include <psemek/ui/grid_layout.hpp>
|
||||
#include <psemek/ui/image_view.hpp>
|
||||
#include <psemek/ui/rich_image_view.hpp>
|
||||
#include <psemek/ui/checkbox.hpp>
|
||||
#include <psemek/ui/slider.hpp>
|
||||
#include <psemek/ui/spinbox.hpp>
|
||||
|
||||
|
|
@ -29,6 +30,7 @@ namespace psemek::ui
|
|||
virtual std::shared_ptr<grid_layout> make_grid_layout();
|
||||
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<checkbox> make_checkbox(bool value);
|
||||
virtual std::shared_ptr<slider> make_slider();
|
||||
virtual std::shared_ptr<spinbox> make_spinbox();
|
||||
|
||||
|
|
|
|||
71
libs/ui/source/checkbox.cpp
Normal file
71
libs/ui/source/checkbox.cpp
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
#include <psemek/ui/checkbox.hpp>
|
||||
|
||||
namespace psemek::ui
|
||||
{
|
||||
|
||||
bool checkbox::on_event(mouse_move const & e)
|
||||
{
|
||||
bool const over = shape().contains(geom::cast<float>(e.position));
|
||||
|
||||
switch (state_) {
|
||||
case state_t::normal:
|
||||
if (over)
|
||||
{
|
||||
state_ = state_t::mouseover;
|
||||
on_state_changed(state_t::normal);
|
||||
}
|
||||
break;
|
||||
case state_t::mouseover:
|
||||
case state_t::mousedown:
|
||||
if (!over)
|
||||
{
|
||||
auto old = state_;
|
||||
state_ = state_t::normal;
|
||||
on_state_changed(old);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool checkbox::on_event(mouse_click const & e)
|
||||
{
|
||||
if (e.button != mouse_button::left) return false;
|
||||
|
||||
switch (state_) {
|
||||
case state_t::normal:
|
||||
break;
|
||||
case state_t::mouseover:
|
||||
if (e.down)
|
||||
{
|
||||
state_ = state_t::mousedown;
|
||||
value_ = !value_;
|
||||
if (callback_)
|
||||
post([cb = callback_, v = value_]{ cb(v); });
|
||||
on_state_changed(state_t::mouseover);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case state_t::mousedown:
|
||||
if (!e.down)
|
||||
{
|
||||
state_ = state_t::mouseover;
|
||||
on_state_changed(state_t::mousedown);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void checkbox::on_state_changed(state_t old)
|
||||
{
|
||||
if (state() == state_t::mousedown || old == state_t::mousedown)
|
||||
{
|
||||
post_reshape();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -360,6 +360,84 @@ namespace psemek::ui
|
|||
element * children_[3];
|
||||
};
|
||||
|
||||
struct checkbox_impl
|
||||
: checkbox
|
||||
{
|
||||
struct shape const & shape() const override
|
||||
{
|
||||
return shape_;
|
||||
}
|
||||
|
||||
void reshape(geom::box<float, 2> const & bbox) override
|
||||
{
|
||||
shape_.box = geom::expand(geom::box<float, 2>::singleton(bbox.center()), size() / 2.f);
|
||||
}
|
||||
|
||||
void draw(painter & p) const override
|
||||
{
|
||||
auto st = merged_style();
|
||||
if (!st) return;
|
||||
|
||||
geom::box<float, 2> boxes[5];
|
||||
|
||||
boxes[0] = {{shape_.box[0], {shape_.box[1].min, shape_.box[1].min + outer_width()}}};
|
||||
boxes[1] = {{shape_.box[0], {shape_.box[1].max - outer_width(), shape_.box[1].max}}};
|
||||
boxes[2] = {{{shape_.box[0].min, shape_.box[0].min + outer_width()}, {shape_.box[1].min + outer_width(), shape_.box[1].max - outer_width()}}};
|
||||
boxes[3] = {{{shape_.box[0].max - outer_width(), shape_.box[0].max}, {shape_.box[1].min + outer_width(), shape_.box[1].max - outer_width()}}};
|
||||
boxes[4] = geom::shrink(shape_.box, 0.f + outer_width() + outer_margin());
|
||||
|
||||
int const box_count = value() ? 5 : 4;
|
||||
|
||||
if (st->shadow_offset != geom::vector{0, 0})
|
||||
{
|
||||
auto const offset = geom::cast<float>(*st->shadow_offset);
|
||||
for (int b = 0; b < box_count; ++b)
|
||||
p.draw_rect(boxes[b] + offset, *st->shadow_color);
|
||||
}
|
||||
|
||||
auto offset = geom::vector{0.f, 0.f};
|
||||
if (state() == state_t::mousedown)
|
||||
offset = geom::cast<float>(*st->action_offset);
|
||||
|
||||
gfx::color_rgba color = *st->fg_color;
|
||||
if (state() == state_t::mouseover)
|
||||
color = *st->highlight_color;
|
||||
else if (state() == state_t::mousedown)
|
||||
color = *st->action_color;
|
||||
|
||||
for (int b = 0; b < box_count; ++b)
|
||||
p.draw_rect(boxes[b] + offset, color);
|
||||
}
|
||||
|
||||
geom::box<float, 2> size_constraints() const override
|
||||
{
|
||||
auto sc = element::size_constraints();
|
||||
|
||||
sc[0] &= geom::interval<float>{size(), std::numeric_limits<float>::infinity()};
|
||||
sc[1] &= geom::interval<float>{size(), std::numeric_limits<float>::infinity()};
|
||||
|
||||
return sc;
|
||||
}
|
||||
|
||||
private:
|
||||
box_shape shape_;
|
||||
|
||||
int size() const
|
||||
{
|
||||
return *merged_style()->ref_height;
|
||||
}
|
||||
|
||||
int outer_width() const
|
||||
{
|
||||
return *merged_style()->ref_height / 8;
|
||||
}
|
||||
|
||||
int outer_margin() const
|
||||
{
|
||||
return *merged_style()->ref_height / 8;
|
||||
}
|
||||
};
|
||||
|
||||
struct slider_impl
|
||||
: slider
|
||||
{
|
||||
|
|
@ -627,6 +705,13 @@ namespace psemek::ui
|
|||
return std::make_shared<spinbox_impl>();
|
||||
}
|
||||
|
||||
std::shared_ptr<checkbox> default_element_factory::make_checkbox(bool value)
|
||||
{
|
||||
auto c = std::make_shared<checkbox_impl>();
|
||||
c->set_value(value);
|
||||
return c;
|
||||
}
|
||||
|
||||
std::shared_ptr<slider> default_element_factory::make_slider()
|
||||
{
|
||||
return std::make_shared<slider_impl>();
|
||||
|
|
|
|||
|
|
@ -73,6 +73,11 @@ namespace psemek::ui
|
|||
return i;
|
||||
}
|
||||
|
||||
std::shared_ptr<checkbox> element_factory::make_checkbox(bool)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<slider> element_factory::make_slider() { return nullptr; }
|
||||
|
||||
std::shared_ptr<spinbox> element_factory::make_spinbox() { return nullptr; }
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue