Initial commit

This commit is contained in:
2026-02-07 18:32:40 +02:00
commit 219734a813
134 changed files with 20257 additions and 0 deletions

View File

@@ -0,0 +1,18 @@
#pragma once
#include <BAN/Span.h>
#include <BAN/StringView.h>
#include <stddef.h>
namespace LibGUI
{
class MessageBox
{
public:
static BAN::ErrorOr<void> create(BAN::StringView message, BAN::StringView title);
static BAN::ErrorOr<size_t> create(BAN::StringView message, BAN::StringView title, BAN::Span<BAN::StringView> buttons);
};
}

View File

@@ -0,0 +1,381 @@
#pragma once
#include <BAN/String.h>
#include <BAN/StringView.h>
#include <BAN/ByteSpan.h>
#include <LibInput/KeyEvent.h>
#include <LibInput/MouseEvent.h>
#include <cstdint>
#include <sys/socket.h>
#define FOR_EACH_0(macro)
#define FOR_EACH_2(macro, type, name) macro(type, name)
#define FOR_EACH_4(macro, type, name, ...) macro(type, name) FOR_EACH_2(macro, __VA_ARGS__)
#define FOR_EACH_6(macro, type, name, ...) macro(type, name) FOR_EACH_4(macro, __VA_ARGS__)
#define FOR_EACH_8(macro, type, name, ...) macro(type, name) FOR_EACH_6(macro, __VA_ARGS__)
#define CONCATENATE_2(arg1, arg2) arg1 ## arg2
#define CONCATENATE_1(arg1, arg2) CONCATENATE_2(arg1, arg2)
#define CONCATENATE(arg1, arg2) CONCATENATE_1(arg1, arg2)
#define FOR_EACH_NARG(...) FOR_EACH_NARG_(__VA_ARGS__ __VA_OPT__(,) FOR_EACH_RSEQ_N())
#define FOR_EACH_NARG_(...) FOR_EACH_ARG_N(__VA_ARGS__)
#define FOR_EACH_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, N, ...) N
#define FOR_EACH_RSEQ_N() 8, 7, 6, 5, 4, 3, 2, 1, 0
#define FOR_EACH_(N, what, ...) CONCATENATE(FOR_EACH_, N)(what __VA_OPT__(,) __VA_ARGS__)
#define FOR_EACH(what, ...) FOR_EACH_(FOR_EACH_NARG(__VA_ARGS__), what __VA_OPT__(,) __VA_ARGS__)
#define FIELD_DECL(type, name) type name;
#define ADD_SERIALIZED_SIZE(type, name) serialized_size += Serialize::serialized_size_impl<type>(this->name);
#define SEND_SERIALIZED(type, name) TRY(Serialize::send_serialized_impl<type>(socket, this->name));
#define DESERIALIZE(type, name) value.name = TRY(Serialize::deserialize_impl<type>(buffer));
#define DEFINE_PACKET_EXTRA(name, extra, ...) \
struct name \
{ \
static constexpr PacketType type = PacketType::name; \
static constexpr uint32_t type_u32 = static_cast<uint32_t>(type); \
\
extra; \
\
FOR_EACH(FIELD_DECL, __VA_ARGS__) \
\
size_t serialized_size() \
{ \
size_t serialized_size = Serialize::serialized_size_impl<uint32_t>(type_u32); \
FOR_EACH(ADD_SERIALIZED_SIZE, __VA_ARGS__) \
return serialized_size; \
} \
\
BAN::ErrorOr<void> send_serialized(int socket) \
{ \
const uint32_t serialized_size = this->serialized_size(); \
TRY(Serialize::send_serialized_impl<uint32_t>(socket, serialized_size)); \
TRY(Serialize::send_serialized_impl<uint32_t>(socket, type_u32)); \
FOR_EACH(SEND_SERIALIZED, __VA_ARGS__) \
return {}; \
} \
\
static BAN::ErrorOr<name> deserialize(BAN::ConstByteSpan buffer) \
{ \
const uint32_t type_u32 = TRY(Serialize::deserialize_impl<uint32_t>(buffer)); \
if (type_u32 != name::type_u32) \
return BAN::Error::from_errno(EINVAL); \
name value; \
FOR_EACH(DESERIALIZE, __VA_ARGS__) \
return value; \
} \
}
#define DEFINE_PACKET(name, ...) DEFINE_PACKET_EXTRA(name, , __VA_ARGS__)
namespace LibGUI
{
namespace detail
{
template<typename T>
concept Vector = requires {
requires BAN::same_as<T, BAN::Vector<typename T::value_type>>;
};
}
static constexpr BAN::StringView s_window_server_socket = "/tmp/window-server.socket"_sv;
namespace Serialize
{
inline BAN::ErrorOr<void> send_raw_data(int socket, BAN::ConstByteSpan data)
{
size_t send_done = 0;
while (send_done < data.size())
{
const ssize_t nsend = ::send(socket, data.data() + send_done, data.size() - send_done, 0);
if (nsend < 0)
return BAN::Error::from_errno(errno);
if (nsend == 0)
return BAN::Error::from_errno(ECONNRESET);
send_done += nsend;
}
return {};
}
template<typename T> requires BAN::is_pod_v<T>
inline size_t serialized_size_impl(const T&)
{
return sizeof(T);
}
template<typename T> requires BAN::is_pod_v<T>
inline BAN::ErrorOr<void> send_serialized_impl(int socket, const T& value)
{
TRY(send_raw_data(socket, BAN::ConstByteSpan::from(value)));
return {};
}
template<typename T> requires BAN::is_pod_v<T>
inline BAN::ErrorOr<T> deserialize_impl(BAN::ConstByteSpan& buffer)
{
if (buffer.size() < sizeof(T))
return BAN::Error::from_errno(ENOBUFS);
const T value = buffer.as<const T>();
buffer = buffer.slice(sizeof(T));
return value;
}
template<typename T> requires BAN::is_same_v<T, BAN::String>
inline size_t serialized_size_impl(const T& value)
{
return sizeof(uint32_t) + value.size();
}
template<typename T> requires BAN::is_same_v<T, BAN::String>
inline BAN::ErrorOr<void> send_serialized_impl(int socket, const T& value)
{
const uint32_t value_size = value.size();
TRY(send_raw_data(socket, BAN::ConstByteSpan::from(value_size)));
auto* u8_data = reinterpret_cast<const uint8_t*>(value.data());
TRY(send_raw_data(socket, BAN::ConstByteSpan(u8_data, value.size())));
return {};
}
template<typename T> requires BAN::is_same_v<T, BAN::String>
inline BAN::ErrorOr<T> deserialize_impl(BAN::ConstByteSpan& buffer)
{
if (buffer.size() < sizeof(uint32_t))
return BAN::Error::from_errno(ENOBUFS);
const uint32_t string_len = buffer.as<const uint32_t>();
buffer = buffer.slice(sizeof(uint32_t));
if (buffer.size() < string_len)
return BAN::Error::from_errno(ENOBUFS);
BAN::String string;
TRY(string.resize(string_len));
memcpy(string.data(), buffer.data(), string_len);
buffer = buffer.slice(string_len);
return string;
}
template<detail::Vector T>
inline size_t serialized_size_impl(const T& vector)
{
size_t result = sizeof(uint32_t);
for (const auto& element : vector)
result += serialized_size_impl(element);
return result;
}
template<detail::Vector T>
inline BAN::ErrorOr<void> send_serialized_impl(int socket, const T& vector)
{
const uint32_t value_size = vector.size();
TRY(send_raw_data(socket, BAN::ConstByteSpan::from(value_size)));
for (const auto& element : vector)
TRY(send_serialized_impl(socket, element));
return {};
}
template<detail::Vector T>
inline BAN::ErrorOr<T> deserialize_impl(BAN::ConstByteSpan& buffer)
{
if (buffer.size() < sizeof(uint32_t))
return BAN::Error::from_errno(ENOBUFS);
const uint32_t vector_size = buffer.as<const uint32_t>();
buffer = buffer.slice(sizeof(uint32_t));
T vector;
TRY(vector.resize(vector_size));
for (auto& element : vector)
element = TRY(deserialize_impl<typename T::value_type>(buffer));
return vector;
}
}
enum class PacketType : uint32_t
{
WindowCreate,
WindowCreateResponse,
WindowInvalidate,
WindowSetPosition,
WindowSetAttributes,
WindowSetMouseRelative,
WindowSetSize,
WindowSetMinSize,
WindowSetMaxSize,
WindowSetFullscreen,
WindowSetTitle,
WindowSetCursor,
DestroyWindowEvent,
CloseWindowEvent,
ResizeWindowEvent,
WindowShownEvent,
WindowFocusEvent,
KeyEvent,
MouseButtonEvent,
MouseMoveEvent,
MouseScrollEvent,
};
namespace WindowPacket
{
struct Attributes
{
bool title_bar;
bool movable;
bool focusable;
bool rounded_corners;
bool alpha_channel;
bool resizable;
bool shown;
bool cursor_visible;
};
DEFINE_PACKET(
WindowCreate,
uint32_t, width,
uint32_t, height,
Attributes, attributes,
BAN::String, title
);
DEFINE_PACKET(
WindowInvalidate,
uint32_t, x,
uint32_t, y,
uint32_t, width,
uint32_t, height
);
DEFINE_PACKET(
WindowSetPosition,
int32_t, x,
int32_t, y
);
DEFINE_PACKET(
WindowSetAttributes,
Attributes, attributes
);
DEFINE_PACKET(
WindowSetMouseRelative,
bool, enabled
);
DEFINE_PACKET(
WindowSetSize,
uint32_t, width,
uint32_t, height
);
DEFINE_PACKET(
WindowSetMinSize,
uint32_t, width,
uint32_t, height
);
DEFINE_PACKET(
WindowSetMaxSize,
uint32_t, width,
uint32_t, height
);
DEFINE_PACKET(
WindowSetFullscreen,
bool, fullscreen
);
DEFINE_PACKET(
WindowSetTitle,
BAN::String, title
);
DEFINE_PACKET(
WindowSetCursor,
uint32_t, width,
uint32_t, height,
BAN::Vector<uint32_t>, pixels
);
}
namespace EventPacket
{
DEFINE_PACKET(
DestroyWindowEvent
);
DEFINE_PACKET(
CloseWindowEvent
);
DEFINE_PACKET(
ResizeWindowEvent,
uint32_t, width,
uint32_t, height,
long, smo_key
);
DEFINE_PACKET_EXTRA(
WindowShownEvent,
struct event_t {
bool shown;
},
event_t, event
);
DEFINE_PACKET_EXTRA(
WindowFocusEvent,
struct event_t {
bool focused;
},
event_t, event
);
DEFINE_PACKET_EXTRA(
KeyEvent,
using event_t = LibInput::KeyEvent,
event_t, event
);
DEFINE_PACKET_EXTRA(
MouseButtonEvent,
struct event_t {
LibInput::MouseButton button;
bool pressed;
int32_t x;
int32_t y;
},
event_t, event
);
DEFINE_PACKET_EXTRA(
MouseMoveEvent,
struct event_t {
int32_t x;
int32_t y;
},
event_t, event
);
DEFINE_PACKET_EXTRA(
MouseScrollEvent,
struct event_t {
int32_t scroll;
},
event_t, event
);
}
}

View File

@@ -0,0 +1,103 @@
#pragma once
#include <BAN/StringView.h>
#include <cstdint>
#include <stdint.h>
namespace LibFont { class Font; }
namespace LibGUI
{
class Texture
{
public:
static constexpr uint32_t color_invisible = 0x69000000;
public:
static BAN::ErrorOr<Texture> create(uint32_t width, uint32_t height, uint32_t color);
Texture() = default;
BAN::ErrorOr<void> resize(uint32_t width, uint32_t height);
void set_pixel(uint32_t x, uint32_t y, uint32_t color)
{
ASSERT(x < m_width);
ASSERT(y < m_height);
if (x < m_clip_x || x >= m_clip_x + m_clip_w)
return;
if (y < m_clip_y || y >= m_clip_y + m_clip_h)
return;
m_pixels[y * m_width + x] = color;
}
uint32_t get_pixel(uint32_t x, uint32_t y) const
{
ASSERT(x < m_width);
ASSERT(y < m_height);
return m_pixels[y * m_width + x];
}
BAN::Span<uint32_t> pixels() { return m_pixels.span(); }
BAN::Span<const uint32_t> pixels() const { return m_pixels.span(); }
void set_clip_area(int32_t x, int32_t y, uint32_t width, uint32_t height);
void fill_rect(int32_t x, int32_t y, uint32_t width, uint32_t height, uint32_t color);
void fill(uint32_t color) { return fill_rect(0, 0, width(), height(), color); }
void clear_rect(int32_t x, int32_t y, uint32_t width, uint32_t height) { fill_rect(x, y, width, height, m_bg_color); }
void clear() { return clear_rect(0, 0, width(), height()); }
void copy_texture(const Texture& texture, int32_t x, int32_t y, uint32_t sub_x = 0, uint32_t sub_y = 0, uint32_t width = -1, uint32_t height = -1);
void draw_character(uint32_t codepoint, const LibFont::Font& font, int32_t x, int32_t y, uint32_t color);
void draw_text(BAN::StringView text, const LibFont::Font& font, int32_t x, int32_t y, uint32_t color);
// shift whole vertically by amount pixels, sign determines the direction
void shift_vertical(int32_t amount);
// copy horizontal slice [src_y, src_y + amount[ to [dst_y, dst_y + amount[
void copy_horizontal_slice(int32_t dst_y, int32_t src_y, uint32_t amount);
// copy rect (src_x, src_y, width, height) to (dst_x, dst_y, width, height)
void copy_rect(int32_t dst_x, int32_t dst_y, int32_t src_x, int32_t src_y, uint32_t width, uint32_t height);
uint32_t width() const { return m_width; }
uint32_t height() const { return m_height; }
// used on resize to fill empty space
void set_bg_color(uint32_t bg_color) { m_bg_color = bg_color; }
private:
Texture(BAN::Vector<uint32_t>&& pixels, uint32_t width, uint32_t height, uint32_t color)
: m_pixels(BAN::move(pixels))
, m_width(width)
, m_height(height)
, m_bg_color(color)
, m_clip_x(0)
, m_clip_y(0)
, m_clip_w(width)
, m_clip_h(height)
{}
bool clamp_to_texture(int32_t& x, int32_t& y, uint32_t& width, uint32_t& height) const;
bool clamp_to_texture(int32_t& dst_x, int32_t& dst_y, int32_t& src_x, int32_t& src_y, uint32_t& width, uint32_t& height, const Texture&) const;
private:
BAN::Vector<uint32_t> m_pixels;
uint32_t m_width { 0 };
uint32_t m_height { 0 };
uint32_t m_bg_color { 0xFFFFFFFF };
uint32_t m_clip_x { 0 };
uint32_t m_clip_y { 0 };
uint32_t m_clip_w { 0 };
uint32_t m_clip_h { 0 };
bool m_has_set_clip { false };
friend class Window;
};
}

