diff --git a/examples/ui.cpp b/examples/ui.cpp index 4057a367..b14fe676 100644 --- a/examples/ui.cpp +++ b/examples/ui.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include @@ -38,42 +39,28 @@ struct ui_example : app("UI example", 1) , ui_controller(&loop) { - auto style = std::make_shared(); + auto style = std::make_shared(ui::default_style()); style->font = ui::make_default_9x12_font(); style->text_scale = 2; auto screen = element_factory.make_screen(); screen->set_style(style); - auto grid = element_factory.make_grid_layout(); - grid->set_size(1, 1); - auto button = element_factory.make_button("0,0"); - grid->set(0, 0, button); - button->on_click(util::recursive([this, grid](auto && self) -> void { - while (true) + std::shared_ptr button; + { + gfx::pixmap_rgba pm({32, 32}); + for (int x = 0; x < pm.width(); ++x) { - for (std::size_t i = 0; i < grid->row_count(); ++i) + for (int y = 0; y < pm.height(); ++y) { - for (std::size_t j = 0; j < grid->column_count(); ++j) - { - if (!grid->get(i, j)) - { - auto button = element_factory.make_button(util::to_string(i, ",", j)); - grid->set(i, j, button); - button->on_click(self); - return; - } - } + pm(x, y) = {(x * 255) / pm.width(), (y * 255) / pm.height(), 0, 255}; } - - if (grid->row_count() <= grid->column_count()) - grid->set_row_count(grid->row_count() + 1); - else - grid->set_column_count(grid->column_count() + 1); } - })); - - screen->add_child(grid, ui::screen::x_policy::center, ui::screen::y_policy::center); + auto tex = std::make_shared(gfx::texture_2d::from_pixmap(pm)); + tex->nearest_filter(); + button = element_factory.make_button(tex); + } + screen->add_child(button, ui::screen::x_policy::center, ui::screen::y_policy::center); ui_controller.set_root(std::move(screen)); } diff --git a/libs/ui/include/psemek/ui/style.hpp b/libs/ui/include/psemek/ui/style.hpp index 47382602..b8da9c7c 100644 --- a/libs/ui/include/psemek/ui/style.hpp +++ b/libs/ui/include/psemek/ui/style.hpp @@ -3,29 +3,34 @@ #include #include +#include + namespace psemek::ui { struct style { - gfx::color_rgba bg_color{95, 95, 95, 255}; - gfx::color_rgba fg_color{127, 127, 127, 255}; - gfx::color_rgba highlight_color{159, 159, 159, 255}; - gfx::color_rgba action_color{63, 63, 63, 255}; + std::optional bg_color; + std::optional fg_color; + std::optional highlight_color; + std::optional action_color; - gfx::color_rgba border_color{255, 255, 255, 255}; - int border_width = 3; + std::optional border_color; + std::optional border_width; - geom::vector shadow_offset{1, 1}; - gfx::color_rgba shadow_color{0, 0, 0, 255}; + std::optional> shadow_offset; + std::optional shadow_color; - int inner_margin = 5; - int outer_margin = 10; + std::optional inner_margin; + std::optional outer_margin; + + std::optional text_color; + std::optional text_scale; + std::optional> text_shadow_offset; - gfx::color_rgba text_color{255, 255, 255, 255}; - int text_scale = 1; - geom::vector text_shadow_offset{1, 1}; std::shared_ptr font; }; + style default_style(); + } diff --git a/libs/ui/source/default_element_factory.cpp b/libs/ui/source/default_element_factory.cpp index db702163..3fa0319c 100644 --- a/libs/ui/source/default_element_factory.cpp +++ b/libs/ui/source/default_element_factory.cpp @@ -39,7 +39,7 @@ namespace psemek::ui shape_.box = bbox; auto s = style(); element * c = label() ? (element *)label() : icon(); - if (s && c) c->reshape(geom::shrink(bbox, 1.f * (s->border_width + s->inner_margin))); + if (s && c) c->reshape(geom::shrink(bbox, 1.f * (*s->border_width + *s->inner_margin))); } void on_state_changed() override @@ -67,17 +67,17 @@ namespace psemek::ui if (!s) return; if (s->shadow_offset != geom::vector{0, 0}) - p.draw_rect(shape_.box + geom::cast(s->shadow_offset), s->shadow_color); + p.draw_rect(shape_.box + geom::cast(*s->shadow_offset), *s->shadow_color); if (s->border_width > 0) - p.draw_rect(shape_.box, s->border_color); + p.draw_rect(shape_.box, *s->border_color); - gfx::color_rgba color = s->fg_color; + gfx::color_rgba color = *s->fg_color; if (state() == state_t::mouseover) - color = s->highlight_color; + color = *s->highlight_color; else if (state() == state_t::mousedown) - color = s->action_color; - p.draw_rect(geom::shrink(shape_.box, 1.f * s->border_width), color); + color = *s->action_color; + p.draw_rect(geom::shrink(shape_.box, 1.f * (*s->border_width)), color); } geom::box size_constraints() const override @@ -92,7 +92,7 @@ namespace psemek::ui if (auto st = style()) { - float extra = 2.f * (st->border_width + st->inner_margin); + float extra = 2.f * (*st->border_width + *st->inner_margin); sc[0] += extra; sc[1] += extra; } @@ -116,7 +116,7 @@ namespace psemek::ui auto st = style(); if (!st) return; for (auto c : children()) - if (c) c->reshape(geom::shrink(bbox, 1.f * (st->border_width + st->outer_margin))); + if (c) c->reshape(geom::shrink(bbox, 1.f * (*st->border_width + *st->outer_margin))); } geom::box size_constraints() const override @@ -130,7 +130,7 @@ namespace psemek::ui auto st = style(); if (st) { - float extra = 2.f * (st->border_width + st->outer_margin); + float extra = 2.f * (*st->border_width + *st->outer_margin); r[0] += extra; r[1] += extra; } @@ -158,11 +158,11 @@ namespace psemek::ui if (!st) return; if (st->shadow_offset != geom::vector{0, 0}) - p.draw_rect(shape_.box + geom::cast(st->shadow_offset), st->shadow_color); + p.draw_rect(shape_.box + geom::cast(*st->shadow_offset), *st->shadow_color); if (st->border_width > 0) - p.draw_rect(shape_.box, st->border_color); - p.draw_rect(geom::shrink(shape_.box, 1.f * st->border_width), st->bg_color); + p.draw_rect(shape_.box, *st->border_color); + p.draw_rect(geom::shrink(shape_.box, 1.f * (*st->border_width)), *st->bg_color); } private: diff --git a/libs/ui/source/grid_layout.cpp b/libs/ui/source/grid_layout.cpp index 0568e10d..68505e25 100644 --- a/libs/ui/source/grid_layout.cpp +++ b/libs/ui/source/grid_layout.cpp @@ -155,8 +155,8 @@ namespace psemek::ui result[0].max += column_size[i].max; } - result[1] += (row_count() + 1) * st->outer_margin; - result[0] += (column_count() + 1) * st->outer_margin; + result[1] += (row_count() + 1) * (*st->outer_margin); + result[0] += (column_count() + 1) * (*st->outer_margin); return result; } @@ -166,7 +166,7 @@ namespace psemek::ui auto st = style(); if (!st) return; - float const margin = st->outer_margin; + float const margin = *st->outer_margin; float const available_width = std::max(0.f, bbox[0].length() - margin * (1 + column_count())); float const available_height = std::max(0.f, bbox[1].length() - margin * (1 + row_count())); diff --git a/libs/ui/source/label.cpp b/libs/ui/source/label.cpp index 885565db..7df4705b 100644 --- a/libs/ui/source/label.cpp +++ b/libs/ui/source/label.cpp @@ -63,10 +63,10 @@ namespace psemek::ui if (st->text_shadow_offset != geom::vector{0, 0}) for (auto & g : cached_state_->glyphs) - p.draw_glyph(*(cached_state_->font), g.character, g.position + geom::cast(st->text_shadow_offset), st->shadow_color); + p.draw_glyph(*(cached_state_->font), g.character, g.position + geom::cast(*st->text_shadow_offset), *st->shadow_color); for (auto & g : cached_state_->glyphs) - p.draw_glyph(*(cached_state_->font), g.character, g.position, st->text_color); + p.draw_glyph(*(cached_state_->font), g.character, g.position, *st->text_color); } void label::on_state_changed() @@ -98,7 +98,7 @@ namespace psemek::ui state.font = st->font.get(); shape_options opts; - opts.scale = st->text_scale; + opts.scale = *st->text_scale; auto glyphs = st->font->shape(text_, opts); geom::box raw_bbox; @@ -114,7 +114,7 @@ namespace psemek::ui break; case multiline_mode::minimize_lines: max_lines = std::isfinite(bbox[1].length()) - ? std::max(1, std::floor(bbox[1].length() / st->font->size()[1] / st->text_scale)) + ? std::max(1, std::floor(bbox[1].length() / st->font->size()[1] / (*st->text_scale))) : std::numeric_limits::max(); break; case multiline_mode::minimize_area: @@ -226,13 +226,13 @@ namespace psemek::ui switch (valign_) { case valignment::top: - offset[1] = bbox[1].min + l * st->text_scale * st->font->size()[1]; + offset[1] = bbox[1].min + l * (*st->text_scale) * st->font->size()[1]; break; case valignment::center: - offset[1] = bbox[1].center() + (l - lines.size() / 2.f) * st->text_scale * st->font->size()[1]; + offset[1] = bbox[1].center() + (l - lines.size() / 2.f) * (*st->text_scale) * st->font->size()[1]; break; case valignment::bottom: - offset[1] = bbox[1].max + (l - lines.size() * 1.f) * st->text_scale * st->font->size()[1]; + offset[1] = bbox[1].max + (l - lines.size() * 1.f) * (*st->text_scale) * st->font->size()[1]; break; } @@ -242,7 +242,7 @@ namespace psemek::ui state.glyphs = std::move(glyphs); state.size[0] = max_line_size; - state.size[1] = lines.size() * st->text_scale * st->font->size()[1]; + state.size[1] = lines.size() * (*st->text_scale) * st->font->size()[1]; return state; } diff --git a/libs/ui/source/style.cpp b/libs/ui/source/style.cpp new file mode 100644 index 00000000..2c20b9e8 --- /dev/null +++ b/libs/ui/source/style.cpp @@ -0,0 +1,29 @@ +#include + +namespace psemek::ui +{ + + style default_style() + { + style s; + s.bg_color = {95, 95, 95, 255}; + s.fg_color = {127, 127, 127, 255}; + s.highlight_color = {159, 159, 159, 255}; + s.action_color = {63, 63, 63, 255}; + + s.border_color = {255, 255, 255, 255}; + s.border_width = 3; + + s.shadow_offset = {1, 1}; + s.shadow_color = {0, 0, 0, 255}; + + s.inner_margin = 5; + s.outer_margin = 10; + + s.text_color = {255, 255, 255, 255}; + s.text_scale = 1; + s.text_shadow_offset = {1, 1}; + return s; + } + +}