mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-22 07:30:19 +00:00
Intense hacking on Widgets.
This commit is contained in:
parent
8c84f9749e
commit
6f37429f57
Notes:
sideshowbarker
2024-07-19 18:51:18 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/6f37429f574
20 changed files with 290 additions and 5 deletions
3
Widgets/.gitignore
vendored
Normal file
3
Widgets/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
*.o
|
||||
*.swp
|
||||
test
|
|
@ -13,7 +13,8 @@ AbstractScreen& AbstractScreen::the()
|
|||
}
|
||||
|
||||
AbstractScreen::AbstractScreen(unsigned width, unsigned height)
|
||||
: m_width(width)
|
||||
: Object(nullptr)
|
||||
, m_width(width)
|
||||
, m_height(height)
|
||||
{
|
||||
ASSERT(!s_the);
|
||||
|
@ -24,6 +25,17 @@ AbstractScreen::~AbstractScreen()
|
|||
{
|
||||
}
|
||||
|
||||
void AbstractScreen::event(Event& event)
|
||||
{
|
||||
if (event.type() == Event::MouseMove) {
|
||||
auto& me = static_cast<MouseEvent&>(event);
|
||||
printf("AbstractScreen::onMouseMove: %d, %d\n", me.x(), me.y());
|
||||
|
||||
auto result = m_rootWidget->hitTest(me.x(), me.y());
|
||||
printf("hit test for %d,%d found: %s{%p} %d,%d\n", me.x(), me.y(), result.widget->className(), result.widget, result.localX, result.localY);
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractScreen::setRootWidget(Widget* widget)
|
||||
{
|
||||
// FIXME: Should we support switching root widgets?
|
||||
|
|
|
@ -1,14 +1,17 @@
|
|||
#pragma once
|
||||
|
||||
#include "Object.h"
|
||||
|
||||
class Widget;
|
||||
|
||||
class AbstractScreen {
|
||||
class AbstractScreen : public Object {
|
||||
public:
|
||||
virtual ~AbstractScreen();
|
||||
|
||||
unsigned width() const { return m_width; }
|
||||
unsigned height() const { return m_height; }
|
||||
|
||||
Widget* rootWidget() { return m_rootWidget; }
|
||||
void setRootWidget(Widget*);
|
||||
|
||||
static AbstractScreen& the();
|
||||
|
@ -17,6 +20,8 @@ protected:
|
|||
AbstractScreen(unsigned width, unsigned height);
|
||||
|
||||
private:
|
||||
virtual void event(Event&) override;
|
||||
|
||||
unsigned m_width { 0 };
|
||||
unsigned m_height { 0 };
|
||||
|
||||
|
|
14
Widgets/Color.h
Normal file
14
Widgets/Color.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
#pragma once
|
||||
|
||||
#include <AK/Types.h>
|
||||
|
||||
class Color {
|
||||
public:
|
||||
Color() { }
|
||||
Color(byte r, byte g, byte b);
|
||||
|
||||
dword value() const { return m_value; }
|
||||
|
||||
private:
|
||||
dword m_value { 0 };
|
||||
};
|
7
Widgets/ColorSDL.cpp
Normal file
7
Widgets/ColorSDL.cpp
Normal file
|
@ -0,0 +1,7 @@
|
|||
#include "Color.h"
|
||||
#include "FrameBufferSDL.h"
|
||||
|
||||
Color::Color(byte r, byte g, byte b)
|
||||
{
|
||||
m_value = SDL_MapRGB(FrameBufferSDL::the().surface()->format, r, g, b);
|
||||
}
|
|
@ -1,6 +1,8 @@
|
|||
#include "EventLoopSDL.h"
|
||||
#include "Event.h"
|
||||
#include <SDL.h>
|
||||
#include "AbstractScreen.h"
|
||||
#include "Widget.h"
|
||||
|
||||
EventLoopSDL::EventLoopSDL()
|
||||
{
|
||||
|
@ -18,6 +20,16 @@ void EventLoopSDL::waitForEvent()
|
|||
case SDL_QUIT:
|
||||
postEvent(nullptr, make<QuitEvent>());
|
||||
return;
|
||||
case SDL_WINDOWEVENT:
|
||||
if (sdlEvent.window.event == SDL_WINDOWEVENT_EXPOSED) {
|
||||
// Spam paint events whenever we get exposed.
|
||||
// This is obviously not ideal, but the SDL backend here is just a prototype anyway.
|
||||
postEvent(AbstractScreen::the().rootWidget(), make<PaintEvent>());
|
||||
}
|
||||
return;
|
||||
case SDL_MOUSEMOTION:
|
||||
postEvent(&AbstractScreen::the(), make<MouseEvent>(Event::MouseMove, sdlEvent.motion.x, sdlEvent.motion.y));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,19 @@
|
|||
#include "FrameBufferSDL.h"
|
||||
#include <AK/Assertions.h>
|
||||
|
||||
FrameBufferSDL* s_the = nullptr;
|
||||
|
||||
FrameBufferSDL& FrameBufferSDL::the()
|
||||
{
|
||||
ASSERT(s_the);
|
||||
return *s_the;
|
||||
}
|
||||
|
||||
FrameBufferSDL::FrameBufferSDL(unsigned width, unsigned height)
|
||||
: AbstractScreen(width, height)
|
||||
{
|
||||
ASSERT(!s_the);
|
||||
s_the = this;
|
||||
initializeSDL();
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,11 @@ public:
|
|||
|
||||
void show();
|
||||
|
||||
SDL_Surface* surface() { return m_surface; }
|
||||
SDL_Window* window() { return m_window; }
|
||||
|
||||
static FrameBufferSDL& the();
|
||||
|
||||
private:
|
||||
void initializeSDL();
|
||||
|
||||
|
|
26
Widgets/Label.cpp
Normal file
26
Widgets/Label.cpp
Normal file
|
@ -0,0 +1,26 @@
|
|||
#include "Label.h"
|
||||
#include "Painter.h"
|
||||
#include <cstdio>
|
||||
|
||||
Label::Label(Widget* parent)
|
||||
: Widget(parent)
|
||||
{
|
||||
setRect(Rect(100, 100, 100, 100));
|
||||
}
|
||||
|
||||
Label::~Label()
|
||||
{
|
||||
}
|
||||
|
||||
void Label::onPaint(PaintEvent&)
|
||||
{
|
||||
Painter painter(*this);
|
||||
painter.fillRect({ 0, 0, width(), height() }, Color(0xc0, 0xc0, 0xc0));
|
||||
}
|
||||
|
||||
void Label::onMouseMove(MouseEvent& event)
|
||||
{
|
||||
printf("Label::onMouseMove: x=%d, y=%d\n", event.x(), event.y());
|
||||
Widget::onMouseMove(event);
|
||||
}
|
||||
|
16
Widgets/Label.h
Normal file
16
Widgets/Label.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
#pragma once
|
||||
|
||||
#include "Widget.h"
|
||||
|
||||
class Label final : public Widget {
|
||||
public:
|
||||
explicit Label(Widget* parent);
|
||||
virtual ~Label() override;
|
||||
|
||||
private:
|
||||
virtual void onPaint(PaintEvent&) override;
|
||||
virtual void onMouseMove(MouseEvent&) override;
|
||||
|
||||
virtual const char* className() const override { return "Label"; }
|
||||
};
|
||||
|
|
@ -14,6 +14,9 @@ VFS_OBJS = \
|
|||
Object.o \
|
||||
Widget.o \
|
||||
RootWidget.o \
|
||||
ColorSDL.o \
|
||||
Painter.o \
|
||||
Label.o \
|
||||
test.o
|
||||
|
||||
OBJS = $(AK_OBJS) $(VFS_OBJS)
|
||||
|
|
|
@ -5,10 +5,17 @@
|
|||
Object::Object(Object* parent)
|
||||
: m_parent(parent)
|
||||
{
|
||||
if (m_parent)
|
||||
m_parent->addChild(*this);
|
||||
}
|
||||
|
||||
Object::~Object()
|
||||
{
|
||||
if (m_parent)
|
||||
m_parent->removeChild(*this);
|
||||
for (auto* child : m_children) {
|
||||
delete child;
|
||||
}
|
||||
}
|
||||
|
||||
void Object::event(Event& event)
|
||||
|
@ -21,3 +28,19 @@ void Object::event(Event& event)
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Object::addChild(Object& object)
|
||||
{
|
||||
m_children.append(&object);
|
||||
}
|
||||
|
||||
void Object::removeChild(Object& object)
|
||||
{
|
||||
// Oh geez, Vector needs a remove() huh...
|
||||
Vector<Object*> newList;
|
||||
for (auto* child : m_children) {
|
||||
if (child != &object)
|
||||
newList.append(child);
|
||||
}
|
||||
m_children = std::move(newList);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <AK/Vector.h>
|
||||
|
||||
class Event;
|
||||
|
||||
class Object {
|
||||
|
@ -7,8 +9,17 @@ public:
|
|||
Object(Object* parent = nullptr);
|
||||
virtual ~Object();
|
||||
|
||||
virtual const char* className() const { return "Object"; }
|
||||
|
||||
virtual void event(Event&);
|
||||
|
||||
Vector<Object*>& children() { return m_children; }
|
||||
|
||||
private:
|
||||
void addChild(Object&);
|
||||
void removeChild(Object&);
|
||||
|
||||
Object* m_parent { nullptr };
|
||||
|
||||
Vector<Object*> m_children;
|
||||
};
|
||||
|
|
30
Widgets/Painter.cpp
Normal file
30
Widgets/Painter.cpp
Normal file
|
@ -0,0 +1,30 @@
|
|||
#include "Painter.h"
|
||||
#include "FrameBufferSDL.h"
|
||||
#include "Widget.h"
|
||||
#include <AK/Assertions.h>
|
||||
#include <SDL.h>
|
||||
|
||||
Painter::Painter(Widget& widget)
|
||||
: m_widget(widget)
|
||||
{
|
||||
}
|
||||
|
||||
Painter::~Painter()
|
||||
{
|
||||
int rc = SDL_UpdateWindowSurface(FrameBufferSDL::the().window());
|
||||
ASSERT(rc == 0);
|
||||
}
|
||||
|
||||
void Painter::fillRect(Rect rect, Color color)
|
||||
{
|
||||
rect.moveBy(m_widget.x(), m_widget.y());
|
||||
|
||||
SDL_Rect sdlRect;
|
||||
sdlRect.x = rect.x();
|
||||
sdlRect.y = rect.y();
|
||||
sdlRect.w = rect.width();
|
||||
sdlRect.h = rect.height();
|
||||
|
||||
int rc = SDL_FillRect(FrameBufferSDL::the().surface(), &sdlRect, color.value());
|
||||
ASSERT(rc == 0);
|
||||
}
|
16
Widgets/Painter.h
Normal file
16
Widgets/Painter.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
#pragma once
|
||||
|
||||
#include "Color.h"
|
||||
#include "Rect.h"
|
||||
|
||||
class Widget;
|
||||
|
||||
class Painter {
|
||||
public:
|
||||
explicit Painter(Widget&);
|
||||
~Painter();
|
||||
void fillRect(Rect, Color);
|
||||
|
||||
private:
|
||||
Widget& m_widget;
|
||||
};
|
45
Widgets/Rect.h
Normal file
45
Widgets/Rect.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
#pragma once
|
||||
|
||||
class Rect {
|
||||
public:
|
||||
Rect() { }
|
||||
Rect(int x, int y, int width, int height)
|
||||
: m_x(x)
|
||||
, m_y(y)
|
||||
, m_width(width)
|
||||
, m_height(height)
|
||||
{
|
||||
}
|
||||
|
||||
void moveBy(int dx, int dy)
|
||||
{
|
||||
m_x += dx;
|
||||
m_y += dy;
|
||||
}
|
||||
|
||||
bool contains(int x, int y) const
|
||||
{
|
||||
return x >= m_x && x <= right() && y >= m_y && y <= bottom();
|
||||
}
|
||||
|
||||
int left() const { return m_x; }
|
||||
int right() const { return m_x + m_width; }
|
||||
int top() const { return m_y; }
|
||||
int bottom() const { return m_y + m_height; }
|
||||
|
||||
int x() const { return m_x; }
|
||||
int y() const { return m_y; }
|
||||
int width() const { return m_width; }
|
||||
int height() const { return m_height; }
|
||||
|
||||
void setX(int x) { m_x = x; }
|
||||
void setY(int y) { m_y = y; }
|
||||
void setWidth(int width) { m_width = width; }
|
||||
void setHeight(int height) { m_height = height; }
|
||||
|
||||
private:
|
||||
int m_x { 0 };
|
||||
int m_y { 0 };
|
||||
int m_width { 0 };
|
||||
int m_height { 0 };
|
||||
};
|
|
@ -1,4 +1,5 @@
|
|||
#include "RootWidget.h"
|
||||
#include "Painter.h"
|
||||
#include <cstdio>
|
||||
|
||||
RootWidget::RootWidget()
|
||||
|
@ -12,6 +13,8 @@ RootWidget::~RootWidget()
|
|||
void RootWidget::onPaint(PaintEvent& event)
|
||||
{
|
||||
printf("RootWidget::onPaint\n");
|
||||
Painter painter(*this);
|
||||
painter.fillRect(Rect(0, 0, 800, 600), Color(0x80, 0x80, 0x80));
|
||||
Widget::onPaint(event);
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,13 @@ Widget::~Widget()
|
|||
{
|
||||
}
|
||||
|
||||
void Widget::setRect(const Rect& rect)
|
||||
{
|
||||
// FIXME: Make some kind of event loop driven ResizeEvent?
|
||||
m_rect = rect;
|
||||
update();
|
||||
}
|
||||
|
||||
void Widget::event(Event& event)
|
||||
{
|
||||
switch (event.type()) {
|
||||
|
@ -36,8 +43,13 @@ void Widget::event(Event& event)
|
|||
}
|
||||
}
|
||||
|
||||
void Widget::onPaint(PaintEvent&)
|
||||
void Widget::onPaint(PaintEvent& event)
|
||||
{
|
||||
printf("Widget::onPaint :)\n");
|
||||
for (auto* ch : children()) {
|
||||
auto* child = (Widget*)ch;
|
||||
child->onPaint(event);
|
||||
}
|
||||
}
|
||||
|
||||
void Widget::onShow(ShowEvent&)
|
||||
|
@ -74,3 +86,15 @@ void Widget::update()
|
|||
EventLoop::main().postEvent(this, make<PaintEvent>());
|
||||
}
|
||||
|
||||
Widget::HitTestResult Widget::hitTest(int x, int y)
|
||||
{
|
||||
// FIXME: Care about z-order.
|
||||
for (auto* ch : children()) {
|
||||
auto* child = (Widget*)ch;
|
||||
if (child->rect().contains(x, y)) {
|
||||
return child->hitTest(x - child->rect().x(), y - child->rect().y());
|
||||
}
|
||||
}
|
||||
return { this, x, y };
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "Event.h"
|
||||
#include "Object.h"
|
||||
#include "Rect.h"
|
||||
|
||||
class Widget : public Object {
|
||||
public:
|
||||
|
@ -18,9 +19,25 @@ public:
|
|||
virtual void onMouseDown(MouseEvent&);
|
||||
virtual void onMouseUp(MouseEvent&);
|
||||
|
||||
Rect rect() const { return m_rect; }
|
||||
int x() const { return rect().x(); }
|
||||
int y() const { return rect().y(); }
|
||||
int width() const { return rect().width(); }
|
||||
int height() const { return rect().height(); }
|
||||
|
||||
void update();
|
||||
|
||||
struct HitTestResult {
|
||||
Widget* widget { nullptr };
|
||||
int localX { 0 };
|
||||
int localY { 0 };
|
||||
};
|
||||
HitTestResult hitTest(int x, int y);
|
||||
|
||||
virtual const char* className() const override { return "Widget"; }
|
||||
|
||||
void setRect(const Rect&);
|
||||
|
||||
private:
|
||||
int m_x { 0 };
|
||||
int m_y { 0 };
|
||||
Rect m_rect;
|
||||
};
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "FrameBufferSDL.h"
|
||||
#include "EventLoopSDL.h"
|
||||
#include "RootWidget.h"
|
||||
#include "Label.h"
|
||||
#include <cstdio>
|
||||
|
||||
int main(int c, char** v)
|
||||
|
@ -13,5 +14,7 @@ int main(int c, char** v)
|
|||
RootWidget w;
|
||||
fb.setRootWidget(&w);
|
||||
|
||||
Label l(&w);
|
||||
|
||||
return loop.exec();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue