silly boxlayout automatic sizing

This commit is contained in:
hippoz 2022-10-18 23:28:48 +03:00
parent 13047e73a7
commit f0acf9522d
Signed by: hippoz
GPG key ID: 7C52899193467641
16 changed files with 88 additions and 26 deletions

View file

@ -95,6 +95,14 @@ double Box::clamp_for_dimension(Direction direction, double value) {
} }
} }
void Box::set_dimension(Direction direction, double value) {
if (direction == Direction::Horizontal) {
set_width(value);
} else {
set_height(value);
}
}
Box Box::united(const Box &other) { Box Box::united(const Box &other) {
if (is_null()) { if (is_null()) {
return other; return other;
@ -112,7 +120,7 @@ Box Box::united(const Box &other) {
} }
bool Box::is_null() const { bool Box::is_null() const {
return !(m_x && m_y && m_width && m_height); return !(m_x || m_y || m_width || m_height);
} }
std::string Box::debug() { std::string Box::debug() {

View file

@ -70,6 +70,7 @@ public:
void set_bottom(double bottom) { set_height(bottom - y() + 1); } void set_bottom(double bottom) { set_height(bottom - y() + 1); }
void set_right(double right) { set_width(right - x() + 1); } void set_right(double right) { set_width(right - x() + 1); }
void set_left(double left) { set_x(left); } void set_left(double left) { set_x(left); }
void set_dimension(Direction direction, double value);
void set_max_width(double max_width) { m_max_width = max_width; set_width(m_width); } void set_max_width(double max_width) { m_max_width = max_width; set_width(m_width); }
void set_max_height(double max_height) { m_max_height = max_height; set_height(m_height); } void set_max_height(double max_height) { m_max_height = max_height; set_height(m_height); }

View file

@ -1,6 +1,7 @@
#include "BoxLayout.hpp" #include "BoxLayout.hpp"
#include "Box.hpp" #include "Box.hpp"
#include "Widget.hpp" #include "Widget.hpp"
#include "src/Events.hpp"
#include <cmath> #include <cmath>
#include <vector> #include <vector>
#include <algorithm> #include <algorithm>
@ -8,19 +9,32 @@
namespace Raven { namespace Raven {
void BoxLayout::run() { bool BoxLayout::run() {
if (!m_target) { if (!m_target) {
return; return false;
} }
double total_space = m_target->rect().dimension_at(m_direction) - 2 * m_margin; double total_space = m_target->rect().dimension_at(m_direction) - 2 * m_margin;
double free_space = total_space; double free_space = total_space;
double maximum_secondary_dimension = 0.0;
Direction secondary_direction = m_direction == Direction::Horizontal ? Direction::Vertical : Direction::Horizontal;
Point current_position { m_margin, m_margin }; Point current_position { m_margin, m_margin };
int unslotted_widgets = 0; int unslotted_widgets = 0;
std::vector<Slot> working_slots(m_slots); std::vector<Slot> working_slots(m_slots);
for (unsigned int i = 0; i < m_target->children().size(); i++) { for (unsigned int i = 0; i < m_target->children().size(); i++) {
auto child = m_target->children()[i]; auto child = m_target->children()[i];
if (child->layout() && child->layout()->dynamically_sizes_target()) {
auto event = RelayoutSubtreeEvent();
child->dispatch_event(event);
}
auto child_secondary_dimension = child->rect().dimension_at(secondary_direction);
if (child_secondary_dimension > maximum_secondary_dimension) {
maximum_secondary_dimension = child_secondary_dimension;
}
if (i >= working_slots.size()) { if (i >= working_slots.size()) {
// widgets which are outside the pre-defined slot range // widgets which are outside the pre-defined slot range
@ -49,6 +63,8 @@ void BoxLayout::run() {
} }
} }
maximum_secondary_dimension = m_target->rect().clamp_for_dimension(secondary_direction, maximum_secondary_dimension);
// compute all percentages for slots // compute all percentages for slots
for (unsigned int i = 0; i < m_target->children().size(); i++) { for (unsigned int i = 0; i < m_target->children().size(); i++) {
Slot *slot = &working_slots[i]; Slot *slot = &working_slots[i];
@ -85,14 +101,27 @@ void BoxLayout::run() {
child->rect().set_y(current_position.y()); child->rect().set_y(current_position.y());
if (m_direction == Direction::Horizontal) { if (m_direction == Direction::Horizontal) {
child->rect().set_width(slot.pixel); child->rect().set_width(slot.pixel);
child->rect().set_height(m_target->rect().max_geometry().height() - 2 * m_margin); child->rect().set_height(m_justify_secondary_dimension ? maximum_secondary_dimension - 2 * m_margin : m_target->rect().max_geometry().height() - 2 * m_margin);
current_position.add(slot.pixel + m_spacing, 0); current_position.add(slot.pixel + m_spacing, 0);
} else { } else {
child->rect().set_width(m_target->rect().max_geometry().width() - 2 * m_margin); child->rect().set_width(m_justify_secondary_dimension ? maximum_secondary_dimension - 2 * m_margin : m_target->rect().max_geometry().width() - 2 * m_margin);
child->rect().set_height(slot.pixel); child->rect().set_height(slot.pixel);
current_position.add(0, slot.pixel + m_spacing); current_position.add(0, slot.pixel + m_spacing);
} }
} }
if (m_justify_secondary_dimension) {
m_target->rect().set_dimension(secondary_direction, maximum_secondary_dimension);
}
for (unsigned int i = 0; i < m_target->children().size(); i++) {
auto child = m_target->children()[i];
auto event = RelayoutSubtreeEvent();
child->dispatch_event(event);
}
return true;
}; };
void BoxLayout::slot_percent(double percent) { void BoxLayout::slot_percent(double percent) {

View file

@ -26,7 +26,7 @@ public:
, m_direction(direction) {} , m_direction(direction) {}
~BoxLayout() {} ~BoxLayout() {}
void run(); bool run() override;
void slot_percent(double percent); void slot_percent(double percent);
void slot_pixel(double pixel); void slot_pixel(double pixel);
void slot_pixel(double pixel, double times); void slot_pixel(double pixel, double times);
@ -36,9 +36,15 @@ public:
void set_spacing(double spacing) { m_spacing = spacing; } void set_spacing(double spacing) { m_spacing = spacing; }
double &spacing() { return m_spacing; } double &spacing() { return m_spacing; }
bool justify_secondary_dimension() { return m_justify_secondary_dimension; }
void set_justify_secondary_dimension(bool justify_secondary_dimension) { m_justify_secondary_dimension = justify_secondary_dimension; }
bool dynamically_sizes_target() override { return m_justify_secondary_dimension; }
private: private:
double m_margin { 0.0 }; double m_margin { 0.0 };
double m_spacing { 0.0 }; double m_spacing { 0.0 };
bool m_justify_secondary_dimension { false };
std::vector<Slot> m_slots; std::vector<Slot> m_slots;
Direction m_direction { Direction::Horizontal }; Direction m_direction { Direction::Horizontal };
}; };

View file

@ -12,7 +12,7 @@ namespace Raven {
void Button::set_text(std::string text) { void Button::set_text(std::string text) {
m_text = text; m_text = text;
if (!fit_text(text)) { if (!fit_text(text, m_padding)) {
repaint(); repaint();
} }
} }
@ -25,7 +25,7 @@ void Button::on_init() {
} }
set_did_init(true); set_did_init(true);
if (!fit_text(m_text)) { if (!fit_text(m_text, m_padding)) {
reflow(); reflow();
} }
} }

View file

@ -23,12 +23,16 @@ public:
void set_text(std::string text); void set_text(std::string text);
std::string &text() { return m_text; } std::string &text() { return m_text; }
double padding() { return m_padding; }
void set_padding(double padding) { m_padding = padding; reflow(); }
protected: protected:
void on_paint(); void on_paint();
void on_init(); void on_init();
private: private:
std::string m_text; std::string m_text;
ButtonType m_button_type; ButtonType m_button_type;
double m_padding { 10 };
}; };
} }

View file

@ -4,9 +4,9 @@
namespace Raven { namespace Raven {
void ColumnLayout::run() { bool ColumnLayout::run() {
if (!m_target) { if (!m_target) {
return; return false;
} }
Point current_point { m_margin, m_margin }; Point current_point { m_margin, m_margin };
@ -33,6 +33,8 @@ void ColumnLayout::run() {
m_target->rect().set_height(requested_height + m_margin); m_target->rect().set_height(requested_height + m_margin);
m_target->rect().set_width(max_width_so_far + m_margin * 2); m_target->rect().set_width(max_width_so_far + m_margin * 2);
return false;
} }
} }

View file

@ -15,7 +15,7 @@ public:
: Layout() : Layout()
, m_margin(margin) {} , m_margin(margin) {}
void run(); bool run() override;
double margin() { return m_margin; } double margin() { return m_margin; }
void set_margin(double margin) { m_margin = margin; run(); } void set_margin(double margin) { m_margin = margin; run(); }

View file

@ -5,9 +5,9 @@
namespace Raven { namespace Raven {
void DocumentLayout::run() { bool DocumentLayout::run() {
if (!m_target) if (!m_target)
return; return false;
Point bound { m_margin + m_target->rect().max_geometry().width(), m_margin }; Point bound { m_margin + m_target->rect().max_geometry().width(), m_margin };
Point current_position { m_margin, m_margin }; Point current_position { m_margin, m_margin };
@ -44,6 +44,8 @@ void DocumentLayout::run() {
m_target->rect().set_width(bound.x()); m_target->rect().set_width(bound.x());
m_target->rect().set_height(bound.y()); m_target->rect().set_height(bound.y());
return false;
} }
} }

View file

@ -15,7 +15,7 @@ public:
: Layout() : Layout()
, m_margin(margin) {} , m_margin(margin) {}
void run(); bool run();
double margin() { return m_margin; } double margin() { return m_margin; }
void set_margin(double margin) { m_margin = margin; run(); } void set_margin(double margin) { m_margin = margin; run(); }

View file

@ -10,11 +10,13 @@ protected:
public: public:
Layout() {} Layout() {}
virtual void run() {}; virtual bool run() {return false;}
void bind_to(Widget *target) { m_target = target; } void bind_to(Widget *target) { m_target = target; }
Widget *target() { return m_target; } Widget *target() { return m_target; }
virtual bool dynamically_sizes_target() { return false; }
virtual ~Layout() {} virtual ~Layout() {}
}; };

View file

@ -4,9 +4,9 @@
namespace Raven { namespace Raven {
void RowLayout::run() { bool RowLayout::run() {
if (!m_target) { if (!m_target) {
return; return false;
} }
Point current_point { m_margin, m_margin }; Point current_point { m_margin, m_margin };
@ -33,6 +33,8 @@ void RowLayout::run() {
m_target->rect().set_width(requested_width + m_margin); m_target->rect().set_width(requested_width + m_margin);
m_target->rect().set_height(max_height_so_far + m_margin * 2); m_target->rect().set_height(max_height_so_far + m_margin * 2);
return false;
} }
} }

View file

@ -15,7 +15,7 @@ public:
: Layout() : Layout()
, m_margin(margin) {} , m_margin(margin) {}
void run(); bool run() override;
double margin() { return m_margin; } double margin() { return m_margin; }
void set_margin(double margin) { m_margin = margin; run(); } void set_margin(double margin) { m_margin = margin; run(); }

View file

@ -25,11 +25,12 @@ Point Widget::compute_window_relative() {
return point; return point;
} }
bool Widget::fit_text(std::string &text) { bool Widget::fit_text(std::string &text, double padding) {
if (!window()) if (!window())
return false; return false;
auto size = window()->painter().compute_text_size(rect(), text, style()->font_description()); auto size = window()->painter().compute_text_size(rect(), text, style()->font_description());
size.add(padding * 2, padding * 2);
return resize(size); return resize(size);
} }
@ -198,11 +199,11 @@ void Widget::handle_relayout_subtree(RelayoutSubtreeEvent &event) {
if (m_layout) { if (m_layout) {
m_layout->run(); m_layout->run();
} } else {
for (auto child : m_children) { for (auto child : m_children) {
child->dispatch_event(event); child->dispatch_event(event);
} }
}
on_after_layout(); on_after_layout();
} }
@ -221,10 +222,13 @@ void Widget::handle_mouse_move_event(MouseMoveEvent &event) {
if (m_is_focused && m_window) if (m_is_focused && m_window)
m_window->set_focused_widget(this); m_window->set_focused_widget(this);
std::cout << "update focus: " << update_focus_to << std::endl;
auto focus_update_event = FocusUpdateEvent(update_focus_to); auto focus_update_event = FocusUpdateEvent(update_focus_to);
on_focus_update(focus_update_event); on_focus_update(focus_update_event);
if (m_style->update_background()) { if (m_style->update_background()) {
std::cout << "should repaint because of focus change" << std::endl;
repaint(); repaint();
} }
} }

View file

@ -46,7 +46,7 @@ public:
std::function<void(Event&)> on_event { [](Event&){} }; std::function<void(Event&)> on_event { [](Event&){} };
std::function<void()> on_click { [](){} }; std::function<void()> on_click { [](){} };
bool fit_text(std::string &text); bool fit_text(std::string &text, double padding = 0);
void move_to(double x, double y); void move_to(double x, double y);
bool resize(double width, double height); bool resize(double width, double height);

View file

@ -43,9 +43,10 @@ int main() {
auto control_row = content->add<Raven::Widget>(); auto control_row = content->add<Raven::Widget>();
control_row->set_style(&Raven::raised_widget_style); control_row->set_style(&Raven::raised_widget_style);
control_row->rect().set_min_height(28.0); //control_row->rect().set_min_height(28.0);
auto control_row_layout = control_row->set_layout<Raven::BoxLayout>(Raven::Direction::Horizontal); auto control_row_layout = control_row->set_layout<Raven::BoxLayout>(Raven::Direction::Horizontal);
control_row_layout->set_spacing(6.0); control_row_layout->set_spacing(6.0);
control_row_layout->set_justify_secondary_dimension(true);
auto next_button = control_row->add<Raven::Button>("Next Item", Raven::Button::Accent); auto next_button = control_row->add<Raven::Button>("Next Item", Raven::Button::Accent);
next_button->set_grows(true); next_button->set_grows(true);
@ -58,9 +59,10 @@ int main() {
auto edit_row = content->add<Raven::Widget>(); auto edit_row = content->add<Raven::Widget>();
edit_row->set_style(&Raven::raised_widget_style); edit_row->set_style(&Raven::raised_widget_style);
edit_row->rect().set_min_height(28.0); //edit_row->rect().set_min_height(28.0);
auto edit_row_layout = edit_row->set_layout<Raven::BoxLayout>(Raven::Direction::Horizontal); auto edit_row_layout = edit_row->set_layout<Raven::BoxLayout>(Raven::Direction::Horizontal);
edit_row_layout->set_spacing(6.0); edit_row_layout->set_spacing(6.0);
edit_row_layout->set_justify_secondary_dimension(true);
auto edit_input = edit_row->add<Raven::TextInput>(); auto edit_input = edit_row->add<Raven::TextInput>();
edit_input->set_style(&Raven::raised_textinput_style); edit_input->set_style(&Raven::raised_textinput_style);