237 lines
6.9 KiB
C++
237 lines
6.9 KiB
C++
/**
|
|
* @file Layout.cpp
|
|
* @author apio (cloudapio.eu)
|
|
* @brief Layout widgets to organize content.
|
|
*
|
|
* @copyright Copyright (c) 2023, the Luna authors.
|
|
*
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <ui/Layout.h>
|
|
|
|
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<EventResult> 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<EventResult> 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<EventResult> 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<EventResult> 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<EventResult> 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<void> 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<void> 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<EventResult> 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<EventResult> 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<EventResult> 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<EventResult> 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<EventResult> 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<void> 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<void> 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 {};
|
|
}
|
|
}
|