From 73895ce043fcd4eeb6f84645dc1b46ca58788e62 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Fri, 12 Oct 2018 12:18:59 +0200 Subject: [PATCH] Add a clock widget. --- Widgets/ClockWidget.cpp | 37 +++++++++++++++++++++++++++++++++++++ Widgets/ClockWidget.h | 16 ++++++++++++++++ Widgets/Event.h | 12 ++++++++++-- Widgets/Makefile | 3 ++- Widgets/Object.cpp | 39 +++++++++++++++++++++++++++++++++++++++ Widgets/Object.h | 9 +++++++++ Widgets/Painter.cpp | 1 - Widgets/Widget.cpp | 5 +++++ Widgets/Window.cpp | 8 +++++--- Widgets/Window.h | 4 ++++ Widgets/WindowManager.cpp | 2 ++ Widgets/test.cpp | 22 ++++++++++++++-------- 12 files changed, 143 insertions(+), 15 deletions(-) create mode 100644 Widgets/ClockWidget.cpp create mode 100644 Widgets/ClockWidget.h diff --git a/Widgets/ClockWidget.cpp b/Widgets/ClockWidget.cpp new file mode 100644 index 0000000000..a4778e2ca2 --- /dev/null +++ b/Widgets/ClockWidget.cpp @@ -0,0 +1,37 @@ +#include "ClockWidget.h" +#include "Painter.h" +#include + +ClockWidget::ClockWidget(Widget* parent) + : Widget(parent) +{ + setRect({ 0, 0, 100, 40 }); + startTimer(250); +} + +ClockWidget::~ClockWidget() +{ +} + +void ClockWidget::onPaint(PaintEvent&) +{ + auto now = time(nullptr); + auto& tm = *localtime(&now); + + char timeBuf[128]; + sprintf(timeBuf, "%02u:%02u:%02u ", tm.tm_hour, tm.tm_min, tm.tm_sec); + + Painter painter(*this); + painter.fillRect(rect(), Color(127, 127, 127)); + painter.drawText(rect(), timeBuf, Painter::TextAlignment::Center, Color(0,0,0)); +} + +void ClockWidget::onTimer(TimerEvent&) +{ + auto now = time(nullptr); + if (now == m_lastSeenTimestamp) + return; + m_lastSeenTimestamp = now; + update(); +} + diff --git a/Widgets/ClockWidget.h b/Widgets/ClockWidget.h new file mode 100644 index 0000000000..3ddf269030 --- /dev/null +++ b/Widgets/ClockWidget.h @@ -0,0 +1,16 @@ +#pragma once + +#include "Widget.h" + +class ClockWidget final : public Widget { +public: + explicit ClockWidget(Widget* parent = nullptr); + virtual ~ClockWidget() override; + +private: + virtual void onPaint(PaintEvent&) override; + virtual void onTimer(TimerEvent&) override; + + dword m_lastSeenTimestamp { 0 }; +}; + diff --git a/Widgets/Event.h b/Widgets/Event.h index 9dcde5827e..6de27b79e0 100644 --- a/Widgets/Event.h +++ b/Widgets/Event.h @@ -14,6 +14,7 @@ static const char* eventNames[] = { "MouseUp", "KeyDown", "KeyUp", + "Timer", }; class Event { @@ -29,6 +30,7 @@ public: MouseUp, KeyDown, KeyUp, + Timer, }; Event() { } @@ -88,7 +90,7 @@ enum class MouseButton : byte { Right, }; -class KeyEvent : public Event { +class KeyEvent final : public Event { public: KeyEvent(Type type, int key) : Event(type) @@ -102,7 +104,7 @@ private: int m_key { 0 }; }; -class MouseEvent : public Event { +class MouseEvent final : public Event { public: MouseEvent(Type type, int x, int y, MouseButton button = MouseButton::None) : Event(type) @@ -121,3 +123,9 @@ private: MouseButton m_button { MouseButton::None }; }; +class TimerEvent final : public Event { +public: + TimerEvent() : Event(Event::Timer) { } + ~TimerEvent() { } +}; + diff --git a/Widgets/Makefile b/Widgets/Makefile index f11a3980df..818de90d2d 100644 --- a/Widgets/Makefile +++ b/Widgets/Makefile @@ -22,11 +22,12 @@ VFS_OBJS = \ WindowManager.o \ Font.o \ Window.o \ + ClockWidget.o \ test.o OBJS = $(AK_OBJS) $(VFS_OBJS) -CXXFLAGS = -std=c++17 -O0 -W -Wall -Wextra -Wconversion -I. -I.. -g `sdl2-config --cflags` +CXXFLAGS = -std=c++17 -O0 -W -Wall -Wextra -Wconversion -I. -I.. -g `sdl2-config --cflags` -DUSE_SDL LDFLAGS = `sdl2-config --libs` diff --git a/Widgets/Object.cpp b/Widgets/Object.cpp index 57216928a2..a46657a6d0 100644 --- a/Widgets/Object.cpp +++ b/Widgets/Object.cpp @@ -1,7 +1,12 @@ #include "Object.h" #include "Event.h" +#include "EventLoop.h" #include +#ifdef USE_SDL +#include +#endif + Object::Object(Object* parent) : m_parent(parent) { @@ -21,6 +26,8 @@ Object::~Object() void Object::event(Event& event) { switch (event.type()) { + case Event::Timer: + return onTimer(static_cast(event)); case Event::Invalid: ASSERT_NOT_REACHED(); break; @@ -44,3 +51,35 @@ void Object::removeChild(Object& object) } m_children = std::move(newList); } + +void Object::onTimer(TimerEvent&) +{ +} + +#ifdef USE_SDL +static dword sdlTimerCallback(dword interval, void* param) +{ + EventLoop::main().postEvent(static_cast(param), make()); + return interval; +} +#endif + +void Object::startTimer(int ms) +{ + if (m_timerID) { + printf("Object{%p} already has a timer!\n", this); + ASSERT_NOT_REACHED(); + } +#if USE_SDL + m_timerID = SDL_AddTimer(ms, sdlTimerCallback, this); +#endif +} + +void Object::stopTimer() +{ + if (!m_timerID) + return; + SDL_RemoveTimer(m_timerID); + m_timerID = 0; +} + diff --git a/Widgets/Object.h b/Widgets/Object.h index 3ecd19db5b..028515ce1a 100644 --- a/Widgets/Object.h +++ b/Widgets/Object.h @@ -3,6 +3,7 @@ #include class Event; +class TimerEvent; class Object { public: @@ -18,11 +19,19 @@ public: Object* parent() { return m_parent; } const Object* parent() const { return m_parent; } + void startTimer(int ms); + void stopTimer(); + bool hasTimer() const { return m_timerID; } + private: + virtual void onTimer(TimerEvent&); + void addChild(Object&); void removeChild(Object&); Object* m_parent { nullptr }; + int m_timerID { 0 }; + Vector m_children; }; diff --git a/Widgets/Painter.cpp b/Widgets/Painter.cpp index c5c8d7adbd..c872d22868 100644 --- a/Widgets/Painter.cpp +++ b/Widgets/Painter.cpp @@ -11,7 +11,6 @@ Painter::Painter(Widget& widget) , m_font(Font::defaultFont()) { if (auto* window = widget.window()) { - printf("window :: %s\n", window->title().characters()); m_translation = window->position(); m_translation.moveBy(widget.position()); } else { diff --git a/Widgets/Widget.cpp b/Widgets/Widget.cpp index ecaf60328d..da4fe8914c 100644 --- a/Widgets/Widget.cpp +++ b/Widgets/Widget.cpp @@ -2,6 +2,7 @@ #include "Event.h" #include "EventLoop.h" #include "WindowManager.h" +#include "Window.h" #include Widget::Widget(Widget* parent) @@ -26,6 +27,10 @@ void Widget::event(Event& event) { switch (event.type()) { case Event::Paint: + if (auto* win = window()) { + if (win->isBeingDragged()) + return; + } m_hasPendingPaintEvent = false; return onPaint(static_cast(event)); case Event::Show: diff --git a/Widgets/Window.cpp b/Widgets/Window.cpp index 230150bfb5..118c75cc27 100644 --- a/Widgets/Window.cpp +++ b/Widgets/Window.cpp @@ -50,10 +50,12 @@ void Window::event(Event& event) } if (event.isPaintEvent()) { - if (m_mainWidget) { - printf("forward to main widget\n"); - return m_mainWidget->event(event); + if (isBeingDragged()) { + // Ignore paint events during window drag. + return; } + if (m_mainWidget) + return m_mainWidget->event(event); } return Object::event(event); diff --git a/Widgets/Window.h b/Widgets/Window.h index 93119c08f9..f37f75c757 100644 --- a/Widgets/Window.h +++ b/Widgets/Window.h @@ -32,9 +32,13 @@ public: virtual void event(Event&) override; + bool isBeingDragged() const { return m_isBeingDragged; } + void setIsBeingDragged(bool b) { m_isBeingDragged = b; } + private: String m_title; Rect m_rect; Widget* m_mainWidget { nullptr }; + bool m_isBeingDragged { false }; }; diff --git a/Widgets/WindowManager.cpp b/Widgets/WindowManager.cpp index 03e5a6cb2e..f12405a8b9 100644 --- a/Widgets/WindowManager.cpp +++ b/Widgets/WindowManager.cpp @@ -124,6 +124,7 @@ void WindowManager::handleTitleBarMouseEvent(Window& window, MouseEvent& event) m_dragWindow = &window; m_dragOrigin = event.position(); m_dragWindowOrigin = window.position(); + window.setIsBeingDragged(true); return; } #if 0 @@ -140,6 +141,7 @@ void WindowManager::processMouseEvent(MouseEvent& event) if (event.type() == Event::MouseUp) { if (m_dragWindow) { printf("[WM] Finish dragging Window{%p}\n", m_dragWindow); + m_dragWindow->setIsBeingDragged(false); m_dragWindow = nullptr; EventLoop::main().postEvent(this, make()); return; diff --git a/Widgets/test.cpp b/Widgets/test.cpp index 0b2bad48ab..43a5a82e58 100644 --- a/Widgets/test.cpp +++ b/Widgets/test.cpp @@ -6,6 +6,7 @@ #include "TerminalWidget.h" #include "WindowManager.h" #include "Window.h" +#include "ClockWidget.h" #include int main(int c, char** v) @@ -20,38 +21,43 @@ int main(int c, char** v) auto* fontTestWindow = new Window; fontTestWindow->setTitle("Font test"); - fontTestWindow->setRect({100, 100, 300, 80 }); + fontTestWindow->setRect({ 100, 100, 300, 80 }); auto* fontTestWindowWidget = new Widget; fontTestWindow->setMainWidget(fontTestWindowWidget); - fontTestWindowWidget->setRect({0, 0, 300, 80 }); + fontTestWindowWidget->setRect({ 0, 0, 300, 80 }); auto* l1 = new Label(fontTestWindowWidget); - l1->setRect(Rect(0, 0, 300, 20)); + l1->setRect({ 0, 0, 300, 20 }); l1->setText("0123456789"); auto* l2 = new Label(fontTestWindowWidget); - l2->setRect(Rect(0, 20, 300, 20)); + l2->setRect({ 0, 20, 300, 20 }); l2->setText("ABCDEFGHIJKLMNOPQRSTUVWXYZ"); auto* l3 = new Label(fontTestWindowWidget); - l3->setRect(Rect(0, 40, 300, 20)); + l3->setRect({ 0, 40, 300, 20 }); l3->setText("abcdefghijklmnopqrstuvwxyz"); auto* l4 = new Label(fontTestWindowWidget); - l4->setRect(Rect(0, 60, 300, 20)); + l4->setRect({ 0, 60, 300, 20 }); l4->setText("!\"#$%&'()*+,-./:;<=>?@[\\]^_{|}~"); auto* b = new Button(&w); - b->setRect(Rect(10, 10, 100, 30)); + b->setRect({ 10, 10, 100, 30 }); b->setCaption("Button!"); auto* win = new Window; win->setTitle("Console"); - win->setRect({100, 300, 644, 254}); + win->setRect({ 100, 300, 644, 254 }); auto* t = new TerminalWidget(nullptr); win->setMainWidget(t); + auto* clockWin = new Window; + clockWin->setTitle("Clock"); + clockWin->setRect({ 500, 50, 100, 40 }); + clockWin->setMainWidget(new ClockWidget); + return loop.exec(); }