diff options
-rw-r--r-- | Widgets/.gitignore | 3 | ||||
-rw-r--r-- | Widgets/AbstractScreen.cpp | 14 | ||||
-rw-r--r-- | Widgets/AbstractScreen.h | 7 | ||||
-rw-r--r-- | Widgets/Color.h | 14 | ||||
-rw-r--r-- | Widgets/ColorSDL.cpp | 7 | ||||
-rw-r--r-- | Widgets/EventLoopSDL.cpp | 12 | ||||
-rw-r--r-- | Widgets/FrameBufferSDL.cpp | 10 | ||||
-rw-r--r-- | Widgets/FrameBufferSDL.h | 5 | ||||
-rw-r--r-- | Widgets/Label.cpp | 26 | ||||
-rw-r--r-- | Widgets/Label.h | 16 | ||||
-rw-r--r-- | Widgets/Makefile | 3 | ||||
-rw-r--r-- | Widgets/Object.cpp | 23 | ||||
-rw-r--r-- | Widgets/Object.h | 11 | ||||
-rw-r--r-- | Widgets/Painter.cpp | 30 | ||||
-rw-r--r-- | Widgets/Painter.h | 16 | ||||
-rw-r--r-- | Widgets/Rect.h | 45 | ||||
-rw-r--r-- | Widgets/RootWidget.cpp | 3 | ||||
-rw-r--r-- | Widgets/Widget.cpp | 26 | ||||
-rw-r--r-- | Widgets/Widget.h | 21 | ||||
-rw-r--r-- | Widgets/test.cpp | 3 |
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(); } |