mirror of
https://github.com/RGBCube/serenity
synced 2025-06-01 10:08:10 +00:00
Move Widget & friends into LibGUI.
This commit is contained in:
parent
7e5b81fe48
commit
a026da47e7
29 changed files with 73 additions and 551 deletions
3
LibGUI/.gitignore
vendored
Normal file
3
LibGUI/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
*.o
|
||||
*.swp
|
||||
test
|
89
LibGUI/Button.cpp
Normal file
89
LibGUI/Button.cpp
Normal file
|
@ -0,0 +1,89 @@
|
|||
#include "Button.h"
|
||||
#include <SharedGraphics/Painter.h>
|
||||
|
||||
Button::Button(Widget* parent)
|
||||
: Widget(parent)
|
||||
{
|
||||
setFillWithBackgroundColor(false);
|
||||
}
|
||||
|
||||
Button::~Button()
|
||||
{
|
||||
}
|
||||
|
||||
void Button::setCaption(String&& caption)
|
||||
{
|
||||
if (caption == m_caption)
|
||||
return;
|
||||
m_caption = move(caption);
|
||||
update();
|
||||
}
|
||||
|
||||
void Button::paintEvent(PaintEvent&)
|
||||
{
|
||||
Color buttonColor = Color::LightGray;
|
||||
Color highlightColor = Color::White;
|
||||
Color shadowColor = Color(96, 96, 96);
|
||||
|
||||
Painter painter(*this);
|
||||
|
||||
painter.draw_line({ 1, 0 }, { width() - 2, 0 }, Color::Black);
|
||||
painter.draw_line({ 1, height() - 1 }, { width() - 2, height() - 1}, Color::Black);
|
||||
painter.draw_line({ 0, 1 }, { 0, height() - 2 }, Color::Black);
|
||||
painter.draw_line({ width() - 1, 1 }, { width() - 1, height() - 2 }, Color::Black);
|
||||
|
||||
if (m_beingPressed) {
|
||||
// Base
|
||||
painter.fill_rect({ 1, 1, width() - 2, height() - 2 }, buttonColor);
|
||||
|
||||
// Sunken shadow
|
||||
painter.draw_line({ 1, 1 }, { width() - 2, 1 }, shadowColor);
|
||||
painter.draw_line({ 1, 2 }, {1, height() - 2 }, shadowColor);
|
||||
} else {
|
||||
// Base
|
||||
painter.fill_rect({ 3, 3, width() - 5, height() - 5 }, buttonColor);
|
||||
|
||||
// White highlight
|
||||
painter.draw_line({ 1, 1 }, { width() - 2, 1 }, highlightColor);
|
||||
painter.draw_line({ 1, 2 }, { width() - 3, 2 }, highlightColor);
|
||||
painter.draw_line({ 1, 3 }, { 1, height() - 2 }, highlightColor);
|
||||
painter.draw_line({ 2, 3 }, { 2, height() - 3 }, highlightColor);
|
||||
|
||||
// Gray shadow
|
||||
painter.draw_line({ width() - 2, 1 }, { width() - 2, height() - 4 }, shadowColor);
|
||||
painter.draw_line({ width() - 3, 2 }, { width() - 3, height() - 4 }, shadowColor);
|
||||
painter.draw_line({ 1, height() - 2 }, { width() - 2, height() - 2 }, shadowColor);
|
||||
painter.draw_line({ 2, height() - 3 }, { width() - 2, height() - 3 }, shadowColor);
|
||||
}
|
||||
|
||||
if (!caption().is_empty()) {
|
||||
auto textRect = rect();
|
||||
if (m_beingPressed)
|
||||
textRect.move_by(1, 1);
|
||||
painter.draw_text(textRect, caption(), Painter::TextAlignment::Center, Color::Black);
|
||||
}
|
||||
}
|
||||
|
||||
void Button::mouseDownEvent(MouseEvent& event)
|
||||
{
|
||||
dbgprintf("Button::mouseDownEvent: x=%d, y=%d, button=%u\n", event.x(), event.y(), (unsigned)event.button());
|
||||
|
||||
m_beingPressed = true;
|
||||
|
||||
update();
|
||||
Widget::mouseDownEvent(event);
|
||||
}
|
||||
|
||||
void Button::mouseUpEvent(MouseEvent& event)
|
||||
{
|
||||
dbgprintf("Button::mouseUpEvent: x=%d, y=%d, button=%u\n", event.x(), event.y(), (unsigned)event.button());
|
||||
|
||||
m_beingPressed = false;
|
||||
|
||||
update();
|
||||
Widget::mouseUpEvent(event);
|
||||
|
||||
if (onClick)
|
||||
onClick(*this);
|
||||
}
|
||||
|
27
LibGUI/Button.h
Normal file
27
LibGUI/Button.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
#pragma once
|
||||
|
||||
#include "Widget.h"
|
||||
#include <AK/AKString.h>
|
||||
#include <AK/Function.h>
|
||||
|
||||
class Button final : public Widget {
|
||||
public:
|
||||
explicit Button(Widget* parent);
|
||||
virtual ~Button() override;
|
||||
|
||||
String caption() const { return m_caption; }
|
||||
void setCaption(String&&);
|
||||
|
||||
Function<void(Button&)> onClick;
|
||||
|
||||
private:
|
||||
virtual void paintEvent(PaintEvent&) override;
|
||||
virtual void mouseDownEvent(MouseEvent&) override;
|
||||
virtual void mouseUpEvent(MouseEvent&) override;
|
||||
|
||||
virtual const char* class_name() const override { return "Button"; }
|
||||
|
||||
String m_caption;
|
||||
bool m_beingPressed { false };
|
||||
};
|
||||
|
102
LibGUI/CheckBox.cpp
Normal file
102
LibGUI/CheckBox.cpp
Normal file
|
@ -0,0 +1,102 @@
|
|||
#include "CheckBox.h"
|
||||
#include <SharedGraphics/Painter.h>
|
||||
#include <SharedGraphics/CharacterBitmap.h>
|
||||
|
||||
CheckBox::CheckBox(Widget* parent)
|
||||
: Widget(parent)
|
||||
{
|
||||
}
|
||||
|
||||
CheckBox::~CheckBox()
|
||||
{
|
||||
}
|
||||
|
||||
void CheckBox::setCaption(String&& caption)
|
||||
{
|
||||
if (caption == m_caption)
|
||||
return;
|
||||
m_caption = move(caption);
|
||||
update();
|
||||
}
|
||||
|
||||
void CheckBox::setIsChecked(bool b)
|
||||
{
|
||||
if (m_isChecked == b)
|
||||
return;
|
||||
m_isChecked = b;
|
||||
update();
|
||||
}
|
||||
|
||||
static const char* uncheckedBitmap = {
|
||||
"###########"
|
||||
"# #"
|
||||
"# #"
|
||||
"# #"
|
||||
"# #"
|
||||
"# #"
|
||||
"# #"
|
||||
"# #"
|
||||
"# #"
|
||||
"# #"
|
||||
"###########"
|
||||
};
|
||||
|
||||
#if 0
|
||||
static const char* checkedBitmap = {
|
||||
"############"
|
||||
"# #"
|
||||
"# ## #"
|
||||
"# ## #"
|
||||
"# ## #"
|
||||
"# ## #"
|
||||
"# ## #"
|
||||
"# ## ## #"
|
||||
"# ## ## #"
|
||||
"# ### #"
|
||||
"# #"
|
||||
"############"
|
||||
};
|
||||
#endif
|
||||
|
||||
static const char* checkedBitmap = {
|
||||
"###########"
|
||||
"## ##"
|
||||
"# # # #"
|
||||
"# # # #"
|
||||
"# # # #"
|
||||
"# # #"
|
||||
"# # # #"
|
||||
"# # # #"
|
||||
"# # # #"
|
||||
"## ##"
|
||||
"###########"
|
||||
};
|
||||
|
||||
void CheckBox::paintEvent(PaintEvent&)
|
||||
{
|
||||
Painter painter(*this);
|
||||
auto bitmap = CharacterBitmap::create_from_ascii(isChecked() ? checkedBitmap : uncheckedBitmap, 11, 11);
|
||||
|
||||
auto textRect = rect();
|
||||
textRect.set_left(bitmap->width() + 4);
|
||||
textRect.set_top(height() / 2 - font().glyph_height() / 2);
|
||||
|
||||
Point bitmapPosition;
|
||||
bitmapPosition.set_x(2);
|
||||
bitmapPosition.set_y(height() / 2 - bitmap->height() / 2 - 1);
|
||||
|
||||
painter.fill_rect(rect(), backgroundColor());
|
||||
painter.draw_bitmap(bitmapPosition, *bitmap, foregroundColor());
|
||||
|
||||
if (!caption().is_empty()) {
|
||||
painter.draw_text(textRect, caption(), Painter::TextAlignment::TopLeft, foregroundColor());
|
||||
}
|
||||
}
|
||||
|
||||
void CheckBox::mouseDownEvent(MouseEvent& event)
|
||||
{
|
||||
dbgprintf("CheckBox::mouseDownEvent: x=%d, y=%d, button=%u\n", event.x(), event.y(), (unsigned)event.button());
|
||||
|
||||
setIsChecked(!isChecked());
|
||||
}
|
||||
|
26
LibGUI/CheckBox.h
Normal file
26
LibGUI/CheckBox.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
#pragma once
|
||||
|
||||
#include "Widget.h"
|
||||
#include <AK/AKString.h>
|
||||
|
||||
class CheckBox final : public Widget {
|
||||
public:
|
||||
explicit CheckBox(Widget* parent);
|
||||
virtual ~CheckBox() override;
|
||||
|
||||
String caption() const { return m_caption; }
|
||||
void setCaption(String&&);
|
||||
|
||||
bool isChecked() const { return m_isChecked; }
|
||||
void setIsChecked(bool);
|
||||
|
||||
private:
|
||||
virtual void paintEvent(PaintEvent&) override;
|
||||
virtual void mouseDownEvent(MouseEvent&) override;
|
||||
|
||||
virtual const char* class_name() const override { return "CheckBox"; }
|
||||
|
||||
String m_caption;
|
||||
bool m_isChecked { false };
|
||||
};
|
||||
|
37
LibGUI/ClockWidget.cpp
Normal file
37
LibGUI/ClockWidget.cpp
Normal file
|
@ -0,0 +1,37 @@
|
|||
#include "ClockWidget.h"
|
||||
#include "Painter.h"
|
||||
#include <time.h>
|
||||
|
||||
ClockWidget::ClockWidget(Widget* parent)
|
||||
: Widget(parent)
|
||||
{
|
||||
setWindowRelativeRect({ 0, 0, 100, 40 });
|
||||
startTimer(250);
|
||||
}
|
||||
|
||||
ClockWidget::~ClockWidget()
|
||||
{
|
||||
}
|
||||
|
||||
void ClockWidget::paintEvent(PaintEvent&)
|
||||
{
|
||||
auto now = time(nullptr);
|
||||
auto& tm = *localtime(&now);
|
||||
|
||||
char timeBuf[128];
|
||||
sprintf(timeBuf, "%02u:%02u:%02u ", tm.tm_hour, tm.tm_min, tm.tm_sec);
|
||||
|
||||
Painter painter(*this);
|
||||
painter.fill_rect(rect(), Color::MidGray);
|
||||
painter.draw_text(rect(), timeBuf, Painter::TextAlignment::Center, Color::Black);
|
||||
}
|
||||
|
||||
void ClockWidget::timerEvent(TimerEvent&)
|
||||
{
|
||||
auto now = time(nullptr);
|
||||
if (now == m_lastSeenTimestamp)
|
||||
return;
|
||||
m_lastSeenTimestamp = now;
|
||||
update();
|
||||
}
|
||||
|
16
LibGUI/ClockWidget.h
Normal file
16
LibGUI/ClockWidget.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
#pragma once
|
||||
|
||||
#include "Widget.h"
|
||||
|
||||
class ClockWidget final : public Widget {
|
||||
public:
|
||||
explicit ClockWidget(Widget* parent = nullptr);
|
||||
virtual ~ClockWidget() override;
|
||||
|
||||
private:
|
||||
virtual void paintEvent(PaintEvent&) override;
|
||||
virtual void timerEvent(TimerEvent&) override;
|
||||
|
||||
dword m_lastSeenTimestamp { 0 };
|
||||
};
|
||||
|
170
LibGUI/Event.h
Normal file
170
LibGUI/Event.h
Normal file
|
@ -0,0 +1,170 @@
|
|||
#pragma once
|
||||
|
||||
#include <SharedGraphics/Point.h>
|
||||
#include <SharedGraphics/Rect.h>
|
||||
#include <AK/AKString.h>
|
||||
#include <AK/Types.h>
|
||||
|
||||
static const char* eventNames[] = {
|
||||
"Invalid",
|
||||
"Quit",
|
||||
"Show",
|
||||
"Hide",
|
||||
"Paint",
|
||||
"MouseMove",
|
||||
"MouseDown",
|
||||
"MouseUp",
|
||||
"KeyDown",
|
||||
"KeyUp",
|
||||
"Timer",
|
||||
"DeferredDestroy",
|
||||
};
|
||||
|
||||
class Event {
|
||||
public:
|
||||
enum Type {
|
||||
Invalid = 0,
|
||||
Quit,
|
||||
Show,
|
||||
Hide,
|
||||
Paint,
|
||||
MouseMove,
|
||||
MouseDown,
|
||||
MouseUp,
|
||||
KeyDown,
|
||||
KeyUp,
|
||||
Timer,
|
||||
DeferredDestroy,
|
||||
WindowBecameInactive,
|
||||
WindowBecameActive,
|
||||
WM_Compose,
|
||||
};
|
||||
|
||||
Event() { }
|
||||
explicit Event(Type type) : m_type(type) { }
|
||||
virtual ~Event() { }
|
||||
|
||||
Type type() const { return m_type; }
|
||||
|
||||
const char* name() const { return eventNames[(unsigned)m_type]; }
|
||||
|
||||
bool isMouseEvent() const { return m_type == MouseMove || m_type == MouseDown || m_type == MouseUp; }
|
||||
bool isKeyEvent() const { return m_type == KeyUp || m_type == KeyDown; }
|
||||
bool isPaintEvent() const { return m_type == Paint; }
|
||||
|
||||
private:
|
||||
Type m_type { Invalid };
|
||||
};
|
||||
|
||||
class DeferredDestroyEvent final : public Event {
|
||||
public:
|
||||
DeferredDestroyEvent()
|
||||
: Event(Event::DeferredDestroy)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class QuitEvent final : public Event {
|
||||
public:
|
||||
QuitEvent()
|
||||
: Event(Event::Quit)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class PaintEvent final : public Event {
|
||||
public:
|
||||
explicit PaintEvent(const Rect& rect = Rect())
|
||||
: Event(Event::Paint)
|
||||
, m_rect(rect)
|
||||
{
|
||||
}
|
||||
|
||||
const Rect& rect() const { return m_rect; }
|
||||
private:
|
||||
friend class WindowManager;
|
||||
Rect m_rect;
|
||||
};
|
||||
|
||||
class ShowEvent final : public Event {
|
||||
public:
|
||||
ShowEvent()
|
||||
: Event(Event::Show)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class HideEvent final : public Event {
|
||||
public:
|
||||
HideEvent()
|
||||
: Event(Event::Hide)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
enum class MouseButton : byte {
|
||||
None = 0,
|
||||
Left,
|
||||
Middle,
|
||||
Right,
|
||||
};
|
||||
|
||||
enum KeyboardKey {
|
||||
Invalid,
|
||||
LeftArrow,
|
||||
RightArrow,
|
||||
UpArrow,
|
||||
DownArrow,
|
||||
Backspace,
|
||||
Return,
|
||||
};
|
||||
|
||||
class KeyEvent final : public Event {
|
||||
public:
|
||||
KeyEvent(Type type, int key)
|
||||
: Event(type)
|
||||
, m_key(key)
|
||||
{
|
||||
}
|
||||
|
||||
int key() const { return m_key; }
|
||||
bool ctrl() const { return m_ctrl; }
|
||||
bool alt() const { return m_alt; }
|
||||
bool shift() const { return m_shift; }
|
||||
String text() const { return m_text; }
|
||||
|
||||
private:
|
||||
friend class EventLoop;
|
||||
friend class AbstractScreen;
|
||||
int m_key { 0 };
|
||||
bool m_ctrl { false };
|
||||
bool m_alt { false };
|
||||
bool m_shift { false };
|
||||
String m_text;
|
||||
};
|
||||
|
||||
class MouseEvent final : public Event {
|
||||
public:
|
||||
MouseEvent(Type type, int x, int y, MouseButton button = MouseButton::None)
|
||||
: Event(type)
|
||||
, m_position(x, y)
|
||||
, m_button(button)
|
||||
{
|
||||
}
|
||||
|
||||
Point position() const { return m_position; }
|
||||
int x() const { return m_position.x(); }
|
||||
int y() const { return m_position.y(); }
|
||||
MouseButton button() const { return m_button; }
|
||||
|
||||
private:
|
||||
Point m_position;
|
||||
MouseButton m_button { MouseButton::None };
|
||||
};
|
||||
|
||||
class TimerEvent final : public Event {
|
||||
public:
|
||||
TimerEvent() : Event(Event::Timer) { }
|
||||
~TimerEvent() { }
|
||||
};
|
||||
|
67
LibGUI/EventLoop.cpp
Normal file
67
LibGUI/EventLoop.cpp
Normal file
|
@ -0,0 +1,67 @@
|
|||
#include "EventLoop.h"
|
||||
#include "Event.h"
|
||||
#include "Object.h"
|
||||
|
||||
static EventLoop* s_mainEventLoop;
|
||||
|
||||
void EventLoop::initialize()
|
||||
{
|
||||
s_mainEventLoop = nullptr;
|
||||
}
|
||||
|
||||
EventLoop::EventLoop()
|
||||
{
|
||||
if (!s_mainEventLoop)
|
||||
s_mainEventLoop = this;
|
||||
}
|
||||
|
||||
EventLoop::~EventLoop()
|
||||
{
|
||||
}
|
||||
|
||||
EventLoop& EventLoop::main()
|
||||
{
|
||||
ASSERT(s_mainEventLoop);
|
||||
return *s_mainEventLoop;
|
||||
}
|
||||
|
||||
int EventLoop::exec()
|
||||
{
|
||||
m_running = true;
|
||||
for (;;) {
|
||||
if (m_queuedEvents.is_empty())
|
||||
waitForEvent();
|
||||
Vector<QueuedEvent> events;
|
||||
{
|
||||
events = move(m_queuedEvents);
|
||||
}
|
||||
for (auto& queuedEvent : events) {
|
||||
auto* receiver = queuedEvent.receiver;
|
||||
auto& event = *queuedEvent.event;
|
||||
//printf("EventLoop: Object{%p} event %u (%s)\n", receiver, (unsigned)event.type(), event.name());
|
||||
if (!receiver) {
|
||||
switch (event.type()) {
|
||||
case Event::Quit:
|
||||
ASSERT_NOT_REACHED();
|
||||
return 0;
|
||||
default:
|
||||
dbgprintf("event type %u with no receiver :(\n", event.type());
|
||||
ASSERT_NOT_REACHED();
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
receiver->event(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EventLoop::postEvent(Object* receiver, OwnPtr<Event>&& event)
|
||||
{
|
||||
//printf("EventLoop::postEvent: {%u} << receiver=%p, event=%p\n", m_queuedEvents.size(), receiver, event.ptr());
|
||||
m_queuedEvents.append({ receiver, move(event) });
|
||||
}
|
||||
|
||||
void EventLoop::waitForEvent()
|
||||
{
|
||||
}
|
37
LibGUI/EventLoop.h
Normal file
37
LibGUI/EventLoop.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
#pragma once
|
||||
|
||||
#include "Event.h"
|
||||
#include <AK/OwnPtr.h>
|
||||
#include <AK/Vector.h>
|
||||
|
||||
class Object;
|
||||
class Process;
|
||||
|
||||
class EventLoop {
|
||||
public:
|
||||
EventLoop();
|
||||
~EventLoop();
|
||||
|
||||
int exec();
|
||||
|
||||
void postEvent(Object* receiver, OwnPtr<Event>&&);
|
||||
|
||||
static EventLoop& main();
|
||||
|
||||
static void initialize();
|
||||
|
||||
bool running() const { return m_running; }
|
||||
Process& server_process() { return *m_server_process; }
|
||||
|
||||
private:
|
||||
void waitForEvent();
|
||||
|
||||
struct QueuedEvent {
|
||||
Object* receiver { nullptr };
|
||||
OwnPtr<Event> event;
|
||||
};
|
||||
Vector<QueuedEvent> m_queuedEvents;
|
||||
|
||||
Process* m_server_process { nullptr };
|
||||
bool m_running { false };
|
||||
};
|
35
LibGUI/Label.cpp
Normal file
35
LibGUI/Label.cpp
Normal file
|
@ -0,0 +1,35 @@
|
|||
#include "Label.h"
|
||||
#include <SharedGraphics/Painter.h>
|
||||
|
||||
Label::Label(Widget* parent)
|
||||
: Widget(parent)
|
||||
{
|
||||
}
|
||||
|
||||
Label::~Label()
|
||||
{
|
||||
}
|
||||
|
||||
void Label::setText(String&& text)
|
||||
{
|
||||
if (text == m_text)
|
||||
return;
|
||||
m_text = move(text);
|
||||
update();
|
||||
}
|
||||
|
||||
void Label::paintEvent(PaintEvent&)
|
||||
{
|
||||
Painter painter(*this);
|
||||
if (fillWithBackgroundColor())
|
||||
painter.fill_rect({ 0, 0, width(), height() }, backgroundColor());
|
||||
if (!text().is_empty())
|
||||
painter.draw_text({ 4, 4, width(), height() }, text(), Painter::TextAlignment::TopLeft, foregroundColor());
|
||||
}
|
||||
|
||||
void Label::mouseMoveEvent(MouseEvent& event)
|
||||
{
|
||||
dbgprintf("Label::mouseMoveEvent: x=%d, y=%d\n", event.x(), event.y());
|
||||
Widget::mouseMoveEvent(event);
|
||||
}
|
||||
|
22
LibGUI/Label.h
Normal file
22
LibGUI/Label.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
#pragma once
|
||||
|
||||
#include "Widget.h"
|
||||
#include <AK/AKString.h>
|
||||
|
||||
class Label final : public Widget {
|
||||
public:
|
||||
explicit Label(Widget* parent);
|
||||
virtual ~Label() override;
|
||||
|
||||
String text() const { return m_text; }
|
||||
void setText(String&&);
|
||||
|
||||
private:
|
||||
virtual void paintEvent(PaintEvent&) override;
|
||||
virtual void mouseMoveEvent(MouseEvent&) override;
|
||||
|
||||
virtual const char* class_name() const override { return "Label"; }
|
||||
|
||||
String m_text;
|
||||
};
|
||||
|
68
LibGUI/ListBox.cpp
Normal file
68
LibGUI/ListBox.cpp
Normal file
|
@ -0,0 +1,68 @@
|
|||
#include "ListBox.h"
|
||||
#include "Window.h"
|
||||
#include <SharedGraphics/Font.h>
|
||||
#include <SharedGraphics/Painter.h>
|
||||
|
||||
ListBox::ListBox(Widget* parent)
|
||||
: Widget(parent)
|
||||
{
|
||||
}
|
||||
|
||||
ListBox::~ListBox()
|
||||
{
|
||||
}
|
||||
|
||||
Rect ListBox::item_rect(int index) const
|
||||
{
|
||||
int item_height = font().glyph_height() + 2;
|
||||
return Rect { 2, 2 + (index * item_height), width() - 4, item_height };
|
||||
}
|
||||
|
||||
void ListBox::paintEvent(PaintEvent&)
|
||||
{
|
||||
Painter painter(*this);
|
||||
|
||||
// FIXME: Reduce overdraw.
|
||||
painter.fill_rect(rect(), Color::White);
|
||||
painter.draw_rect(rect(), Color::Black);
|
||||
|
||||
if (isFocused())
|
||||
painter.draw_focus_rect(rect());
|
||||
|
||||
for (int i = m_scrollOffset; i < static_cast<int>(m_items.size()); ++i) {
|
||||
auto itemRect = item_rect(i);
|
||||
Rect textRect(itemRect.x() + 1, itemRect.y() + 1, itemRect.width() - 2, itemRect.height() - 2);
|
||||
|
||||
Color itemTextColor = foregroundColor();
|
||||
if (m_selectedIndex == i) {
|
||||
if (isFocused())
|
||||
painter.fill_rect(itemRect, Color(0, 32, 128));
|
||||
else
|
||||
painter.fill_rect(itemRect, Color(96, 96, 96));
|
||||
itemTextColor = Color::White;
|
||||
}
|
||||
painter.draw_text(textRect, m_items[i], Painter::TextAlignment::TopLeft, itemTextColor);
|
||||
}
|
||||
}
|
||||
|
||||
void ListBox::mouseDownEvent(MouseEvent& event)
|
||||
{
|
||||
dbgprintf("ListBox::mouseDownEvent %d,%d\n", event.x(), event.y());
|
||||
for (int i = m_scrollOffset; i < static_cast<int>(m_items.size()); ++i) {
|
||||
auto itemRect = item_rect(i);
|
||||
if (itemRect.contains(event.position())) {
|
||||
m_selectedIndex = i;
|
||||
dbgprintf("ListBox: selected item %u (\"%s\")\n", i, m_items[i].characters());
|
||||
update();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ListBox::addItem(String&& item)
|
||||
{
|
||||
m_items.append(move(item));
|
||||
if (m_selectedIndex == -1)
|
||||
m_selectedIndex = 0;
|
||||
}
|
||||
|
25
LibGUI/ListBox.h
Normal file
25
LibGUI/ListBox.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
#pragma once
|
||||
|
||||
#include "Widget.h"
|
||||
|
||||
class ListBox final : public Widget {
|
||||
public:
|
||||
explicit ListBox(Widget* parent);
|
||||
virtual ~ListBox() override;
|
||||
|
||||
void addItem(String&&);
|
||||
int selectedIndex() const { return m_selectedIndex; }
|
||||
|
||||
private:
|
||||
virtual void paintEvent(PaintEvent&) override;
|
||||
virtual void mouseDownEvent(MouseEvent&) override;
|
||||
virtual const char* class_name() const override { return "ListBox"; }
|
||||
|
||||
Rect item_rect(int index) const;
|
||||
|
||||
int m_scrollOffset { 0 };
|
||||
int m_selectedIndex { -1 };
|
||||
|
||||
Vector<String> m_items;
|
||||
};
|
||||
|
76
LibGUI/Object.cpp
Normal file
76
LibGUI/Object.cpp
Normal file
|
@ -0,0 +1,76 @@
|
|||
#include "Object.h"
|
||||
#include "Event.h"
|
||||
#include "EventLoop.h"
|
||||
#include <AK/Assertions.h>
|
||||
|
||||
Object::Object(Object* parent)
|
||||
: m_parent(parent)
|
||||
{
|
||||
if (m_parent)
|
||||
m_parent->addChild(*this);
|
||||
}
|
||||
|
||||
Object::~Object()
|
||||
{
|
||||
if (m_parent)
|
||||
m_parent->removeChild(*this);
|
||||
auto childrenToDelete = move(m_children);
|
||||
for (auto* child : childrenToDelete)
|
||||
delete child;
|
||||
}
|
||||
|
||||
void Object::event(Event& event)
|
||||
{
|
||||
switch (event.type()) {
|
||||
case Event::Timer:
|
||||
return timerEvent(static_cast<TimerEvent&>(event));
|
||||
case Event::DeferredDestroy:
|
||||
delete this;
|
||||
break;
|
||||
case Event::Invalid:
|
||||
ASSERT_NOT_REACHED();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Object::addChild(Object& object)
|
||||
{
|
||||
m_children.append(&object);
|
||||
}
|
||||
|
||||
void Object::removeChild(Object& object)
|
||||
{
|
||||
for (unsigned i = 0; i < m_children.size(); ++i) {
|
||||
if (m_children[i] == &object) {
|
||||
m_children.remove(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Object::timerEvent(TimerEvent&)
|
||||
{
|
||||
}
|
||||
|
||||
void Object::startTimer(int ms)
|
||||
{
|
||||
if (m_timerID) {
|
||||
dbgprintf("Object{%p} already has a timer!\n", this);
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
void Object::stopTimer()
|
||||
{
|
||||
if (!m_timerID)
|
||||
return;
|
||||
m_timerID = 0;
|
||||
}
|
||||
|
||||
void Object::deleteLater()
|
||||
{
|
||||
EventLoop::main().postEvent(this, make<DeferredDestroyEvent>());
|
||||
}
|
||||
|
40
LibGUI/Object.h
Normal file
40
LibGUI/Object.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
#pragma once
|
||||
|
||||
#include <AK/Vector.h>
|
||||
#include <AK/Weakable.h>
|
||||
|
||||
class Event;
|
||||
class TimerEvent;
|
||||
|
||||
class Object : public Weakable<Object> {
|
||||
public:
|
||||
Object(Object* parent = nullptr);
|
||||
virtual ~Object();
|
||||
|
||||
virtual const char* class_name() const { return "Object"; }
|
||||
|
||||
virtual void event(Event&);
|
||||
|
||||
Vector<Object*>& children() { return m_children; }
|
||||
|
||||
Object* parent() { return m_parent; }
|
||||
const Object* parent() const { return m_parent; }
|
||||
|
||||
void startTimer(int ms);
|
||||
void stopTimer();
|
||||
bool hasTimer() const { return m_timerID; }
|
||||
|
||||
void addChild(Object&);
|
||||
void removeChild(Object&);
|
||||
|
||||
void deleteLater();
|
||||
|
||||
private:
|
||||
virtual void timerEvent(TimerEvent&);
|
||||
|
||||
Object* m_parent { nullptr };
|
||||
|
||||
int m_timerID { 0 };
|
||||
|
||||
Vector<Object*> m_children;
|
||||
};
|
139
LibGUI/TextBox.cpp
Normal file
139
LibGUI/TextBox.cpp
Normal file
|
@ -0,0 +1,139 @@
|
|||
#include "TextBox.h"
|
||||
#include <AK/StdLibExtras.h>
|
||||
#include <SharedGraphics/CharacterBitmap.h>
|
||||
#include <SharedGraphics/Font.h>
|
||||
#include <SharedGraphics/Painter.h>
|
||||
|
||||
TextBox::TextBox(Widget* parent)
|
||||
: Widget(parent)
|
||||
{
|
||||
startTimer(500);
|
||||
}
|
||||
|
||||
TextBox::~TextBox()
|
||||
{
|
||||
}
|
||||
|
||||
void TextBox::setText(String&& text)
|
||||
{
|
||||
m_text = move(text);
|
||||
m_cursorPosition = m_text.length();
|
||||
update();
|
||||
}
|
||||
|
||||
void TextBox::paintEvent(PaintEvent&)
|
||||
{
|
||||
Painter painter(*this);
|
||||
|
||||
// FIXME: Reduce overdraw.
|
||||
painter.fill_rect(rect(), backgroundColor());
|
||||
painter.draw_rect(rect(), foregroundColor());
|
||||
|
||||
if (isFocused())
|
||||
painter.draw_focus_rect(rect());
|
||||
|
||||
Rect innerRect = rect();
|
||||
innerRect.shrink(6, 6);
|
||||
|
||||
size_t maxCharsToPaint = innerRect.width() / font().glyph_width();
|
||||
|
||||
int firstVisibleChar = max((int)m_cursorPosition - (int)maxCharsToPaint, 0);
|
||||
size_t charsToPaint = min(m_text.length() - firstVisibleChar, maxCharsToPaint);
|
||||
|
||||
int y = innerRect.center().y() - font().glyph_height() / 2;
|
||||
for (size_t i = 0; i < charsToPaint; ++i) {
|
||||
char ch = m_text[firstVisibleChar + i];
|
||||
if (ch == ' ')
|
||||
continue;
|
||||
int x = innerRect.x() + (i * font().glyph_width());
|
||||
auto* bitmap = font().glyph_bitmap(ch);
|
||||
if (!bitmap) {
|
||||
dbgprintf("TextBox: glyph missing: %02x\n", ch);
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
painter.draw_bitmap({x, y}, *bitmap, Color::Black);
|
||||
}
|
||||
|
||||
if (isFocused() && m_cursorBlinkState) {
|
||||
unsigned visibleCursorPosition = m_cursorPosition - firstVisibleChar;
|
||||
Rect cursorRect(innerRect.x() + visibleCursorPosition * font().glyph_width(), innerRect.y(), 1, innerRect.height());
|
||||
painter.fill_rect(cursorRect, foregroundColor());
|
||||
}
|
||||
}
|
||||
|
||||
void TextBox::mouseDownEvent(MouseEvent&)
|
||||
{
|
||||
}
|
||||
|
||||
void TextBox::handleBackspace()
|
||||
{
|
||||
if (m_cursorPosition == 0)
|
||||
return;
|
||||
|
||||
if (m_text.length() == 1) {
|
||||
m_text = String::empty();
|
||||
m_cursorPosition = 0;
|
||||
update();
|
||||
return;
|
||||
}
|
||||
|
||||
char* buffer;
|
||||
auto newText = StringImpl::create_uninitialized(m_text.length() - 1, buffer);
|
||||
|
||||
memcpy(buffer, m_text.characters(), m_cursorPosition - 1);
|
||||
memcpy(buffer + m_cursorPosition - 1, m_text.characters() + m_cursorPosition, m_text.length() - (m_cursorPosition - 1));
|
||||
|
||||
m_text = move(newText);
|
||||
--m_cursorPosition;
|
||||
update();
|
||||
}
|
||||
|
||||
void TextBox::keyDownEvent(KeyEvent& event)
|
||||
{
|
||||
switch (event.key()) {
|
||||
case KeyboardKey::LeftArrow:
|
||||
if (m_cursorPosition)
|
||||
--m_cursorPosition;
|
||||
m_cursorBlinkState = true;
|
||||
update();
|
||||
return;
|
||||
case KeyboardKey::RightArrow:
|
||||
if (m_cursorPosition < m_text.length())
|
||||
++m_cursorPosition;
|
||||
m_cursorBlinkState = true;
|
||||
update();
|
||||
return;
|
||||
case KeyboardKey::Backspace:
|
||||
return handleBackspace();
|
||||
case KeyboardKey::Return:
|
||||
if (onReturnPressed)
|
||||
onReturnPressed(*this);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!event.text().is_empty()) {
|
||||
ASSERT(event.text().length() == 1);
|
||||
|
||||
char* buffer;
|
||||
auto newText = StringImpl::create_uninitialized(m_text.length() + 1, buffer);
|
||||
|
||||
memcpy(buffer, m_text.characters(), m_cursorPosition);
|
||||
buffer[m_cursorPosition] = event.text()[0];
|
||||
memcpy(buffer + m_cursorPosition + 1, m_text.characters() + m_cursorPosition, m_text.length() - m_cursorPosition);
|
||||
|
||||
m_text = move(newText);
|
||||
++m_cursorPosition;
|
||||
update();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void TextBox::timerEvent(TimerEvent&)
|
||||
{
|
||||
// FIXME: Disable the timer when not focused.
|
||||
if (!isFocused())
|
||||
return;
|
||||
|
||||
m_cursorBlinkState = !m_cursorBlinkState;
|
||||
update();
|
||||
}
|
29
LibGUI/TextBox.h
Normal file
29
LibGUI/TextBox.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
#pragma once
|
||||
|
||||
#include "Widget.h"
|
||||
#include <AK/Function.h>
|
||||
|
||||
class TextBox final : public Widget {
|
||||
public:
|
||||
explicit TextBox(Widget* parent = nullptr);
|
||||
virtual ~TextBox() override;
|
||||
|
||||
String text() const { return m_text; }
|
||||
void setText(String&&);
|
||||
|
||||
Function<void(TextBox&)> onReturnPressed;
|
||||
|
||||
private:
|
||||
virtual const char* class_name() const override { return "TextBox"; }
|
||||
virtual void paintEvent(PaintEvent&) override;
|
||||
virtual void mouseDownEvent(MouseEvent&) override;
|
||||
virtual void keyDownEvent(KeyEvent&) override;
|
||||
virtual void timerEvent(TimerEvent&) override;
|
||||
|
||||
void handleBackspace();
|
||||
|
||||
String m_text;
|
||||
unsigned m_cursorPosition { 0 };
|
||||
bool m_cursorBlinkState { false };
|
||||
};
|
||||
|
163
LibGUI/Widget.cpp
Normal file
163
LibGUI/Widget.cpp
Normal file
|
@ -0,0 +1,163 @@
|
|||
#include "Widget.h"
|
||||
#include "Event.h"
|
||||
#include "EventLoop.h"
|
||||
#include "Window.h"
|
||||
#include <AK/Assertions.h>
|
||||
#include <SharedGraphics/GraphicsBitmap.h>
|
||||
#include <SharedGraphics/Painter.h>
|
||||
|
||||
Widget::Widget(Widget* parent)
|
||||
: Object(parent)
|
||||
{
|
||||
setFont(nullptr);
|
||||
m_backgroundColor = Color::White;
|
||||
m_foregroundColor = Color::Black;
|
||||
}
|
||||
|
||||
Widget::~Widget()
|
||||
{
|
||||
}
|
||||
|
||||
void Widget::setWindowRelativeRect(const Rect& rect, bool should_update)
|
||||
{
|
||||
// FIXME: Make some kind of event loop driven ResizeEvent?
|
||||
m_relativeRect = rect;
|
||||
if (should_update)
|
||||
update();
|
||||
}
|
||||
|
||||
void Widget::repaint(const Rect& rect)
|
||||
{
|
||||
// FIXME: Implement.
|
||||
}
|
||||
|
||||
void Widget::event(Event& event)
|
||||
{
|
||||
switch (event.type()) {
|
||||
case Event::Paint:
|
||||
m_hasPendingPaintEvent = false;
|
||||
if (auto* win = window()) {
|
||||
if (win->is_being_dragged())
|
||||
return;
|
||||
if (!win->is_visible())
|
||||
return;
|
||||
}
|
||||
return paintEvent(static_cast<PaintEvent&>(event));
|
||||
case Event::Show:
|
||||
return showEvent(static_cast<ShowEvent&>(event));
|
||||
case Event::Hide:
|
||||
return hideEvent(static_cast<HideEvent&>(event));
|
||||
case Event::KeyDown:
|
||||
return keyDownEvent(static_cast<KeyEvent&>(event));
|
||||
case Event::KeyUp:
|
||||
return keyUpEvent(static_cast<KeyEvent&>(event));
|
||||
case Event::MouseMove:
|
||||
return mouseMoveEvent(static_cast<MouseEvent&>(event));
|
||||
case Event::MouseDown:
|
||||
// FIXME: Focus self if needed.
|
||||
return mouseDownEvent(static_cast<MouseEvent&>(event));
|
||||
case Event::MouseUp:
|
||||
return mouseUpEvent(static_cast<MouseEvent&>(event));
|
||||
default:
|
||||
return Object::event(event);
|
||||
}
|
||||
}
|
||||
|
||||
void Widget::paintEvent(PaintEvent& event)
|
||||
{
|
||||
//printf("Widget::paintEvent :)\n");
|
||||
if (fillWithBackgroundColor()) {
|
||||
Painter painter(*this);
|
||||
painter.fill_rect(rect(), backgroundColor());
|
||||
}
|
||||
for (auto* ch : children()) {
|
||||
auto* child = (Widget*)ch;
|
||||
child->event(event);
|
||||
}
|
||||
}
|
||||
|
||||
void Widget::showEvent(ShowEvent&)
|
||||
{
|
||||
}
|
||||
|
||||
void Widget::hideEvent(HideEvent&)
|
||||
{
|
||||
}
|
||||
|
||||
void Widget::keyDownEvent(KeyEvent&)
|
||||
{
|
||||
}
|
||||
|
||||
void Widget::keyUpEvent(KeyEvent&)
|
||||
{
|
||||
}
|
||||
|
||||
void Widget::mouseDownEvent(MouseEvent&)
|
||||
{
|
||||
}
|
||||
|
||||
void Widget::mouseUpEvent(MouseEvent&)
|
||||
{
|
||||
}
|
||||
|
||||
void Widget::mouseMoveEvent(MouseEvent&)
|
||||
{
|
||||
}
|
||||
|
||||
void Widget::update()
|
||||
{
|
||||
auto* w = window();
|
||||
if (!w)
|
||||
return;
|
||||
if (m_hasPendingPaintEvent)
|
||||
return;
|
||||
m_hasPendingPaintEvent = true;
|
||||
EventLoop::main().postEvent(w, make<PaintEvent>(relativeRect()));
|
||||
}
|
||||
|
||||
Widget::HitTestResult Widget::hitTest(int x, int y)
|
||||
{
|
||||
// FIXME: Care about z-order.
|
||||
for (auto* ch : children()) {
|
||||
auto* child = (Widget*)ch;
|
||||
if (child->relativeRect().contains(x, y)) {
|
||||
return child->hitTest(x - child->relativeRect().x(), y - child->relativeRect().y());
|
||||
}
|
||||
}
|
||||
return { this, x, y };
|
||||
}
|
||||
|
||||
void Widget::setWindow(Window* window)
|
||||
{
|
||||
if (m_window == window)
|
||||
return;
|
||||
m_window = window;
|
||||
}
|
||||
|
||||
bool Widget::isFocused() const
|
||||
{
|
||||
// FIXME: Implement.
|
||||
return false;
|
||||
}
|
||||
|
||||
void Widget::setFocus(bool focus)
|
||||
{
|
||||
if (focus == isFocused())
|
||||
return;
|
||||
// FIXME: Implement.
|
||||
}
|
||||
|
||||
void Widget::setFont(RetainPtr<Font>&& font)
|
||||
{
|
||||
if (!font)
|
||||
m_font = Font::default_font();
|
||||
else
|
||||
m_font = move(font);
|
||||
}
|
||||
|
||||
GraphicsBitmap* Widget::backing()
|
||||
{
|
||||
if (auto* w = window())
|
||||
return w->backing();
|
||||
return nullptr;
|
||||
}
|
99
LibGUI/Widget.h
Normal file
99
LibGUI/Widget.h
Normal file
|
@ -0,0 +1,99 @@
|
|||
#pragma once
|
||||
|
||||
#include "Event.h"
|
||||
#include "Object.h"
|
||||
#include <SharedGraphics/Rect.h>
|
||||
#include <SharedGraphics/Color.h>
|
||||
#include <SharedGraphics/Font.h>
|
||||
#include <AK/AKString.h>
|
||||
|
||||
class GraphicsBitmap;
|
||||
class Window;
|
||||
|
||||
class Widget : public Object {
|
||||
public:
|
||||
explicit Widget(Widget* parent = nullptr);
|
||||
virtual ~Widget();
|
||||
|
||||
virtual void event(Event&) override;
|
||||
virtual void paintEvent(PaintEvent&);
|
||||
virtual void showEvent(ShowEvent&);
|
||||
virtual void hideEvent(HideEvent&);
|
||||
virtual void keyDownEvent(KeyEvent&);
|
||||
virtual void keyUpEvent(KeyEvent&);
|
||||
virtual void mouseMoveEvent(MouseEvent&);
|
||||
virtual void mouseDownEvent(MouseEvent&);
|
||||
virtual void mouseUpEvent(MouseEvent&);
|
||||
|
||||
Rect relativeRect() const { return m_relativeRect; }
|
||||
Point relativePosition() const { return m_relativeRect.location(); }
|
||||
|
||||
int x() const { return m_relativeRect.x(); }
|
||||
int y() const { return m_relativeRect.y(); }
|
||||
int width() const { return m_relativeRect.width(); }
|
||||
int height() const { return m_relativeRect.height(); }
|
||||
|
||||
Rect rect() const { return { 0, 0, width(), height() }; }
|
||||
Size size() const { return m_relativeRect.size(); }
|
||||
|
||||
void update();
|
||||
void repaint(const Rect&);
|
||||
|
||||
bool isFocused() const;
|
||||
void setFocus(bool);
|
||||
|
||||
struct HitTestResult {
|
||||
Widget* widget { nullptr };
|
||||
int localX { 0 };
|
||||
int localY { 0 };
|
||||
};
|
||||
HitTestResult hitTest(int x, int y);
|
||||
|
||||
virtual const char* class_name() const override { return "Widget"; }
|
||||
|
||||
void setWindowRelativeRect(const Rect&, bool should_update = true);
|
||||
|
||||
Color backgroundColor() const { return m_backgroundColor; }
|
||||
Color foregroundColor() const { return m_foregroundColor; }
|
||||
|
||||
void setBackgroundColor(Color color) { m_backgroundColor = color; }
|
||||
void setForegroundColor(Color color) { m_foregroundColor = color; }
|
||||
|
||||
Window* window()
|
||||
{
|
||||
if (auto* pw = parentWidget())
|
||||
return pw->window();
|
||||
return m_window;
|
||||
}
|
||||
|
||||
const Window* window() const
|
||||
{
|
||||
if (auto* pw = parentWidget())
|
||||
return pw->window();
|
||||
return m_window;
|
||||
}
|
||||
|
||||
void setWindow(Window*);
|
||||
|
||||
Widget* parentWidget() { return static_cast<Widget*>(parent()); }
|
||||
const Widget* parentWidget() const { return static_cast<const Widget*>(parent()); }
|
||||
|
||||
void setFillWithBackgroundColor(bool b) { m_fillWithBackgroundColor = b; }
|
||||
bool fillWithBackgroundColor() const { return m_fillWithBackgroundColor; }
|
||||
|
||||
const Font& font() const { return *m_font; }
|
||||
void setFont(RetainPtr<Font>&&);
|
||||
|
||||
virtual GraphicsBitmap* backing();
|
||||
|
||||
private:
|
||||
Window* m_window { nullptr };
|
||||
|
||||
Rect m_relativeRect;
|
||||
Color m_backgroundColor { 0xffffff };
|
||||
Color m_foregroundColor { 0x000000 };
|
||||
RetainPtr<Font> m_font;
|
||||
|
||||
bool m_hasPendingPaintEvent { false };
|
||||
bool m_fillWithBackgroundColor { true };
|
||||
};
|
42
LibGUI/Window.cpp
Normal file
42
LibGUI/Window.cpp
Normal file
|
@ -0,0 +1,42 @@
|
|||
#include "Window.h"
|
||||
#include "Event.h"
|
||||
#include "EventLoop.h"
|
||||
#include <SharedGraphics/GraphicsBitmap.h>
|
||||
|
||||
Window::Window(int window_id)
|
||||
: m_window_id(window_id)
|
||||
{
|
||||
}
|
||||
|
||||
Window::~Window()
|
||||
{
|
||||
}
|
||||
|
||||
void Window::set_title(String&& title)
|
||||
{
|
||||
if (m_title == title)
|
||||
return;
|
||||
|
||||
m_title = move(title);
|
||||
}
|
||||
void Window::set_rect(const Rect& rect)
|
||||
{
|
||||
if (m_rect == rect)
|
||||
return;
|
||||
m_rect = rect;
|
||||
dbgprintf("Window::setRect %d,%d %dx%d\n", m_rect.x(), m_rect.y(), m_rect.width(), m_rect.height());
|
||||
}
|
||||
|
||||
void Window::event(Event& event)
|
||||
{
|
||||
}
|
||||
|
||||
bool Window::is_visible() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void Window::close()
|
||||
{
|
||||
}
|
||||
|
49
LibGUI/Window.h
Normal file
49
LibGUI/Window.h
Normal file
|
@ -0,0 +1,49 @@
|
|||
#pragma once
|
||||
|
||||
#include "Object.h"
|
||||
#include <SharedGraphics/Rect.h>
|
||||
#include <SharedGraphics/GraphicsBitmap.h>
|
||||
#include <AK/AKString.h>
|
||||
|
||||
class Window final : public Object {
|
||||
public:
|
||||
explicit Window(int window_id);
|
||||
virtual ~Window() override;
|
||||
|
||||
int window_id() const { return m_window_id; }
|
||||
|
||||
String title() const { return m_title; }
|
||||
void set_title(String&&);
|
||||
|
||||
int x() const { return m_rect.x(); }
|
||||
int y() const { return m_rect.y(); }
|
||||
int width() const { return m_rect.width(); }
|
||||
int height() const { return m_rect.height(); }
|
||||
|
||||
const Rect& rect() const { return m_rect; }
|
||||
void set_rect(const Rect&);
|
||||
void set_rect_without_repaint(const Rect& rect) { m_rect = rect; }
|
||||
|
||||
Point position() const { return m_rect.location(); }
|
||||
void set_position_without_repaint(const Point& position) { set_rect_without_repaint({ position.x(), position.y(), width(), height() }); }
|
||||
|
||||
virtual void event(Event&) override;
|
||||
|
||||
bool is_being_dragged() const { return m_is_being_dragged; }
|
||||
void set_is_being_dragged(bool b) { m_is_being_dragged = b; }
|
||||
|
||||
bool is_visible() const;
|
||||
|
||||
void close();
|
||||
|
||||
GraphicsBitmap* backing() { return m_backing.ptr(); }
|
||||
|
||||
private:
|
||||
String m_title;
|
||||
Rect m_rect;
|
||||
bool m_is_being_dragged { false };
|
||||
|
||||
RetainPtr<GraphicsBitmap> m_backing;
|
||||
int m_window_id { -1 };
|
||||
};
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue