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) {
|
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() {
|
||||||
|
|
|
@ -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); }
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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 };
|
||||||
};
|
};
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 };
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(); }
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(); }
|
||||||
|
|
|
@ -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() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(); }
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue