silly boxlayout automatic sizing
This commit is contained in:
parent
13047e73a7
commit
f0acf9522d
16 changed files with 88 additions and 26 deletions
10
src/Box.cpp
10
src/Box.cpp
|
@ -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() {
|
||||
|
|
|
@ -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); }
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 };
|
||||
};
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 };
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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(); }
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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(); }
|
||||
|
|
|
@ -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() {}
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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(); }
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue