mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 17:27:35 +00:00
Intense hacking on Widgets.
This commit is contained in:
parent
8c84f9749e
commit
6f37429f57
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)
|
AbstractScreen::AbstractScreen(unsigned width, unsigned height)
|
||||||
: m_width(width)
|
: Object(nullptr)
|
||||||
|
, m_width(width)
|
||||||
, m_height(height)
|
, m_height(height)
|
||||||
{
|
{
|
||||||
ASSERT(!s_the);
|
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)
|
void AbstractScreen::setRootWidget(Widget* widget)
|
||||||
{
|
{
|
||||||
// FIXME: Should we support switching root widgets?
|
// FIXME: Should we support switching root widgets?
|
||||||
|
|
|
@ -1,14 +1,17 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "Object.h"
|
||||||
|
|
||||||
class Widget;
|
class Widget;
|
||||||
|
|
||||||
class AbstractScreen {
|
class AbstractScreen : public Object {
|
||||||
public:
|
public:
|
||||||
virtual ~AbstractScreen();
|
virtual ~AbstractScreen();
|
||||||
|
|
||||||
unsigned width() const { return m_width; }
|
unsigned width() const { return m_width; }
|
||||||
unsigned height() const { return m_height; }
|
unsigned height() const { return m_height; }
|
||||||
|
|
||||||
|
Widget* rootWidget() { return m_rootWidget; }
|
||||||
void setRootWidget(Widget*);
|
void setRootWidget(Widget*);
|
||||||
|
|
||||||
static AbstractScreen& the();
|
static AbstractScreen& the();
|
||||||
|
@ -17,6 +20,8 @@ protected:
|
||||||
AbstractScreen(unsigned width, unsigned height);
|
AbstractScreen(unsigned width, unsigned height);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
virtual void event(Event&) override;
|
||||||
|
|
||||||
unsigned m_width { 0 };
|
unsigned m_width { 0 };
|
||||||
unsigned m_height { 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 "EventLoopSDL.h"
|
||||||
#include "Event.h"
|
#include "Event.h"
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
|
#include "AbstractScreen.h"
|
||||||
|
#include "Widget.h"
|
||||||
|
|
||||||
EventLoopSDL::EventLoopSDL()
|
EventLoopSDL::EventLoopSDL()
|
||||||
{
|
{
|
||||||
|
@ -18,6 +20,16 @@ void EventLoopSDL::waitForEvent()
|
||||||
case SDL_QUIT:
|
case SDL_QUIT:
|
||||||
postEvent(nullptr, make<QuitEvent>());
|
postEvent(nullptr, make<QuitEvent>());
|
||||||
return;
|
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 "FrameBufferSDL.h"
|
||||||
#include <AK/Assertions.h>
|
#include <AK/Assertions.h>
|
||||||
|
|
||||||
|
FrameBufferSDL* s_the = nullptr;
|
||||||
|
|
||||||
|
FrameBufferSDL& FrameBufferSDL::the()
|
||||||
|
{
|
||||||
|
ASSERT(s_the);
|
||||||
|
return *s_the;
|
||||||
|
}
|
||||||
|
|
||||||
FrameBufferSDL::FrameBufferSDL(unsigned width, unsigned height)
|
FrameBufferSDL::FrameBufferSDL(unsigned width, unsigned height)
|
||||||
: AbstractScreen(width, height)
|
: AbstractScreen(width, height)
|
||||||
{
|
{
|
||||||
|
ASSERT(!s_the);
|
||||||
|
s_the = this;
|
||||||
initializeSDL();
|
initializeSDL();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,11 @@ public:
|
||||||
|
|
||||||
void show();
|
void show();
|
||||||
|
|
||||||
|
SDL_Surface* surface() { return m_surface; }
|
||||||
|
SDL_Window* window() { return m_window; }
|
||||||
|
|
||||||
|
static FrameBufferSDL& the();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void initializeSDL();
|
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 \
|
Object.o \
|
||||||
Widget.o \
|
Widget.o \
|
||||||
RootWidget.o \
|
RootWidget.o \
|
||||||
|
ColorSDL.o \
|
||||||
|
Painter.o \
|
||||||
|
Label.o \
|
||||||
test.o
|
test.o
|
||||||
|
|
||||||
OBJS = $(AK_OBJS) $(VFS_OBJS)
|
OBJS = $(AK_OBJS) $(VFS_OBJS)
|
||||||
|
|
|
@ -5,10 +5,17 @@
|
||||||
Object::Object(Object* parent)
|
Object::Object(Object* parent)
|
||||||
: m_parent(parent)
|
: m_parent(parent)
|
||||||
{
|
{
|
||||||
|
if (m_parent)
|
||||||
|
m_parent->addChild(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object::~Object()
|
Object::~Object()
|
||||||
{
|
{
|
||||||
|
if (m_parent)
|
||||||
|
m_parent->removeChild(*this);
|
||||||
|
for (auto* child : m_children) {
|
||||||
|
delete child;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Object::event(Event& event)
|
void Object::event(Event& event)
|
||||||
|
@ -21,3 +28,19 @@ void Object::event(Event& event)
|
||||||
break;
|
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
|
#pragma once
|
||||||
|
|
||||||
|
#include <AK/Vector.h>
|
||||||
|
|
||||||
class Event;
|
class Event;
|
||||||
|
|
||||||
class Object {
|
class Object {
|
||||||
|
@ -7,8 +9,17 @@ public:
|
||||||
Object(Object* parent = nullptr);
|
Object(Object* parent = nullptr);
|
||||||
virtual ~Object();
|
virtual ~Object();
|
||||||
|
|
||||||
|
virtual const char* className() const { return "Object"; }
|
||||||
|
|
||||||
virtual void event(Event&);
|
virtual void event(Event&);
|
||||||
|
|
||||||
|
Vector<Object*>& children() { return m_children; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void addChild(Object&);
|
||||||
|
void removeChild(Object&);
|
||||||
|
|
||||||
Object* m_parent { nullptr };
|
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 "RootWidget.h"
|
||||||
|
#include "Painter.h"
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
|
||||||
RootWidget::RootWidget()
|
RootWidget::RootWidget()
|
||||||
|
@ -12,6 +13,8 @@ RootWidget::~RootWidget()
|
||||||
void RootWidget::onPaint(PaintEvent& event)
|
void RootWidget::onPaint(PaintEvent& event)
|
||||||
{
|
{
|
||||||
printf("RootWidget::onPaint\n");
|
printf("RootWidget::onPaint\n");
|
||||||
|
Painter painter(*this);
|
||||||
|
painter.fillRect(Rect(0, 0, 800, 600), Color(0x80, 0x80, 0x80));
|
||||||
Widget::onPaint(event);
|
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)
|
void Widget::event(Event& event)
|
||||||
{
|
{
|
||||||
switch (event.type()) {
|
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&)
|
void Widget::onShow(ShowEvent&)
|
||||||
|
@ -74,3 +86,15 @@ void Widget::update()
|
||||||
EventLoop::main().postEvent(this, make<PaintEvent>());
|
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 "Event.h"
|
||||||
#include "Object.h"
|
#include "Object.h"
|
||||||
|
#include "Rect.h"
|
||||||
|
|
||||||
class Widget : public Object {
|
class Widget : public Object {
|
||||||
public:
|
public:
|
||||||
|
@ -18,9 +19,25 @@ public:
|
||||||
virtual void onMouseDown(MouseEvent&);
|
virtual void onMouseDown(MouseEvent&);
|
||||||
virtual void onMouseUp(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();
|
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:
|
private:
|
||||||
int m_x { 0 };
|
Rect m_rect;
|
||||||
int m_y { 0 };
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "FrameBufferSDL.h"
|
#include "FrameBufferSDL.h"
|
||||||
#include "EventLoopSDL.h"
|
#include "EventLoopSDL.h"
|
||||||
#include "RootWidget.h"
|
#include "RootWidget.h"
|
||||||
|
#include "Label.h"
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
|
||||||
int main(int c, char** v)
|
int main(int c, char** v)
|
||||||
|
@ -13,5 +14,7 @@ int main(int c, char** v)
|
||||||
RootWidget w;
|
RootWidget w;
|
||||||
fb.setRootWidget(&w);
|
fb.setRootWidget(&w);
|
||||||
|
|
||||||
|
Label l(&w);
|
||||||
|
|
||||||
return loop.exec();
|
return loop.exec();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue