Compare commits
No commits in common. "945d83816603382dbe7672e9f8ed2437e1cf5701" and "60f9c0e5a3b168d28f574c81cec5ec8a719a3313" have entirely different histories.
945d838166
...
60f9c0e5a3
@ -49,5 +49,3 @@ luna_app(shmem-test.cpp shmem-test)
|
|||||||
luna_app(touch.cpp touch)
|
luna_app(touch.cpp touch)
|
||||||
luna_app(gclient.cpp gclient)
|
luna_app(gclient.cpp gclient)
|
||||||
target_link_libraries(gclient PUBLIC ui)
|
target_link_libraries(gclient PUBLIC ui)
|
||||||
luna_app(taskbar.cpp taskbar)
|
|
||||||
target_link_libraries(taskbar PUBLIC ui)
|
|
||||||
|
129
apps/gclient.cpp
129
apps/gclient.cpp
@ -1,75 +1,94 @@
|
|||||||
#include <ui/App.h>
|
#include <errno.h>
|
||||||
#include <ui/Layout.h>
|
#include <os/ArgumentParser.h>
|
||||||
|
#include <os/File.h>
|
||||||
|
#include <os/LocalClient.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <ui/Canvas.h>
|
||||||
|
#include <ui/ipc/Server.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
struct ColorWidget : public ui::Widget
|
struct Window
|
||||||
{
|
{
|
||||||
public:
|
ui::Canvas canvas;
|
||||||
ColorWidget(ui::Color first, ui::Color second) : m_color(first), m_first_color(first), m_second_color(second)
|
int id;
|
||||||
|
|
||||||
|
void set_title(os::LocalClient& client, const char* title)
|
||||||
{
|
{
|
||||||
|
ui::SetWindowTitleRequest request;
|
||||||
|
request.window = id;
|
||||||
|
SET_IPC_STRING(request.title, title);
|
||||||
|
os::IPC::send_async(client, request);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<ui::EventResult> handle_mouse_move(ui::Point) override
|
void redraw(os::LocalClient& client)
|
||||||
{
|
{
|
||||||
m_color = m_second_color;
|
ui::InvalidateRequest request;
|
||||||
return ui::EventResult::DidHandle;
|
request.window = id;
|
||||||
|
os::IPC::send_async(client, request);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<ui::EventResult> handle_mouse_leave(ui::Point) override
|
|
||||||
{
|
|
||||||
m_color = m_first_color;
|
|
||||||
return ui::EventResult::DidHandle;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<ui::EventResult> handle_mouse_down(ui::Point, int) override
|
|
||||||
{
|
|
||||||
return ui::EventResult::DidNotHandle;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<ui::EventResult> handle_mouse_up(ui::Point, int) override
|
|
||||||
{
|
|
||||||
return ui::EventResult::DidNotHandle;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<void> draw(ui::Canvas& canvas) override
|
|
||||||
{
|
|
||||||
canvas.fill(m_color);
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
ui::Color m_color;
|
|
||||||
ui::Color m_first_color;
|
|
||||||
ui::Color m_second_color;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Result<void> handle_ipc_client_event(os::LocalClient&, u8)
|
||||||
|
{
|
||||||
|
todo();
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result<u32*> create_shm_region(const char* path, int* outfd, ui::Rect rect)
|
||||||
|
{
|
||||||
|
int fd = shm_open(path, O_RDWR, 0600);
|
||||||
|
shm_unlink(path);
|
||||||
|
if (fd < 0) return err(errno);
|
||||||
|
|
||||||
|
usize size = rect.width * rect.height * 4; // 4 bytes per pixel
|
||||||
|
|
||||||
|
void* p = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||||
|
if (p == MAP_FAILED)
|
||||||
|
{
|
||||||
|
shm_unlink(path);
|
||||||
|
close(fd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (outfd) *outfd = fd;
|
||||||
|
else
|
||||||
|
close(fd);
|
||||||
|
return (u32*)p;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<Window> create_window(os::LocalClient& client, ui::Rect rect)
|
||||||
|
{
|
||||||
|
ui::CreateWindowRequest request;
|
||||||
|
request.rect = rect;
|
||||||
|
auto response = TRY(os::IPC::send_sync<ui::CreateWindowResponse>(client, request));
|
||||||
|
u32* pixels = TRY(create_shm_region(response.shm_path, nullptr, rect));
|
||||||
|
return Window { ui::Canvas { rect.width, rect.height, rect.width, (u8*)pixels }, response.window };
|
||||||
|
}
|
||||||
|
|
||||||
Result<int> luna_main(int argc, char** argv)
|
Result<int> luna_main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
ui::App app;
|
StringView socket_path = "/tmp/wind.sock";
|
||||||
TRY(app.init(argc, argv));
|
|
||||||
|
|
||||||
auto* window = TRY(ui::Window::create(ui::Rect { 200, 200, 400, 300 }));
|
os::ArgumentParser parser;
|
||||||
app.set_main_window(window);
|
parser.add_description("A graphical user interface client."_sv);
|
||||||
|
parser.add_system_program_info("gclient"_sv);
|
||||||
|
parser.add_value_argument(socket_path, 's', "socket"_sv, "the path for the local IPC socket"_sv);
|
||||||
|
parser.parse(argc, argv);
|
||||||
|
|
||||||
window->set_title("Main Window");
|
auto client = TRY(os::LocalClient::connect(socket_path, false));
|
||||||
window->set_background(ui::CYAN);
|
|
||||||
|
|
||||||
ui::HorizontalLayout layout;
|
Window window = TRY(create_window(*client, ui::Rect { 200, 200, 400, 300 }));
|
||||||
window->set_main_widget(layout);
|
os::println("Created new window with id %d!", window.id);
|
||||||
|
|
||||||
ColorWidget green(ui::GREEN, ui::WHITE);
|
sleep(3);
|
||||||
layout.add_widget(green);
|
|
||||||
ColorWidget blue(ui::BLUE, ui::GRAY);
|
|
||||||
layout.add_widget(blue);
|
|
||||||
|
|
||||||
ui::VerticalLayout sublayout;
|
window.set_title(*client, "Example Window");
|
||||||
layout.add_widget(sublayout);
|
|
||||||
|
|
||||||
ColorWidget red(ui::RED, ui::CYAN);
|
sleep(3);
|
||||||
sublayout.add_widget(red);
|
|
||||||
ColorWidget white(ui::WHITE, ui::GREEN);
|
|
||||||
sublayout.add_widget(white);
|
|
||||||
|
|
||||||
window->draw();
|
window.canvas.fill(ui::CYAN);
|
||||||
|
window.redraw(*client);
|
||||||
|
|
||||||
return app.run();
|
sleep(3);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1,40 +0,0 @@
|
|||||||
#include <os/Process.h>
|
|
||||||
#include <ui/App.h>
|
|
||||||
#include <ui/Button.h>
|
|
||||||
#include <ui/Container.h>
|
|
||||||
#include <ui/Image.h>
|
|
||||||
#include <ui/Layout.h>
|
|
||||||
|
|
||||||
Result<int> luna_main(int argc, char** argv)
|
|
||||||
{
|
|
||||||
ui::App app;
|
|
||||||
TRY(app.init(argc, argv));
|
|
||||||
|
|
||||||
ui::Rect screen = app.screen_rect();
|
|
||||||
|
|
||||||
ui::Rect bar = ui::Rect { ui::Point { 0, screen.height - 50 }, screen.width, 50 };
|
|
||||||
|
|
||||||
auto window = TRY(ui::Window::create(bar, false));
|
|
||||||
app.set_main_window(window);
|
|
||||||
window->set_background(ui::GRAY);
|
|
||||||
|
|
||||||
ui::HorizontalLayout layout(ui::AdjustHeight::Yes, ui::AdjustWidth::No);
|
|
||||||
window->set_main_widget(layout);
|
|
||||||
|
|
||||||
ui::Button button({ 0, 0, 50, 50 });
|
|
||||||
layout.add_widget(button);
|
|
||||||
|
|
||||||
ui::Container container({ 0, 0, 50, 50 }, ui::VerticalAlignment::Center, ui::HorizontalAlignment::Center);
|
|
||||||
button.set_widget(container);
|
|
||||||
button.set_action([] {
|
|
||||||
StringView args[] = { "/usr/bin/gclient" };
|
|
||||||
os::Process::spawn("/usr/bin/gclient", Slice<StringView> { args, 1 }, false);
|
|
||||||
});
|
|
||||||
|
|
||||||
auto image = TRY(ui::ImageWidget::load("/usr/share/icons/32x32/start-icon.tga"));
|
|
||||||
container.set_widget(*image);
|
|
||||||
|
|
||||||
window->draw();
|
|
||||||
|
|
||||||
return app.run();
|
|
||||||
}
|
|
@ -1,4 +0,0 @@
|
|||||||
Name=taskbar
|
|
||||||
Description=Start the taskbar.
|
|
||||||
Command=/usr/bin/taskbar
|
|
||||||
Restart=true
|
|
@ -54,7 +54,7 @@ namespace os
|
|||||||
*/
|
*/
|
||||||
template <typename Client, typename T> Result<void> send_async(Client& client, const T& message)
|
template <typename Client, typename T> Result<void> send_async(Client& client, const T& message)
|
||||||
{
|
{
|
||||||
u8 id = T::ID;
|
u8 id = T::id;
|
||||||
TRY(client.send_typed(id));
|
TRY(client.send_typed(id));
|
||||||
TRY(client.send_typed(message));
|
TRY(client.send_typed(message));
|
||||||
return {};
|
return {};
|
||||||
@ -90,7 +90,7 @@ namespace os
|
|||||||
Result<ResponseType> send_sync(os::LocalClient& client, const T& message,
|
Result<ResponseType> send_sync(os::LocalClient& client, const T& message,
|
||||||
decltype(handle_ipc_client_event) handler = handle_ipc_client_event)
|
decltype(handle_ipc_client_event) handler = handle_ipc_client_event)
|
||||||
{
|
{
|
||||||
u8 id = T::ID;
|
u8 id = T::id;
|
||||||
TRY(client.send_typed(id));
|
TRY(client.send_typed(id));
|
||||||
TRY(client.send_typed(message));
|
TRY(client.send_typed(message));
|
||||||
|
|
||||||
@ -115,7 +115,7 @@ namespace os
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (response_id != ResponseType::ID)
|
if (response_id != ResponseType::id)
|
||||||
{
|
{
|
||||||
TRY(handler(client, response_id));
|
TRY(handler(client, response_id));
|
||||||
max_other_messages--;
|
max_other_messages--;
|
||||||
|
@ -10,12 +10,6 @@ set(SOURCES
|
|||||||
src/Rect.cpp
|
src/Rect.cpp
|
||||||
src/Font.cpp
|
src/Font.cpp
|
||||||
src/Image.cpp
|
src/Image.cpp
|
||||||
src/App.cpp
|
|
||||||
src/Window.cpp
|
|
||||||
src/Layout.cpp
|
|
||||||
src/Alignment.cpp
|
|
||||||
src/Container.cpp
|
|
||||||
src/Button.cpp
|
|
||||||
)
|
)
|
||||||
|
|
||||||
add_library(ui ${SOURCES})
|
add_library(ui ${SOURCES})
|
||||||
|
@ -1,30 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file Alignment.h
|
|
||||||
* @author apio (cloudapio.eu)
|
|
||||||
* @brief UI component alignment.
|
|
||||||
*
|
|
||||||
* @copyright Copyright (c) 2023, the Luna authors.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include <ui/Rect.h>
|
|
||||||
|
|
||||||
namespace ui
|
|
||||||
{
|
|
||||||
enum class VerticalAlignment
|
|
||||||
{
|
|
||||||
Top,
|
|
||||||
Center,
|
|
||||||
Bottom
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class HorizontalAlignment
|
|
||||||
{
|
|
||||||
Left,
|
|
||||||
Center,
|
|
||||||
Right
|
|
||||||
};
|
|
||||||
|
|
||||||
Rect align(Rect container, Rect contained, VerticalAlignment valign, HorizontalAlignment halign);
|
|
||||||
}
|
|
@ -1,65 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file App.h
|
|
||||||
* @author apio (cloudapio.eu)
|
|
||||||
* @brief UI application event loop.
|
|
||||||
*
|
|
||||||
* @copyright Copyright (c) 2023, the Luna authors.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include <luna/HashMap.h>
|
|
||||||
#include <os/LocalClient.h>
|
|
||||||
#include <ui/Window.h>
|
|
||||||
|
|
||||||
namespace ui
|
|
||||||
{
|
|
||||||
class App
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
App();
|
|
||||||
~App();
|
|
||||||
|
|
||||||
Result<void> init(int, char**);
|
|
||||||
Result<int> run();
|
|
||||||
|
|
||||||
Rect screen_rect();
|
|
||||||
|
|
||||||
os::LocalClient& client()
|
|
||||||
{
|
|
||||||
return *m_client;
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_should_close(bool b)
|
|
||||||
{
|
|
||||||
m_should_close = b;
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_main_window(Window* window)
|
|
||||||
{
|
|
||||||
check(!m_main_window);
|
|
||||||
m_main_window = window;
|
|
||||||
}
|
|
||||||
|
|
||||||
Window* main_window()
|
|
||||||
{
|
|
||||||
return m_main_window;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<void> register_window(OwnedPtr<Window>&& window, Badge<Window>);
|
|
||||||
void unregister_window(Window* window, Badge<Window>);
|
|
||||||
|
|
||||||
Result<void> handle_ipc_event(u8 id);
|
|
||||||
|
|
||||||
static App& the();
|
|
||||||
|
|
||||||
private:
|
|
||||||
static App* s_app;
|
|
||||||
OwnedPtr<os::LocalClient> m_client;
|
|
||||||
Window* m_main_window { nullptr };
|
|
||||||
HashMap<int, OwnedPtr<Window>> m_windows;
|
|
||||||
bool m_should_close { false };
|
|
||||||
|
|
||||||
Window* find_window(int id);
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,35 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file Button.h
|
|
||||||
* @author apio (cloudapio.eu)
|
|
||||||
* @brief A clickable component that triggers an action when pressed.
|
|
||||||
*
|
|
||||||
* @copyright Copyright (c) 2023, the Luna authors.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include <ui/Widget.h>
|
|
||||||
|
|
||||||
namespace ui
|
|
||||||
{
|
|
||||||
class Button : public Widget
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Button(Rect rect);
|
|
||||||
|
|
||||||
void set_widget(Widget& widget);
|
|
||||||
void set_action(void (*action)(void));
|
|
||||||
|
|
||||||
Result<EventResult> handle_mouse_move(Point position) override;
|
|
||||||
Result<EventResult> handle_mouse_leave(Point position) override;
|
|
||||||
Result<EventResult> handle_mouse_down(Point position, int buttons) override;
|
|
||||||
Result<EventResult> handle_mouse_up(Point position, int buttons) override;
|
|
||||||
Result<void> draw(Canvas& canvas) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool m_hovered { false };
|
|
||||||
bool m_clicked { false };
|
|
||||||
Widget* m_child;
|
|
||||||
void (*m_action)(void);
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,34 +0,0 @@
|
|||||||
/**
|
|
||||||
* @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 <ui/Alignment.h>
|
|
||||||
#include <ui/Widget.h>
|
|
||||||
|
|
||||||
namespace ui
|
|
||||||
{
|
|
||||||
class Container : public Widget
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Container(Rect rect, VerticalAlignment valign, HorizontalAlignment halign);
|
|
||||||
|
|
||||||
void set_widget(Widget& widget);
|
|
||||||
|
|
||||||
Result<EventResult> handle_mouse_move(Point position) override;
|
|
||||||
Result<EventResult> handle_mouse_leave(Point position) override;
|
|
||||||
Result<EventResult> handle_mouse_down(Point position, int buttons) override;
|
|
||||||
Result<EventResult> handle_mouse_up(Point position, int buttons) override;
|
|
||||||
Result<void> draw(Canvas& canvas) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
Widget* m_widget;
|
|
||||||
VerticalAlignment m_valign;
|
|
||||||
HorizontalAlignment m_halign;
|
|
||||||
};
|
|
||||||
}
|
|
@ -11,7 +11,6 @@
|
|||||||
#include <luna/Buffer.h>
|
#include <luna/Buffer.h>
|
||||||
#include <luna/SharedPtr.h>
|
#include <luna/SharedPtr.h>
|
||||||
#include <os/Path.h>
|
#include <os/Path.h>
|
||||||
#include <ui/Widget.h>
|
|
||||||
|
|
||||||
namespace ui
|
namespace ui
|
||||||
{
|
{
|
||||||
@ -78,19 +77,4 @@ namespace ui
|
|||||||
TGAHeader m_tga_header;
|
TGAHeader m_tga_header;
|
||||||
Buffer m_image_data;
|
Buffer m_image_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ImageWidget final : public Widget
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static Result<OwnedPtr<ImageWidget>> load(const os::Path& path);
|
|
||||||
|
|
||||||
Result<EventResult> handle_mouse_move(Point position) override;
|
|
||||||
Result<EventResult> handle_mouse_leave(Point position) override;
|
|
||||||
Result<EventResult> handle_mouse_down(Point position, int buttons) override;
|
|
||||||
Result<EventResult> handle_mouse_up(Point position, int buttons) override;
|
|
||||||
Result<void> draw(Canvas& canvas) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
SharedPtr<Image> m_image;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
@ -1,69 +0,0 @@
|
|||||||
/**
|
|
||||||
* @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_mouse_move(Point position) override;
|
|
||||||
Result<EventResult> handle_mouse_leave(Point position) override;
|
|
||||||
Result<EventResult> handle_mouse_down(Point position, int buttons) override;
|
|
||||||
Result<EventResult> handle_mouse_up(Point position, int buttons) 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;
|
|
||||||
};
|
|
||||||
|
|
||||||
class VerticalLayout final : public Widget
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
VerticalLayout(AdjustHeight adjust_height = AdjustHeight::Yes, AdjustWidth adjust_width = AdjustWidth::Yes);
|
|
||||||
|
|
||||||
Result<EventResult> handle_mouse_move(Point position) override;
|
|
||||||
Result<EventResult> handle_mouse_leave(Point position) override;
|
|
||||||
Result<EventResult> handle_mouse_down(Point position, int buttons) override;
|
|
||||||
Result<EventResult> handle_mouse_up(Point position, int buttons) 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_height;
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file Mouse.h
|
|
||||||
* @author apio (cloudapio.eu)
|
|
||||||
* @brief Mouse buttons.
|
|
||||||
*
|
|
||||||
* @copyright Copyright (c) 2023, the Luna authors.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include <moon/Mouse.h>
|
|
||||||
|
|
||||||
namespace ui
|
|
||||||
{
|
|
||||||
enum MouseButtons
|
|
||||||
{
|
|
||||||
LEFT = moon::Left,
|
|
||||||
MIDDLE = moon::Middle,
|
|
||||||
RIGHT = moon::Right,
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,68 +0,0 @@
|
|||||||
/**
|
|
||||||
* @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_mouse_move(Point position);
|
|
||||||
virtual Result<EventResult> handle_mouse_down(Point position, int buttons);
|
|
||||||
virtual Result<EventResult> handle_mouse_up(Point position, int buttons);
|
|
||||||
virtual Result<EventResult> handle_mouse_leave(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 };
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,66 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file Window.h
|
|
||||||
* @author apio (cloudapio.eu)
|
|
||||||
* @brief UI windows.
|
|
||||||
*
|
|
||||||
* @copyright Copyright (c) 2023, the Luna authors.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include <luna/OwnedPtr.h>
|
|
||||||
#include <luna/StringView.h>
|
|
||||||
#include <ui/Canvas.h>
|
|
||||||
#include <ui/Mouse.h>
|
|
||||||
#include <ui/Rect.h>
|
|
||||||
#include <ui/Widget.h>
|
|
||||||
|
|
||||||
namespace ui
|
|
||||||
{
|
|
||||||
class Window
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static Result<Window*> create(Rect rect, bool decorated = true);
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
void update();
|
|
||||||
|
|
||||||
void close();
|
|
||||||
|
|
||||||
Result<void> draw();
|
|
||||||
Result<void> handle_mouse_move(ui::Point position);
|
|
||||||
Result<void> handle_mouse_buttons(ui::Point position, int buttons);
|
|
||||||
|
|
||||||
int id() const
|
|
||||||
{
|
|
||||||
return m_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
~Window();
|
|
||||||
|
|
||||||
private:
|
|
||||||
int m_id;
|
|
||||||
Canvas m_canvas;
|
|
||||||
Widget* m_main_widget { nullptr };
|
|
||||||
Color m_background { ui::BLACK };
|
|
||||||
Option<int> m_old_mouse_buttons;
|
|
||||||
};
|
|
||||||
}
|
|
@ -9,7 +9,6 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <os/IPC.h>
|
#include <os/IPC.h>
|
||||||
#include <ui/Point.h>
|
|
||||||
|
|
||||||
namespace ui
|
namespace ui
|
||||||
{
|
{
|
||||||
@ -17,39 +16,13 @@ namespace ui
|
|||||||
{
|
{
|
||||||
IPC_ENUM_CLIENT(ui),
|
IPC_ENUM_CLIENT(ui),
|
||||||
CREATE_WINDOW_RESPONSE_ID,
|
CREATE_WINDOW_RESPONSE_ID,
|
||||||
WINDOW_CLOSE_REQUEST_ID,
|
|
||||||
MOUSE_EVENT_REQUEST_ID,
|
|
||||||
GET_SCREEN_RECT_RESPONSE_ID
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CreateWindowResponse
|
struct CreateWindowResponse
|
||||||
{
|
{
|
||||||
static constexpr u8 ID = CREATE_WINDOW_RESPONSE_ID;
|
static constexpr u8 id = CREATE_WINDOW_RESPONSE_ID;
|
||||||
|
|
||||||
int window;
|
int window;
|
||||||
IPC_STRING(shm_path);
|
IPC_STRING(shm_path);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct WindowCloseRequest
|
|
||||||
{
|
|
||||||
static constexpr u8 ID = WINDOW_CLOSE_REQUEST_ID;
|
|
||||||
|
|
||||||
int window;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct MouseEventRequest
|
|
||||||
{
|
|
||||||
static constexpr u8 ID = MOUSE_EVENT_REQUEST_ID;
|
|
||||||
|
|
||||||
int window;
|
|
||||||
Point position;
|
|
||||||
int buttons;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct GetScreenRectResponse
|
|
||||||
{
|
|
||||||
static constexpr u8 ID = GET_SCREEN_RECT_RESPONSE_ID;
|
|
||||||
|
|
||||||
Rect rect;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
@ -21,22 +21,19 @@ namespace ui
|
|||||||
CREATE_WINDOW_ID,
|
CREATE_WINDOW_ID,
|
||||||
SET_WINDOW_TITLE_ID,
|
SET_WINDOW_TITLE_ID,
|
||||||
INVALIDATE_ID,
|
INVALIDATE_ID,
|
||||||
CLOSE_WINDOW_ID,
|
|
||||||
GET_SCREEN_RECT_ID,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CreateWindowRequest
|
struct CreateWindowRequest
|
||||||
{
|
{
|
||||||
using ResponseType = CreateWindowResponse;
|
using ResponseType = CreateWindowResponse;
|
||||||
static constexpr u8 ID = CREATE_WINDOW_ID;
|
static constexpr u8 id = CREATE_WINDOW_ID;
|
||||||
|
|
||||||
ui::Rect rect;
|
ui::Rect rect;
|
||||||
bool decorated;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SetWindowTitleRequest
|
struct SetWindowTitleRequest
|
||||||
{
|
{
|
||||||
static constexpr u8 ID = SET_WINDOW_TITLE_ID;
|
static constexpr u8 id = SET_WINDOW_TITLE_ID;
|
||||||
|
|
||||||
int window;
|
int window;
|
||||||
IPC_STRING(title);
|
IPC_STRING(title);
|
||||||
@ -44,23 +41,8 @@ namespace ui
|
|||||||
|
|
||||||
struct InvalidateRequest
|
struct InvalidateRequest
|
||||||
{
|
{
|
||||||
static constexpr u8 ID = INVALIDATE_ID;
|
static constexpr u8 id = INVALIDATE_ID;
|
||||||
|
|
||||||
int window;
|
int window;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CloseWindowRequest
|
|
||||||
{
|
|
||||||
static constexpr u8 ID = CLOSE_WINDOW_ID;
|
|
||||||
|
|
||||||
int window;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct GetScreenRectRequest
|
|
||||||
{
|
|
||||||
using ResponseType = GetScreenRectResponse;
|
|
||||||
static constexpr u8 ID = GET_SCREEN_RECT_ID;
|
|
||||||
|
|
||||||
int _shadow; // Unused.
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
@ -1,40 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file Alignment.cpp
|
|
||||||
* @author apio (cloudapio.eu)
|
|
||||||
* @brief UI component alignment.
|
|
||||||
*
|
|
||||||
* @copyright Copyright (c) 2023, the Luna authors.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <ui/Alignment.h>
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,115 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file App.cpp
|
|
||||||
* @author apio (cloudapio.eu)
|
|
||||||
* @brief UI application event loop.
|
|
||||||
*
|
|
||||||
* @copyright Copyright (c) 2023, the Luna authors.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <os/ArgumentParser.h>
|
|
||||||
#include <os/File.h>
|
|
||||||
#include <os/IPC.h>
|
|
||||||
#include <ui/App.h>
|
|
||||||
#include <ui/ipc/Client.h>
|
|
||||||
#include <ui/ipc/Server.h>
|
|
||||||
|
|
||||||
Result<void> handle_ipc_client_event(os::LocalClient&, u8 id)
|
|
||||||
{
|
|
||||||
return ui::App::the().handle_ipc_event(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace ui
|
|
||||||
{
|
|
||||||
App* App::s_app { nullptr };
|
|
||||||
|
|
||||||
App::App()
|
|
||||||
{
|
|
||||||
s_app = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
App::~App()
|
|
||||||
{
|
|
||||||
s_app = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<void> App::init(int argc, char** argv)
|
|
||||||
{
|
|
||||||
StringView socket_path = "/tmp/wind.sock";
|
|
||||||
|
|
||||||
os::ArgumentParser parser;
|
|
||||||
parser.add_description("A UI application."_sv);
|
|
||||||
parser.add_system_program_info(argv[0]);
|
|
||||||
parser.add_value_argument(socket_path, 's', "socket"_sv, "the path for the local IPC socket"_sv);
|
|
||||||
parser.parse(argc, argv);
|
|
||||||
|
|
||||||
m_client = TRY(os::LocalClient::connect(socket_path, true));
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<int> App::run()
|
|
||||||
{
|
|
||||||
check(m_main_window);
|
|
||||||
while (!m_should_close) { TRY(os::IPC::check_for_messages(*m_client)); }
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
App& App::the()
|
|
||||||
{
|
|
||||||
check(s_app);
|
|
||||||
return *s_app;
|
|
||||||
}
|
|
||||||
|
|
||||||
Rect App::screen_rect()
|
|
||||||
{
|
|
||||||
ui::GetScreenRectRequest request {};
|
|
||||||
auto response = os::IPC::send_sync<ui::GetScreenRectResponse>(*m_client, request).release_value();
|
|
||||||
return response.rect;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<void> App::register_window(OwnedPtr<Window>&& window, Badge<Window>)
|
|
||||||
{
|
|
||||||
int id = window->id();
|
|
||||||
check(TRY(m_windows.try_set(id, move(window))));
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
void App::unregister_window(Window* window, Badge<Window>)
|
|
||||||
{
|
|
||||||
int id = window->id();
|
|
||||||
check(m_windows.try_remove(id));
|
|
||||||
}
|
|
||||||
|
|
||||||
Window* App::find_window(int id)
|
|
||||||
{
|
|
||||||
auto* window = m_windows.try_get_ref(id);
|
|
||||||
check(window);
|
|
||||||
return window->ptr();
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<void> App::handle_ipc_event(u8 id)
|
|
||||||
{
|
|
||||||
switch (id)
|
|
||||||
{
|
|
||||||
case WINDOW_CLOSE_REQUEST_ID: {
|
|
||||||
WindowCloseRequest request;
|
|
||||||
TRY(m_client->recv_typed(request));
|
|
||||||
os::eprintln("ui: Window close request from server! Shall comply.");
|
|
||||||
auto* window = find_window(request.window);
|
|
||||||
window->close();
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
case MOUSE_EVENT_REQUEST_ID: {
|
|
||||||
MouseEventRequest request;
|
|
||||||
TRY(m_client->recv_typed(request));
|
|
||||||
auto* window = find_window(request.window);
|
|
||||||
window->handle_mouse_move(request.position);
|
|
||||||
window->handle_mouse_buttons(request.position, request.buttons);
|
|
||||||
window->draw();
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
default: fail("Unexpected IPC request from server!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,68 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file Button.cpp
|
|
||||||
* @author apio (cloudapio.eu)
|
|
||||||
* @brief A clickable component that triggers an action when pressed.
|
|
||||||
*
|
|
||||||
* @copyright Copyright (c) 2023, the Luna authors.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <ui/Button.h>
|
|
||||||
#include <ui/Mouse.h>
|
|
||||||
|
|
||||||
namespace ui
|
|
||||||
{
|
|
||||||
Button::Button(Rect rect)
|
|
||||||
{
|
|
||||||
m_rect = rect;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Button::set_widget(Widget& widget)
|
|
||||||
{
|
|
||||||
widget.rect() = m_rect;
|
|
||||||
m_child = &widget;
|
|
||||||
widget.set_parent(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Button::set_action(void (*action)(void))
|
|
||||||
{
|
|
||||||
m_action = action;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<EventResult> Button::handle_mouse_move(Point position)
|
|
||||||
{
|
|
||||||
m_hovered = true;
|
|
||||||
return m_child->handle_mouse_move(position);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<EventResult> Button::handle_mouse_leave(Point position)
|
|
||||||
{
|
|
||||||
m_hovered = m_clicked = false;
|
|
||||||
return m_child->handle_mouse_leave(position);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<EventResult> Button::handle_mouse_down(Point position, int buttons)
|
|
||||||
{
|
|
||||||
auto result = TRY(m_child->handle_mouse_down(position, buttons));
|
|
||||||
if (result == EventResult::DidNotHandle)
|
|
||||||
{
|
|
||||||
if (!m_clicked && (buttons == ui::MouseButtons::LEFT))
|
|
||||||
{
|
|
||||||
m_clicked = true;
|
|
||||||
m_action();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return EventResult::DidHandle;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<EventResult> Button::handle_mouse_up(Point position, int buttons)
|
|
||||||
{
|
|
||||||
if (buttons & ui::MouseButtons::LEFT) m_clicked = false;
|
|
||||||
return m_child->handle_mouse_up(position, buttons);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<void> Button::draw(Canvas& canvas)
|
|
||||||
{
|
|
||||||
return m_child->draw(canvas);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,55 +0,0 @@
|
|||||||
/**
|
|
||||||
* @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 <ui/Container.h>
|
|
||||||
|
|
||||||
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);
|
|
||||||
widget.set_parent(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<EventResult> Container::handle_mouse_move(Point position)
|
|
||||||
{
|
|
||||||
return m_widget->handle_mouse_move(position);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<EventResult> Container::handle_mouse_leave(Point position)
|
|
||||||
{
|
|
||||||
return m_widget->handle_mouse_leave(position);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<EventResult> Container::handle_mouse_down(Point position, int buttons)
|
|
||||||
{
|
|
||||||
return m_widget->handle_mouse_down(position, buttons);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<EventResult> Container::handle_mouse_up(Point position, int buttons)
|
|
||||||
{
|
|
||||||
return m_widget->handle_mouse_up(position, buttons);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<void> 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -8,7 +8,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <os/File.h>
|
#include <os/File.h>
|
||||||
#include <ui/Alignment.h>
|
|
||||||
#include <ui/Image.h>
|
#include <ui/Image.h>
|
||||||
|
|
||||||
namespace ui
|
namespace ui
|
||||||
@ -31,38 +30,4 @@ namespace ui
|
|||||||
|
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<OwnedPtr<ImageWidget>> ImageWidget::load(const os::Path& path)
|
|
||||||
{
|
|
||||||
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<EventResult> ImageWidget::handle_mouse_move(Point)
|
|
||||||
{
|
|
||||||
return EventResult::DidNotHandle;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<EventResult> ImageWidget::handle_mouse_leave(Point)
|
|
||||||
{
|
|
||||||
return EventResult::DidNotHandle;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<EventResult> ImageWidget::handle_mouse_up(Point, int)
|
|
||||||
{
|
|
||||||
return EventResult::DidNotHandle;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<EventResult> ImageWidget::handle_mouse_down(Point, int)
|
|
||||||
{
|
|
||||||
return EventResult::DidNotHandle;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<void> ImageWidget::draw(Canvas& canvas)
|
|
||||||
{
|
|
||||||
canvas.subcanvas({ 0, 0, m_image->width(), m_image->height() }).fill(m_image->pixels(), m_image->width());
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,192 +0,0 @@
|
|||||||
/**
|
|
||||||
* @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_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(position));
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<EventResult> HorizontalLayout::handle_mouse_leave(Point position)
|
|
||||||
{
|
|
||||||
for (auto widget : m_widgets) TRY(widget->handle_mouse_leave(position));
|
|
||||||
|
|
||||||
return ui::EventResult::DidNotHandle;
|
|
||||||
}
|
|
||||||
|
|
||||||
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<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 {};
|
|
||||||
}
|
|
||||||
|
|
||||||
VerticalLayout::VerticalLayout(AdjustHeight adjust_height, AdjustWidth adjust_width)
|
|
||||||
: 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(position));
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<EventResult> VerticalLayout::handle_mouse_leave(Point position)
|
|
||||||
{
|
|
||||||
for (auto widget : m_widgets) TRY(widget->handle_mouse_leave(position));
|
|
||||||
|
|
||||||
return ui::EventResult::DidNotHandle;
|
|
||||||
}
|
|
||||||
|
|
||||||
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<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_used_height += widget.rect().height;
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
w->rect().height = result.quot;
|
|
||||||
used_height += result.quot;
|
|
||||||
}
|
|
||||||
m_widgets[m_widgets.size() - 1]->rect().height += result.rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
widget.rect().pos.x = m_rect.pos.x;
|
|
||||||
|
|
||||||
if (m_adjust_width == AdjustWidth::Yes) { widget.rect().width = m_rect.width; }
|
|
||||||
|
|
||||||
widget.set_parent(this);
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,124 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file Window.cpp
|
|
||||||
* @author apio (cloudapio.eu)
|
|
||||||
* @brief UI windows.
|
|
||||||
*
|
|
||||||
* @copyright Copyright (c) 2023, the Luna authors.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <sys/mman.h>
|
|
||||||
#include <ui/App.h>
|
|
||||||
#include <ui/Window.h>
|
|
||||||
#include <ui/ipc/Server.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
static Result<u32*> create_shm_region(const char* path, int* outfd, ui::Rect rect)
|
|
||||||
{
|
|
||||||
int fd = shm_open(path, O_RDWR, 0600);
|
|
||||||
shm_unlink(path);
|
|
||||||
if (fd < 0) return err(errno);
|
|
||||||
|
|
||||||
usize size = rect.width * rect.height * 4; // 4 bytes per pixel
|
|
||||||
|
|
||||||
void* p = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
|
||||||
if (p == MAP_FAILED)
|
|
||||||
{
|
|
||||||
shm_unlink(path);
|
|
||||||
close(fd);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (outfd) *outfd = fd;
|
|
||||||
else
|
|
||||||
close(fd);
|
|
||||||
return (u32*)p;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace ui
|
|
||||||
{
|
|
||||||
Result<Window*> Window::create(Rect rect, bool decorated)
|
|
||||||
{
|
|
||||||
auto window = TRY(make_owned<Window>());
|
|
||||||
|
|
||||||
ui::CreateWindowRequest request;
|
|
||||||
request.rect = rect;
|
|
||||||
request.decorated = decorated;
|
|
||||||
auto response = TRY(os::IPC::send_sync<ui::CreateWindowResponse>(App::the().client(), request));
|
|
||||||
|
|
||||||
u32* pixels = TRY(create_shm_region(response.shm_path, nullptr, rect));
|
|
||||||
|
|
||||||
window->m_canvas = ui::Canvas { rect.width, rect.height, rect.width, (u8*)pixels };
|
|
||||||
window->m_id = response.window;
|
|
||||||
|
|
||||||
Window* p = window.ptr();
|
|
||||||
|
|
||||||
App::the().register_window(move(window), {});
|
|
||||||
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
Window::~Window()
|
|
||||||
{
|
|
||||||
if (m_canvas.ptr) munmap(m_canvas.ptr, ((usize)m_canvas.width) * ((usize)m_canvas.height) * 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Window::set_title(StringView title)
|
|
||||||
{
|
|
||||||
ui::SetWindowTitleRequest request;
|
|
||||||
request.window = m_id;
|
|
||||||
SET_IPC_STRING(request.title, title.chars());
|
|
||||||
os::IPC::send_async(App::the().client(), request);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Window::update()
|
|
||||||
{
|
|
||||||
ui::InvalidateRequest request;
|
|
||||||
request.window = m_id;
|
|
||||||
os::IPC::send_async(App::the().client(), request);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Window::close()
|
|
||||||
{
|
|
||||||
App& app = App::the();
|
|
||||||
|
|
||||||
ui::CloseWindowRequest request;
|
|
||||||
request.window = m_id;
|
|
||||||
os::IPC::send_async(app.client(), request);
|
|
||||||
|
|
||||||
if (this == app.main_window()) app.set_should_close(true);
|
|
||||||
|
|
||||||
app.unregister_window(this, {});
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<void> Window::draw()
|
|
||||||
{
|
|
||||||
m_canvas.fill(m_background);
|
|
||||||
if (m_main_widget) return m_main_widget->draw(m_canvas);
|
|
||||||
update();
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<void> Window::handle_mouse_move(ui::Point position)
|
|
||||||
{
|
|
||||||
if (!m_main_widget) return {};
|
|
||||||
TRY(m_main_widget->handle_mouse_move(position));
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<void> Window::handle_mouse_buttons(ui::Point position, int buttons)
|
|
||||||
{
|
|
||||||
if (!m_main_widget) return {};
|
|
||||||
if (buttons) TRY(m_main_widget->handle_mouse_down(position, buttons));
|
|
||||||
if (m_old_mouse_buttons.has_value())
|
|
||||||
{
|
|
||||||
int old_buttons = m_old_mouse_buttons.value();
|
|
||||||
int diff = old_buttons & ~buttons;
|
|
||||||
if (diff) TRY(m_main_widget->handle_mouse_up(position, diff));
|
|
||||||
}
|
|
||||||
m_old_mouse_buttons = buttons;
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
}
|
|
66
wind/IPC.cpp
66
wind/IPC.cpp
@ -1,5 +1,4 @@
|
|||||||
#include "IPC.h"
|
#include "IPC.h"
|
||||||
#include "Screen.h"
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <luna/Alignment.h>
|
#include <luna/Alignment.h>
|
||||||
#include <luna/String.h>
|
#include <luna/String.h>
|
||||||
@ -65,7 +64,7 @@ static Result<u32*> create_shm_region(const char* path, int* outfd, ui::Rect rec
|
|||||||
if (rc.error() == EAGAIN) \
|
if (rc.error() == EAGAIN) \
|
||||||
{ \
|
{ \
|
||||||
client.rpc_in_progress = true; \
|
client.rpc_in_progress = true; \
|
||||||
client.rpc_id = decltype(request)::ID; \
|
client.rpc_id = decltype(request)::id; \
|
||||||
return {}; \
|
return {}; \
|
||||||
} \
|
} \
|
||||||
else \
|
else \
|
||||||
@ -73,32 +72,17 @@ static Result<u32*> create_shm_region(const char* path, int* outfd, ui::Rect rec
|
|||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define CHECK_WINDOW_ID(request) \
|
|
||||||
do { \
|
|
||||||
if ((usize)request.window >= client.windows.size() || !client.windows[request.window]) \
|
|
||||||
{ \
|
|
||||||
os::eprintln("wind: Window id is invalid!"); \
|
|
||||||
return {}; \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
static Result<void> handle_create_window_message(Client& client)
|
static Result<void> handle_create_window_message(Client& client)
|
||||||
{
|
{
|
||||||
ui::CreateWindowRequest request;
|
ui::CreateWindowRequest request;
|
||||||
READ_MESSAGE(request);
|
READ_MESSAGE(request);
|
||||||
|
|
||||||
request.rect = request.rect.normalized();
|
request.rect = request.rect.normalized();
|
||||||
|
request.rect.height += Window::titlebar_height(); // Make sure we provide the full contents rect that was asked for.
|
||||||
if (request.decorated)
|
|
||||||
{
|
|
||||||
request.rect.height +=
|
|
||||||
Window::titlebar_height(); // Make sure we provide the full contents rect that was asked for.
|
|
||||||
request.rect.pos.y -= Window::titlebar_height(); // Adjust it so the contents begin at the expected coordinates.
|
|
||||||
}
|
|
||||||
|
|
||||||
auto name = TRY(String::from_cstring("Window"));
|
auto name = TRY(String::from_cstring("Window"));
|
||||||
|
|
||||||
auto* window = new (std::nothrow) Window(request.rect, move(name), request.decorated);
|
auto* window = new (std::nothrow) Window(request.rect, move(name));
|
||||||
if (!window)
|
if (!window)
|
||||||
{
|
{
|
||||||
os::IPC::send_error(client.conn, ENOMEM);
|
os::IPC::send_error(client.conn, ENOMEM);
|
||||||
@ -112,9 +96,6 @@ static Result<void> handle_create_window_message(Client& client)
|
|||||||
TRY_OR_IPC_ERROR(client.windows.try_append(window));
|
TRY_OR_IPC_ERROR(client.windows.try_append(window));
|
||||||
int id = static_cast<int>(client.windows.size() - 1);
|
int id = static_cast<int>(client.windows.size() - 1);
|
||||||
|
|
||||||
window->client = &client;
|
|
||||||
window->id = id;
|
|
||||||
|
|
||||||
ui::CreateWindowResponse response;
|
ui::CreateWindowResponse response;
|
||||||
response.window = id;
|
response.window = id;
|
||||||
SET_IPC_STRING(response.shm_path, shm_path.chars());
|
SET_IPC_STRING(response.shm_path, shm_path.chars());
|
||||||
@ -131,7 +112,11 @@ static Result<void> handle_set_window_title_message(Client& client)
|
|||||||
|
|
||||||
os::println("wind: SetWindowTitle(\"%s\") for window %d", name.chars(), request.window);
|
os::println("wind: SetWindowTitle(\"%s\") for window %d", name.chars(), request.window);
|
||||||
|
|
||||||
CHECK_WINDOW_ID(request);
|
if ((usize)request.window >= client.windows.size())
|
||||||
|
{
|
||||||
|
os::eprintln("wind: Window id out of range!");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
client.windows[request.window]->name = move(name);
|
client.windows[request.window]->name = move(name);
|
||||||
|
|
||||||
@ -143,40 +128,17 @@ static Result<void> handle_invalidate_message(Client& client)
|
|||||||
ui::InvalidateRequest request;
|
ui::InvalidateRequest request;
|
||||||
READ_MESSAGE(request);
|
READ_MESSAGE(request);
|
||||||
|
|
||||||
CHECK_WINDOW_ID(request);
|
if ((usize)request.window >= client.windows.size())
|
||||||
|
{
|
||||||
|
os::eprintln("wind: Window id out of range!");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
client.windows[request.window]->dirty = true;
|
client.windows[request.window]->dirty = true;
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
static Result<void> handle_close_window_message(Client& client)
|
|
||||||
{
|
|
||||||
ui::CloseWindowRequest request;
|
|
||||||
READ_MESSAGE(request);
|
|
||||||
|
|
||||||
CHECK_WINDOW_ID(request);
|
|
||||||
|
|
||||||
auto* window = client.windows[request.window];
|
|
||||||
client.windows[request.window] = nullptr;
|
|
||||||
g_windows.remove(window);
|
|
||||||
delete window;
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
static Result<void> handle_get_screen_rect_message(Client& client)
|
|
||||||
{
|
|
||||||
ui::GetScreenRectRequest request;
|
|
||||||
READ_MESSAGE(request); // Kinda pointless, but required.
|
|
||||||
|
|
||||||
ui::GetScreenRectResponse response;
|
|
||||||
response.rect = Screen::the().canvas().rect();
|
|
||||||
os::IPC::send_async(client.conn, response);
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace wind
|
namespace wind
|
||||||
{
|
{
|
||||||
Result<void> handle_ipc_message(Client& client, u8 id)
|
Result<void> handle_ipc_message(Client& client, u8 id)
|
||||||
@ -187,8 +149,6 @@ namespace wind
|
|||||||
case ui::CREATE_WINDOW_ID: return handle_create_window_message(client);
|
case ui::CREATE_WINDOW_ID: return handle_create_window_message(client);
|
||||||
case ui::SET_WINDOW_TITLE_ID: return handle_set_window_title_message(client);
|
case ui::SET_WINDOW_TITLE_ID: return handle_set_window_title_message(client);
|
||||||
case ui::INVALIDATE_ID: return handle_invalidate_message(client);
|
case ui::INVALIDATE_ID: return handle_invalidate_message(client);
|
||||||
case ui::CLOSE_WINDOW_ID: return handle_close_window_message(client);
|
|
||||||
case ui::GET_SCREEN_RECT_ID: return handle_get_screen_rect_message(client);
|
|
||||||
default: os::eprintln("wind: Invalid IPC message from client!"); return err(EINVAL);
|
default: os::eprintln("wind: Invalid IPC message from client!"); return err(EINVAL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
#include "Mouse.h"
|
#include "Mouse.h"
|
||||||
#include "Client.h"
|
|
||||||
#include <os/File.h>
|
#include <os/File.h>
|
||||||
#include <os/IPC.h>
|
|
||||||
#include <ui/Image.h>
|
#include <ui/Image.h>
|
||||||
#include <ui/ipc/Client.h>
|
|
||||||
|
|
||||||
static SharedPtr<ui::Image> g_mouse_cursor;
|
static SharedPtr<ui::Image> g_mouse_cursor;
|
||||||
|
|
||||||
@ -54,10 +51,9 @@ void Mouse::update(const moon::MousePacket& packet)
|
|||||||
{
|
{
|
||||||
if (window->surface.absolute(window->close_button).contains(m_position))
|
if (window->surface.absolute(window->close_button).contains(m_position))
|
||||||
{
|
{
|
||||||
ui::WindowCloseRequest request;
|
// Close button pressed
|
||||||
request.window = window->id;
|
g_windows.remove(window);
|
||||||
auto& client = *window->client;
|
delete window;
|
||||||
os::IPC::send_async(client.conn, request);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if (window->surface.absolute(window->titlebar).contains(m_position))
|
else if (window->surface.absolute(window->titlebar).contains(m_position))
|
||||||
@ -78,21 +74,4 @@ void Mouse::update(const moon::MousePacket& packet)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Window* window = g_windows.last().value_or(nullptr); window;
|
|
||||||
window = g_windows.previous(window).value_or(nullptr))
|
|
||||||
{
|
|
||||||
auto titlebar = window->surface.absolute(window->titlebar);
|
|
||||||
auto contents = window->surface.absolute(window->contents);
|
|
||||||
if (titlebar.contains(m_position)) break;
|
|
||||||
if (contents.contains(m_position))
|
|
||||||
{
|
|
||||||
ui::MouseEventRequest request;
|
|
||||||
request.window = window->id;
|
|
||||||
request.position = contents.relative(m_position);
|
|
||||||
request.buttons = packet.buttons;
|
|
||||||
os::IPC::send_async(window->client->conn, request);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -5,9 +5,7 @@
|
|||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
Screen Screen::s_the;
|
Result<Screen> Screen::open()
|
||||||
|
|
||||||
Result<void> Screen::open()
|
|
||||||
{
|
{
|
||||||
int fd = ::open("/dev/fb0", O_RDWR);
|
int fd = ::open("/dev/fb0", O_RDWR);
|
||||||
if (fd < 0) return err(errno);
|
if (fd < 0) return err(errno);
|
||||||
@ -25,9 +23,7 @@ Result<void> Screen::open()
|
|||||||
screen.m_canvas = ui::Canvas::create((u8*)p, width, height);
|
screen.m_canvas = ui::Canvas::create((u8*)p, width, height);
|
||||||
screen.m_size = width * height * BYTES_PER_PIXEL;
|
screen.m_size = width * height * BYTES_PER_PIXEL;
|
||||||
|
|
||||||
s_the = screen;
|
return screen;
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Screen::sync()
|
void Screen::sync()
|
||||||
|
@ -7,7 +7,7 @@ constexpr int BYTES_PER_PIXEL = 4;
|
|||||||
class Screen
|
class Screen
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static Result<void> open();
|
static Result<Screen> open();
|
||||||
|
|
||||||
ui::Canvas& canvas()
|
ui::Canvas& canvas()
|
||||||
{
|
{
|
||||||
@ -19,16 +19,9 @@ class Screen
|
|||||||
return m_size;
|
return m_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Screen& the()
|
|
||||||
{
|
|
||||||
return s_the;
|
|
||||||
}
|
|
||||||
|
|
||||||
void sync();
|
void sync();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ui::Canvas m_canvas;
|
ui::Canvas m_canvas;
|
||||||
int m_size;
|
int m_size;
|
||||||
|
|
||||||
static Screen s_the;
|
|
||||||
};
|
};
|
||||||
|
@ -41,15 +41,14 @@ void Window::focus()
|
|||||||
g_windows.append(this);
|
g_windows.append(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Window::Window(ui::Rect r, String&& n, bool d) : surface(r), name(move(n)), decorated(d)
|
Window::Window(ui::Rect r, String&& n) : surface(r), name(move(n))
|
||||||
{
|
{
|
||||||
auto font = ui::Font::default_font();
|
auto font = ui::Font::default_font();
|
||||||
if (decorated && surface.width < 36) surface.width = 36;
|
if (surface.width < 36) surface.width = 36;
|
||||||
if (decorated && surface.height < (font->height() + 20)) surface.height = font->height() + 20;
|
if (surface.height < (font->height() + 20)) surface.height = font->height() + 20;
|
||||||
titlebar = decorated ? ui::Rect { 0, 0, surface.width, font->height() + 20 } : ui::Rect { 0, 0, 0, 0 };
|
titlebar = ui::Rect { 0, 0, surface.width, font->height() + 20 };
|
||||||
close_button = decorated ? ui::Rect { surface.width - 26, 10, 16, 16 } : ui::Rect { 0, 0, 0, 0 };
|
close_button = ui::Rect { surface.width - 26, 10, 16, 16 };
|
||||||
contents = decorated ? ui::Rect { 0, font->height() + 20, surface.width, surface.height - (font->height() + 20) }
|
contents = ui::Rect { 0, font->height() + 20, surface.width, surface.height - (font->height() + 20) };
|
||||||
: ui::Rect { 0, 0, surface.width, surface.height };
|
|
||||||
g_windows.append(this);
|
g_windows.append(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,8 +5,6 @@
|
|||||||
#include <ui/Color.h>
|
#include <ui/Color.h>
|
||||||
#include <ui/Rect.h>
|
#include <ui/Rect.h>
|
||||||
|
|
||||||
struct Client;
|
|
||||||
|
|
||||||
struct Window : public LinkedListNode<Window>
|
struct Window : public LinkedListNode<Window>
|
||||||
{
|
{
|
||||||
ui::Rect surface;
|
ui::Rect surface;
|
||||||
@ -16,13 +14,10 @@ struct Window : public LinkedListNode<Window>
|
|||||||
u32* pixels;
|
u32* pixels;
|
||||||
String name;
|
String name;
|
||||||
bool dirty { false };
|
bool dirty { false };
|
||||||
Client* client;
|
|
||||||
int id;
|
|
||||||
bool decorated;
|
|
||||||
|
|
||||||
static int titlebar_height();
|
static int titlebar_height();
|
||||||
|
|
||||||
Window(ui::Rect, String&&, bool);
|
Window(ui::Rect, String&&);
|
||||||
~Window();
|
~Window();
|
||||||
|
|
||||||
void focus();
|
void focus();
|
||||||
|
@ -49,8 +49,7 @@ Result<int> luna_main(int argc, char** argv)
|
|||||||
keyboard->set_buffer(os::File::NotBuffered);
|
keyboard->set_buffer(os::File::NotBuffered);
|
||||||
keyboard->set_close_on_exec();
|
keyboard->set_close_on_exec();
|
||||||
|
|
||||||
TRY(Screen::open());
|
auto screen = TRY(Screen::open());
|
||||||
auto& screen = Screen::the();
|
|
||||||
|
|
||||||
Mouse mouse_pointer { screen.canvas() };
|
Mouse mouse_pointer { screen.canvas() };
|
||||||
|
|
||||||
@ -129,11 +128,8 @@ Result<int> luna_main(int argc, char** argv)
|
|||||||
client.conn.disconnect();
|
client.conn.disconnect();
|
||||||
for (auto& window : client.windows)
|
for (auto& window : client.windows)
|
||||||
{
|
{
|
||||||
if (window)
|
g_windows.remove(window);
|
||||||
{
|
delete window;
|
||||||
g_windows.remove(window);
|
|
||||||
delete window;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user