Add ui::color_picker composite element

This commit is contained in:
Nikita Lisitsa 2022-12-20 17:12:18 +03:00
parent 5af0c66599
commit 8e0c27c8c0
2 changed files with 209 additions and 0 deletions

View file

@ -0,0 +1,28 @@
#pragma once
#include <psemek/ui/element.hpp>
#include <psemek/ui/single_container.hpp>
#include <psemek/ui/element_factory.hpp>
#include <functional>
namespace psemek::ui
{
struct color_picker
: single_container
{
virtual gfx::color_rgba color() const = 0;
virtual void set_color(gfx::color_rgba value, bool notify = true) = 0;
using on_value_changed_callback = std::function<void(gfx::color_rgba)>;
virtual void on_value_changed(on_value_changed_callback callback) { on_value_changed_callback_ = callback; }
protected:
on_value_changed_callback on_value_changed_callback_;
};
std::shared_ptr<color_picker> make_color_picker(element_factory & factory);
}

View file

@ -0,0 +1,181 @@
#include <psemek/ui/color_picker.hpp>
#include <psemek/ui/frame.hpp>
#include <psemek/ui/color_view.hpp>
#include <psemek/ui/grid_layout.hpp>
#include <psemek/ui/slider.hpp>
#include <psemek/ui/label.hpp>
#include <psemek/ui/screen.hpp>
#include <psemek/util/to_string.hpp>
#include <functional>
namespace psemek::ui
{
namespace
{
struct color_picker_impl
: color_picker
{
color_picker_impl(element_factory & factory)
{
auto frame = std::make_shared<ui::frame>();
frame->set_min_size(geom::vector{250.f, 0.f});
auto main_layout = factory.make_grid_layout();
main_layout->set_size(1, 2);
main_layout->set_column_weight(0, 0.f);
main_layout->set_outer_margin(false);
main_layout->set_width_first(false);
color_view_ = std::make_shared<ui::color_view>();
color_view_->set_square(true);
auto sliders_layout = factory.make_grid_layout();
sliders_layout->set_size(3, 2);
sliders_layout->set_column_weight(0, 0.f);
sliders_layout->set_outer_margin(false);
hidden_label_ = factory.make_label("000");
hidden_label_->set_hidden(true);
auto hidden_screen = factory.make_screen();
hidden_screen->add_child(hidden_label_, screen::x_policy::fill, screen::y_policy::fill);
red_label_ = factory.make_label("");
red_label_->set_halign(label::halignment::right);
red_label_->set_valign(label::valignment::center);
green_label_ = factory.make_label("");
green_label_->set_halign(label::halignment::right);
green_label_->set_valign(label::valignment::center);
blue_label_ = factory.make_label("");
blue_label_->set_halign(label::halignment::right);
blue_label_->set_valign(label::valignment::center);
auto slider_callback = [this](int){
set_color(color(), true);
};
red_slider_ = factory.make_slider();
red_slider_->set_value_range({0, 255}, false);
red_slider_->on_value_changed(slider_callback, false);
green_slider_ = factory.make_slider();
green_slider_->set_value_range({0, 255}, false);
green_slider_->on_value_changed(slider_callback, false);
blue_slider_ = factory.make_slider();
blue_slider_->set_value_range({0, 255}, false);
blue_slider_->on_value_changed(slider_callback, false);
hidden_screen->add_child(red_label_, screen::x_policy::fill, screen::y_policy::fill);
sliders_layout->set(0, 0, hidden_screen);
sliders_layout->set(1, 0, green_label_);
sliders_layout->set(2, 0, blue_label_);
sliders_layout->set(0, 1, red_slider_);
sliders_layout->set(1, 1, green_slider_);
sliders_layout->set(2, 1, blue_slider_);
main_layout->set(0, 0, color_view_);
main_layout->set(0, 1, sliders_layout);
frame->set_child(main_layout);
set_child(frame);
}
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
{}
geom::box<float, 2> size_constraints() const override
{
return child_->size_constraints();
}
geom::interval<float> width_constraints(float height) const override
{
return child_->width_constraints(height);
}
geom::interval<float> height_constraints(float width) const override
{
return child_->height_constraints(width);
}
gfx::color_rgba color() const override
{
return {
red_slider_->value(),
green_slider_->value(),
blue_slider_->value(),
255
};
}
void set_color(gfx::color_rgba value, bool notify) override
{
color_view_->set_color(value);
red_label_ ->set_tagged_text(util::to_string("[color:f00]", static_cast<int>(value[0]), "[/color]"));
green_label_->set_tagged_text(util::to_string("[color:0f0]", static_cast<int>(value[1]), "[/color]"));
blue_label_ ->set_tagged_text(util::to_string("[color:00f]", static_cast<int>(value[2]), "[/color]"));
red_slider_->set_value(value[0], false);
green_slider_->set_value(value[1], false);
blue_slider_->set_value(value[2], false);
if (notify && on_value_changed_callback_)
post([cb = on_value_changed_callback_, value]{ cb(value); });
}
void style_updated() const override
{
color_picker::style_updated();
auto st = merged_own_style();
if (!st->font) return;
auto glyphs = st->font->shape("0123456789", {});
float max_width = 0.f;
char max_width_char = '0';
for (auto const & g : glyphs)
if (geom::make_max(max_width, g.position[0].length()))
max_width_char = g.character;
hidden_label_->set_text(std::string(3, max_width_char));
}
private:
std::shared_ptr<color_view> color_view_;
std::shared_ptr<label> hidden_label_;
std::shared_ptr<label> red_label_;
std::shared_ptr<label> green_label_;
std::shared_ptr<label> blue_label_;
std::shared_ptr<slider> red_slider_;
std::shared_ptr<slider> green_slider_;
std::shared_ptr<slider> blue_slider_;
};
}
std::shared_ptr<color_picker> make_color_picker(element_factory & factory)
{
return std::make_shared<color_picker_impl>(factory);
}
}