Files
Custom-Operating-System/libs/libui/src/StackView.cpp

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