add very basic layout system

This commit is contained in:
hippoz 2022-03-30 14:49:31 +03:00
parent 9efac54ffa
commit 4401b7b5b2
Signed by: hippoz
GPG key ID: 7C52899193467641
10 changed files with 118 additions and 13 deletions

View file

@ -11,6 +11,7 @@ executable(
'./src/Window.cpp', './src/Window.cpp',
'./src/Widget.cpp', './src/Widget.cpp',
'./src/Button.cpp', './src/Button.cpp',
'./src/Layout.cpp',
'./src/Label.cpp', './src/Label.cpp',
'./src/main.cpp', './src/main.cpp',
dependencies : [cairomm_dep, xlib_dep, pangocairo_dep] dependencies : [cairomm_dep, xlib_dep, pangocairo_dep]

View file

@ -22,6 +22,8 @@ public:
std::function<void()> on_click { [](){} }; std::function<void()> on_click { [](){} };
protected: protected:
WidgetType m_type { WidgetType::Button };
void on_paint(); void on_paint();
void on_init(); void on_init();
void on_focus_update(FocusUpdateEvent &event); void on_focus_update(FocusUpdateEvent &event);

View file

@ -5,6 +5,7 @@ namespace Raven {
class Painter; class Painter;
class Point; class Point;
class TopLevelStyles; class TopLevelStyles;
class Layout;
class Widget; class Widget;
class Window; class Window;

View file

@ -18,6 +18,8 @@ public:
std::string &get_text() { return m_text; } std::string &get_text() { return m_text; }
void set_text(std::string text) { m_text = text; wants_repaint(); } void set_text(std::string text) { m_text = text; wants_repaint(); }
protected: protected:
WidgetType m_type { WidgetType::Label };
void on_paint(); void on_paint();
void on_init(); void on_init();
}; };

29
src/Layout.cpp Normal file
View file

@ -0,0 +1,29 @@
#include <iostream>
#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);
}
}
}

14
src/Layout.hpp Normal file
View file

@ -0,0 +1,14 @@
#pragma once
#include "Forward.hpp"
namespace Raven {
class Layout {
public:
Layout() {}
void run_on(Widget *target);
};
}

View file

@ -4,20 +4,23 @@ namespace Raven {
class Point { class Point {
private: private:
int m_x; double m_x;
int m_y; double m_y;
public: public:
Point(int x, int y) Point(double x, double y)
: m_x(x) : m_x(x)
, m_y(y) {} , m_y(y) {}
int get_x() { return m_x; } double get_x() { return m_x; }
const int get_x() const { return m_x; } const double get_x() const { return m_x; }
int get_y() { return m_y; } double get_y() { return m_y; }
const int get_y() const { return m_y; } const double get_y() const { return m_y; }
void set_x(int x) { m_x = x; } void set_x(double x) { m_x = x; }
void set_y(int y) { m_y = y; } 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(); }
}; };
} }

View file

