mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-22 07:30:19 +00:00
Start working on a Widgets library.
This commit is contained in:
parent
a181a8f6e7
commit
8c84f9749e
Notes:
sideshowbarker
2024-07-19 18:51:21 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/8c84f9749e3
18 changed files with 594 additions and 0 deletions
35
Widgets/AbstractScreen.cpp
Normal file
35
Widgets/AbstractScreen.cpp
Normal file
|
@ -0,0 +1,35 @@
|
|||
#include "AbstractScreen.h"
|
||||
#include "EventLoop.h"
|
||||
#include "Event.h"
|
||||
#include "Widget.h"
|
||||
#include <AK/Assertions.h>
|
||||
|
||||
static AbstractScreen* s_the;
|
||||
|
||||
AbstractScreen& AbstractScreen::the()
|
||||
{
|
||||
ASSERT(s_the);
|
||||
return *s_the;
|
||||
}
|
||||
|
||||
AbstractScreen::AbstractScreen(unsigned width, unsigned height)
|
||||
: m_width(width)
|
||||
, m_height(height)
|
||||
{
|
||||
ASSERT(!s_the);
|
||||
s_the = this;
|
||||
}
|
||||
|
||||
AbstractScreen::~AbstractScreen()
|
||||
{
|
||||
}
|
||||
|
||||
void AbstractScreen::setRootWidget(Widget* widget)
|
||||
{
|
||||
// FIXME: Should we support switching root widgets?
|
||||
ASSERT(!m_rootWidget);
|
||||
ASSERT(widget);
|
||||
|
||||
m_rootWidget = widget;
|
||||
EventLoop::main().postEvent(m_rootWidget, make<ShowEvent>());
|
||||
}
|
25
Widgets/AbstractScreen.h
Normal file
25
Widgets/AbstractScreen.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
#pragma once
|
||||
|
||||
class Widget;
|
||||
|
||||
class AbstractScreen {
|
||||
public:
|
||||
virtual ~AbstractScreen();
|
||||
|
||||
unsigned width() const { return m_width; }
|
||||
unsigned height() const { return m_height; }
|
||||
|
||||
void setRootWidget(Widget*);
|
||||
|
||||
static AbstractScreen& the();
|
||||
|
||||
protected:
|
||||
AbstractScreen(unsigned width, unsigned height);
|
||||
|
||||
private:
|
||||
unsigned m_width { 0 };
|
||||
unsigned m_height { 0 };
|
||||
|
||||
Widget* m_rootWidget { nullptr };
|
||||
};
|
||||
|
118
Widgets/Event.h
Normal file
118
Widgets/Event.h
Normal file
|
@ -0,0 +1,118 @@
|
|||
#pragma once
|
||||
|
||||
#include <AK/Types.h>
|
||||
|
||||
static const char* eventNames[] = {
|
||||
"Invalid",
|
||||
"Quit",
|
||||
"Show",
|
||||
"Hide",
|
||||
"Paint",
|
||||
"MouseMove",
|
||||
"MouseDown",
|
||||
"MouseUp",
|
||||
"KeyDown",
|
||||
"KeyUp",
|
||||
};
|
||||
|
||||
class Event {
|
||||
public:
|
||||
enum Type {
|
||||
Invalid = 0,
|
||||
Quit,
|
||||
Show,
|
||||
Hide,
|
||||
Paint,
|
||||
MouseMove,
|
||||
MouseDown,
|
||||
MouseUp,
|
||||
KeyDown,
|
||||
KeyUp,
|
||||
};
|
||||
|
||||
Event() { }
|
||||
~Event() { }
|
||||
|
||||
Type type() const { return m_type; }
|
||||
|
||||
const char* name() const { return eventNames[(unsigned)m_type]; }
|
||||
|
||||
protected:
|
||||
explicit Event(Type type) : m_type(type) { }
|
||||
|
||||
private:
|
||||
Type m_type { Invalid };
|
||||
};
|
||||
|
||||
class QuitEvent final : public Event {
|
||||
public:
|
||||
QuitEvent()
|
||||
: Event(Event::Quit)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class PaintEvent final : public Event {
|
||||
public:
|
||||
PaintEvent()
|
||||
: Event(Event::Paint)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
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,
|
||||
Right,
|
||||
};
|
||||
|
||||
class KeyEvent : public Event {
|
||||
public:
|
||||
KeyEvent(Type type, int key)
|
||||
: Event(type)
|
||||
, m_key(key)
|
||||
{
|
||||
}
|
||||
|
||||
int key() const { return m_key; }
|
||||
|
||||
private:
|
||||
int m_key { 0 };
|
||||
};
|
||||
|
||||
class MouseEvent : public Event {
|
||||
public:
|
||||
MouseEvent(Type type, int x, int y, MouseButton button = MouseButton::None)
|
||||
: Event(type)
|
||||
, m_x(x)
|
||||
, m_y(y)
|
||||
, m_button(button)
|
||||
{
|
||||
}
|
||||
|
||||
int x() const { return m_x; }
|
||||
int y() const { return m_y; }
|
||||
MouseButton button() const { return m_button; }
|
||||
|
||||
private:
|
||||
int m_x { 0 };
|
||||
int m_y { 0 };
|
||||
MouseButton m_button { MouseButton::None };
|
||||
};
|
||||
|
52
Widgets/EventLoop.cpp
Normal file
52
Widgets/EventLoop.cpp
Normal file
|
@ -0,0 +1,52 @@
|
|||
#include "EventLoop.h"
|
||||
#include "Event.h"
|
||||
#include "Object.h"
|
||||
|
||||
static EventLoop* s_mainEventLoop;
|
||||
|
||||
EventLoop::EventLoop()
|
||||
{
|
||||
if (!s_mainEventLoop)
|
||||
s_mainEventLoop = this;
|
||||
}
|
||||
|
||||
EventLoop::~EventLoop()
|
||||
{
|
||||
}
|
||||
|
||||
EventLoop& EventLoop::main()
|
||||
{
|
||||
ASSERT(s_mainEventLoop);
|
||||
return *s_mainEventLoop;
|
||||
}
|
||||
|
||||
int EventLoop::exec()
|
||||
{
|
||||
for (;;) {
|
||||
if (m_queuedEvents.isEmpty())
|
||||
waitForEvent();
|
||||
auto events = std::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:
|
||||
return 0;
|
||||
default:
|
||||
printf("event type %u with no receiver :(\n", event.type());
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
receiver->event(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EventLoop::postEvent(Object* receiver, OwnPtr<Event>&& event)
|
||||
{
|
||||
m_queuedEvents.append({ receiver, std::move(event) });
|
||||
}
|
||||
|
30
Widgets/EventLoop.h
Normal file
30
Widgets/EventLoop.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
#pragma once
|
||||
|
||||
#include <AK/OwnPtr.h>
|
||||
#include <AK/Vector.h>
|
||||
|
||||
class Event;
|
||||
class Object;
|
||||
|
||||
class EventLoop {
|
||||
public:
|
||||
virtual ~EventLoop();
|
||||
|
||||
int exec();
|
||||
|
||||
virtual void waitForEvent() = 0;
|
||||
|
||||
void postEvent(Object* receiver, OwnPtr<Event>&&);
|
||||
|
||||
static EventLoop& main();
|
||||
|
||||
protected:
|
||||
EventLoop();
|
||||
|
||||
private:
|
||||
struct QueuedEvent {
|
||||
Object* receiver { nullptr };
|
||||
OwnPtr<Event> event;
|
||||
};
|
||||
Vector<QueuedEvent> m_queuedEvents;
|
||||
};
|
24
Widgets/EventLoopSDL.cpp
Normal file
24
Widgets/EventLoopSDL.cpp
Normal file
|
@ -0,0 +1,24 @@
|
|||
#include "EventLoopSDL.h"
|
||||
#include "Event.h"
|
||||
#include <SDL.h>
|
||||
|
||||
EventLoopSDL::EventLoopSDL()
|
||||
{
|
||||
}
|
||||
|
||||
EventLoopSDL::~EventLoopSDL()
|
||||
{
|
||||
}
|
||||
|
||||
void EventLoopSDL::waitForEvent()
|
||||
{
|
||||
SDL_Event sdlEvent;
|
||||
while (SDL_WaitEvent(&sdlEvent) != 0) {
|
||||
switch (sdlEvent.type) {
|
||||
case SDL_QUIT:
|
||||
postEvent(nullptr, make<QuitEvent>());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
13
Widgets/EventLoopSDL.h
Normal file
13
Widgets/EventLoopSDL.h
Normal file
|
@ -0,0 +1,13 @@
|
|||
#pragma once
|
||||
|
||||
#include "EventLoop.h"
|
||||
|
||||
class EventLoopSDL final : public EventLoop {
|
||||
public:
|
||||
EventLoopSDL();
|
||||
virtual ~EventLoopSDL() override;
|
||||
|
||||
private:
|
||||
virtual void waitForEvent() override;
|
||||
};
|
||||
|
BIN
Widgets/FrameBuffer.o
Normal file
BIN
Widgets/FrameBuffer.o
Normal file
Binary file not shown.
49
Widgets/FrameBufferSDL.cpp
Normal file
49
Widgets/FrameBufferSDL.cpp
Normal file
|
@ -0,0 +1,49 @@
|
|||
#include "FrameBufferSDL.h"
|
||||
#include <AK/Assertions.h>
|
||||
|
||||
FrameBufferSDL::FrameBufferSDL(unsigned width, unsigned height)
|
||||
: AbstractScreen(width, height)
|
||||
{
|
||||
initializeSDL();
|
||||
}
|
||||
|
||||
FrameBufferSDL::~FrameBufferSDL()
|
||||
{
|
||||
SDL_DestroyWindow(m_window);
|
||||
m_surface = nullptr;
|
||||
m_window = nullptr;
|
||||
|
||||
SDL_Quit();
|
||||
}
|
||||
|
||||
void FrameBufferSDL::show()
|
||||
{
|
||||
}
|
||||
|
||||
void FrameBufferSDL::initializeSDL()
|
||||
{
|
||||
if (m_window)
|
||||
return;
|
||||
|
||||
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
m_window = SDL_CreateWindow(
|
||||
"FrameBuffer",
|
||||
SDL_WINDOWPOS_UNDEFINED,
|
||||
SDL_WINDOWPOS_UNDEFINED,
|
||||
width(),
|
||||
height(),
|
||||
SDL_WINDOW_SHOWN);
|
||||
|
||||
ASSERT(m_window);
|
||||
|
||||
m_surface = SDL_GetWindowSurface(m_window);
|
||||
ASSERT(m_surface);
|
||||
|
||||
SDL_FillRect(m_surface, nullptr, SDL_MapRGB(m_surface->format, 0xff, 0xff, 0xff));
|
||||
|
||||
SDL_UpdateWindowSurface(m_window);
|
||||
}
|
||||
|
19
Widgets/FrameBufferSDL.h
Normal file
19
Widgets/FrameBufferSDL.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
|
||||
#include "AbstractScreen.h"
|
||||
#include <SDL.h>
|
||||
|
||||
class FrameBufferSDL final : public AbstractScreen {
|
||||
public:
|
||||
FrameBufferSDL(unsigned width, unsigned height);
|
||||
virtual ~FrameBufferSDL() override;
|
||||
|
||||
void show();
|
||||
|
||||
private:
|
||||
void initializeSDL();
|
||||
|
||||
SDL_Window* m_window { nullptr };
|
||||
SDL_Surface* m_surface { nullptr };
|
||||
};
|
||||
|
37
Widgets/Makefile
Normal file
37
Widgets/Makefile
Normal file
|
@ -0,0 +1,37 @@
|
|||
PROGRAM = test
|
||||
|
||||
AK_OBJS = \
|
||||
../AK/String.o \
|
||||
../AK/StringImpl.o \
|
||||
../AK/SimpleMalloc.o \
|
||||
../AK/kmalloc.o
|
||||
|
||||
VFS_OBJS = \
|
||||
AbstractScreen.o \
|
||||
FrameBufferSDL.o \
|
||||
EventLoop.o \
|
||||
EventLoopSDL.o \
|
||||
Object.o \
|
||||
Widget.o \
|
||||
RootWidget.o \
|
||||
test.o
|
||||
|
||||
OBJS = $(AK_OBJS) $(VFS_OBJS)
|
||||
|
||||
CXXFLAGS = -std=c++17 -O0 -W -Wall -Wextra -Wconversion -I. -I.. -g `sdl2-config --cflags`
|
||||
|
||||
LDFLAGS = `sdl2-config --libs`
|
||||
|
||||
#test.o: BlockDevice.h FileBackedBlockDevice.h FileSystem.h Ext2FileSystem.h VirtualFileSystem.h FileHandle.h
|
||||
|
||||
all: $(PROGRAM)
|
||||
|
||||
.cpp.o:
|
||||
$(CXX) $(CXXFLAGS) -o $@ -c $<
|
||||
|
||||
clean:
|
||||
rm -f $(OBJS) $(PROGRAM)
|
||||
|
||||
$(PROGRAM): $(OBJS)
|
||||
$(CXX) $(LDFLAGS) -o $@ $(OBJS)
|
||||
|
23
Widgets/Object.cpp
Normal file
23
Widgets/Object.cpp
Normal file
|
@ -0,0 +1,23 @@
|
|||
#include "Object.h"
|
||||
#include "Event.h"
|
||||
#include <AK/Assertions.h>
|
||||
|
||||
Object::Object(Object* parent)
|
||||
: m_parent(parent)
|
||||
{
|
||||
}
|
||||
|
||||
Object::~Object()
|
||||
{
|
||||
}
|
||||
|
||||
void Object::event(Event& event)
|
||||
{
|
||||
switch (event.type()) {
|
||||
case Event::Invalid:
|
||||
ASSERT_NOT_REACHED();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
14
Widgets/Object.h
Normal file
14
Widgets/Object.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
#pragma once
|
||||
|
||||
class Event;
|
||||
|
||||
class Object {
|
||||
public:
|
||||
Object(Object* parent = nullptr);
|
||||
virtual ~Object();
|
||||
|
||||
virtual void event(Event&);
|
||||
|
||||
private:
|
||||
Object* m_parent { nullptr };
|
||||
};
|
23
Widgets/RootWidget.cpp
Normal file
23
Widgets/RootWidget.cpp
Normal file
|
@ -0,0 +1,23 @@
|
|||
#include "RootWidget.h"
|
||||
#include <cstdio>
|
||||
|
||||
RootWidget::RootWidget()
|
||||
{
|
||||
}
|
||||
|
||||
RootWidget::~RootWidget()
|
||||
{
|
||||
}
|
||||
|
||||
void RootWidget::onPaint(PaintEvent& event)
|
||||
{
|
||||
printf("RootWidget::onPaint\n");
|
||||
Widget::onPaint(event);
|
||||
}
|
||||
|
||||
void RootWidget::onMouseMove(MouseEvent& event)
|
||||
{
|
||||
printf("RootWidget::onMouseMove: x=%d, y=%d\n", event.x(), event.y());
|
||||
Widget::onMouseMove(event);
|
||||
}
|
||||
|
13
Widgets/RootWidget.h
Normal file
13
Widgets/RootWidget.h
Normal file
|
@ -0,0 +1,13 @@
|
|||
#pragma once
|
||||
|
||||
#include "Widget.h"
|
||||
|
||||
class RootWidget final : public Widget {
|
||||
public:
|
||||
RootWidget();
|
||||
virtual ~RootWidget() override;
|
||||
|
||||
private:
|
||||
virtual void onPaint(PaintEvent&) override;
|
||||
virtual void onMouseMove(MouseEvent&) override;
|
||||
};
|
76
Widgets/Widget.cpp
Normal file
76
Widgets/Widget.cpp
Normal file
|
@ -0,0 +1,76 @@
|
|||
#include "Widget.h"
|
||||
#include "Event.h"
|
||||
#include "EventLoop.h"
|
||||
#include <AK/Assertions.h>
|
||||
|
||||
Widget::Widget(Widget* parent)
|
||||
: Object(parent)
|
||||
{
|
||||
}
|
||||
|
||||
Widget::~Widget()
|
||||
{
|
||||
}
|
||||
|
||||
void Widget::event(Event& event)
|
||||
{
|
||||
switch (event.type()) {
|
||||
case Event::Paint:
|
||||
return onPaint(static_cast<PaintEvent&>(event));
|
||||
case Event::Show:
|
||||
return onShow(static_cast<ShowEvent&>(event));
|
||||
case Event::Hide:
|
||||
return onHide(static_cast<HideEvent&>(event));
|
||||
case Event::KeyDown:
|
||||
return onKeyDown(static_cast<KeyEvent&>(event));
|
||||
case Event::KeyUp:
|
||||
return onKeyUp(static_cast<KeyEvent&>(event));
|
||||
case Event::MouseMove:
|
||||
return onMouseMove(static_cast<MouseEvent&>(event));
|
||||
case Event::MouseDown:
|
||||
return onMouseDown(static_cast<MouseEvent&>(event));
|
||||
case Event::MouseUp:
|
||||
return onMouseUp(static_cast<MouseEvent&>(event));
|
||||
default:
|
||||
return Object::event(event);
|
||||
}
|
||||
}
|
||||
|
||||
void Widget::onPaint(PaintEvent&)
|
||||
{
|
||||
}
|
||||
|
||||
void Widget::onShow(ShowEvent&)
|
||||
{
|
||||
update();
|
||||
}
|
||||
|
||||
void Widget::onHide(HideEvent&)
|
||||
{
|
||||
}
|
||||
|
||||
void Widget::onKeyDown(KeyEvent&)
|
||||
{
|
||||
}
|
||||
|
||||
void Widget::onKeyUp(KeyEvent&)
|
||||
{
|
||||
}
|
||||
|
||||
void Widget::onMouseDown(MouseEvent&)
|
||||
{
|
||||
}
|
||||
|
||||
void Widget::onMouseUp(MouseEvent&)
|
||||
{
|
||||
}
|
||||
|
||||
void Widget::onMouseMove(MouseEvent&)
|
||||
{
|
||||
}
|
||||
|
||||
void Widget::update()
|
||||
{
|
||||
EventLoop::main().postEvent(this, make<PaintEvent>());
|
||||
}
|
||||
|
26
Widgets/Widget.h
Normal file
26
Widgets/Widget.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
#pragma once
|
||||
|
||||
#include "Event.h"
|
||||
#include "Object.h"
|
||||
|
||||
class Widget : public Object {
|
||||
public:
|
||||
explicit Widget(Widget* parent = nullptr);
|
||||
virtual ~Widget();
|
||||
|
||||
virtual void event(Event&);
|
||||
virtual void onPaint(PaintEvent&);
|
||||
virtual void onShow(ShowEvent&);
|
||||
virtual void onHide(HideEvent&);
|
||||
virtual void onKeyDown(KeyEvent&);
|
||||
virtual void onKeyUp(KeyEvent&);
|
||||
virtual void onMouseMove(MouseEvent&);
|
||||
virtual void onMouseDown(MouseEvent&);
|
||||
virtual void onMouseUp(MouseEvent&);
|
||||
|
||||
void update();
|
||||
|
||||
private:
|
||||
int m_x { 0 };
|
||||
int m_y { 0 };
|
||||
};
|
17
Widgets/test.cpp
Normal file
17
Widgets/test.cpp
Normal file
|
@ -0,0 +1,17 @@
|
|||
#include "FrameBufferSDL.h"
|
||||
#include "EventLoopSDL.h"
|
||||
#include "RootWidget.h"
|
||||
#include <cstdio>
|
||||
|
||||
int main(int c, char** v)
|
||||
{
|
||||
FrameBufferSDL fb(800, 600);
|
||||
fb.show();
|
||||
|
||||
EventLoopSDL loop;
|
||||
|
||||
RootWidget w;
|
||||
fb.setRootWidget(&w);
|
||||
|
||||
return loop.exec();
|
||||
}
|
Loading…
Reference in a new issue