diff --git a/meson.build b/meson.build index 7da0c32..7ff3704 100644 --- a/meson.build +++ b/meson.build @@ -11,6 +11,7 @@ executable( './src/Window.cpp', './src/Widget.cpp', './src/Button.cpp', + './src/Layout.cpp', './src/Label.cpp', './src/main.cpp', dependencies : [cairomm_dep, xlib_dep, pangocairo_dep] diff --git a/src/Button.hpp b/src/Button.hpp index 90b531c..1b4bc06 100644 --- a/src/Button.hpp +++ b/src/Button.hpp @@ -22,6 +22,8 @@ public: std::function on_click { [](){} }; protected: + WidgetType m_type { WidgetType::Button }; + void on_paint(); void on_init(); void on_focus_update(FocusUpdateEvent &event); diff --git a/src/Forward.hpp b/src/Forward.hpp index 8961741..7b20264 100644 --- a/src/Forward.hpp +++ b/src/Forward.hpp @@ -5,6 +5,7 @@ namespace Raven { class Painter; class Point; class TopLevelStyles; + class Layout; class Widget; class Window; diff --git a/src/Label.hpp b/src/Label.hpp index 49ef34d..9a13188 100644 --- a/src/Label.hpp +++ b/src/Label.hpp @@ -18,6 +18,8 @@ public: std::string &get_text() { return m_text; } void set_text(std::string text) { m_text = text; wants_repaint(); } protected: + WidgetType m_type { WidgetType::Label }; + void on_paint(); void on_init(); }; diff --git a/src/Layout.cpp b/src/Layout.cpp new file mode 100644 index 0000000..d93fc83 --- /dev/null +++ b/src/Layout.cpp @@ -0,0 +1,29 @@ +#include +#include "Layout.hpp" +#include "Point.hpp" +#include "Box.hpp" +#include "Widget.hpp" + +namespace Raven { + +void Layout::run_on(Widget *target) { + Point point { target->get_current_geometry().get_x(), target->get_current_geometry().get_y() }; + double row_largest_height = 0.0; + + auto children = target->get_children(); + for (auto& c : children) { + if (c->get_control_type() == ControlWidgetType::NewRow && row_largest_height) { + point.add(0, row_largest_height); + row_largest_height = 0.0; + point.set_x(0); + } + if (c->get_current_geometry().get_height() > row_largest_height) { + row_largest_height = c->get_current_geometry().get_height(); + } + auto new_geometry = Box{ point.get_x(), point.get_y(), c->get_current_geometry().get_width(), c->get_current_geometry().get_height() }; + c->set_current_geometry(std::move(new_geometry)); + point.add(c->get_current_geometry().get_width(), 0); + } +} + +} \ No newline at end of file diff --git a/src/Layout.hpp b/src/Layout.hpp new file mode 100644 index 0000000..3ec74e7 --- /dev/null +++ b/src/Layout.hpp @@ -0,0 +1,14 @@ +#pragma once + +#include "Forward.hpp" + +namespace Raven { + +class Layout { +public: + Layout() {} + + void run_on(Widget *target); +}; + +} \ No newline at end of file diff --git a/src/Point.hpp b/src/Point.hpp index 4104a47..ee5db3e 100644 --- a/src/Point.hpp +++ b/src/Point.hpp @@ -4,20 +4,23 @@ namespace Raven { class Point { private: - int m_x; - int m_y; + double m_x; + double m_y; public: - Point(int x, int y) + Point(double x, double y) : m_x(x) , m_y(y) {} - int get_x() { return m_x; } - const int get_x() const { return m_x; } - int get_y() { return m_y; } - const int get_y() const { return m_y; } + double get_x() { return m_x; } + const double get_x() const { return m_x; } + double get_y() { return m_y; } + const double get_y() const { return m_y; } - void set_x(int x) { m_x = x; } - void set_y(int y) { m_y = y; } + void set_x(double x) { m_x = x; } + void set_y(double y) { m_y = y; } + + void add(double x, double y) { m_x += x; m_y += y; } + void add(Point const& other) { m_x += other.get_x(); m_y += other.get_y(); } }; } \ No newline at end of file diff --git a/src/Widget.cpp b/src/Widget.cpp index 083df8e..b84ccb6 100644 --- a/src/Widget.cpp +++ b/src/Widget.cpp @@ -3,9 +3,16 @@ #include "Widget.hpp" #include "Events.hpp" #include "Window.hpp" +#include "Layout.hpp" namespace Raven { +void Widget::do_layout() { + if (m_layout) { + m_layout->run_on(this); + } +} + void Widget::set_window(Window *window) { m_window = window; m_styles = m_window->get_top_level_styles(); @@ -22,6 +29,7 @@ bool Widget::add_child(Widget *child) { // children inherit the window from the parent // TODO?: what happens when the parent changes its window? child->set_window(m_window); + do_layout(); return true; } @@ -132,6 +140,9 @@ void Widget::handle_mouse_button_event(MouseButtonEvent &event) { } void Widget::dispatch_event(Event &event) { + if (!m_accepts_events) + return; + switch (event.get_type()) { case EventType::MouseMove: { handle_mouse_move_event(reinterpret_cast(event)); diff --git a/src/Widget.hpp b/src/Widget.hpp index e7fe5cd..3afcae3 100644 --- a/src/Widget.hpp +++ b/src/Widget.hpp @@ -3,7 +3,7 @@ #include #include #include -#include "Box.hpp" +#include "Box.hpp" #include "Events.hpp" #include "Forward.hpp" #include "RGB.hpp" @@ -12,6 +12,18 @@ namespace Raven { +enum class WidgetType { + Widget = 0, + Button, + Label, + Control +}; + +enum class ControlWidgetType { + Widget = 0, + NewRow +}; + class Widget { DEF_WIDGET_STYLE_PROP(do_background_fill, bool, false) @@ -20,18 +32,28 @@ DEF_WIDGET_STYLE_PROP(background_border_radius, double, 0.0) private: - Box m_current_geometry {}; + Box m_current_geometry { 0, 0, 0, 0 }; std::vector m_children; Widget *m_parent { nullptr }; Window *m_window { nullptr }; std::shared_ptr m_styles = nullptr; + Layout *m_layout { nullptr }; bool m_did_init { false }; bool m_is_focused { false }; bool m_is_active { false }; bool m_consumes_hits { false }; + bool m_accepts_events { true }; + ControlWidgetType m_control_type { ControlWidgetType::Widget }; public: Widget() {} + Widget(ControlWidgetType type) + : m_control_type(type) { + m_type = WidgetType::Control; + m_control_type = type; + m_accepts_events = false; + } + Box &get_current_geometry() { return m_current_geometry; } void set_current_geometry(Box current_geometry) { m_current_geometry = current_geometry; wants_repaint(); } @@ -58,13 +80,24 @@ public: bool get_consumes_hits() { return m_consumes_hits; } void set_consumes_hits(bool consumes_hits) { m_consumes_hits = consumes_hits; } + bool get_accepts_events() { return m_accepts_events; } + void set_accepts_events(bool accepts_events) { m_accepts_events = accepts_events; } + + void set_layout(Layout *layout) { m_layout = layout; } + Layout *get_layout() { return m_layout; } + + WidgetType get_type() { return m_type; } + ControlWidgetType get_control_type() { return m_control_type; } void dispatch_event(Event &event); void wants_repaint(); void wants_full_repaint(); + void do_layout(); virtual ~Widget() {}; protected: + WidgetType m_type { WidgetType::Widget }; + virtual void on_init(); virtual void on_mouse_button(MouseButtonEvent &event) {} virtual void on_mouse_move(MouseMoveEvent &event) {} diff --git a/src/main.cpp b/src/main.cpp index 60e5bad..618d13f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,19 +4,26 @@ #include "Button.hpp" #include "Box.hpp" #include "Label.hpp" +#include "Layout.hpp" int main() { + Raven::Layout main_layout {}; + Raven::Widget new_row { Raven::ControlWidgetType::NewRow }; Raven::Window window {}; Raven::Widget main_widget {}; Raven::Button button {"click meeeeeeeeeeee"}; + Raven::Button impostor_button {"other button"}; Raven::Label label {"click it!"}; int times_clicked = 0; window.spawn_window(); - button.set_current_geometry(Raven::Box(10, 10, 100, 30)); - label.set_current_geometry(Raven::Box(10, 45, 100, 20)); + button.set_current_geometry(Raven::Box(0, 0, 100, 30)); + impostor_button.set_current_geometry(Raven::Box(0, 0, 100, 30)); + label.set_current_geometry(Raven::Box(0, 0, 100, 20)); + + main_widget.set_layout(&main_layout); window.set_main_widget(&main_widget); button.on_click = [&]() { @@ -26,6 +33,8 @@ int main() { main_widget.add_child(&button); main_widget.add_child(&label); + main_widget.add_child(&new_row); + main_widget.add_child(&impostor_button); window.run(true);