158 lines
4.6 KiB
C++
158 lines
4.6 KiB
C++
#include <libfoundation/EventLoop.h>
|
|
#include <libg/Color.h>
|
|
#include <libui/Context.h>
|
|
#include <libui/StackView.h>
|
|
|
|
namespace UI {
|
|
|
|
StackView::StackView(View* superview, const LG::Rect& frame)
|
|
: View(superview, frame)
|
|
{
|
|
}
|
|
|
|
StackView::StackView(View* superview, Window* window, const LG::Rect& frame)
|
|
: View(superview, window, frame)
|
|
{
|
|
}
|
|
|
|
bool StackView::receive_layout_event(const LayoutEvent& event, bool force_layout_if_not_target)
|
|
{
|
|
// StackView uses receive_layout_event to recalculate positions of
|
|
// subviews.
|
|
bool res = View::receive_layout_event(event, force_layout_if_not_target);
|
|
if (this == event.target() || force_layout_if_not_target) {
|
|
recalc_subviews_positions();
|
|
}
|
|
return res;
|
|
}
|
|
|
|
size_t StackView::recalc_subview_min_x(View* view)
|
|
{
|
|
size_t width = bounds().width();
|
|
switch (alignment()) {
|
|
case Alignment::Leading:
|
|
return 0;
|
|
case Alignment::Center:
|
|
return (width - view->bounds().width()) / 2;
|
|
case Alignment::Trailing:
|
|
return width - view->bounds().width();
|
|
default:
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
size_t StackView::recalc_subview_min_y(View* view)
|
|
{
|
|
size_t height = bounds().height();
|
|
switch (alignment()) {
|
|
case Alignment::Leading:
|
|
return 0;
|
|
case Alignment::Center:
|
|
return (height - view->bounds().height()) / 2;
|
|
case Alignment::Trailing:
|
|
return height - view->bounds().height();
|
|
default:
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void StackView::recalc_fill_equally()
|
|
{
|
|
// TODO: May be to reinterpret contstraints here?
|
|
size_t total_spacing = spacing() * (m_views.size() - 1);
|
|
if (axis() == LayoutConstraints::Axis::Horizontal) {
|
|
size_t width = (bounds().width() - total_spacing) / m_views.size();
|
|
for (int i = 0; i < m_views.size(); i++) {
|
|
constraint_interpreter(Constraint(*m_views[i], Constraint::Attribute::Width, Constraint::Relation::Equal, width));
|
|
}
|
|
} else {
|
|
size_t height = (bounds().height() - total_spacing) / m_views.size();
|
|
for (int i = 0; i < m_views.size(); i++) {
|
|
constraint_interpreter(Constraint(*m_views[i], Constraint::Attribute::Height, Constraint::Relation::Equal, height));
|
|
}
|
|
}
|
|
}
|
|
|
|
size_t StackView::recalc_total_content_width()
|
|
{
|
|
size_t res = 0;
|
|
for (int i = 0; i < m_views.size(); i++) {
|
|
res += m_views[i]->frame().width();
|
|
}
|
|
return res;
|
|
}
|
|
|
|
size_t StackView::recalc_total_content_height()
|
|
{
|
|
size_t res = 0;
|
|
for (int i = 0; i < m_views.size(); i++) {
|
|
res += m_views[i]->frame().height();
|
|
}
|
|
return res;
|
|
}
|
|
|
|
size_t StackView::recalc_initial_spacing(size_t element_spacing)
|
|
{
|
|
size_t total_spacing = element_spacing * (m_views.size() - 1);
|
|
|
|
switch (distribution()) {
|
|
case Distribution::EqualCentering:
|
|
if (axis() == LayoutConstraints::Axis::Horizontal) {
|
|
int content_width = recalc_total_content_width() + total_spacing;
|
|
return (bounds().width() - content_width) / 2;
|
|
} else {
|
|
int content_height = recalc_total_content_height() + total_spacing;
|
|
return (bounds().height() - content_height) / 2;
|
|
}
|
|
default:
|
|
return 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
size_t StackView::recalc_spacing()
|
|
{
|
|
switch (distribution()) {
|
|
case Distribution::Standard:
|
|
case Distribution::EqualCentering:
|
|
return spacing();
|
|
case Distribution::EqualSpacing:
|
|
if (axis() == LayoutConstraints::Axis::Horizontal) {
|
|
return recalc_equal_spacing_horizontal();
|
|
} else {
|
|
return recalc_equal_spacing_vertical();
|
|
}
|
|
case Distribution::FillEqually:
|
|
recalc_fill_equally();
|
|
return spacing();
|
|
default:
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// recalc_subviews_positions recalculates the posistion of all subviews.
|
|
// You have to call set_needs_layout instread of direct call to recalc_subviews_positions.
|
|
void StackView::recalc_subviews_positions()
|
|
{
|
|
size_t spacing = recalc_spacing();
|
|
size_t initial_spacing = recalc_initial_spacing(spacing);
|
|
size_t primary_coord = initial_spacing;
|
|
if (axis() == LayoutConstraints::Axis::Horizontal) {
|
|
for (int i = 0; i < m_views.size(); i++) {
|
|
m_views[i]->frame().set_y(recalc_subview_min_y(m_views[i]));
|
|
m_views[i]->frame().set_x(primary_coord);
|
|
primary_coord += m_views[i]->frame().width() + spacing;
|
|
}
|
|
} else {
|
|
for (int i = 0; i < m_views.size(); i++) {
|
|
m_views[i]->frame().set_x(recalc_subview_min_x(m_views[i]));
|
|
m_views[i]->frame().set_y(primary_coord);
|
|
primary_coord += m_views[i]->frame().height() + spacing;
|
|
}
|
|
}
|
|
}
|
|
|
|
} // namespace UI
|