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) {
if (is_null()) {
return other;
@ -112,7 +120,7 @@ Box Box::united(const Box &other) {
}
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() {

View file

@ -70,6 +70,7 @@ public:
void set_bottom(double bottom) { set_height(bottom - y() + 1); }
void set_right(double right) { set_width(right - x() + 1); }
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_height(double max_height) { m_max_height = max_height; set_height(m_height); }

View file

@ -1,6 +1,7 @@
#include "BoxLayout.hpp"
#include "Box.hpp"
#include "Widget.hpp"
#include "src/Events.hpp"
#include <cmath>
#include <vector>
#include <algorithm>
@ -8,19 +9,32 @@
namespace Raven {
void BoxLayout::run() {
bool BoxLayout::run() {
if (!m_target) {
return;
return false;
}
double total_space = m_target->rect().dimension_at(m_direction) - 2 * m_margin;
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 };
int unslotted_widgets = 0;
std::vector<Slot> working_slots(m_slots);
for (unsigned int i = 0; i < m_target->children().size(); 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()) {
// 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
for (unsigned int i = 0; i < m_target->children().size(); i++) {
Slot *slot = &working_slots[i];
@ -85,14 +101,27 @@ void BoxLayout::run() {
child->rect().set_y(current_position.y());
if (m_direction == Direction::Horizontal) {
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);
} 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);
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) {

View file

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

View file

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

View file

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

View file

@ -4,9 +4,9 @@
namespace Raven {
void ColumnLayout::run() {
bool ColumnLayout::run() {
if (!m_target) {
return;
return false;
}
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_width(max_width_so_far + m_margin * 2);
return false;
}
}

View file

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

View file

@ -5,9 +5,9 @@
namespace Raven {
void DocumentLayout::run() {
bool DocumentLayout::run() {
if (!m_target)
return;
return false;
Point bound { m_margin + m_target->rect().max_geometry().width(), 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_height(bound.y());
return false;
}
}

View file

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

View file

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

View file

@ -4,9 +4,9 @@
namespace Raven {
void RowLayout::run() {
bool RowLayout::run() {
if (!m_target) {
return;
return false;
}
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_height(max_height_so_far + m_margin * 2);
return false;
}
}

View file

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

View file

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

View file

@ -46,7 +46,7 @@ public:
std::function<void(Event&)> on_event { [](Event&){} };
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);
bool resize(double width, double height);

View file

@ -43,9 +43,10 @@ int main() {
auto control_row = content->add<Raven::Widget>();
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);
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);
next_button->set_grows(true);
@ -58,9 +59,10 @@ int main() {
auto edit_row = content->add<Raven::Widget>();
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);
edit_row_layout->set_spacing(6.0);
edit_row_layout->set_justify_secondary_dimension(true);
auto edit_input = edit_row->add<Raven::TextInput>();
edit_input->set_style(&Raven::raised_textinput_style);