View File

@@ -0,0 +1,54 @@
#pragma once
#include <BAN/Function.h>
#include <BAN/StringView.h>
#include <LibGUI/Widget/RoundedWidget.h>
namespace LibGUI::Widget
{
class Button : public RoundedWidget
{
public:
struct Style : RoundedWidget::Style
{
Style()
: RoundedWidget::Style()
, color_hovered(0x808080)
, color_text(0x000000)
{}
uint32_t color_hovered;
uint32_t color_text;
};
public:
static BAN::ErrorOr<BAN::RefPtr<Button>> create(BAN::RefPtr<Widget> parent, BAN::StringView text, Rectangle geometry = {});
BAN::ErrorOr<void> set_text(BAN::StringView);
Style& style() { return m_style; }
const Style& style() const { return m_style; }
void set_click_callback(BAN::Function<void()> callback) { m_click_callback = callback; }
protected:
Button(BAN::RefPtr<Widget> parent, Rectangle area)
: RoundedWidget(parent, area)
{ }
void update_impl() override;
void show_impl() override;
bool on_mouse_button_impl(LibGUI::EventPacket::MouseButtonEvent::event_t) override;
private:
Style m_style;
bool m_hover_state { false };
BAN::String m_text;
BAN::Function<void()> m_click_callback;
};
}

