Add a clock widget.

This commit is contained in:
Andreas Kling 2018-10-12 12:18:59 +02:00
parent 6637dec958
commit 73895ce043
Notes: sideshowbarker 2024-07-19 18:50:16 +09:00
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",
"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() { }
};

View file

@ -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`

View file

@ -1,7 +1,12 @@
#include "Object.h"
#include "Event.h"
#include "EventLoop.h"
#include <AK/Assertions.h>
#ifdef USE_SDL
#include <SDL.h>
#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<TimerEvent&>(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<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>
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<Object*> m_children;
};

View file

@ -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 {

View file

@ -2,6 +2,7 @@
#include "Event.h"
#include "EventLoop.h"
#include "WindowManager.h"
#include "Window.h"
#include <AK/Assertions.h>
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<PaintEvent&>(event));
case Event::Show:

View file

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

View file

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

View file

@ -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<PaintEvent>());
return;

View file

@ -6,6 +6,7 @@
#include "TerminalWidget.h"
#include "WindowManager.h"
#include "Window.h"
#include "ClockWidget.h"
#include <cstdio>
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();
}