From a53b32067feb02fca2391db3f99876129864dbe1 Mon Sep 17 00:00:00 2001 From: lisyarus Date: Thu, 25 Feb 2021 09:07:39 +0300 Subject: [PATCH] UI library prototype wip --- examples/ui.cpp | 74 ++++++++++ libs/ui/CMakeLists.txt | 6 + libs/ui/include/psemek/ui/box_shape.hpp | 23 ++++ libs/ui/include/psemek/ui/button.hpp | 52 ++++++++ libs/ui/include/psemek/ui/container.hpp | 32 +++++ libs/ui/include/psemek/ui/controller.hpp | 32 +++++ .../psemek/ui/default_element_factory.hpp | 15 +++ libs/ui/include/psemek/ui/element.hpp | 53 ++++++++ libs/ui/include/psemek/ui/event.hpp | 35 +++++ libs/ui/include/psemek/ui/font.hpp | 70 ++++++++++ libs/ui/include/psemek/ui/label.hpp | 68 ++++++++++ libs/ui/include/psemek/ui/monospace_font.hpp | 36 +++++ libs/ui/include/psemek/ui/painter.hpp | 19 +++ libs/ui/include/psemek/ui/painter_impl.hpp | 30 +++++ libs/ui/include/psemek/ui/screen.hpp | 51 +++++++ libs/ui/include/psemek/ui/shape.hpp | 17 +++ libs/ui/source/box_shape.cpp | 13 ++ libs/ui/source/button.cpp | 74 ++++++++++ libs/ui/source/container.cpp | 65 +++++++++ libs/ui/source/controller.cpp | 112 ++++++++++++++++ libs/ui/source/default_element_factory.cpp | 55 ++++++++ libs/ui/source/default_fonts.cpp | 41 ++++++ libs/ui/source/element.cpp | 31 +++++ libs/ui/source/label.cpp | 38 ++++++ libs/ui/source/monospace_font.cpp | 63 +++++++++ libs/ui/source/painter_impl.cpp | 126 ++++++++++++++++++ libs/ui/source/screen.cpp | 95 +++++++++++++ 27 files changed, 1326 insertions(+) create mode 100644 examples/ui.cpp create mode 100644 libs/ui/CMakeLists.txt create mode 100644 libs/ui/include/psemek/ui/box_shape.hpp create mode 100644 libs/ui/include/psemek/ui/button.hpp create mode 100644 libs/ui/include/psemek/ui/container.hpp create mode 100644 libs/ui/include/psemek/ui/controller.hpp create mode 100644 libs/ui/include/psemek/ui/default_element_factory.hpp create mode 100644 libs/ui/include/psemek/ui/element.hpp create mode 100644 libs/ui/include/psemek/ui/event.hpp create mode 100644 libs/ui/include/psemek/ui/font.hpp create mode 100644 libs/ui/include/psemek/ui/label.hpp create mode 100644 libs/ui/include/psemek/ui/monospace_font.hpp create mode 100644 libs/ui/include/psemek/ui/painter.hpp create mode 100644 libs/ui/include/psemek/ui/painter_impl.hpp create mode 100644 libs/ui/include/psemek/ui/screen.hpp create mode 100644 libs/ui/include/psemek/ui/shape.hpp create mode 100644 libs/ui/source/box_shape.cpp create mode 100644 libs/ui/source/button.cpp create mode 100644 libs/ui/source/container.cpp create mode 100644 libs/ui/source/controller.cpp create mode 100644 libs/ui/source/default_element_factory.cpp create mode 100644 libs/ui/source/default_fonts.cpp create mode 100644 libs/ui/source/element.cpp create mode 100644 libs/ui/source/label.cpp create mode 100644 libs/ui/source/monospace_font.cpp create mode 100644 libs/ui/source/painter_impl.cpp create mode 100644 libs/ui/source/screen.cpp diff --git a/examples/ui.cpp b/examples/ui.cpp new file mode 100644 index 00000000..2a885944 --- /dev/null +++ b/examples/ui.cpp @@ -0,0 +1,74 @@ +#include +#include + +#include + +#include +#include +#include + +#include + +using namespace psemek; + +struct ui_example + : app::app +{ + ui_example() + : app("UI example", 1) + { + ui_controller.set_font(ui::make_default_9x12_font()); + + auto screen = element_factory.make_screen(); + screen->add(element_factory.make_button(), ui::screen::x_policy::center, ui::screen::y_policy::center); + + ui_controller.set_root(std::move(screen)); + } + + void on_resize(int width, int height) override + { + app::on_resize(width, height); + ui_controller.reshape({{{0, width}, {0, height}}}); + } + + void on_mouse_move(int x, int y, int dx, int dy) override + { + app::on_mouse_move(x, y, dx, dy); + ui_controller.event(ui::mouse_move{{x, y}}); + } + + void on_left_button_down() override + { + app::on_left_button_down(); + ui_controller.event(ui::mouse_click{ui::mouse_button::left, true}); + } + + void on_left_button_up() override + { + app::on_left_button_up(); + ui_controller.event(ui::mouse_click{ui::mouse_button::left, false}); + } + + void present() override; + + ui::controller ui_controller; + ui::default_element_factory element_factory; +}; + +void ui_example::present() +{ + gl::ClearColor(0.8f, 0.8f, 0.8f, 1.f); + gl::Clear(gl::COLOR_BUFFER_BIT); + + gfx::render_target rt; + rt.framebuffer = &gfx::framebuffer::null(); + rt.draw_buffer = gl::BACK_LEFT; + rt.viewport = {{{0, width()}, {0, height()}}}; + + ui_controller.render(rt); +} + +int main() +{ + return app::main(); +} diff --git a/libs/ui/CMakeLists.txt b/libs/ui/CMakeLists.txt new file mode 100644 index 00000000..85a5ea66 --- /dev/null +++ b/libs/ui/CMakeLists.txt @@ -0,0 +1,6 @@ +file(GLOB_RECURSE PSEMEK_UI_HEADERS RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "include/*.hpp") +file(GLOB_RECURSE PSEMEK_UI_SOURCES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "source/*.cpp") + +psemek_add_library(psemek-ui ${PSEMEK_UI_HEADERS} ${PSEMEK_UI_SOURCES}) +target_include_directories(psemek-ui PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include") +target_link_libraries(psemek-ui PUBLIC psemek-util psemek-log psemek-geom psemek-cg psemek-gfx psemek-async) diff --git a/libs/ui/include/psemek/ui/box_shape.hpp b/libs/ui/include/psemek/ui/box_shape.hpp new file mode 100644 index 00000000..1d4f3332 --- /dev/null +++ b/libs/ui/include/psemek/ui/box_shape.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include + +namespace psemek::ui +{ + + struct box_shape + : shape + { + geom::box box; + + box_shape() = default; + + box_shape(geom::box box) + : box{box} + {} + + bool contains(geom::point const & point) const override; + geom::box bbox() const override { return box; } + }; + +} diff --git a/libs/ui/include/psemek/ui/button.hpp b/libs/ui/include/psemek/ui/button.hpp new file mode 100644 index 00000000..4bcee76a --- /dev/null +++ b/libs/ui/include/psemek/ui/button.hpp @@ -0,0 +1,52 @@ +#pragma once + +#include +#include + +#include + +namespace psemek::ui +{ + + struct button + : element + { + struct label * label() { return label_.get(); } + struct label const * label() const { return label_.get(); } + + children_range children() const override; + + bool on_event(mouse_move const & e) override; + bool on_event(mouse_click const & e) override; + + using on_click_callback = std::function; + + void on_click(on_click_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() {} + + void set_label(std::unique_ptr label); + + private: + state_t state_ = state_t::normal; + + on_click_callback callback_; + + std::unique_ptr label_; + element * children_[1]{nullptr}; + }; + +} diff --git a/libs/ui/include/psemek/ui/container.hpp b/libs/ui/include/psemek/ui/container.hpp new file mode 100644 index 00000000..a25f01de --- /dev/null +++ b/libs/ui/include/psemek/ui/container.hpp @@ -0,0 +1,32 @@ +#pragma once + +#include + +#include + +namespace psemek::ui +{ + + struct container + : element + { + children_range children() const override; + + protected: + std::size_t children_count() const { return children_.size(); } + + std::size_t add(std::unique_ptr c); + void add(std::unique_ptr c, std::size_t index); + + element * get(std::size_t index); + std::optional find(element * c); + + std::unique_ptr remove(element * c); + std::unique_ptr remove(std::size_t index); + + private: + std::vector> children_; + std::vector children_range_; + }; + +} diff --git a/libs/ui/include/psemek/ui/controller.hpp b/libs/ui/include/psemek/ui/controller.hpp new file mode 100644 index 00000000..9c360b9b --- /dev/null +++ b/libs/ui/include/psemek/ui/controller.hpp @@ -0,0 +1,32 @@ +#pragma once + +#include +#include +#include +#include + +namespace psemek::ui +{ + + struct controller + { + controller(); + ~controller(); + + std::unique_ptr set_root(std::unique_ptr r); + element * root(); + + void set_font(std::shared_ptr f); + void reshape(geom::box const & shape); + + bool event(mouse_move const & e); + bool event(mouse_click const & e); + bool event(mouse_wheel const & e); + + void render(gfx::render_target const & rt); + + private: + psemek_declare_pimpl + }; + +} diff --git a/libs/ui/include/psemek/ui/default_element_factory.hpp b/libs/ui/include/psemek/ui/default_element_factory.hpp new file mode 100644 index 00000000..8f3d53a1 --- /dev/null +++ b/libs/ui/include/psemek/ui/default_element_factory.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include +#include + +namespace psemek::ui +{ + + struct default_element_factory + { + std::unique_ptr