View File

@@ -0,0 +1,42 @@
#pragma once
#include <LibGUI/Widget/Widget.h>
namespace LibGUI::Widget
{
class Grid : public Widget
{
public:
static BAN::ErrorOr<BAN::RefPtr<Grid>> create(BAN::RefPtr<Widget> parent, uint32_t cols, uint32_t rows, uint32_t color = color_invisible, Rectangle geometry = {});
BAN::ErrorOr<void> set_widget_position(BAN::RefPtr<Widget> widget, uint32_t col, uint32_t col_span, uint32_t row, uint32_t row_span);
protected:
Grid(BAN::RefPtr<Widget> parent, Rectangle geometry, uint32_t cols, uint32_t rows)
: Widget(parent, geometry)
, m_cols(cols)
, m_rows(rows)
{ }
BAN::ErrorOr<void> update_geometry_impl() override;
private:
struct GridElement
{
BAN::RefPtr<Widget> widget;
uint32_t col;
uint32_t col_span;
uint32_t row;
uint32_t row_span;
};
Rectangle grid_element_area(const GridElement& element) const;
private:
const uint32_t m_cols;
const uint32_t m_rows;
BAN::Vector<GridElement> m_grid_elements;
};
}

View File

@@ -0,0 +1,44 @@
#pragma once
#include <BAN/StringView.h>
#include <LibGUI/Widget/RoundedWidget.h>
namespace LibGUI::Widget
{
class Label : public RoundedWidget
{
public:
struct Style : RoundedWidget::Style
{
Style()
: RoundedWidget::Style()
, color_text(0x000000)
{}
uint32_t color_text;
};
public:
static BAN::ErrorOr<BAN::RefPtr<Label>> create(BAN::RefPtr<Widget> parent, BAN::StringView text, Rectangle geometry = {});
BAN::StringView text() const { return m_text; }
BAN::ErrorOr<void> set_text(BAN::StringView);
Style& style() { return m_style; }
const Style& style() const { return m_style; }
protected:
Label(BAN::RefPtr<Widget> parent, Rectangle area)
: RoundedWidget(parent, area)
{ }
void show_impl() override;
private:
Style m_style;
BAN::String m_text;
};
}

