/** * @file Layout.cpp * @author apio (cloudapio.eu) * @brief Layout widgets to organize content. * * @copyright Copyright (c) 2023, the Luna authors. * */ #include #include namespace ui { HorizontalLayout::HorizontalLayout(Margins margins, AdjustHeight adjust_height, AdjustWidth adjust_width) : m_margins(margins), m_adjust_height(adjust_height), m_adjust_width(adjust_width) { } Result HorizontalLayout::handle_mouse_move(Point position) { EventResult result = ui::EventResult::DidNotHandle; for (auto widget : m_widgets) { if (widget->rect().contains(position)) result = TRY(widget->handle_mouse_move(position)); else TRY(widget->handle_mouse_leave()); } return result; } Result HorizontalLayout::handle_mouse_leave() { EventResult result = ui::EventResult::DidNotHandle; for (auto widget : m_widgets) { auto rc = TRY(widget->handle_mouse_leave()); if (rc == ui::EventResult::DidHandle) result = rc; } return result; } Result HorizontalLayout::handle_mouse_up(Point position, int buttons) { for (auto widget : m_widgets) { if (widget->rect().contains(position)) return widget->handle_mouse_up(position, buttons); } return ui::EventResult::DidNotHandle; } Result HorizontalLayout::handle_mouse_down(Point position, int buttons) { for (auto widget : m_widgets) { if (widget->rect().contains(position)) return widget->handle_mouse_down(position, buttons); } return ui::EventResult::DidNotHandle; } Result HorizontalLayout::handle_key_event(const ui::KeyEventRequest& request) { EventResult result = ui::EventResult::DidNotHandle; for (auto widget : m_widgets) { auto rc = TRY(widget->handle_key_event(request)); if (rc == ui::EventResult::DidHandle) result = rc; } return result; } Result HorizontalLayout::draw(Canvas& canvas) { for (auto widget : m_widgets) { ui::Rect rect = { m_rect.relative(widget->rect().pos), widget->rect().width, widget->rect().height }; auto subcanvas = canvas.subcanvas(rect); TRY(widget->draw(subcanvas)); } return {}; } Result HorizontalLayout::add_widget(Widget& widget) { TRY(m_widgets.try_append(&widget)); if (m_adjust_width == AdjustWidth::No) { widget.rect().pos.x = m_rect.pos.x + m_used_width + m_margins.left; m_used_width += m_margins.left + widget.rect().width + m_margins.right; } else { int used_width = 0; div_t result = div(m_rect.width, (int)m_widgets.size()); for (auto w : m_widgets) { w->rect().pos.x = m_rect.pos.x + used_width + m_margins.left; w->rect().width = result.quot - (m_margins.left + m_margins.right); used_width += result.quot; } m_widgets[m_widgets.size() - 1]->rect().width += result.rem; } widget.rect().pos.y = m_rect.pos.y + m_margins.top; if (m_adjust_height == AdjustHeight::Yes) { widget.rect().height = m_rect.height - (m_margins.top + m_margins.bottom); } widget.set_parent(this); return {}; } VerticalLayout::VerticalLayout(Margins margins, AdjustHeight adjust_height, AdjustWidth adjust_width) : m_margins(margins), m_adjust_height(adjust_height), m_adjust_width(adjust_width) { } Result VerticalLayout::handle_mouse_move(Point position) { EventResult result = ui::EventResult::DidNotHandle; for (auto widget : m_widgets) { if (widget->rect().contains(position)) result = TRY(widget->handle_mouse_move(position)); else TRY(widget->handle_mouse_leave()); } return result; } Result VerticalLayout::handle_mouse_leave() { EventResult result = ui::EventResult::DidNotHandle; for (auto widget : m_widgets) { auto rc = TRY(widget->handle_mouse_leave()); if (rc == ui::EventResult::DidHandle) result = rc; } return result; } Result VerticalLayout::handle_mouse_up(Point position, int buttons) { for (auto widget : m_widgets) { if (widget->rect().contains(position)) return widget->handle_mouse_up(position, buttons); } return ui::EventResult::DidNotHandle; } Result VerticalLayout::handle_mouse_down(Point position, int buttons) { for (auto widget : m_widgets) { if (widget->rect().contains(position)) return widget->handle_mouse_down(position, buttons); } return ui::EventResult::DidNotHandle; } Result VerticalLayout::handle_key_event(const ui::KeyEventRequest& request) { EventResult result = ui::EventResult::DidNotHandle; for (auto widget : m_widgets) { auto rc = TRY(widget->handle_key_event(request)); if (rc == ui::EventResult::DidHandle) result = rc; } return result; } Result VerticalLayout::draw(Canvas& canvas) { for (auto widget : m_widgets) { ui::Rect rect = { m_rect.relative(widget->rect().pos), widget->rect().width, widget->rect().height }; auto subcanvas = canvas.subcanvas(rect); TRY(widget->draw(subcanvas)); } return {}; } Result VerticalLayout::add_widget(Widget& widget) { TRY(m_widgets.try_append(&widget)); if (m_adjust_height == AdjustHeight::No) { widget.rect().pos.y = m_rect.pos.y + m_used_height + m_margins.top; m_used_height += m_margins.top + widget.rect().height + m_margins.bottom; } else { int used_height = 0; div_t result = div(m_rect.height, (int)m_widgets.size()); for (auto w : m_widgets) { w->rect().pos.y = m_rect.pos.y + used_height + m_margins.top; w->rect().height = result.quot - (m_margins.top + m_margins.bottom); used_height += result.quot; } m_widgets[m_widgets.size() - 1]->rect().height += result.rem; } widget.rect().pos.x = m_rect.pos.x + m_margins.left; if (m_adjust_width == AdjustWidth::Yes) { widget.rect().width = m_rect.width - (m_margins.left + m_margins.right); } widget.set_parent(this); return {}; } }