diff --git a/apps/taskbar.cpp b/apps/taskbar.cpp index f6e7ba38..975df284 100644 --- a/apps/taskbar.cpp +++ b/apps/taskbar.cpp @@ -1,4 +1,6 @@ #include +#include +#include #include Result luna_main(int argc, char** argv) @@ -17,6 +19,12 @@ Result luna_main(int argc, char** argv) ui::HorizontalLayout layout(ui::AdjustHeight::Yes, ui::AdjustWidth::No); window->set_main_widget(layout); + ui::Container container({ 0, 0, 50, 50 }, ui::VerticalAlignment::Center, ui::HorizontalAlignment::Center); + layout.add_widget(container); + + auto image = TRY(ui::ImageWidget::load("/usr/share/icons/32x32/start-icon.tga")); + container.set_widget(*image); + window->draw(); return app.run(); diff --git a/libui/CMakeLists.txt b/libui/CMakeLists.txt index ad9cb181..9885e476 100644 --- a/libui/CMakeLists.txt +++ b/libui/CMakeLists.txt @@ -13,6 +13,8 @@ set(SOURCES src/App.cpp src/Window.cpp src/Layout.cpp + src/Alignment.cpp + src/Container.cpp ) add_library(ui ${SOURCES}) diff --git a/libui/include/ui/Alignment.h b/libui/include/ui/Alignment.h new file mode 100644 index 00000000..660eb605 --- /dev/null +++ b/libui/include/ui/Alignment.h @@ -0,0 +1,30 @@ +/** + * @file Alignment.h + * @author apio (cloudapio.eu) + * @brief UI component alignment. + * + * @copyright Copyright (c) 2023, the Luna authors. + * + */ + +#pragma once +#include + +namespace ui +{ + enum class VerticalAlignment + { + Top, + Center, + Bottom + }; + + enum class HorizontalAlignment + { + Left, + Center, + Right + }; + + Rect align(Rect container, Rect contained, VerticalAlignment valign, HorizontalAlignment halign); +} diff --git a/libui/include/ui/Container.h b/libui/include/ui/Container.h new file mode 100644 index 00000000..6a4e565c --- /dev/null +++ b/libui/include/ui/Container.h @@ -0,0 +1,31 @@ +/** + * @file Container.h + * @author apio (cloudapio.eu) + * @brief A container widget to pad and align objects inside it. + * + * @copyright Copyright (c) 2023, the Luna authors. + * + */ + +#pragma once +#include +#include + +namespace ui +{ + class Container : public Widget + { + public: + Container(Rect rect, VerticalAlignment valign, HorizontalAlignment halign); + + void set_widget(Widget& widget); + + Result handle_mousemove(Point position) override; + Result draw(Canvas& canvas) override; + + private: + Widget* m_widget; + VerticalAlignment m_valign; + HorizontalAlignment m_halign; + }; +} diff --git a/libui/include/ui/Image.h b/libui/include/ui/Image.h index bebffa84..6ad0bd13 100644 --- a/libui/include/ui/Image.h +++ b/libui/include/ui/Image.h @@ -11,6 +11,7 @@ #include #include #include +#include namespace ui { @@ -77,4 +78,16 @@ namespace ui TGAHeader m_tga_header; Buffer m_image_data; }; + + class ImageWidget final : public Widget + { + public: + static Result> load(const os::Path& path); + + Result handle_mousemove(Point position) override; + Result draw(Canvas& canvas) override; + + private: + SharedPtr m_image; + }; } diff --git a/libui/src/Alignment.cpp b/libui/src/Alignment.cpp new file mode 100644 index 00000000..87292fdc --- /dev/null +++ b/libui/src/Alignment.cpp @@ -0,0 +1,40 @@ +/** + * @file Alignment.cpp + * @author apio (cloudapio.eu) + * @brief UI component alignment. + * + * @copyright Copyright (c) 2023, the Luna authors. + * + */ + +#include + +namespace ui +{ + Rect align(Rect container, Rect contained, VerticalAlignment valign, HorizontalAlignment halign) + { + Rect result; + result.width = contained.width; + result.height = contained.height; + result.pos.y = container.pos.y; + result.pos.x = container.pos.x; + + switch (valign) + { + case VerticalAlignment::Top: break; + case VerticalAlignment::Center: result.pos.y += (container.height - contained.height) / 2; break; + case VerticalAlignment::Bottom: result.pos.y += container.height - contained.height; break; + default: break; + } + + switch (halign) + { + case HorizontalAlignment::Left: break; + case HorizontalAlignment::Center: result.pos.x += (container.width - contained.width) / 2; break; + case HorizontalAlignment::Right: result.pos.x += container.width - contained.width; break; + default: break; + } + + return result; + } +} diff --git a/libui/src/Container.cpp b/libui/src/Container.cpp new file mode 100644 index 00000000..f6fe7abd --- /dev/null +++ b/libui/src/Container.cpp @@ -0,0 +1,39 @@ +/** + * @file Container.cpp + * @author apio (cloudapio.eu) + * @brief A container widget to pad and align objects inside it. + * + * @copyright Copyright (c) 2023, the Luna authors. + * + */ + +#include + +namespace ui +{ + Container::Container(Rect rect, VerticalAlignment valign, HorizontalAlignment halign) + : m_valign(valign), m_halign(halign) + { + m_rect = rect; + } + + void Container::set_widget(Widget& widget) + { + m_widget = &widget; + widget.rect() = ui::align(m_rect, widget.rect(), m_valign, m_halign); + } + + Result Container::handle_mousemove(Point position) + { + return m_widget->handle_mousemove(position); + } + + Result Container::draw(Canvas& canvas) + { + auto rect = ui::Rect { m_widget->rect().pos.x - m_rect.pos.x, m_widget->rect().pos.y - m_rect.pos.y, + m_widget->rect().width, m_widget->rect().height }; + auto subcanvas = canvas.subcanvas(rect); + return m_widget->draw(subcanvas); + } + +} diff --git a/libui/src/Image.cpp b/libui/src/Image.cpp index 4a284736..e8f9b6ba 100644 --- a/libui/src/Image.cpp +++ b/libui/src/Image.cpp @@ -8,6 +8,7 @@ */ #include +#include #include namespace ui @@ -30,4 +31,23 @@ namespace ui return image; } + + Result> ImageWidget::load(const os::Path& path) + { + auto widget = TRY(make_owned()); + widget->m_image = TRY(Image::load(path)); + widget->m_rect = { 0, 0, widget->m_image->width(), widget->m_image->height() }; + return widget; + } + + Result ImageWidget::handle_mousemove(Point) + { + return EventResult::DidNotHandle; + } + + Result ImageWidget::draw(Canvas& canvas) + { + canvas.subcanvas({ 0, 0, m_image->width(), m_image->height() }).fill(m_image->pixels(), m_image->width()); + return {}; + } }