#include #include #include #include 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