opuntiaOS - an operating system targeting x86 and ARMv7
at master 5.0 kB view raw
1/* 2 * Copyright (C) 2020-2022 The opuntiaOS Project Authors. 3 * + Contributed by Nikita Melekhin <nimelehin@gmail.com> 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 9#include <libfoundation/EventLoop.h> 10#include <libg/Color.h> 11#include <libui/Context.h> 12#include <libui/StackView.h> 13 14namespace UI { 15 16StackView::StackView(View* superview, const LG::Rect& frame) 17 : View(superview, frame) 18{ 19} 20 21StackView::StackView(View* superview, Window* window, const LG::Rect& frame) 22 : View(superview, window, frame) 23{ 24} 25 26bool StackView::receive_layout_event(const LayoutEvent& event, bool force_layout_if_not_target) 27{ 28 // StackView uses receive_layout_event to recalculate positions of 29 // subviews. 30 bool res = View::receive_layout_event(event, force_layout_if_not_target); 31 if (this == event.target() || force_layout_if_not_target) { 32 recalc_subviews_positions(); 33 } 34 return res; 35} 36 37size_t StackView::recalc_subview_min_x(View* view) 38{ 39 size_t width = bounds().width(); 40 switch (alignment()) { 41 case Alignment::Leading: 42 return 0; 43 case Alignment::Center: 44 return (width - view->bounds().width()) / 2; 45 case Alignment::Trailing: 46 return width - view->bounds().width(); 47 default: 48 break; 49 } 50 return 0; 51} 52 53size_t StackView::recalc_subview_min_y(View* view) 54{ 55 size_t height = bounds().height(); 56 switch (alignment()) { 57 case Alignment::Leading: 58 return 0; 59 case Alignment::Center: 60 return (height - view->bounds().height()) / 2; 61 case Alignment::Trailing: 62 return height - view->bounds().height(); 63 default: 64 break; 65 } 66 return 0; 67} 68 69void StackView::recalc_fill_equally() 70{ 71 // TODO: May be to reinterpret contstraints here? 72 size_t total_spacing = spacing() * (m_views.size() - 1); 73 if (axis() == LayoutConstraints::Axis::Horizontal) { 74 size_t width = (bounds().width() - total_spacing) / m_views.size(); 75 for (int i = 0; i < m_views.size(); i++) { 76 constraint_interpreter(Constraint(*m_views[i], Constraint::Attribute::Width, Constraint::Relation::Equal, width)); 77 } 78 } else { 79 size_t height = (bounds().height() - total_spacing) / m_views.size(); 80 for (int i = 0; i < m_views.size(); i++) { 81 constraint_interpreter(Constraint(*m_views[i], Constraint::Attribute::Height, Constraint::Relation::Equal, height)); 82 } 83 } 84} 85 86size_t StackView::recalc_total_content_width() 87{ 88 size_t res = 0; 89 for (int i = 0; i < m_views.size(); i++) { 90 res += m_views[i]->frame().width(); 91 } 92 return res; 93} 94 95size_t StackView::recalc_total_content_height() 96{ 97 size_t res = 0; 98 for (int i = 0; i < m_views.size(); i++) { 99 res += m_views[i]->frame().height(); 100 } 101 return res; 102} 103 104size_t StackView::recalc_initial_spacing(size_t element_spacing) 105{ 106 size_t total_spacing = element_spacing * (m_views.size() - 1); 107 108 switch (distribution()) { 109 case Distribution::EqualCentering: 110 if (axis() == LayoutConstraints::Axis::Horizontal) { 111 int content_width = recalc_total_content_width() + total_spacing; 112 return (bounds().width() - content_width) / 2; 113 } else { 114 int content_height = recalc_total_content_height() + total_spacing; 115 return (bounds().height() - content_height) / 2; 116 } 117 default: 118 return 0; 119 } 120 return 0; 121} 122 123size_t StackView::recalc_spacing() 124{ 125 switch (distribution()) { 126 case Distribution::Standard: 127 case Distribution::EqualCentering: 128 return spacing(); 129 case Distribution::EqualSpacing: 130 if (axis() == LayoutConstraints::Axis::Horizontal) { 131 return recalc_equal_spacing_horizontal(); 132 } else { 133 return recalc_equal_spacing_vertical(); 134 } 135 case Distribution::FillEqually: 136 recalc_fill_equally(); 137 return spacing(); 138 default: 139 break; 140 } 141 return 0; 142} 143 144// recalc_subviews_positions recalculates the posistion of all subviews. 145// You have to call set_needs_layout instread of direct call to recalc_subviews_positions. 146void StackView::recalc_subviews_positions() 147{ 148 size_t spacing = recalc_spacing(); 149 size_t initial_spacing = recalc_initial_spacing(spacing); 150 size_t primary_coord = initial_spacing; 151 if (axis() == LayoutConstraints::Axis::Horizontal) { 152 for (int i = 0; i < m_views.size(); i++) { 153 m_views[i]->frame().set_y(recalc_subview_min_y(m_views[i])); 154 m_views[i]->frame().set_x(primary_coord); 155 primary_coord += m_views[i]->frame().width() + spacing; 156 } 157 } else { 158 for (int i = 0; i < m_views.size(); i++) { 159 m_views[i]->frame().set_x(recalc_subview_min_x(m_views[i])); 160 m_views[i]->frame().set_y(primary_coord); 161 primary_coord += m_views[i]->frame().height() + spacing; 162 } 163 } 164} 165 166} // namespace UI