diff --git a/Widgets/AbstractScreen.cpp b/Widgets/AbstractScreen.cpp index 4f2536bbc1..203b743b89 100644 --- a/Widgets/AbstractScreen.cpp +++ b/Widgets/AbstractScreen.cpp @@ -27,12 +27,15 @@ AbstractScreen::~AbstractScreen() void AbstractScreen::event(Event& event) { - if (event.type() == Event::MouseMove) { + if (event.type() == Event::MouseMove + || event.type() == Event::MouseDown + || event.type() == Event::MouseUp) { auto& me = static_cast(event); - printf("AbstractScreen::onMouseMove: %d, %d\n", me.x(), me.y()); - + //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); + //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); + auto localEvent = make(event.type(), result.localX, result.localY, me.button()); + result.widget->event(*localEvent); } } diff --git a/Widgets/Button.cpp b/Widgets/Button.cpp new file mode 100644 index 0000000000..f42977dafb --- /dev/null +++ b/Widgets/Button.cpp @@ -0,0 +1,39 @@ +#include "Button.h" +#include "Painter.h" +#include + +Button::Button(Widget* parent) + : Widget(parent) +{ +} + +Button::~Button() +{ +} + +void Button::setCaption(String&& caption) +{ + if (caption == m_caption) + return; + m_caption = std::move(caption); + update(); +} + +void Button::onPaint(PaintEvent&) +{ + Painter painter(*this); + painter.fillRect({ 0, 0, width(), height() }, backgroundColor()); + if (!caption().isEmpty()) { + painter.drawText({ 0, 0, width(), height() }, caption(), Painter::TextAlignment::Center, Color(0, 0, 0)); + } +} + +void Button::onMouseDown(MouseEvent& event) +{ + printf("Button::onMouseDown: x=%d, y=%d, button=%u\n", event.x(), event.y(), (unsigned)event.button()); + + setBackgroundColor(Color(0xff, 0xc0, 0xc0)); + update(); + Widget::onMouseDown(event); +} + diff --git a/Widgets/Button.h b/Widgets/Button.h new file mode 100644 index 0000000000..9bd51334bf --- /dev/null +++ b/Widgets/Button.h @@ -0,0 +1,22 @@ +#pragma once + +#include "Widget.h" +#include + +class Button final : public Widget { +public: + explicit Button(Widget* parent); + virtual ~Button() override; + + String caption() const { return m_caption; } + void setCaption(String&&); + +private: + virtual void onPaint(PaintEvent&) override; + virtual void onMouseDown(MouseEvent&) override; + + virtual const char* className() const override { return "Button"; } + + String m_caption; +}; + diff --git a/Widgets/Event.h b/Widgets/Event.h index 28297a9b6c..2ab0aa6433 100644 --- a/Widgets/Event.h +++ b/Widgets/Event.h @@ -79,6 +79,7 @@ public: enum class MouseButton : byte { None = 0, Left, + Middle, Right, }; diff --git a/Widgets/EventLoopSDL.cpp b/Widgets/EventLoopSDL.cpp index 13eb047075..f607c3be15 100644 --- a/Widgets/EventLoopSDL.cpp +++ b/Widgets/EventLoopSDL.cpp @@ -12,6 +12,19 @@ EventLoopSDL::~EventLoopSDL() { } +static inline MouseButton toMouseButton(byte sdlButton) +{ + printf("sdlbutton = %u\n", sdlButton); + if (sdlButton == 1) + return MouseButton::Left; + if (sdlButton == 2) + return MouseButton::Middle; + if (sdlButton == 3) + return MouseButton::Right; + ASSERT_NOT_REACHED(); + return MouseButton::None; +} + void EventLoopSDL::waitForEvent() { SDL_Event sdlEvent; @@ -30,6 +43,9 @@ void EventLoopSDL::waitForEvent() case SDL_MOUSEMOTION: postEvent(&AbstractScreen::the(), make(Event::MouseMove, sdlEvent.motion.x, sdlEvent.motion.y)); return; + case SDL_MOUSEBUTTONDOWN: + postEvent(&AbstractScreen::the(), make(Event::MouseDown, sdlEvent.button.x, sdlEvent.button.y, toMouseButton(sdlEvent.button.button))); + return; } } } diff --git a/Widgets/Label.cpp b/Widgets/Label.cpp index ab761702bf..0f53fc50c4 100644 --- a/Widgets/Label.cpp +++ b/Widgets/Label.cpp @@ -24,7 +24,7 @@ void Label::onPaint(PaintEvent&) Painter painter(*this); painter.fillRect({ 0, 0, width(), height() }, Color(0x0, 0x0, 0x0)); if (!text().isEmpty()) - painter.drawText({ 4, 4 }, text(), Color(0xff, 0xff, 0xff)); + painter.drawText({ 4, 4, width(), height() }, text(), Painter::TextAlignment::TopLeft, Color(0xff, 0xff, 0xff)); } void Label::onMouseMove(MouseEvent& event) diff --git a/Widgets/Makefile b/Widgets/Makefile index fa5049643b..0ddb811396 100644 --- a/Widgets/Makefile +++ b/Widgets/Makefile @@ -17,6 +17,7 @@ VFS_OBJS = \ ColorSDL.o \ Painter.o \ Label.o \ + Button.o \ test.o OBJS = $(AK_OBJS) $(VFS_OBJS) diff --git a/Widgets/Painter.cpp b/Widgets/Painter.cpp index 284c47cefb..b9a2e3f1f1 100644 --- a/Widgets/Painter.cpp +++ b/Widgets/Painter.cpp @@ -35,24 +35,32 @@ void Painter::fillRect(const Rect& rect, Color color) } } -void Painter::drawText(const Point& point, const String& text, const Color& color) +void Painter::drawText(const Rect& rect, const String& text, TextAlignment alignment, const Color& color) { - Point p = point; - p.moveBy(m_widget.x(), m_widget.y()); + Point point; + + if (alignment == TextAlignment::TopLeft) { + point = rect.location(); + point.moveBy(m_widget.x(), m_widget.y());; + } else if (alignment == TextAlignment::Center) { + int textWidth = text.length() * Peanut8x8::fontWidth; + point = rect.center(); + point.moveBy(-(textWidth / 2), -(Peanut8x8::fontWidth / 2)); + point.moveBy(m_widget.x(), m_widget.y()); + } else { + ASSERT_NOT_REACHED(); + } - byte fontWidth = 8; - byte fontHeight = 8; - - for (int row = 0; row < fontHeight; ++row) { - int y = p.y() + row; + for (int row = 0; row < Peanut8x8::fontHeight; ++row) { + int y = point.y() + row; dword* bits = scanline(y); for (unsigned i = 0; i < text.length(); ++i) { if (text[i] == ' ') continue; const char* fontCharacter = Peanut8x8::font[text[i] - Peanut8x8::firstCharacter]; - int x = p.x() + i * fontWidth; - for (unsigned j = 0; j < fontWidth; ++j) { - char fc = fontCharacter[row * fontWidth + j]; + int x = point.x() + i * Peanut8x8::fontWidth; + for (unsigned j = 0; j < Peanut8x8::fontWidth; ++j) { + char fc = fontCharacter[row * Peanut8x8::fontWidth + j]; if (fc == '#') bits[x + j] = color.value(); } diff --git a/Widgets/Painter.h b/Widgets/Painter.h index 671d928c0b..524548b0af 100644 --- a/Widgets/Painter.h +++ b/Widgets/Painter.h @@ -9,10 +9,11 @@ class Widget; class Painter { public: + enum class TextAlignment { TopLeft, Center }; explicit Painter(Widget&); ~Painter(); void fillRect(const Rect&, Color); - void drawText(const Point&, const String&, const Color& = Color()); + void drawText(const Rect&, const String&, TextAlignment = TextAlignment::TopLeft, const Color& = Color()); private: Widget& m_widget; diff --git a/Widgets/Peanut8x8.h b/Widgets/Peanut8x8.h index 0a25fa41fc..6d8535bf67 100644 --- a/Widgets/Peanut8x8.h +++ b/Widgets/Peanut8x8.h @@ -3,6 +3,8 @@ namespace Peanut8x8 { static constexpr char firstCharacter = '!'; +static constexpr byte fontWidth = 8; +static constexpr byte fontHeight = 8; static constexpr const char* font[] { diff --git a/Widgets/Rect.h b/Widgets/Rect.h index 8316f6fc98..08e1d5860a 100644 --- a/Widgets/Rect.h +++ b/Widgets/Rect.h @@ -17,6 +17,11 @@ public: m_location.moveBy(dx, dy); } + Point center() const + { + return { x() + width() / 2, y() + height() / 2 }; + } + bool contains(int x, int y) const { return x >= m_location.x() && x <= right() && y >= m_location.y() && y <= bottom(); diff --git a/Widgets/RootWidget.cpp b/Widgets/RootWidget.cpp index 67d9a372b3..614ef8709e 100644 --- a/Widgets/RootWidget.cpp +++ b/Widgets/RootWidget.cpp @@ -14,7 +14,7 @@ void RootWidget::onPaint(PaintEvent& event) { printf("RootWidget::onPaint\n"); Painter painter(*this); - painter.fillRect(Rect(0, 0, 800, 600), Color(0x80, 0x80, 0x80)); + painter.fillRect(Rect(0, 0, 800, 600), Color(0x40, 0x40, 0x40)); Widget::onPaint(event); } diff --git a/Widgets/Widget.cpp b/Widgets/Widget.cpp index a51cb0ba7c..9a1b66b16f 100644 --- a/Widgets/Widget.cpp +++ b/Widgets/Widget.cpp @@ -6,6 +6,8 @@ Widget::Widget(Widget* parent) : Object(parent) { + m_backgroundColor = Color(255, 255, 255); + m_foregroundColor = Color(0, 0, 0); } Widget::~Widget() diff --git a/Widgets/Widget.h b/Widgets/Widget.h index b934a157a9..7b49e92c0f 100644 --- a/Widgets/Widget.h +++ b/Widgets/Widget.h @@ -3,6 +3,7 @@ #include "Event.h" #include "Object.h" #include "Rect.h" +#include "Color.h" class Widget : public Object { public: @@ -38,6 +39,14 @@ public: void setRect(const Rect&); + Color backgroundColor() const { return m_backgroundColor; } + Color foregroundColor() const { return m_foregroundColor; } + + void setBackgroundColor(Color color) { m_backgroundColor = color; } + void setForegroundColor(Color color) { m_foregroundColor = color; } + private: Rect m_rect; + Color m_backgroundColor; + Color m_foregroundColor; }; diff --git a/Widgets/test.cpp b/Widgets/test.cpp index 0d5aa3bc33..b6d437041a 100644 --- a/Widgets/test.cpp +++ b/Widgets/test.cpp @@ -2,6 +2,7 @@ #include "EventLoopSDL.h" #include "RootWidget.h" #include "Label.h" +#include "Button.h" #include int main(int c, char** v) @@ -30,7 +31,13 @@ int main(int c, char** v) l4->setRect(Rect(100, 160, 300, 20)); l4->setText("!\"#$%&'()*+,-./:;<=>?@[\\]^_{|}~"); - //l5->setText("Welcome to the Serenity Operating System"); + auto* l5 = new Label(&w); + l5->setRect(Rect(200, 200, 400, 50)); + l5->setText("Welcome to the Serenity Operating System"); + + auto* b = new Button(&w); + b->setRect(Rect(10, 10, 100, 30)); + b->setCaption("Button!"); return loop.exec(); }