mirror of
https://github.com/SerenityOS/serenity
synced 2024-07-21 18:15:58 +00:00
Add a clock widget.
This commit is contained in:
parent
6637dec958
commit
73895ce043
37
Widgets/ClockWidget.cpp
Normal file
37
Widgets/ClockWidget.cpp
Normal 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
16
Widgets/ClockWidget.h
Normal 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 };
|
||||||
|
};
|
||||||
|
|
|
@ -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() { }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
|
@ -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`
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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 };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue