libui: Add basic widget and layout system =D
This commit is contained in:
parent
0a39628bb1
commit
d0c4264608
@ -1,4 +1,27 @@
|
||||
#include <ui/App.h>
|
||||
#include <ui/Layout.h>
|
||||
|
||||
struct ColorWidget : public ui::Widget
|
||||
{
|
||||
public:
|
||||
ColorWidget(ui::Color color) : m_color(color)
|
||||
{
|
||||
}
|
||||
|
||||
Result<ui::EventResult> handle_mousemove(ui::Point) override
|
||||
{
|
||||
return ui::EventResult::DidNotHandle;
|
||||
}
|
||||
|
||||
Result<void> draw(ui::Canvas& canvas) override
|
||||
{
|
||||
canvas.fill(m_color);
|
||||
return {};
|
||||
}
|
||||
|
||||
private:
|
||||
ui::Color m_color;
|
||||
};
|
||||
|
||||
Result<int> luna_main(int argc, char** argv)
|
||||
{
|
||||
@ -9,13 +32,25 @@ Result<int> luna_main(int argc, char** argv)
|
||||
app.set_main_window(window);
|
||||
|
||||
window->set_title("Main Window");
|
||||
window->canvas().fill(ui::CYAN);
|
||||
window->update();
|
||||
window->set_background(ui::CYAN);
|
||||
|
||||
auto* dialog = TRY(ui::Window::create(ui::Rect { 400, 400, 200, 150 }));
|
||||
dialog->set_title("Error: Unknown Error");
|
||||
dialog->canvas().fill(ui::RED);
|
||||
dialog->update();
|
||||
ui::HorizontalLayout layout;
|
||||
window->set_main_widget(layout);
|
||||
|
||||
ColorWidget green(ui::GREEN);
|
||||
layout.add_widget(green);
|
||||
ColorWidget blue(ui::BLUE);
|
||||
layout.add_widget(blue);
|
||||
|
||||
ui::HorizontalLayout sublayout;
|
||||
layout.add_widget(sublayout);
|
||||
|
||||
ColorWidget red(ui::RED);
|
||||
sublayout.add_widget(red);
|
||||
ColorWidget white(ui::WHITE);
|
||||
sublayout.add_widget(white);
|
||||
|
||||
window->draw();
|
||||
|
||||
return app.run();
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ set(SOURCES
|
||||
src/Image.cpp
|
||||
src/App.cpp
|
||||
src/Window.cpp
|
||||
src/Layout.cpp
|
||||
)
|
||||
|
||||
add_library(ui ${SOURCES})
|
||||
|
45
libui/include/ui/Layout.h
Normal file
45
libui/include/ui/Layout.h
Normal file
@ -0,0 +1,45 @@
|
||||
/**
|
||||
* @file Layout.h
|
||||
* @author apio (cloudapio.eu)
|
||||
* @brief Layout widgets to organize content.
|
||||
*
|
||||
* @copyright Copyright (c) 2023, the Luna authors.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <luna/Vector.h>
|
||||
#include <ui/Widget.h>
|
||||
|
||||
namespace ui
|
||||
{
|
||||
enum class AdjustHeight
|
||||
{
|
||||
No,
|
||||
Yes
|
||||
};
|
||||
|
||||
enum class AdjustWidth
|
||||
{
|
||||
No,
|
||||
Yes
|
||||
};
|
||||
|
||||
class HorizontalLayout final : public Widget
|
||||
{
|
||||
public:
|
||||
HorizontalLayout(AdjustHeight adjust_height = AdjustHeight::Yes, AdjustWidth adjust_width = AdjustWidth::Yes);
|
||||
|
||||
Result<EventResult> handle_mousemove(Point position) override;
|
||||
|
||||
Result<void> draw(Canvas& canvas) override;
|
||||
|
||||
Result<void> add_widget(Widget& widget);
|
||||
|
||||
private:
|
||||
Vector<Widget*> m_widgets;
|
||||
AdjustHeight m_adjust_height;
|
||||
AdjustWidth m_adjust_width;
|
||||
int m_used_width;
|
||||
};
|
||||
}
|
65
libui/include/ui/Widget.h
Normal file
65
libui/include/ui/Widget.h
Normal file
@ -0,0 +1,65 @@
|
||||
/**
|
||||
* @file Widget.h
|
||||
* @author apio (cloudapio.eu)
|
||||
* @brief Abstract widget class.
|
||||
*
|
||||
* @copyright Copyright (c) 2023, the Luna authors.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <luna/Result.h>
|
||||
#include <ui/Canvas.h>
|
||||
#include <ui/Point.h>
|
||||
#include <ui/Rect.h>
|
||||
|
||||
namespace ui
|
||||
{
|
||||
class Window;
|
||||
|
||||
enum class EventResult
|
||||
{
|
||||
DidHandle,
|
||||
DidNotHandle,
|
||||
};
|
||||
|
||||
class Widget
|
||||
{
|
||||
public:
|
||||
virtual Result<EventResult> handle_mousemove(Point position);
|
||||
|
||||
virtual Result<void> draw(Canvas& canvas);
|
||||
|
||||
void set_window(Window* window, Rect rect, Badge<Window>)
|
||||
{
|
||||
m_window = window;
|
||||
m_rect = rect;
|
||||
}
|
||||
|
||||
void set_parent(Widget* parent)
|
||||
{
|
||||
m_parent = parent;
|
||||
m_window = parent->m_window;
|
||||
}
|
||||
|
||||
Widget* parent()
|
||||
{
|
||||
return m_parent;
|
||||
}
|
||||
|
||||
Window* window()
|
||||
{
|
||||
return m_window;
|
||||
}
|
||||
|
||||
Rect& rect()
|
||||
{
|
||||
return m_rect;
|
||||
}
|
||||
|
||||
protected:
|
||||
Widget* m_parent { nullptr };
|
||||
Window* m_window;
|
||||
Rect m_rect { 0, 0, 50, 50 };
|
||||
};
|
||||
}
|
@ -12,6 +12,7 @@
|
||||
#include <luna/StringView.h>
|
||||
#include <ui/Canvas.h>
|
||||
#include <ui/Rect.h>
|
||||
#include <ui/Widget.h>
|
||||
|
||||
namespace ui
|
||||
{
|
||||
@ -22,6 +23,18 @@ namespace ui
|
||||
|
||||
void set_title(StringView title);
|
||||
|
||||
void set_background(Color color)
|
||||
{
|
||||
m_background = color;
|
||||
}
|
||||
|
||||
void set_main_widget(Widget& widget)
|
||||
{
|
||||
check(!m_main_widget);
|
||||
widget.set_window(this, m_canvas.rect(), {});
|
||||
m_main_widget = &widget;
|
||||
}
|
||||
|
||||
Canvas& canvas()
|
||||
{
|
||||
return m_canvas;
|
||||
@ -31,6 +44,9 @@ namespace ui
|
||||
|
||||
void close();
|
||||
|
||||
Result<void> draw();
|
||||
Result<void> handle_mousemove(ui::Point position);
|
||||
|
||||
int id() const
|
||||
{
|
||||
return m_id;
|
||||
@ -41,5 +57,7 @@ namespace ui
|
||||
private:
|
||||
int m_id;
|
||||
Canvas m_canvas;
|
||||
Widget* m_main_widget { nullptr };
|
||||
Color m_background { ui::BLACK };
|
||||
};
|
||||
}
|
||||
|
@ -95,7 +95,9 @@ namespace ui
|
||||
case MOUSE_EVENT_REQUEST_ID: {
|
||||
MouseEventRequest request;
|
||||
TRY(m_client->recv_typed(request));
|
||||
os::eprintln("ui: Mouse move to (%d, %d)", request.position.x, request.position.y);
|
||||
auto* window = find_window(request.window);
|
||||
window->handle_mousemove(request.position);
|
||||
window->draw();
|
||||
return {};
|
||||
}
|
||||
default: fail("Unexpected IPC request from server!");
|
||||
|
72
libui/src/Layout.cpp
Normal file
72
libui/src/Layout.cpp
Normal file
@ -0,0 +1,72 @@
|
||||
/**
|
||||
* @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(AdjustHeight adjust_height, AdjustWidth adjust_width)
|
||||
: m_adjust_height(adjust_height), m_adjust_width(adjust_width)
|
||||
{
|
||||
}
|
||||
|
||||
Result<EventResult> HorizontalLayout::handle_mousemove(Point position)
|
||||
{
|
||||
for (auto widget : m_widgets)
|
||||
{
|
||||
if (widget->rect().contains(position)) return widget->handle_mousemove(position);
|
||||
}
|
||||
|
||||
return ui::EventResult::DidNotHandle;
|
||||
}
|
||||
|
||||
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_used_width += widget.rect().width;
|
||||
}
|
||||
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;
|
||||
w->rect().width = result.quot;
|
||||
used_width += result.quot;
|
||||
}
|
||||
m_widgets[m_widgets.size() - 1]->rect().width += result.rem;
|
||||
}
|
||||
|
||||
widget.rect().pos.y = m_rect.pos.y;
|
||||
|
||||
if (m_adjust_height == AdjustHeight::Yes) { widget.rect().height = m_rect.height; }
|
||||
|
||||
widget.set_parent(this);
|
||||
|
||||
return {};
|
||||
}
|
||||
}
|
@ -91,4 +91,17 @@ namespace ui
|
||||
|
||||
app.unregister_window(this, {});
|
||||
}
|
||||
|
||||
Result<void> Window::draw()
|
||||
{
|
||||
if (m_main_widget) return m_main_widget->draw(m_canvas);
|
||||
update();
|
||||
return {};
|
||||
}
|
||||
|
||||
Result<void> Window::handle_mousemove(ui::Point position)
|
||||
{
|
||||
if (m_main_widget) TRY(m_main_widget->handle_mousemove(position));
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user