diff options
Diffstat (limited to 'Widgets')
-rw-r--r-- | Widgets/Button.cpp | 4 | ||||
-rw-r--r-- | Widgets/CheckBox.cpp | 84 | ||||
-rw-r--r-- | Widgets/CheckBox.h | 26 | ||||
-rw-r--r-- | Widgets/ClockWidget.cpp | 2 | ||||
-rw-r--r-- | Widgets/Makefile | 1 | ||||
-rw-r--r-- | Widgets/Painter.cpp | 8 | ||||
-rw-r--r-- | Widgets/Rect.h | 12 | ||||
-rw-r--r-- | Widgets/TerminalWidget.cpp | 2 | ||||
-rw-r--r-- | Widgets/Widget.cpp | 8 | ||||
-rw-r--r-- | Widgets/Widget.h | 18 | ||||
-rw-r--r-- | Widgets/Window.cpp | 9 | ||||
-rw-r--r-- | Widgets/WindowManager.cpp | 6 | ||||
-rw-r--r-- | Widgets/test.cpp | 33 |
13 files changed, 177 insertions, 36 deletions
diff --git a/Widgets/Button.cpp b/Widgets/Button.cpp index f42977dafb..b5648252f0 100644 --- a/Widgets/Button.cpp +++ b/Widgets/Button.cpp @@ -22,9 +22,9 @@ void Button::setCaption(String&& caption) void Button::onPaint(PaintEvent&) { Painter painter(*this); - painter.fillRect({ 0, 0, width(), height() }, backgroundColor()); + painter.fillRect(rect(), backgroundColor()); if (!caption().isEmpty()) { - painter.drawText({ 0, 0, width(), height() }, caption(), Painter::TextAlignment::Center, Color(0, 0, 0)); + painter.drawText(rect(), caption(), Painter::TextAlignment::Center, Color(0, 0, 0)); } } diff --git a/Widgets/CheckBox.cpp b/Widgets/CheckBox.cpp new file mode 100644 index 0000000000..f9ee65e333 --- /dev/null +++ b/Widgets/CheckBox.cpp @@ -0,0 +1,84 @@ +#include "CheckBox.h" +#include "Painter.h" +#include "CBitmap.h" +#include <cstdio> + +CheckBox::CheckBox(Widget* parent) + : Widget(parent) +{ +} + +CheckBox::~CheckBox() +{ +} + +void CheckBox::setCaption(String&& caption) +{ + if (caption == m_caption) + return; + m_caption = std::move(caption); + update(); +} + +void CheckBox::setIsChecked(bool b) +{ + if (m_isChecked == b) + return; + m_isChecked = b; + update(); +} + +static const char* uncheckedBitmap = { + "############" + "# #" + "# #" + "# #" + "# #" + "# #" + "# #" + "# #" + "# #" + "# #" + "# #" + "############" +}; + +static const char* checkedBitmap = { + "############" + "# #" + "# # # #" + "# # # #" + "# # # #" + "# ## #" + "# ## #" + "# # # #" + "# # # #" + "# # # #" + "# #" + "############" +}; + +void CheckBox::onPaint(PaintEvent&) +{ + Painter painter(*this); + auto bitmap = CBitmap::createFromASCII(isChecked() ? checkedBitmap : uncheckedBitmap, 12, 12); + + auto textRect = rect(); + textRect.setLeft(bitmap->width() + 4); + textRect.setTop(height() / 2 - bitmap->height() / 2); + + painter.fillRect(rect(), backgroundColor()); + painter.drawBitmap({ 2, textRect.y() }, *bitmap, Color(0, 0, 0)); + + if (!caption().isEmpty()) { + painter.drawText(textRect, caption(), Painter::TextAlignment::TopLeft, Color(0, 0, 0)); + } +} + +void CheckBox::onMouseDown(MouseEvent& event) +{ + printf("CheckBox::onMouseDown: x=%d, y=%d, button=%u\n", event.x(), event.y(), (unsigned)event.button()); + + setIsChecked(!isChecked()); +} + diff --git a/Widgets/CheckBox.h b/Widgets/CheckBox.h new file mode 100644 index 0000000000..f653aa803d --- /dev/null +++ b/Widgets/CheckBox.h @@ -0,0 +1,26 @@ +#pragma once + +#include "Widget.h" +#include <AK/String.h> + +class CheckBox final : public Widget { +public: + explicit CheckBox(Widget* parent); + virtual ~CheckBox() override; + + String caption() const { return m_caption; } + void setCaption(String&&); + + bool isChecked() const { return m_isChecked; } + void setIsChecked(bool); + +private: + virtual void onPaint(PaintEvent&) override; + virtual void onMouseDown(MouseEvent&) override; + + virtual const char* className() const override { return "CheckBox"; } + + String m_caption; + bool m_isChecked { false }; +}; + diff --git a/Widgets/ClockWidget.cpp b/Widgets/ClockWidget.cpp index a4778e2ca2..a0e2aadcaa 100644 --- a/Widgets/ClockWidget.cpp +++ b/Widgets/ClockWidget.cpp @@ -5,7 +5,7 @@ ClockWidget::ClockWidget(Widget* parent) : Widget(parent) { - setRect({ 0, 0, 100, 40 }); + setWindowRelativeRect({ 0, 0, 100, 40 }); startTimer(250); } diff --git a/Widgets/Makefile b/Widgets/Makefile index 2754956941..2777bed7e1 100644 --- a/Widgets/Makefile +++ b/Widgets/Makefile @@ -24,6 +24,7 @@ VFS_OBJS = \ Window.o \ ClockWidget.o \ CBitmap.o \ + CheckBox.o \ test.o OBJS = $(AK_OBJS) $(VFS_OBJS) diff --git a/Widgets/Painter.cpp b/Widgets/Painter.cpp index 03cd713a7f..c95bb5cdaa 100644 --- a/Widgets/Painter.cpp +++ b/Widgets/Painter.cpp @@ -12,7 +12,7 @@ Painter::Painter(Widget& widget) { if (auto* window = widget.window()) { m_translation = window->position(); - m_translation.moveBy(widget.position()); + m_translation.moveBy(widget.relativePosition()); } else { m_translation.setX(widget.x()); m_translation.setY(widget.y()); @@ -80,8 +80,10 @@ void Painter::xorRect(const Rect& rect, Color color) } } -void Painter::drawBitmap(const Point& point, const CBitmap& bitmap, Color color) +void Painter::drawBitmap(const Point& p, const CBitmap& bitmap, Color color) { + Point point = p; + point.moveBy(m_translation); for (unsigned row = 0; row < bitmap.height(); ++row) { int y = point.y() + row; int x = point.x(); @@ -100,12 +102,10 @@ void Painter::drawText(const Rect& rect, const String& text, TextAlignment align if (alignment == TextAlignment::TopLeft) { point = rect.location(); - point.moveBy(m_translation); } else if (alignment == TextAlignment::Center) { int textWidth = text.length() * m_font.glyphWidth(); point = rect.center(); point.moveBy(-(textWidth / 2), -(m_font.glyphWidth() / 2)); - point.moveBy(m_translation); } else { ASSERT_NOT_REACHED(); } diff --git a/Widgets/Rect.h b/Widgets/Rect.h index a9e25c3760..d61ae16f7f 100644 --- a/Widgets/Rect.h +++ b/Widgets/Rect.h @@ -55,6 +55,18 @@ public: int top() const { return y(); } int bottom() const { return y() + height(); } + void setLeft(int left) + { + setWidth(x() - left); + setX(left); + } + + void setTop(int top) + { + setHeight(y() - top); + setY(top); + } + int x() const { return location().x(); } int y() const { return location().y(); } int width() const { return m_width; } diff --git a/Widgets/TerminalWidget.cpp b/Widgets/TerminalWidget.cpp index 577f86b19d..570bfd2c01 100644 --- a/Widgets/TerminalWidget.cpp +++ b/Widgets/TerminalWidget.cpp @@ -16,7 +16,7 @@ TerminalWidget::TerminalWidget(Widget* parent) auto& font = Font::defaultFont(); - setRect({ 0, 0, (columns() * font.glyphWidth()) + 4, (rows() * font.glyphHeight()) + 4 }); + setWindowRelativeRect({ 0, 0, (columns() * font.glyphWidth()) + 4, (rows() * font.glyphHeight()) + 4 }); printf("rekt: %d x %d\n", width(), height()); m_screen = new CharacterWithAttributes[rows() * columns()]; diff --git a/Widgets/Widget.cpp b/Widgets/Widget.cpp index 8332abd92d..f5a66e79f1 100644 --- a/Widgets/Widget.cpp +++ b/Widgets/Widget.cpp @@ -16,10 +16,10 @@ Widget::~Widget() { } -void Widget::setRect(const Rect& rect) +void Widget::setWindowRelativeRect(const Rect& rect) { // FIXME: Make some kind of event loop driven ResizeEvent? - m_rect = rect; + m_relativeRect = rect; update(); } @@ -102,8 +102,8 @@ Widget::HitTestResult Widget::hitTest(int x, int y) // FIXME: Care about z-order. for (auto* ch : children()) { auto* child = (Widget*)ch; - if (child->rect().contains(x, y)) { - return child->hitTest(x - child->rect().x(), y - child->rect().y()); + if (child->relativeRect().contains(x, y)) { + return child->hitTest(x - child->relativeRect().x(), y - child->relativeRect().y()); } } return { this, x, y }; diff --git a/Widgets/Widget.h b/Widgets/Widget.h index dff665c4ac..2979c529e1 100644 --- a/Widgets/Widget.h +++ b/Widgets/Widget.h @@ -23,13 +23,15 @@ public: virtual void onMouseDown(MouseEvent&); virtual void onMouseUp(MouseEvent&); - Rect rect() const { return m_rect; } - Point position() const { return m_rect.location(); } + Rect relativeRect() const { return m_relativeRect; } + Point relativePosition() const { return m_relativeRect.location(); } - int x() const { return rect().x(); } - int y() const { return rect().y(); } - int width() const { return rect().width(); } - int height() const { return rect().height(); } + int x() const { return m_relativeRect.x(); } + int y() const { return m_relativeRect.y(); } + int width() const { return m_relativeRect.width(); } + int height() const { return m_relativeRect.height(); } + + Rect rect() const { return { 0, 0, width(), height() }; } void update(); @@ -42,7 +44,7 @@ public: virtual const char* className() const override { return "Widget"; } - void setRect(const Rect&); + void setWindowRelativeRect(const Rect&); Color backgroundColor() const { return m_backgroundColor; } Color foregroundColor() const { return m_foregroundColor; } @@ -72,7 +74,7 @@ public: private: Window* m_window { nullptr }; - Rect m_rect; + Rect m_relativeRect; Color m_backgroundColor; Color m_foregroundColor; diff --git a/Widgets/Window.cpp b/Widgets/Window.cpp index 118c75cc27..2e0b95746e 100644 --- a/Widgets/Window.cpp +++ b/Widgets/Window.cpp @@ -46,6 +46,14 @@ void Window::event(Event& event) if (event.isMouseEvent()) { auto& me = static_cast<MouseEvent&>(event); printf("Window{%p}: %s %d,%d\n", this, me.name(), me.x(), me.y()); + if (m_mainWidget) { + auto result = m_mainWidget->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); + // FIXME: Re-use the existing event instead of crafting a new one? + auto localEvent = make<MouseEvent>(event.type(), result.localX, result.localY, me.button()); + result.widget->event(*localEvent); + return m_mainWidget->event(event); + } return Object::event(event); } @@ -56,6 +64,7 @@ void Window::event(Event& event) } if (m_mainWidget) return m_mainWidget->event(event); + return Object::event(event); } return Object::event(event); diff --git a/Widgets/WindowManager.cpp b/Widgets/WindowManager.cpp index f12405a8b9..6f1f235bb0 100644 --- a/Widgets/WindowManager.cpp +++ b/Widgets/WindowManager.cpp @@ -174,12 +174,6 @@ void WindowManager::processMouseEvent(MouseEvent& event) } } - // Otherwise: send it to root the root widget... - auto result = m_rootWidget->hitTest(event.x(), event.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); - // FIXME: Re-use the existing event instead of crafting a new one? - auto localEvent = make<MouseEvent>(event.type(), result.localX, result.localY, event.button()); - result.widget->event(*localEvent); } void WindowManager::handlePaintEvent(PaintEvent& event) diff --git a/Widgets/test.cpp b/Widgets/test.cpp index 43a5a82e58..404b80f5fb 100644 --- a/Widgets/test.cpp +++ b/Widgets/test.cpp @@ -7,9 +7,10 @@ #include "WindowManager.h" #include "Window.h" #include "ClockWidget.h" +#include "CheckBox.h" #include <cstdio> -int main(int c, char** v) +int main(int argc, char** argv) { FrameBufferSDL fb(800, 600); fb.show(); @@ -21,31 +22,43 @@ int main(int c, char** v) auto* fontTestWindow = new Window; fontTestWindow->setTitle("Font test"); - fontTestWindow->setRect({ 100, 100, 300, 80 }); + fontTestWindow->setRect({ 140, 100, 300, 80 }); auto* fontTestWindowWidget = new Widget; fontTestWindow->setMainWidget(fontTestWindowWidget); - fontTestWindowWidget->setRect({ 0, 0, 300, 80 }); + fontTestWindowWidget->setWindowRelativeRect({ 0, 0, 300, 80 }); auto* l1 = new Label(fontTestWindowWidget); - l1->setRect({ 0, 0, 300, 20 }); + l1->setWindowRelativeRect({ 0, 0, 300, 20 }); l1->setText("0123456789"); auto* l2 = new Label(fontTestWindowWidget); - l2->setRect({ 0, 20, 300, 20 }); + l2->setWindowRelativeRect({ 0, 20, 300, 20 }); l2->setText("ABCDEFGHIJKLMNOPQRSTUVWXYZ"); auto* l3 = new Label(fontTestWindowWidget); - l3->setRect({ 0, 40, 300, 20 }); + l3->setWindowRelativeRect({ 0, 40, 300, 20 }); l3->setText("abcdefghijklmnopqrstuvwxyz"); auto* l4 = new Label(fontTestWindowWidget); - l4->setRect({ 0, 60, 300, 20 }); + l4->setWindowRelativeRect({ 0, 60, 300, 20 }); l4->setText("!\"#$%&'()*+,-./:;<=>?@[\\]^_{|}~"); - auto* b = new Button(&w); - b->setRect({ 10, 10, 100, 30 }); - b->setCaption("Button!"); + auto* widgetTestWindow = new Window; + widgetTestWindow->setTitle("Widget test"); + widgetTestWindow->setRect({ 20, 40, 100, 100 }); + + auto* widgetTestWindowWidget = new Widget; + widgetTestWindowWidget->setWindowRelativeRect({ 0, 0, 100, 100 }); + widgetTestWindow->setMainWidget(widgetTestWindowWidget); + + auto* b = new Button(widgetTestWindowWidget); + b->setWindowRelativeRect({ 0, 0, 100, 30 }); + b->setCaption("Button"); + + auto* c = new CheckBox(widgetTestWindowWidget); + c->setWindowRelativeRect({ 0, 30, 100, 30 }); + c->setCaption("CheckBox"); auto* win = new Window; win->setTitle("Console"); |