View File

@@ -0,0 +1,42 @@
#pragma once
#include <LibGUI/Widget/Widget.h>
namespace LibGUI::Widget
{
class RoundedWidget : public Widget
{
public:
struct Style
{
Style(uint32_t color_normal = 0xA0A0A0, uint32_t border_width = 1, uint32_t color_border = 0x000000, uint32_t corner_radius = 5)
: color_normal(color_normal)
, border_width(border_width)
, color_border(color_border)
, corner_radius(corner_radius)
{}
uint32_t color_normal;
uint32_t border_width;
uint32_t color_border;
uint32_t corner_radius;
};
Style& style() { return m_style; }
const Style& style() const { return m_style; }
protected:
RoundedWidget(BAN::RefPtr<Widget> parent, Rectangle area)
: Widget(parent, area)
{ }
bool contains(Point point) const override;
void show_impl() override;
private:
Style m_style;
};
}

View File

@@ -0,0 +1,50 @@
#pragma once
#include <BAN/StringView.h>
#include <LibGUI/Widget/RoundedWidget.h>
namespace LibGUI::Widget
{
class TextArea : public RoundedWidget
{
public:
struct Style : RoundedWidget::Style
{
Style()
: RoundedWidget::Style()
, color_text(0x000000)
{}
uint32_t color_text;
};
public:
static BAN::ErrorOr<BAN::RefPtr<TextArea>> create(BAN::RefPtr<Widget> parent, BAN::StringView text, Rectangle geometry = {});
BAN::StringView text() const { return m_text; }
BAN::ErrorOr<void> set_text(BAN::StringView);
uint32_t get_required_height() const;
Style& style() { return m_style; }
const Style& style() const { return m_style; }
protected:
TextArea(BAN::RefPtr<Widget> parent, Rectangle area)
: RoundedWidget(parent, area)
{ }
BAN::ErrorOr<void> wrap_text();
BAN::ErrorOr<void> update_geometry_impl() override;
void show_impl() override;
private:
Style m_style;
BAN::String m_text;
BAN::Vector<BAN::String> m_wrapped_text;
};
}

View File

@@ -0,0 +1,163 @@
#pragma once
#include <BAN/RefPtr.h>
#include <LibGUI/Texture.h>
#include <LibGUI/Packet.h>
namespace LibGUI { class Window; }
namespace LibGUI::Widget
{
class Widget : public BAN::RefCounted<Widget>
{
public:
static constexpr uint32_t color_invisible = Texture::color_invisible;
struct Point
{
int32_t x, y;
};
struct FloatRectangle
{
float x, y;
float w, h;
};
struct Rectangle
{
int32_t x, y;
uint32_t w, h;
struct Bounds
{
int32_t min_x, min_y;
int32_t max_x, max_y;
};
bool contains(Point point) const
{
if (point.x < x || point.x >= x + static_cast<int32_t>(w))
return false;
if (point.y < y || point.y >= y + static_cast<int32_t>(h))
return false;
return true;
}
Bounds bounds(Rectangle other) const
{
return Bounds {
.min_x = BAN::Math::max(x, other.x),
.min_y = BAN::Math::max(y, other.y),
.max_x = BAN::Math::min(x + static_cast<int32_t>(w), other.x + static_cast<int32_t>(other.w)),
.max_y = BAN::Math::min(y + static_cast<int32_t>(h), other.y + static_cast<int32_t>(other.h)),
};
};
Rectangle overlap(Rectangle other) const
{
const auto min_x = BAN::Math::max(x, other.x);
const auto min_y = BAN::Math::max(y, other.y);
const auto max_x = BAN::Math::min(x + static_cast<int32_t>(w), other.x + static_cast<int32_t>(other.w));
const auto max_y = BAN::Math::min(y + static_cast<int32_t>(h), other.y + static_cast<int32_t>(other.h));
if (min_x >= max_x || min_y >= max_y)
return {};
return Rectangle {
.x = min_x,
.y = min_y,
.w = static_cast<uint32_t>(max_x - min_x),
.h = static_cast<uint32_t>(max_y - min_y),
};
}
Rectangle bounding_box(Rectangle other) const
{
if (w == 0 || h == 0)
return other;
if (other.w == 0 || other.h == 0)
return *this;
const auto min_x = BAN::Math::min(x, other.x);
const auto min_y = BAN::Math::min(y, other.y);
const auto max_x = BAN::Math::max(x + static_cast<int32_t>(w), other.x + static_cast<int32_t>(other.w));
const auto max_y = BAN::Math::max(y + static_cast<int32_t>(h), other.y + static_cast<int32_t>(other.h));
return Rectangle {
.x = min_x,
.y = min_y,
.w = static_cast<uint32_t>(max_x - min_x),
.h = static_cast<uint32_t>(max_y - min_y),
};
}
};
public:
static BAN::ErrorOr<BAN::RefPtr<Widget>> create(BAN::RefPtr<Widget> parent, uint32_t color = color_invisible, Rectangle geometry = {});
static BAN::ErrorOr<void> set_default_font(BAN::StringView path);
static const LibFont::Font& default_font();
void show();
void hide();
BAN::ErrorOr<void> set_fixed_geometry(Rectangle);
BAN::ErrorOr<void> set_relative_geometry(FloatRectangle);
BAN::RefPtr<Widget> parent() { return m_parent; }
uint32_t width() const { return m_fixed_area.w; }
uint32_t height() const { return m_fixed_area.h; }
private:
void before_mouse_move();
void after_mouse_move();
bool on_mouse_move(LibGUI::EventPacket::MouseMoveEvent::event_t);
bool on_mouse_button(LibGUI::EventPacket::MouseButtonEvent::event_t);
protected:
Widget(BAN::RefPtr<Widget> parent, Rectangle area)
: m_parent(parent)
, m_fixed_area(area)
{ }
BAN::ErrorOr<void> initialize(uint32_t color);
virtual bool contains(Point point) const { return Rectangle { 0, 0, width(), height() }.contains(point); }
bool is_hovered() const { return m_hovered; }
bool is_child_hovered() const;
bool is_shown() const { return m_shown; }
Rectangle render(Texture& output, Point parent_position, Rectangle out_area);
virtual void update_impl() {}
virtual void show_impl() {}
virtual BAN::ErrorOr<void> update_geometry_impl();
virtual void on_hover_change_impl(bool hovered) { (void)hovered; }
virtual bool on_mouse_move_impl(LibGUI::EventPacket::MouseMoveEvent::event_t) { return true; }
virtual bool on_mouse_button_impl(LibGUI::EventPacket::MouseButtonEvent::event_t) { return true; }
protected:
Texture m_texture;
private:
BAN::RefPtr<Widget> m_parent;
BAN::Vector<BAN::RefPtr<Widget>> m_children;
bool m_shown { false };
Rectangle m_fixed_area;
BAN::Optional<FloatRectangle> m_relative_area;
bool m_changed { false };
bool m_hovered { false };
bool m_old_hovered { false };
friend class LibGUI::Window;
};
}

View File

@@ -0,0 +1,123 @@
#pragma once
#include <BAN/Function.h>
#include <BAN/StringView.h>
#include <BAN/UniqPtr.h>
#include <LibGUI/Packet.h>
#include <LibGUI/Texture.h>
#include <LibGUI/Widget/Widget.h>
namespace LibFont { class Font; }
namespace LibGUI
{
class Window
{
public:
using Attributes = WindowPacket::Attributes;
static constexpr Attributes default_attributes = {
.title_bar = true,
.movable = true,
.focusable = true,
.rounded_corners = true,
.alpha_channel = false,
.resizable = false,
.shown = true,
.cursor_visible = true,
};
public:
~Window();
static BAN::ErrorOr<BAN::UniqPtr<Window>> create(uint32_t width, uint32_t height, BAN::StringView title, Attributes attributes = default_attributes);
BAN::ErrorOr<void> set_root_widget(BAN::RefPtr<Widget::Widget> widget);
BAN::RefPtr<Widget::Widget> root_widget() { return m_root_widget; }
Texture& texture() { return m_texture; }
const Texture& texture() const { return m_texture; }
void invalidate(int32_t x, int32_t y, uint32_t width, uint32_t height);
void invalidate() { return invalidate(0, 0, width(), height()); }
void set_mouse_relative(bool enabled);
void set_fullscreen(bool fullscreen);
void set_title(BAN::StringView title);
void set_position(int32_t x, int32_t y);
void set_cursor_visible(bool visible);
void set_cursor(uint32_t width, uint32_t height, BAN::Span<uint32_t> pixels);
Attributes get_attributes() const { return m_attributes; }
void set_attributes(Attributes attributes);
void set_min_size(uint32_t width, uint32_t height);
void set_max_size(uint32_t width, uint32_t height);
// send resize request to window server
// actual resize is only done after resize callback is called
void request_resize(uint32_t width, uint32_t height);
uint32_t width() const { return m_width; }
uint32_t height() const { return m_height; }
void wait_events();
void poll_events();
void set_socket_error_callback(BAN::Function<void()> callback) { m_socket_error_callback = callback; }
void set_close_window_event_callback(BAN::Function<void()> callback) { m_close_window_event_callback = callback; }
void set_resize_window_event_callback(BAN::Function<void()> callback) { m_resize_window_event_callback = callback; }
void set_key_event_callback(BAN::Function<void(EventPacket::KeyEvent::event_t)> callback) { m_key_event_callback = callback; }
void set_mouse_button_event_callback(BAN::Function<void(EventPacket::MouseButtonEvent::event_t)> callback) { m_mouse_button_event_callback = callback; }
void set_mouse_move_event_callback(BAN::Function<void(EventPacket::MouseMoveEvent::event_t)> callback) { m_mouse_move_event_callback = callback; }
void set_mouse_scroll_event_callback(BAN::Function<void(EventPacket::MouseScrollEvent::event_t)> callback) { m_mouse_scroll_event_callback = callback; }
void set_window_shown_event_callback(BAN::Function<void(EventPacket::WindowShownEvent::event_t)> callback) { m_window_shown_event_callback = callback; }
void set_window_focus_event_callback(BAN::Function<void(EventPacket::WindowFocusEvent::event_t)> callback) { m_window_focus_event_callback = callback; }
int server_fd() const { return m_server_fd; }
private:
Window(int server_fd, int epoll_fd, Attributes attributes)
: m_server_fd(server_fd)
, m_epoll_fd(epoll_fd)
, m_attributes(attributes)
{ }
void on_socket_error(BAN::StringView function);
void cleanup();
BAN::ErrorOr<void> handle_resize_event(const EventPacket::ResizeWindowEvent&);
private:
const int m_server_fd;
const int m_epoll_fd;
bool m_handling_socket_error { false };
Attributes m_attributes;
uint32_t* m_framebuffer_smo { nullptr };
uint32_t m_width { 0 };
uint32_t m_height { 0 };
Texture m_texture;
BAN::RefPtr<Widget::Widget> m_root_widget;
BAN::Function<void()> m_socket_error_callback;
BAN::Function<void()> m_close_window_event_callback;
BAN::Function<void()> m_resize_window_event_callback;
BAN::Function<void(EventPacket::WindowShownEvent::event_t)> m_window_shown_event_callback;
BAN::Function<void(EventPacket::WindowFocusEvent::event_t)> m_window_focus_event_callback;
BAN::Function<void(EventPacket::KeyEvent::event_t)> m_key_event_callback;
BAN::Function<void(EventPacket::MouseButtonEvent::event_t)> m_mouse_button_event_callback;
BAN::Function<void(EventPacket::MouseMoveEvent::event_t)> m_mouse_move_event_callback;
BAN::Function<void(EventPacket::MouseScrollEvent::event_t)> m_mouse_scroll_event_callback;
friend class BAN::UniqPtr<Window>;
};
}