apps+editor+libui+terminal: Rework the layout system
Some checks failed
Build and test / build (push) Failing after 1m49s
Some checks failed
Build and test / build (push) Failing after 1m49s
This commit is contained in:
parent
907049c405
commit
280b0c90af
@ -23,6 +23,16 @@ struct Tile
|
||||
class GameWidget final : public ui::Widget
|
||||
{
|
||||
public:
|
||||
GameWidget(ui::Window* window, ui::Widget* parent) : ui::Widget(window, parent)
|
||||
{
|
||||
}
|
||||
|
||||
void show_tree(int indent) override
|
||||
{
|
||||
os::println("%*s- 2048 GameWidget (%d,%d,%d,%d)", indent, "", m_rect.pos.x, m_rect.pos.y, m_rect.width,
|
||||
m_rect.height);
|
||||
}
|
||||
|
||||
static constexpr int MARGIN = 5;
|
||||
|
||||
Result<void> draw(ui::Canvas& canvas) override
|
||||
@ -356,9 +366,8 @@ Result<int> luna_main(int, char**)
|
||||
window->set_background(ui::BLACK);
|
||||
window->set_title("2048");
|
||||
|
||||
GameWidget game;
|
||||
window->set_main_widget(game);
|
||||
game.reset();
|
||||
auto* game = TRY(window->create_main_widget<GameWidget>());
|
||||
game->reset();
|
||||
|
||||
return app.run();
|
||||
}
|
||||
|
@ -21,27 +21,26 @@ Result<int> luna_main(int, char**)
|
||||
utsname info;
|
||||
uname(&info);
|
||||
|
||||
ui::VerticalLayout main_layout;
|
||||
window->set_main_widget(main_layout);
|
||||
auto* main_layout = TRY(window->create_main_widget<ui::VerticalLayout>());
|
||||
main_layout->set_layout_settings(ui::Margins { 0, 0, 20, 40 });
|
||||
|
||||
ui::Label title("About Luna");
|
||||
title.set_font(ui::Font::default_bold_font());
|
||||
auto* title = TRY(main_layout->add_child_widget<ui::Label>());
|
||||
title->set_text("About Luna");
|
||||
title->set_font(ui::Font::default_bold_font());
|
||||
|
||||
main_layout.add_widget(title);
|
||||
|
||||
ui::VerticalLayout version_info;
|
||||
main_layout.add_widget(version_info);
|
||||
|
||||
ui::Label license("Licensed under the BSD-2-Clause license.");
|
||||
main_layout.add_widget(license);
|
||||
auto* version_info = TRY(main_layout->add_child_widget<ui::VerticalLayout>());
|
||||
version_info->set_layout_settings(ui::Margins { 0, 0, 10, 10 });
|
||||
|
||||
auto* os_release = TRY(version_info->add_child_widget<ui::Label>());
|
||||
String os_release_text = TRY(String::format("OS release: %s"_sv, info.release));
|
||||
ui::Label os_release(os_release_text.view());
|
||||
version_info.add_widget(os_release);
|
||||
os_release->set_text(os_release_text.view());
|
||||
|
||||
auto* kernel_version = TRY(version_info->add_child_widget<ui::Label>());
|
||||
String kernel_version_text = TRY(String::format("Kernel version: %s"_sv, info.version));
|
||||
ui::Label kernel_version(kernel_version_text.view());
|
||||
version_info.add_widget(kernel_version);
|
||||
kernel_version->set_text(kernel_version_text.view());
|
||||
|
||||
auto* license = TRY(version_info->add_child_widget<ui::Label>());
|
||||
license->set_text("Licensed under the BSD-2-Clause license.");
|
||||
|
||||
return app.run();
|
||||
}
|
||||
|
@ -29,12 +29,12 @@ Result<int> luna_main(int, char**)
|
||||
window->set_title("Clock");
|
||||
window->set_background(ui::GRAY);
|
||||
|
||||
g_label = TRY(make<ui::Label>("00:00:00"));
|
||||
g_label = TRY(window->create_main_widget<ui::Label>());
|
||||
|
||||
g_label->set_text("00:00:00");
|
||||
g_label->set_font(ui::Font::default_bold_font());
|
||||
g_label->set_color(ui::BLACK);
|
||||
|
||||
window->set_main_widget(*g_label);
|
||||
|
||||
update_time();
|
||||
|
||||
auto timer = TRY(os::Timer::create_repeating(1000, update_time));
|
||||
|
@ -30,24 +30,19 @@ void sighup_handler(int)
|
||||
os::Process::exec(args[0], { args, 1 });
|
||||
}
|
||||
|
||||
Result<void> create_widget_group_for_app(ui::HorizontalLayout& layout, StringView path, StringView icon)
|
||||
Result<void> create_widget_group_for_app(ui::HorizontalLayout* layout, StringView path, StringView icon)
|
||||
{
|
||||
auto* button = TRY(make<ui::Button>(ui::Rect { 0, 0, 50, 50 }));
|
||||
layout.add_widget(*button);
|
||||
auto* button = TRY(layout->add_child_widget<ui::Button>());
|
||||
|
||||
auto* container = TRY(
|
||||
make<ui::Container>(ui::Rect { 0, 0, 50, 50 }, ui::VerticalAlignment::Center, ui::HorizontalAlignment::Center));
|
||||
button->set_widget(*container);
|
||||
auto* container = TRY(button->create_child_widget<ui::Container>());
|
||||
button->set_action([=] {
|
||||
os::Launcher::LaunchDetachedRequest request;
|
||||
SET_IPC_STRING(request.command, path.chars());
|
||||
launcher_client->send_async(request);
|
||||
});
|
||||
|
||||
auto image = TRY(ui::ImageWidget::load(icon));
|
||||
container->set_widget(*image);
|
||||
|
||||
image.leak();
|
||||
auto image = TRY(container->create_child_widget<ui::ImageWidget>());
|
||||
image->load(icon);
|
||||
|
||||
return {};
|
||||
}
|
||||
@ -165,8 +160,8 @@ Result<int> luna_main(int, char**)
|
||||
window->set_background(TASKBAR_COLOR);
|
||||
window->set_special_attributes(ui::UNFOCUSEABLE);
|
||||
|
||||
ui::HorizontalLayout layout(ui::Margins { 0, 0, 0, 0 }, ui::AdjustHeight::Yes, ui::AdjustWidth::No);
|
||||
window->set_main_widget(layout);
|
||||
auto* layout = TRY(window->create_main_widget<ui::HorizontalLayout>());
|
||||
layout->set_layout_settings(ui::Margins { 0, 0, 0, 0 }, ui::AdjustHeight::Yes, ui::AdjustWidth::No);
|
||||
|
||||
load_app_files_from_path("/usr/share/applications/");
|
||||
|
||||
|
@ -15,7 +15,8 @@
|
||||
#include <os/FileSystem.h>
|
||||
#include <ui/App.h>
|
||||
|
||||
EditorWidget::EditorWidget(SharedPtr<ui::Font> font) : ui::TextInput(), m_font(font)
|
||||
EditorWidget::EditorWidget(ui::Window* window, ui::Widget* parent)
|
||||
: ui::TextInput(window, parent), m_font(ui::Font::default_font())
|
||||
{
|
||||
recalculate_lines();
|
||||
}
|
||||
|
@ -16,7 +16,7 @@
|
||||
class EditorWidget : public ui::TextInput
|
||||
{
|
||||
public:
|
||||
EditorWidget(SharedPtr<ui::Font> font);
|
||||
EditorWidget(ui::Window* window, ui::Widget* parent);
|
||||
|
||||
Result<void> load_file(const os::Path& path);
|
||||
|
||||
@ -31,6 +31,11 @@ class EditorWidget : public ui::TextInput
|
||||
return m_path;
|
||||
}
|
||||
|
||||
void set_font(SharedPtr<ui::Font> font)
|
||||
{
|
||||
m_font = font;
|
||||
}
|
||||
|
||||
private:
|
||||
SharedPtr<ui::Font> m_font;
|
||||
|
||||
|
@ -30,8 +30,7 @@ Result<int> luna_main(int argc, char** argv)
|
||||
window->set_title("Text Editor");
|
||||
app.set_main_window(window);
|
||||
|
||||
auto* editor = TRY(make<EditorWidget>(ui::Font::default_font()));
|
||||
window->set_main_widget(*editor);
|
||||
auto* editor = TRY(window->create_main_widget<EditorWidget>());
|
||||
if (!path.is_empty()) TRY(editor->load_file(path));
|
||||
|
||||
TRY(window->add_keyboard_shortcut({ moon::K_CH26, ui::Mod_Ctrl }, true, [&](ui::Shortcut) {
|
||||
@ -41,7 +40,5 @@ Result<int> luna_main(int argc, char** argv)
|
||||
os::println("editor: buffer saved to %s successfully", editor->path().name().chars());
|
||||
}));
|
||||
|
||||
window->draw();
|
||||
|
||||
return app.run();
|
||||
}
|
||||
|
@ -9,16 +9,25 @@
|
||||
|
||||
#pragma once
|
||||
#include <os/Action.h>
|
||||
#include <os/File.h>
|
||||
#include <ui/Widget.h>
|
||||
#include <ui/Window.h>
|
||||
|
||||
namespace ui
|
||||
{
|
||||
class Button : public Widget
|
||||
{
|
||||
public:
|
||||
Button(Rect rect);
|
||||
Button(ui::Window* window, ui::Widget* parent);
|
||||
|
||||
template <typename T> Result<T*> create_child_widget()
|
||||
{
|
||||
auto* widget = TRY(make<T>(window(), this));
|
||||
m_child = widget;
|
||||
window()->recalculate_layout();
|
||||
return widget;
|
||||
}
|
||||
|
||||
void set_widget(Widget& widget);
|
||||
void set_action(os::Action&& action);
|
||||
|
||||
Result<EventResult> handle_mouse_move(Point position) override;
|
||||
@ -28,10 +37,20 @@ namespace ui
|
||||
Result<EventResult> handle_key_event(const ui::KeyEventRequest& request) override;
|
||||
Result<void> draw(Canvas& canvas) override;
|
||||
|
||||
void recalculate_true_rects() override;
|
||||
void recalculate_pseudo_rects() override;
|
||||
|
||||
void show_tree(int indent) override
|
||||
{
|
||||
os::println("%*s- ui::Button (%d,%d,%d,%d)", indent, "", m_rect.pos.x, m_rect.pos.y, m_rect.width,
|
||||
m_rect.height);
|
||||
if (m_child) m_child->show_tree(indent + 1);
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_hovered { false };
|
||||
bool m_clicked { false };
|
||||
Widget* m_child;
|
||||
Widget* m_child { nullptr };
|
||||
os::Action m_action;
|
||||
};
|
||||
}
|
||||
|
@ -8,17 +8,31 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <os/File.h>
|
||||
#include <ui/Alignment.h>
|
||||
#include <ui/Widget.h>
|
||||
#include <ui/Window.h>
|
||||
|
||||
namespace ui
|
||||
{
|
||||
class Container : public Widget
|
||||
{
|
||||
public:
|
||||
Container(Rect rect, VerticalAlignment valign, HorizontalAlignment halign);
|
||||
Container(ui::Window* window, ui::Widget* parent);
|
||||
|
||||
void set_widget(Widget& widget);
|
||||
void set_container_settings(VerticalAlignment valign, HorizontalAlignment halign)
|
||||
{
|
||||
m_valign = valign;
|
||||
m_halign = halign;
|
||||
}
|
||||
|
||||
template <typename T> Result<T*> create_child_widget()
|
||||
{
|
||||
auto* widget = TRY(make<T>(window(), this));
|
||||
m_widget = widget;
|
||||
window()->recalculate_layout();
|
||||
return widget;
|
||||
}
|
||||
|
||||
Result<EventResult> handle_mouse_move(Point position) override;
|
||||
Result<EventResult> handle_mouse_leave() override;
|
||||
@ -27,9 +41,19 @@ namespace ui
|
||||
Result<EventResult> handle_key_event(const ui::KeyEventRequest& request) override;
|
||||
Result<void> draw(Canvas& canvas) override;
|
||||
|
||||
void recalculate_true_rects() override;
|
||||
void recalculate_pseudo_rects() override;
|
||||
|
||||
void show_tree(int indent) override
|
||||
{
|
||||
os::println("%*s- ui::Container (%d,%d,%d,%d)", indent, "", m_rect.pos.x, m_rect.pos.y, m_rect.width,
|
||||
m_rect.height);
|
||||
if (m_widget) m_widget->show_tree(indent + 1);
|
||||
}
|
||||
|
||||
private:
|
||||
Widget* m_widget;
|
||||
VerticalAlignment m_valign;
|
||||
HorizontalAlignment m_halign;
|
||||
Widget* m_widget { nullptr };
|
||||
VerticalAlignment m_valign = VerticalAlignment::Center;
|
||||
HorizontalAlignment m_halign = HorizontalAlignment::Center;
|
||||
};
|
||||
}
|
||||
|
@ -10,6 +10,7 @@
|
||||
#pragma once
|
||||
#include <luna/Buffer.h>
|
||||
#include <luna/SharedPtr.h>
|
||||
#include <os/File.h>
|
||||
#include <os/Path.h>
|
||||
#include <ui/Widget.h>
|
||||
|
||||
@ -82,10 +83,20 @@ namespace ui
|
||||
class ImageWidget final : public Widget
|
||||
{
|
||||
public:
|
||||
static Result<OwnedPtr<ImageWidget>> load(const os::Path& path);
|
||||
ImageWidget(ui::Window* window, ui::Widget* parent);
|
||||
|
||||
Result<void> load(const os::Path& path);
|
||||
|
||||
Result<void> draw(Canvas& canvas) override;
|
||||
|
||||
void recalculate_pseudo_rects() override;
|
||||
|
||||
void show_tree(int indent) override
|
||||
{
|
||||
os::println("%*s- ui::Image %dx%d (%d,%d,%d,%d)", indent, "", m_image->width(), m_image->height(),
|
||||
m_rect.pos.x, m_rect.pos.y, m_rect.width, m_rect.height);
|
||||
}
|
||||
|
||||
private:
|
||||
SharedPtr<Image> m_image;
|
||||
};
|
||||
|
@ -17,7 +17,12 @@ namespace ui
|
||||
class InputField : public ui::TextInput
|
||||
{
|
||||
public:
|
||||
InputField(SharedPtr<ui::Font> font);
|
||||
InputField(Window* window, Widget* parent);
|
||||
|
||||
void set_font(SharedPtr<ui::Font> font)
|
||||
{
|
||||
m_font = font;
|
||||
}
|
||||
|
||||
Result<ui::EventResult> handle_key_event(const ui::KeyEventRequest& request) override;
|
||||
|
||||
|
@ -8,6 +8,7 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <os/File.h>
|
||||
#include <ui/Alignment.h>
|
||||
#include <ui/Font.h>
|
||||
#include <ui/Widget.h>
|
||||
@ -22,7 +23,7 @@ namespace ui
|
||||
class Label final : public Widget
|
||||
{
|
||||
public:
|
||||
Label(StringView text);
|
||||
Label(Window* window, Widget* parent);
|
||||
|
||||
void set_alignment(VerticalAlignment valign, HorizontalAlignment halign)
|
||||
{
|
||||
@ -47,6 +48,14 @@ namespace ui
|
||||
|
||||
Result<void> draw(Canvas& canvas) override;
|
||||
|
||||
void recalculate_pseudo_rects() override;
|
||||
|
||||
void show_tree(int indent) override
|
||||
{
|
||||
os::println("%*s- ui::Label '%s' (%d,%d,%d,%d)", indent, "", m_text.chars(), m_rect.pos.x, m_rect.pos.y,
|
||||
m_rect.width, m_rect.height);
|
||||
}
|
||||
|
||||
private:
|
||||
StringView m_text;
|
||||
VerticalAlignment m_valign = VerticalAlignment::Center;
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#pragma once
|
||||
#include <luna/Vector.h>
|
||||
#include <os/File.h>
|
||||
#include <ui/Widget.h>
|
||||
|
||||
namespace ui
|
||||
@ -36,8 +37,16 @@ namespace ui
|
||||
class HorizontalLayout final : public Widget
|
||||
{
|
||||
public:
|
||||
HorizontalLayout(Margins margins = Margins { 0, 0, 0, 0 }, AdjustHeight adjust_height = AdjustHeight::Yes,
|
||||
AdjustWidth adjust_width = AdjustWidth::Yes);
|
||||
HorizontalLayout(ui::Window* window, ui::Widget* parent);
|
||||
|
||||
void set_layout_settings(Margins margins = Margins { 0, 0, 0, 0 },
|
||||
AdjustHeight adjust_height = AdjustHeight::Yes,
|
||||
AdjustWidth adjust_width = AdjustWidth::No)
|
||||
{
|
||||
m_margins = margins;
|
||||
m_adjust_height = adjust_height;
|
||||
m_adjust_width = adjust_width;
|
||||
}
|
||||
|
||||
Result<EventResult> handle_mouse_move(Point position) override;
|
||||
Result<EventResult> handle_mouse_leave() override;
|
||||
@ -47,21 +56,46 @@ namespace ui
|
||||
|
||||
Result<void> draw(Canvas& canvas) override;
|
||||
|
||||
Result<void> add_widget(Widget& widget);
|
||||
template <typename T> Result<T*> add_child_widget()
|
||||
{
|
||||
auto* widget = TRY(make<T>(window(), this));
|
||||
add_widget(*widget);
|
||||
return widget;
|
||||
}
|
||||
|
||||
void recalculate_pseudo_rects() override;
|
||||
void recalculate_true_rects() override;
|
||||
|
||||
void show_tree(int indent) override
|
||||
{
|
||||
os::println("%*s- ui::HorizontalLayout [%zu widgets] (%d,%d,%d,%d)", indent, "", m_widgets.size(),
|
||||
m_rect.pos.x, m_rect.pos.y, m_rect.width, m_rect.height);
|
||||
for (auto* w : m_widgets) { w->show_tree(indent + 1); }
|
||||
}
|
||||
|
||||
private:
|
||||
Vector<Widget*> m_widgets;
|
||||
Margins m_margins;
|
||||
AdjustHeight m_adjust_height;
|
||||
AdjustWidth m_adjust_width;
|
||||
Margins m_margins { 0, 0, 0, 0 };
|
||||
AdjustHeight m_adjust_height = AdjustHeight::Yes;
|
||||
AdjustWidth m_adjust_width = AdjustWidth::No;
|
||||
int m_used_width { 0 };
|
||||
|
||||
Result<void> add_widget(Widget& widget);
|
||||
};
|
||||
|
||||
class VerticalLayout final : public Widget
|
||||
{
|
||||
public:
|
||||
VerticalLayout(Margins margins = Margins { 0, 0, 0, 0 }, AdjustHeight adjust_height = AdjustHeight::Yes,
|
||||
AdjustWidth adjust_width = AdjustWidth::Yes);
|
||||
VerticalLayout(ui::Window* window, ui::Widget* parent);
|
||||
|
||||
void set_layout_settings(Margins margins = Margins { 0, 0, 0, 0 },
|
||||
AdjustHeight adjust_height = AdjustHeight::No,
|
||||
AdjustWidth adjust_width = AdjustWidth::Yes)
|
||||
{
|
||||
m_margins = margins;
|
||||
m_adjust_height = adjust_height;
|
||||
m_adjust_width = adjust_width;
|
||||
}
|
||||
|
||||
Result<EventResult> handle_mouse_move(Point position) override;
|
||||
Result<EventResult> handle_mouse_leave() override;
|
||||
@ -71,13 +105,30 @@ namespace ui
|
||||
|
||||
Result<void> draw(Canvas& canvas) override;
|
||||
|
||||
Result<void> add_widget(Widget& widget);
|
||||
template <typename T> Result<T*> add_child_widget()
|
||||
{
|
||||
auto* widget = TRY(make<T>(window(), this));
|
||||
add_widget(*widget);
|
||||
return widget;
|
||||
}
|
||||
|
||||
void recalculate_pseudo_rects() override;
|
||||
void recalculate_true_rects() override;
|
||||
|
||||
void show_tree(int indent) override
|
||||
{
|
||||
os::println("%*s- ui::VerticalLayout [%zu widgets] (%d,%d,%d,%d)", indent, "", m_widgets.size(),
|
||||
m_rect.pos.x, m_rect.pos.y, m_rect.width, m_rect.height);
|
||||
for (auto* w : m_widgets) { w->show_tree(indent + 1); }
|
||||
}
|
||||
|
||||
private:
|
||||
Vector<Widget*> m_widgets;
|
||||
Margins m_margins;
|
||||
AdjustHeight m_adjust_height;
|
||||
AdjustWidth m_adjust_width;
|
||||
Margins m_margins { 0, 0, 0, 0 };
|
||||
AdjustHeight m_adjust_height = AdjustHeight::No;
|
||||
AdjustWidth m_adjust_width = AdjustWidth::Yes;
|
||||
int m_used_height { 0 };
|
||||
|
||||
Result<void> add_widget(Widget& widget);
|
||||
};
|
||||
}
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#pragma once
|
||||
#include <luna/Buffer.h>
|
||||
#include <os/File.h>
|
||||
#include <os/Timer.h>
|
||||
#include <ui/Widget.h>
|
||||
|
||||
@ -17,12 +18,18 @@ namespace ui
|
||||
class TextInput : public Widget
|
||||
{
|
||||
public:
|
||||
TextInput();
|
||||
TextInput(Window* window, Widget* parent);
|
||||
|
||||
virtual Result<ui::EventResult> handle_key_event(const ui::KeyEventRequest& request) = 0;
|
||||
|
||||
virtual Result<void> draw(ui::Canvas& canvas) = 0;
|
||||
|
||||
void show_tree(int indent) override
|
||||
{
|
||||
os::println("%*s- ui::TextInput (%d,%d,%d,%d)", indent, "", m_rect.pos.x, m_rect.pos.y, m_rect.width,
|
||||
m_rect.height);
|
||||
}
|
||||
|
||||
protected:
|
||||
Buffer m_data;
|
||||
|
||||
|
@ -28,6 +28,10 @@ namespace ui
|
||||
class Widget
|
||||
{
|
||||
public:
|
||||
Widget(Window* window, Widget* parent) : m_window(window), m_parent(parent)
|
||||
{
|
||||
}
|
||||
|
||||
virtual Result<EventResult> handle_mouse_move(Point position)
|
||||
{
|
||||
ignore(position);
|
||||
@ -59,16 +63,14 @@ namespace ui
|
||||
|
||||
virtual Result<void> draw(Canvas& canvas);
|
||||
|
||||
void set_window(Window* window, Rect rect, Badge<Window>)
|
||||
void set_rect(Rect rect, Badge<Window>)
|
||||
{
|
||||
m_window = window;
|
||||
m_rect = rect;
|
||||
}
|
||||
|
||||
void set_parent(Widget* parent)
|
||||
void resize(Rect rect)
|
||||
{
|
||||
m_parent = parent;
|
||||
m_window = parent->m_window;
|
||||
m_preferred_rect = rect;
|
||||
}
|
||||
|
||||
Widget* parent()
|
||||
@ -86,9 +88,36 @@ namespace ui
|
||||
return m_rect;
|
||||
}
|
||||
|
||||
Rect pseudo_rect()
|
||||
{
|
||||
return m_pseudo_rect;
|
||||
}
|
||||
|
||||
Rect preferred_rect()
|
||||
{
|
||||
return m_preferred_rect.value_or({ 0, 0, 50, 50 });
|
||||
}
|
||||
|
||||
virtual void recalculate_pseudo_rects()
|
||||
{
|
||||
m_pseudo_rect = preferred_rect();
|
||||
return;
|
||||
}
|
||||
|
||||
virtual void recalculate_true_rects()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
virtual void show_tree(int indent) = 0;
|
||||
|
||||
protected:
|
||||
Widget* m_parent { nullptr };
|
||||
Window* m_window;
|
||||
Widget* m_parent { nullptr };
|
||||
|
||||
Option<Rect> m_preferred_rect;
|
||||
|
||||
Rect m_pseudo_rect;
|
||||
Rect m_rect { 0, 0, 50, 50 };
|
||||
};
|
||||
}
|
||||
|
@ -8,9 +8,12 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <luna/Alloc.h>
|
||||
#include <luna/HashMap.h>
|
||||
#include <luna/OwnedPtr.h>
|
||||
#include <luna/String.h>
|
||||
#include <luna/StringView.h>
|
||||
#include <os/File.h>
|
||||
#include <ui/Canvas.h>
|
||||
#include <ui/Mouse.h>
|
||||
#include <ui/Rect.h>
|
||||
@ -49,11 +52,13 @@ namespace ui
|
||||
m_background = color;
|
||||
}
|
||||
|
||||
void set_main_widget(Widget& widget)
|
||||
template <typename T> Result<T*> create_main_widget()
|
||||
{
|
||||
check(!m_main_widget);
|
||||
widget.set_window(this, m_window_canvas.rect(), {});
|
||||
m_main_widget = &widget;
|
||||
auto* widget = TRY(make<T>(this, nullptr));
|
||||
m_main_widget = widget;
|
||||
widget->set_rect(m_window_canvas.rect(), {});
|
||||
return widget;
|
||||
}
|
||||
|
||||
Canvas& canvas()
|
||||
@ -75,11 +80,25 @@ namespace ui
|
||||
|
||||
Result<void> add_keyboard_shortcut(ui::Shortcut shortcut, bool intercept, os::Function<ui::Shortcut>&& action);
|
||||
|
||||
void recalculate_layout()
|
||||
{
|
||||
check(m_main_widget);
|
||||
m_main_widget->recalculate_pseudo_rects();
|
||||
m_main_widget->recalculate_true_rects();
|
||||
}
|
||||
|
||||
int id() const
|
||||
{
|
||||
return m_id;
|
||||
}
|
||||
|
||||
void show_tree()
|
||||
{
|
||||
os::println("- ui::Window %d (%d,%d,%d,%d)", m_id, m_canvas.rect().pos.x, m_canvas.rect().pos.y,
|
||||
m_canvas.rect().width, m_canvas.rect().height);
|
||||
m_main_widget->show_tree(1);
|
||||
}
|
||||
|
||||
~Window();
|
||||
|
||||
private:
|
||||
|
@ -12,16 +12,26 @@
|
||||
|
||||
namespace ui
|
||||
{
|
||||
Button::Button(Rect rect)
|
||||
Button::Button(Window* window, Widget* parent) : ui::Widget(window, parent)
|
||||
{
|
||||
m_rect = rect;
|
||||
}
|
||||
|
||||
void Button::set_widget(Widget& widget)
|
||||
void Button::recalculate_true_rects()
|
||||
{
|
||||
widget.rect() = m_rect;
|
||||
m_child = &widget;
|
||||
widget.set_parent(this);
|
||||
if (!m_child) return;
|
||||
m_child->rect() = m_rect;
|
||||
m_child->recalculate_true_rects();
|
||||
}
|
||||
|
||||
void Button::recalculate_pseudo_rects()
|
||||
{
|
||||
if (m_child)
|
||||
{
|
||||
m_child->recalculate_pseudo_rects();
|
||||
m_pseudo_rect = m_child->pseudo_rect();
|
||||
}
|
||||
|
||||
if (m_preferred_rect.has_value()) m_pseudo_rect = m_preferred_rect.value();
|
||||
}
|
||||
|
||||
void Button::set_action(os::Action&& action)
|
||||
|
@ -11,17 +11,22 @@
|
||||
|
||||
namespace ui
|
||||
{
|
||||
Container::Container(Rect rect, VerticalAlignment valign, HorizontalAlignment halign)
|
||||
: m_valign(valign), m_halign(halign)
|
||||
Container::Container(Window* window, Widget* parent) : ui::Widget(window, parent)
|
||||
{
|
||||
m_rect = rect;
|
||||
}
|
||||
|
||||
void Container::set_widget(Widget& widget)
|
||||
void Container::recalculate_true_rects()
|
||||
{
|
||||
m_widget = &widget;
|
||||
widget.rect() = ui::align(m_rect, widget.rect(), m_valign, m_halign);
|
||||
widget.set_parent(this);
|
||||
if (!m_widget) return;
|
||||
m_widget->rect() = ui::align(m_rect, m_widget->pseudo_rect(), m_valign, m_halign);
|
||||
m_widget->recalculate_true_rects();
|
||||
}
|
||||
|
||||
void Container::recalculate_pseudo_rects()
|
||||
{
|
||||
if (m_widget) m_widget->recalculate_pseudo_rects();
|
||||
|
||||
m_pseudo_rect = preferred_rect();
|
||||
}
|
||||
|
||||
Result<EventResult> Container::handle_mouse_move(Point position)
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <os/File.h>
|
||||
#include <ui/Alignment.h>
|
||||
#include <ui/Image.h>
|
||||
#include <ui/Window.h>
|
||||
|
||||
namespace ui
|
||||
{
|
||||
@ -32,17 +33,28 @@ namespace ui
|
||||
return image;
|
||||
}
|
||||
|
||||
Result<OwnedPtr<ImageWidget>> ImageWidget::load(const os::Path& path)
|
||||
ImageWidget::ImageWidget(Window* window, Widget* parent) : ui::Widget(window, parent)
|
||||
{
|
||||
auto widget = TRY(make_owned<ImageWidget>());
|
||||
widget->m_image = TRY(Image::load(path));
|
||||
widget->m_rect = { 0, 0, widget->m_image->width(), widget->m_image->height() };
|
||||
return widget;
|
||||
}
|
||||
|
||||
Result<void> ImageWidget::load(const os::Path& path)
|
||||
{
|
||||
m_image = TRY(Image::load(path));
|
||||
window()->recalculate_layout();
|
||||
return {};
|
||||
}
|
||||
|
||||
Result<void> ImageWidget::draw(Canvas& canvas)
|
||||
{
|
||||
if (!m_image) return;
|
||||
canvas.subcanvas({ 0, 0, m_image->width(), m_image->height() }).fill(m_image->pixels(), m_image->width());
|
||||
return {};
|
||||
}
|
||||
|
||||
void ImageWidget::recalculate_pseudo_rects()
|
||||
{
|
||||
if (m_preferred_rect.has_value()) m_pseudo_rect = m_preferred_rect.value();
|
||||
|
||||
if (m_image) m_pseudo_rect = ui::Rect { 0, 0, m_image->width(), m_image->height() };
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,8 @@
|
||||
|
||||
namespace ui
|
||||
{
|
||||
InputField::InputField(SharedPtr<ui::Font> font) : ui::TextInput(), m_font(font)
|
||||
InputField::InputField(Window* window, Widget* parent)
|
||||
: ui::TextInput(window, parent), m_font(ui::Font::default_font())
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,7 @@
|
||||
|
||||
namespace ui
|
||||
{
|
||||
Label::Label(StringView text) : m_text(text)
|
||||
Label::Label(Window* window, Widget* parent) : Widget(window, parent), m_text()
|
||||
{
|
||||
m_font = ui::Font::default_font();
|
||||
}
|
||||
@ -33,4 +33,14 @@ namespace ui
|
||||
m_font->render(buf, m_color, subcanvas);
|
||||
return {};
|
||||
}
|
||||
|
||||
void Label::recalculate_pseudo_rects()
|
||||
{
|
||||
if (m_preferred_rect.has_value()) m_pseudo_rect = m_preferred_rect.value();
|
||||
|
||||
int height = m_font->height();
|
||||
int width = m_font->width() * (int)m_text.length();
|
||||
|
||||
m_pseudo_rect = { 0, 0, width, height };
|
||||
}
|
||||
}
|
||||
|
@ -9,11 +9,11 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <ui/Layout.h>
|
||||
#include <ui/Window.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)
|
||||
HorizontalLayout::HorizontalLayout(Window* window, Widget* parent) : ui::Widget(window, parent)
|
||||
{
|
||||
}
|
||||
|
||||
@ -93,38 +93,85 @@ namespace ui
|
||||
{
|
||||
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;
|
||||
window()->recalculate_layout();
|
||||
|
||||
return {};
|
||||
}
|
||||
else
|
||||
|
||||
void HorizontalLayout::recalculate_pseudo_rects()
|
||||
{
|
||||
int min_height = 0;
|
||||
int width = 0;
|
||||
|
||||
for (auto w : m_widgets)
|
||||
{
|
||||
w->recalculate_pseudo_rects();
|
||||
if (w->pseudo_rect().height > min_height) min_height = w->pseudo_rect().height;
|
||||
width += (m_margins.left + w->pseudo_rect().width + m_margins.right);
|
||||
}
|
||||
|
||||
min_height += (m_margins.top + m_margins.bottom);
|
||||
|
||||
m_pseudo_rect = { 0, 0, width, min_height };
|
||||
|
||||
if (m_preferred_rect.has_value()) m_pseudo_rect = m_preferred_rect.value();
|
||||
}
|
||||
|
||||
void HorizontalLayout::recalculate_true_rects()
|
||||
{
|
||||
if (m_adjust_width == AdjustWidth::Yes)
|
||||
{
|
||||
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().pos.y = m_rect.pos.y + m_margins.top;
|
||||
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);
|
||||
w->rect().height = m_rect.height - (m_margins.top + m_margins.bottom);
|
||||
}
|
||||
else
|
||||
w->rect().height = w->pseudo_rect().height;
|
||||
|
||||
used_width += result.quot;
|
||||
|
||||
w->recalculate_true_rects();
|
||||
}
|
||||
|
||||
widget.set_parent(this);
|
||||
if (result.rem != 0 && m_widgets.size())
|
||||
{
|
||||
auto* last = m_widgets[m_widgets.size() - 1];
|
||||
last->rect().width += result.rem;
|
||||
last->recalculate_true_rects();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int used_width = 0;
|
||||
for (auto w : m_widgets)
|
||||
{
|
||||
w->rect() = w->pseudo_rect();
|
||||
w->rect().pos.x = m_rect.pos.x + used_width + m_margins.left;
|
||||
w->rect().pos.y = m_rect.pos.y + m_margins.top;
|
||||
|
||||
return {};
|
||||
if (m_adjust_height == AdjustHeight::Yes)
|
||||
{
|
||||
w->rect().height = m_rect.height - (m_margins.top + m_margins.bottom);
|
||||
}
|
||||
else
|
||||
w->rect().height = w->pseudo_rect().height;
|
||||
|
||||
used_width += (m_margins.left + m_margins.right + w->rect().width);
|
||||
|
||||
w->recalculate_true_rects();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VerticalLayout::VerticalLayout(Margins margins, AdjustHeight adjust_height, AdjustWidth adjust_width)
|
||||
: m_margins(margins), m_adjust_height(adjust_height), m_adjust_width(adjust_width)
|
||||
VerticalLayout::VerticalLayout(Window* window, Widget* parent) : ui::Widget(window, parent)
|
||||
{
|
||||
}
|
||||
|
||||
@ -200,36 +247,84 @@ namespace ui
|
||||
return {};
|
||||
}
|
||||
|
||||
Result<void> VerticalLayout::add_widget(Widget& widget)
|
||||
void VerticalLayout::recalculate_pseudo_rects()
|
||||
{
|
||||
TRY(m_widgets.try_append(&widget));
|
||||
int min_width = 0;
|
||||
int height = 0;
|
||||
|
||||
if (m_adjust_height == AdjustHeight::No)
|
||||
for (auto w : m_widgets)
|
||||
{
|
||||
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;
|
||||
w->recalculate_pseudo_rects();
|
||||
if (w->pseudo_rect().width > min_width) min_width = w->pseudo_rect().width;
|
||||
height += (m_margins.top + w->pseudo_rect().height + m_margins.bottom);
|
||||
}
|
||||
else
|
||||
|
||||
min_width += (m_margins.left + m_margins.right);
|
||||
|
||||
m_pseudo_rect = { 0, 0, min_width, height };
|
||||
|
||||
if (m_preferred_rect.has_value()) m_pseudo_rect = m_preferred_rect.value();
|
||||
}
|
||||
|
||||
void VerticalLayout::recalculate_true_rects()
|
||||
{
|
||||
if (m_adjust_height == AdjustHeight::Yes)
|
||||
{
|
||||
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().pos.x = m_rect.pos.x + m_margins.left;
|
||||
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);
|
||||
w->rect().width = m_rect.width - (m_margins.left + m_margins.right);
|
||||
}
|
||||
else
|
||||
w->rect().width = w->pseudo_rect().width;
|
||||
|
||||
used_height += result.quot;
|
||||
|
||||
w->recalculate_true_rects();
|
||||
}
|
||||
|
||||
widget.set_parent(this);
|
||||
if (result.rem != 0 && m_widgets.size())
|
||||
{
|
||||
auto* last = m_widgets[m_widgets.size() - 1];
|
||||
last->rect().height += result.rem;
|
||||
last->recalculate_true_rects();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int used_height = 0;
|
||||
for (auto w : m_widgets)
|
||||
{
|
||||
w->rect() = w->pseudo_rect();
|
||||
w->rect().pos.y = m_rect.pos.y + used_height + m_margins.top;
|
||||
w->rect().pos.x = m_rect.pos.x + m_margins.left;
|
||||
|
||||
if (m_adjust_width == AdjustWidth::Yes)
|
||||
{
|
||||
w->rect().width = m_rect.width - (m_margins.left + m_margins.right);
|
||||
}
|
||||
else
|
||||
w->rect().width = w->pseudo_rect().width;
|
||||
|
||||
used_height += (m_margins.top + m_margins.bottom + w->rect().height);
|
||||
|
||||
w->recalculate_true_rects();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Result<void> VerticalLayout::add_widget(Widget& widget)
|
||||
{
|
||||
TRY(m_widgets.try_append(&widget));
|
||||
|
||||
window()->recalculate_layout();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
@ -12,7 +12,7 @@
|
||||
|
||||
namespace ui
|
||||
{
|
||||
TextInput::TextInput() : Widget()
|
||||
TextInput::TextInput(Window* window, Widget* parent) : Widget(window, parent)
|
||||
{
|
||||
m_cursor_timer = os::Timer::create_repeating(500, [this]() { this->tick_cursor(); }).release_value();
|
||||
}
|
||||
|
@ -35,6 +35,10 @@ static void sigchld_handler(int)
|
||||
ui::App::the().set_should_close(true);
|
||||
}
|
||||
|
||||
TerminalWidget::TerminalWidget(ui::Window* window, ui::Widget* parent) : ui::Widget(window, parent)
|
||||
{
|
||||
}
|
||||
|
||||
Result<void> TerminalWidget::init(char* const* args)
|
||||
{
|
||||
m_font = ui::Font::default_font();
|
||||
|
@ -2,6 +2,7 @@
|
||||
#include <luna/EscapeSequence.h>
|
||||
#include <luna/Utf8.h>
|
||||
#include <luna/Vector.h>
|
||||
#include <os/File.h>
|
||||
#include <os/Timer.h>
|
||||
#include <stdio.h>
|
||||
#include <termios.h>
|
||||
@ -11,12 +12,20 @@
|
||||
class TerminalWidget : public ui::Widget
|
||||
{
|
||||
public:
|
||||
TerminalWidget(ui::Window* window, ui::Widget* parent);
|
||||
|
||||
Result<void> init(char* const* args);
|
||||
|
||||
Result<ui::EventResult> handle_key_event(const ui::KeyEventRequest& request) override;
|
||||
|
||||
Result<void> draw(ui::Canvas& canvas) override;
|
||||
|
||||
void show_tree(int indent) override
|
||||
{
|
||||
os::println("%*s- TerminalWidget (%d,%d,%d,%d)", indent, "", m_rect.pos.x, m_rect.pos.y, m_rect.width,
|
||||
m_rect.height);
|
||||
}
|
||||
|
||||
private:
|
||||
ui::Canvas m_terminal_canvas;
|
||||
Vector<u8> m_line_buffer;
|
||||
|
@ -12,13 +12,10 @@ Result<int> luna_main(int, char**)
|
||||
app.set_main_window(window);
|
||||
window->set_title("Terminal");
|
||||
|
||||
TerminalWidget terminal;
|
||||
window->set_main_widget(terminal);
|
||||
auto* terminal = TRY(window->create_main_widget<TerminalWidget>());
|
||||
|
||||
char* args[] = { "/bin/sh", nullptr };
|
||||
TRY(terminal.init(args));
|
||||
|
||||
window->draw();
|
||||
TRY(terminal->init(args));
|
||||
|
||||
return app.run();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user