summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Widgets/.gitignore3
-rw-r--r--Widgets/AbstractScreen.cpp14
-rw-r--r--Widgets/AbstractScreen.h7
-rw-r--r--Widgets/Color.h14
-rw-r--r--Widgets/ColorSDL.cpp7
-rw-r--r--Widgets/EventLoopSDL.cpp12
-rw-r--r--Widgets/FrameBufferSDL.cpp10
-rw-r--r--Widgets/FrameBufferSDL.h5
-rw-r--r--Widgets/Label.cpp26
-rw-r--r--Widgets/Label.h16
-rw-r--r--Widgets/Makefile3
-rw-r--r--Widgets/Object.cpp23
-rw-r--r--Widgets/Object.h11
-rw-r--r--Widgets/Painter.cpp30
-rw-r--r--Widgets/Painter.h16
-rw-r--r--Widgets/Rect.h45
-rw-r--r--Widgets/RootWidget.cpp3
-rw-r--r--Widgets/Widget.cpp26
-rw-r--r--Widgets/Widget.h21
-rw-r--r--Widgets/test.cpp3
20 files changed, 290 insertions, 5 deletions
diff --git a/Widgets/.gitignore b/Widgets/.gitignore
new file mode 100644
index 0000000000..677b78a50b
--- /dev/null
+++ b/Widgets/.gitignore
@@ -0,0 +1,3 @@
+*.o
+*.swp
+test
diff --git a/Widgets/AbstractScreen.cpp b/Widgets/AbstractScreen.cpp
index d9216de1e1..4f2536bbc1 100644
--- a/Widgets/AbstractScreen.cpp
+++ b/Widgets/AbstractScreen.cpp
@@ -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?
diff --git a/Widgets/AbstractScreen.h b/Widgets/AbstractScreen.h
index a607221777..f56d7fdb28 100644
--- a/Widgets/AbstractScreen.h
+++ b/Widgets/AbstractScreen.h
@@ -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 };
diff --git a/Widgets/Color.h b/Widgets/Color.h
new file mode 100644
index 0000000000..162261723e
--- /dev/null
+++ b/Widgets/Color.h
@@ -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 };
+};
diff --git a/Widgets/ColorSDL.cpp b/Widgets/ColorSDL.cpp
new file mode 100644
index 0000000000..ec6f94bf89
--- /dev/null
+++ b/Widgets/ColorSDL.cpp
@@ -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);
+}
diff --git a/Widgets/EventLoopSDL.cpp b/Widgets/EventLoopSDL.cpp
index 8092a67bd0..13eb047075 100644
--- a/Widgets/EventLoopSDL.cpp
+++ b/Widgets/EventLoopSDL.cpp
@@ -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;
}
}
}
diff --git a/Widgets/FrameBufferSDL.cpp b/Widgets/FrameBufferSDL.cpp
index cc43c41706..f7dce0dfc8 100644
--- a/Widgets/FrameBufferSDL.cpp
+++ b/Widgets/FrameBufferSDL.cpp
@@ -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();
}
diff --git a/Widgets/FrameBufferSDL.h b/Widgets/FrameBufferSDL.h
index 9d58894427..f85b633d64 100644
--- a/Widgets/FrameBufferSDL.h
+++ b/Widgets/FrameBufferSDL.h
@@ -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();
diff --git a/Widgets/Label.cpp b/Widgets/Label.cpp
new file mode 100644
index 0000000000..33fa210179
--- /dev/null
+++ b/Widgets/Label.cpp
@@ -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);
+}
+
diff --git a/Widgets/Label.h b/Widgets/Label.h
new file mode 100644
index 0000000000..959b284e75
--- /dev/null
+++ b/Widgets/Label.h
@@ -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"; }
+};
+
diff --git a/Widgets/Makefile b/Widgets/Makefile
index 58c3678f0c..fa5049643b 100644
--- a/Widgets/Makefile
+++ b/Widgets/Makefile
@@ -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)
diff --git a/Widgets/Object.cpp b/Widgets/Object.cpp
index bf7fa7469b..70d96b2c8c 100644
--- a/Widgets/Object.cpp
+++ b/Widgets/Object.cpp
@@ -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);
+}
diff --git a/Widgets/Object.h b/Widgets/Object.h
index 4b0d0a64f9..bee2d06e56 100644
--- a/Widgets/Object.h
+++ b/Widgets/Object.h
@@ -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;
};
diff --git a/Widgets/Painter.cpp b/Widgets/Painter.cpp
new file mode 100644
index 0000000000..589b9c6558
--- /dev/null
+++ b/Widgets/Painter.cpp
@@ -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);
+}
diff --git a/Widgets/Painter.h b/Widgets/Painter.h
new file mode 100644
index 0000000000..2865b9dcce
--- /dev/null
+++ b/Widgets/Painter.h
@@ -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;
+};
diff --git a/Widgets/Rect.h b/Widgets/Rect.h
new file mode 100644
index 0000000000..7726dbc718
--- /dev/null
+++ b/Widgets/Rect.h
@@ -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 };
+};
diff --git a/Widgets/RootWidget.cpp b/Widgets/RootWidget.cpp
index b1b54a5682..67d9a372b3 100644
--- a/Widgets/RootWidget.cpp
+++ b/Widgets/RootWidget.cpp
@@ -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);
}
diff --git a/Widgets/Widget.cpp b/Widgets/Widget.cpp
index 3a1ec8e0f8..a51cb0ba7c 100644
--- a/Widgets/Widget.cpp
+++ b/Widgets/Widget.cpp
@@ -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 };
+}
+
diff --git a/Widgets/Widget.h b/Widgets/Widget.h
index be6966300d..b934a157a9 100644
--- a/Widgets/Widget.h
+++ b/Widgets/Widget.h
@@ -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;
};
diff --git a/Widgets/test.cpp b/Widgets/test.cpp
index b42c7a8275..a77fb3063e 100644
--- a/Widgets/test.cpp
+++ b/Widgets/test.cpp
@@ -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();
}