Add a clock widget.

This commit is contained in:
Andreas Kling 2018-10-12 12:18:59 +02:00
parent 6637dec958
commit 73895ce043
12 changed files with 143 additions and 15 deletions

37
Widgets/ClockWidget.cpp Normal file
View file

@ -0,0 +1,37 @@
#include "ClockWidget.h"
#include "Painter.h"
#include <time.h>
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();
}

16
Widgets/ClockWidget.h Normal file
View file

@ -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 };
};

View file

@ -14,6 +14,7 @@ static const char* eventNames[] = {
"MouseUp", "MouseUp",
"KeyDown", "KeyDown",
"KeyUp", "KeyUp",
"Timer",
}; };
class Event { class Event {
@ -29,6 +30,7 @@ public:
MouseUp, MouseUp,
KeyDown, KeyDown,
KeyUp, KeyUp,
Timer,
}; };
Event() { } Event() { }
@ -88,7 +90,7 @@ enum class MouseButton : byte {
Right, Right,
}; };
class KeyEvent : public Event { class KeyEvent final : public Event {
public: public:
KeyEvent(Type type, int key) KeyEvent(Type type, int key)
: Event(type) : Event(type)
@ -102,7 +104,7 @@ private:
int m_key { 0 }; int m_key { 0 };
}; };
class MouseEvent : public Event { class MouseEvent final : public Event {
public: public:
MouseEvent(Type type, int x, int y, MouseButton button = MouseButton::None) MouseEvent(Type type, int x, int y, MouseButton button = MouseButton::None)
: Event(type) : Event(type)
@ -121,3 +123,9 @@ private:
MouseButton m_button { MouseButton::None }; MouseButton m_button { MouseButton::None };
}; };
class TimerEvent final : public Event {
public:
TimerEvent() : Event(Event::Timer) { }
~TimerEvent() { }
};

View file