@ -3,9 +3,16 @@
#include "Widget.hpp" #include "Widget.hpp"
#include "Events.hpp" #include "Events.hpp"
#include "Window.hpp" #include "Window.hpp"
#include "Layout.hpp"
namespace Raven { namespace Raven {
void Widget::do_layout() {
if (m_layout) {
m_layout->run_on(this);
}
}
void Widget::set_window(Window *window) { void Widget::set_window(Window *window) {
m_window = window; m_window = window;
m_styles = m_window->get_top_level_styles(); 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 // children inherit the window from the parent
// TODO?: what happens when the parent changes its window? // TODO?: what happens when the parent changes its window?
child->set_window(m_window); child->set_window(m_window);
do_layout();
return true; return true;
} }
@ -132,6 +140,9 @@ void Widget::handle_mouse_button_event(MouseButtonEvent &event) {
} }
void Widget::dispatch_event(Event &event) { void Widget::dispatch_event(Event &event) {
if (!m_accepts_events)
return;
switch (event.get_type()) { switch (event.get_type()) {
case EventType::MouseMove: { case EventType::MouseMove: {
handle_mouse_move_event(reinterpret_cast<MouseMoveEvent&>(event)); handle_mouse_move_event(reinterpret_cast<MouseMoveEvent&>(event));

View file

@ -3,7 +3,7 @@
#include <memory> #include <memory>
#include <vector> #include <vector>
#include <string> #include <string>
#include "Box.hpp" #include "Box.hpp"
#include "Events.hpp" #include "Events.hpp"
#include "Forward.hpp" #include "Forward.hpp"
#include "RGB.hpp" #include "RGB.hpp"
@ -12,6 +12,18 @@
namespace Raven { namespace Raven {
enum class WidgetType {
Widget = 0,
Button,
Label,
Control
};
enum class ControlWidgetType {
Widget = 0,
NewRow
};
class Widget { class Widget {
DEF_WIDGET_STYLE_PROP(do_background_fill, bool, false) DEF_WIDGET_STYLE_PROP(do_background_fill, bool, false)
@ -20,18 +32,28 @@ DEF_WIDGET_STYLE_PROP(background_border_radius, double, 0.0)
private: private:
Box m_current_geometry {}; Box m_current_geometry { 0, 0, 0, 0 };
std::vector<Widget*> m_children; std::vector<Widget*> m_children;
Widget *m_parent { nullptr }; Widget *m_parent { nullptr };
Window *m_window { nullptr }; Window *m_window { nullptr };
std::shared_ptr<TopLevelStyles> m_styles = nullptr; std::shared_ptr<TopLevelStyles> m_styles = nullptr;
Layout *m_layout { nullptr };
bool m_did_init { false }; bool m_did_init { false };
bool m_is_focused { false }; bool m_is_focused { false };
bool m_is_active { false }; bool m_is_active { false };
bool m_consumes_hits { false }; bool m_consumes_hits { false };
bool m_accepts_events { true };
ControlWidgetType m_control_type { ControlWidgetType::Widget };
public: public:
Widget() {} 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; } Box &get_current_geometry() { return m_current_geometry; }
void set_current_geometry(Box current_geometry) { m_current_geometry = current_geometry; wants_repaint(); } 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; } bool get_consumes_hits() { return m_consumes_hits; }
void set_consumes_hits(bool consumes_hits) { m_consumes_hits = 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 dispatch_event(Event &event);
void wants_repaint(); void wants_repaint();
void wants_full_repaint(); void wants_full_repaint();
void do_layout();
virtual ~Widget() {}; virtual ~Widget() {};
protected: protected:
WidgetType m_type { WidgetType::Widget };
virtual void on_init(); virtual void on_init();
virtual void on_mouse_button(MouseButtonEvent &event) {} virtual void on_mouse_button(MouseButtonEvent &event) {}
virtual void on_mouse_move(MouseMoveEvent &event) {} virtual void on_mouse_move(MouseMoveEvent &event) {}

View file

@ -4,19 +4,26 @@
#include "Button.hpp" #include "Button.hpp"
#include "Box.hpp" #include "Box.hpp"
#include "Label.hpp" #include "Label.hpp"
#include "Layout.hpp"
int main() { int main() {
Raven::Layout main_layout {};
Raven::Widget new_row { Raven::ControlWidgetType::NewRow };
Raven::Window window {}; Raven::Window window {};
Raven::Widget main_widget {}; Raven::Widget main_widget {};
Raven::Button button {"click meeeeeeeeeeee"}; Raven::Button button {"click meeeeeeeeeeee"};
Raven::Button impostor_button {"other button"};
Raven::Label label {"click it!"}; Raven::Label label {"click it!"};
int times_clicked = 0; int times_clicked = 0;
window.spawn_window(); window.spawn_window();
button.set_current_geometry(Raven::Box(10, 10, 100, 30)); button.set_current_geometry(Raven::Box(0, 0, 100, 30));
label.set_current_geometry(Raven::Box(10, 45, 100, 20)); 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); window.set_main_widget(&main_widget);
button.on_click = [&]() { button.on_click = [&]() {
@ -26,6 +33,8 @@ int main() {
main_widget.add_child(&button); main_widget.add_child(&button);
main_widget.add_child(&label); main_widget.add_child(&label);
main_widget.add_child(&new_row);
main_widget.add_child(&impostor_button);
window.run(true); window.run(true);