@ -22,11 +22,12 @@ VFS_OBJS = \
WindowManager.o \ WindowManager.o \
Font.o \ Font.o \
Window.o \ Window.o \
ClockWidget.o \
test.o test.o
OBJS = $(AK_OBJS) $(VFS_OBJS) 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` LDFLAGS = `sdl2-config --libs`

View file

@ -1,7 +1,12 @@
#include "Object.h" #include "Object.h"
#include "Event.h" #include "Event.h"
#include "EventLoop.h"
#include <AK/Assertions.h> #include <AK/Assertions.h>
#ifdef USE_SDL
#include <SDL.h>
#endif
Object::Object(Object* parent) Object::Object(Object* parent)
: m_parent(parent) : m_parent(parent)
{ {
@ -21,6 +26,8 @@ Object::~Object()
void Object::event(Event& event) void Object::event(Event& event)
{ {
switch (event.type()) { switch (event.type()) {
case Event::Timer:
return onTimer(static_cast<TimerEvent&>(event));
case Event::Invalid: case Event::Invalid:
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
break; break;
@ -44,3 +51,35 @@ void Object::removeChild(Object& object)
} }
m_children = std::move(newList); m_children = std::move(newList);
} }
void Object::onTimer(TimerEvent&)
{
}
#ifdef USE_SDL
static dword sdlTimerCallback(dword interval, void* param)
{
EventLoop::main().postEvent(static_cast<Object*>(param), make<TimerEvent>());
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;
}

View file

@ -3,6 +3,7 @@
#include <AK/Vector.h> #include <AK/Vector.h>
class Event; class Event;
class TimerEvent;
class Object { class Object {
public: public:
@ -18,11 +19,19 @@ public:
Object* parent() { return m_parent; } Object* parent() { return m_parent; }
const Object* parent() const { return m_parent; } const Object* parent() const { return m_parent; }
void startTimer(int ms);
void stopTimer();
bool hasTimer() const { return m_timerID; }
private: private:
virtual void onTimer(TimerEvent&);
void addChild(Object&); void addChild(Object&);
void removeChild(Object&); void removeChild(Object&);
Object* m_parent { nullptr }; Object* m_parent { nullptr };
int m_timerID { 0 };
Vector<Object*> m_children; Vector<Object*> m_children;
}; };

View file

@ -11,7 +11,6 @@ Painter::Painter(Widget& widget)
, m_font(Font::defaultFont()) , m_font(Font::defaultFont())
{ {
if (auto* window = widget.window()) { if (auto* window = widget.window()) {
printf("window :: %s\n", window->title().characters());
m_translation = window->position(); m_translation = window->position();
m_translation.moveBy(widget.position()); m_translation.moveBy(widget.position());
} else { } else {

View file

@ -2,6 +2,7 @@
#include "Event.h" #include "Event.h"
#include "EventLoop.h" #include "EventLoop.h"
#include "WindowManager.h" #include "WindowManager.h"
#include "Window.h"
#include <AK/Assertions.h> #include <AK/Assertions.h>
Widget::Widget(Widget* parent) Widget::Widget(Widget* parent)
@ -26,6 +27,10 @@ void Widget::event(Event& event)
{ {
switch (event.type()) { switch (event.type()) {
case Event::Paint: case Event::Paint:
if (auto* win = window()) {
if (win->isBeingDragged())
return;
}
m_hasPendingPaintEvent = false; m_hasPendingPaintEvent = false;
return onPaint(static_cast<PaintEvent&>(event)); return onPaint(static_cast<PaintEvent&>(event));
case Event::Show: case Event::Show:

View file

@ -50,10 +50,12 @@ void Window::event(Event& event)
} }
if (event.isPaintEvent()) { if (event.isPaintEvent()) {
if (m_mainWidget) { if (isBeingDragged()) {
printf("forward to main widget\n"); // Ignore paint events during window drag.
return m_mainWidget->event(event); return;
} }
if (m_mainWidget)
return m_mainWidget->event(event);
} }
return Object::event(event); return Object::event(event);

View file

@ -32,9 +32,13 @@ public:
virtual void event(Event&) override; virtual void event(Event&) override;
bool isBeingDragged() const { return m_isBeingDragged; }
void setIsBeingDragged(bool b) { m_isBeingDragged = b; }
private: private:
String m_title; String m_title;
Rect m_rect; Rect m_rect;
Widget* m_mainWidget { nullptr }; Widget* m_mainWidget { nullptr };
bool m_isBeingDragged { false };
}; };

View file

@ -124,6 +124,7 @@ void WindowManager::handleTitleBarMouseEvent(Window& window, MouseEvent& event)
m_dragWindow = &window; m_dragWindow = &window;
m_dragOrigin = event.position(); m_dragOrigin = event.position();
m_dragWindowOrigin = window.position(); m_dragWindowOrigin = window.position();
window.setIsBeingDragged(true);
return; return;
} }
#if 0 #if 0
@ -140,6 +141,7 @@ void WindowManager::processMouseEvent(MouseEvent& event)
if (event.type() == Event::MouseUp) { if (event.type() == Event::MouseUp) {
if (m_dragWindow) { if (m_dragWindow) {
printf("[WM] Finish dragging Window{%p}\n", m_dragWindow); printf("[WM] Finish dragging Window{%p}\n", m_dragWindow);
m_dragWindow->setIsBeingDragged(false);
m_dragWindow = nullptr; m_dragWindow = nullptr;
EventLoop::main().postEvent(this, make<PaintEvent>()); EventLoop::main().postEvent(this, make<PaintEvent>());
return; return;

View file

@ -6,6 +6,7 @@
#include "TerminalWidget.h" #include "TerminalWidget.h"
#include "WindowManager.h" #include "WindowManager.h"
#include "Window.h" #include "Window.h"
#include "ClockWidget.h"
#include <cstdio> #include <cstdio>
int main(int c, char** v) int main(int c, char** v)
@ -20,38 +21,43 @@ int main(int c, char** v)
auto* fontTestWindow = new Window; auto* fontTestWindow = new Window;
fontTestWindow->setTitle("Font test"); fontTestWindow->setTitle("Font test");
fontTestWindow->setRect({100, 100, 300, 80 }); fontTestWindow->setRect({ 100, 100, 300, 80 });
auto* fontTestWindowWidget = new Widget; auto* fontTestWindowWidget = new Widget;
fontTestWindow->setMainWidget(fontTestWindowWidget); fontTestWindow->setMainWidget(fontTestWindowWidget);
fontTestWindowWidget->setRect({0, 0, 300, 80 }); fontTestWindowWidget->setRect({ 0, 0, 300, 80 });
auto* l1 = new Label(fontTestWindowWidget); auto* l1 = new Label(fontTestWindowWidget);
l1->setRect(Rect(0, 0, 300, 20)); l1->setRect({ 0, 0, 300, 20 });
l1->setText("0123456789"); l1->setText("0123456789");
auto* l2 = new Label(fontTestWindowWidget); auto* l2 = new Label(fontTestWindowWidget);
l2->setRect(Rect(0, 20, 300, 20)); l2->setRect({ 0, 20, 300, 20 });
l2->setText("ABCDEFGHIJKLMNOPQRSTUVWXYZ"); l2->setText("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
auto* l3 = new Label(fontTestWindowWidget); auto* l3 = new Label(fontTestWindowWidget);
l3->setRect(Rect(0, 40, 300, 20)); l3->setRect({ 0, 40, 300, 20 });
l3->setText("abcdefghijklmnopqrstuvwxyz"); l3->setText("abcdefghijklmnopqrstuvwxyz");
auto* l4 = new Label(fontTestWindowWidget); auto* l4 = new Label(fontTestWindowWidget);
l4->setRect(Rect(0, 60, 300, 20)); l4->setRect({ 0, 60, 300, 20 });
l4->setText("!\"#$%&'()*+,-./:;<=>?@[\\]^_{|}~"); l4->setText("!\"#$%&'()*+,-./:;<=>?@[\\]^_{|}~");
auto* b = new Button(&w); auto* b = new Button(&w);
b->setRect(Rect(10, 10, 100, 30)); b->setRect({ 10, 10, 100, 30 });
b->setCaption("Button!"); b->setCaption("Button!");
auto* win = new Window; auto* win = new Window;
win->setTitle("Console"); win->setTitle("Console");
win->setRect({100, 300, 644, 254}); win->setRect({ 100, 300, 644, 254 });
auto* t = new TerminalWidget(nullptr); auto* t = new TerminalWidget(nullptr);
win->setMainWidget(t); win->setMainWidget(t);
auto* clockWin = new Window;
clockWin->setTitle("Clock");
clockWin->setRect({ 500, 50, 100, 40 });
clockWin->setMainWidget(new ClockWidget);
return loop.exec(); return loop.exec();
} }