From fd106c1e3e2ad37b80b6004a4bcbde84b999e6f2 Mon Sep 17 00:00:00 2001 From: skyjake Date: Wed, 30 Jan 2013 16:10:10 +0200 Subject: [PATCH] libdeng2|Shell: Improvements in the widget framework --- doomsday/libdeng2/include/de/widgets/widget.h | 6 ++++ doomsday/libdeng2/src/widgets/rootwidget.cpp | 9 +++-- doomsday/libdeng2/src/widgets/widget.cpp | 33 ++++++++++++++++++- .../include/de/shell/lineeditwidget.h | 2 +- .../libshell/include/de/shell/textcanvas.h | 3 ++ .../libshell/include/de/shell/textwidget.h | 9 ++++- doomsday/libshell/src/labelwidget.cpp | 9 ++--- doomsday/libshell/src/libshell.cpp | 1 + doomsday/libshell/src/lineeditwidget.cpp | 5 +-- doomsday/libshell/src/textcanvas.cpp | 31 +++++++++++++++++ doomsday/libshell/src/textwidget.cpp | 29 ++++++++++++---- .../tools/shell/shell-text/src/logwidget.cpp | 5 --- .../tools/shell/shell-text/src/logwidget.h | 5 --- 13 files changed, 117 insertions(+), 30 deletions(-) diff --git a/doomsday/libdeng2/include/de/widgets/widget.h b/doomsday/libdeng2/include/de/widgets/widget.h index 1dbcae7531..1c397e585e 100644 --- a/doomsday/libdeng2/include/de/widgets/widget.h +++ b/doomsday/libdeng2/include/de/widgets/widget.h @@ -46,6 +46,10 @@ class DENG2_PUBLIC Widget void setName(String const &name); bool hasRoot() const; RootWidget &root() const; + bool hasFocus() const; + bool isHidden() const; + inline void hide() { show(false); } + void show(bool doShow = true); // Tree organization. void clear(); @@ -60,11 +64,13 @@ class DENG2_PUBLIC Widget void notifyTree(void (Widget::*notifyFunc)()); void notifyTreeReversed(void (Widget::*notifyFunc)()); bool dispatchEvent(Event const *event, bool (Widget::*memberFunc)(Event const *)); + void redraw(); // Events. virtual void initialize(); virtual void viewResized(); virtual void update(); + virtual void drawIfVisible(); virtual void draw(); virtual bool handleEvent(Event const *event); diff --git a/doomsday/libdeng2/src/widgets/rootwidget.cpp b/doomsday/libdeng2/src/widgets/rootwidget.cpp index e54a118d1e..e1babbb48e 100644 --- a/doomsday/libdeng2/src/widgets/rootwidget.cpp +++ b/doomsday/libdeng2/src/widgets/rootwidget.cpp @@ -40,7 +40,7 @@ struct RootWidget::Instance ~Instance() { - releaseRef(viewRect); + delete viewRect; } Vector2i viewSize() const @@ -118,13 +118,18 @@ void RootWidget::initialize() void RootWidget::draw() { - notifyTree(&Widget::draw); + notifyTree(&Widget::drawIfVisible); Rule::markRulesValid(); // All done for this frame. } bool RootWidget::processEvent(Event const *event) { + if(focus() && focus()->handleEvent(event)) + { + // The focused widget ate the event. + return true; + } return dispatchEvent(event, &Widget::handleEvent); } diff --git a/doomsday/libdeng2/src/widgets/widget.cpp b/doomsday/libdeng2/src/widgets/widget.cpp index 9db899e5fe..e736663a8e 100644 --- a/doomsday/libdeng2/src/widgets/widget.cpp +++ b/doomsday/libdeng2/src/widgets/widget.cpp @@ -29,13 +29,14 @@ struct Widget::Instance Widget &self; String name; Widget *parent; + bool hidden; typedef QList Children; typedef QMap NamedChildren; Children children; NamedChildren index; - Instance(Widget &w, String const &n) : self(w), name(n), parent(0) + Instance(Widget &w, String const &n) : self(w), name(n), parent(0), hidden(false) {} ~Instance() @@ -113,6 +114,25 @@ RootWidget &Widget::root() const throw NotFoundError("Widget::root", "No root widget found"); } +bool Widget::hasFocus() const +{ + return hasRoot() && root().focus() == this; +} + +bool Widget::isHidden() const +{ + for(Widget const *w = this; w != 0; w = w->d->parent) + { + if(w->d->hidden) return true; + } + return false; +} + +void Widget::show(bool doShow) +{ + d->hidden = doShow; +} + void Widget::clear() { d->clear(); @@ -195,6 +215,9 @@ void Widget::notifyTreeReversed(void (Widget::*notifyFunc)()) bool Widget::dispatchEvent(Event const *event, bool (Widget::*memberFunc)(Event const *)) { + // Hidden widgets do not get events. + if(isHidden()) return false; + // Tree is traversed in reverse order. for(int i = d->children.size() - 1; i >= 0; --i) { @@ -227,6 +250,14 @@ void Widget::viewResized() void Widget::update() {} +void Widget::drawIfVisible() +{ + if(!isHidden()) + { + draw(); + } +} + void Widget::draw() {} diff --git a/doomsday/libshell/include/de/shell/lineeditwidget.h b/doomsday/libshell/include/de/shell/lineeditwidget.h index c173e75579..d6da2c25b8 100644 --- a/doomsday/libshell/include/de/shell/lineeditwidget.h +++ b/doomsday/libshell/include/de/shell/lineeditwidget.h @@ -58,7 +58,7 @@ class LIBSHELL_PUBLIC LineEditWidget : public TextWidget void setCursor(int index); int cursor() const; - Vector2i cursorPosition(); + Vector2i cursorPosition() const; bool handleControlKey(int key); diff --git a/doomsday/libshell/include/de/shell/textcanvas.h b/doomsday/libshell/include/de/shell/textcanvas.h index aea97afc17..147594b57a 100644 --- a/doomsday/libshell/include/de/shell/textcanvas.h +++ b/doomsday/libshell/include/de/shell/textcanvas.h @@ -105,6 +105,7 @@ class LIBSHELL_PUBLIC TextCanvas Size size() const; int width() const; int height() const; + Rectanglei rect() const; void resize(Size const &newSize); @@ -140,6 +141,8 @@ class LIBSHELL_PUBLIC TextCanvas void drawText(Vector2i const &pos, String const &text, Char::Attribs const &attribs = Char::DefaultAttributes); + void drawLineRect(Rectanglei const &rect, Char::Attribs const &attribs = Char::DefaultAttributes); + /** * Draws the contents of a canvas onto this canvas. * diff --git a/doomsday/libshell/include/de/shell/textwidget.h b/doomsday/libshell/include/de/shell/textwidget.h index 7420991d0c..674ffa87fe 100644 --- a/doomsday/libshell/include/de/shell/textwidget.h +++ b/doomsday/libshell/include/de/shell/textwidget.h @@ -83,6 +83,11 @@ class LIBSHELL_PUBLIC TextWidget : public QObject, public Widget */ TextCanvas &targetCanvas() const; + /** + * Requests the root widget to redraw all the user interface. + */ + void redraw(); + /** * Draw this widget and all its children, and show the target canvas * afterwards. Use this in special cases for faster redrawing of portions @@ -101,13 +106,15 @@ class LIBSHELL_PUBLIC TextWidget : public QObject, public Widget RectangleRule &rule(); + RectangleRule const &rule() const; + /** * Returns the position of the cursor for the widget. If the widget * has focus, this is where the cursor will be positioned. * * @return Cursor position. */ - virtual Vector2i cursorPosition(); + virtual Vector2i cursorPosition() const; /** * Adds a new action for the widget. During event processing actions are diff --git a/doomsday/libshell/src/labelwidget.cpp b/doomsday/libshell/src/labelwidget.cpp index d6c5fa68c8..42d809f754 100644 --- a/doomsday/libshell/src/labelwidget.cpp +++ b/doomsday/libshell/src/labelwidget.cpp @@ -49,22 +49,19 @@ void LabelWidget::setLabel(String const &text, TextCanvas::Char::Attribs attribs { d->label = text; d->attribs = attribs; - - if(hasRoot()) root().requestDraw(); + redraw(); } void LabelWidget::setAttribs(TextCanvas::Char::Attribs const &attribs) { d->attribs = attribs; - - if(hasRoot()) root().requestDraw(); + redraw(); } void LabelWidget::setAlignment(Alignment align) { d->align = align; - - if(hasRoot()) root().requestDraw(); + redraw(); } String LabelWidget::label() const diff --git a/doomsday/libshell/src/libshell.cpp b/doomsday/libshell/src/libshell.cpp index ce9c898cb1..ec3db04661 100644 --- a/doomsday/libshell/src/libshell.cpp +++ b/doomsday/libshell/src/libshell.cpp @@ -20,5 +20,6 @@ namespace de { namespace shell { + } // namespace shell } // namespace de diff --git a/doomsday/libshell/src/lineeditwidget.cpp b/doomsday/libshell/src/lineeditwidget.cpp index 9f19193ace..26c42c1e41 100644 --- a/doomsday/libshell/src/lineeditwidget.cpp +++ b/doomsday/libshell/src/lineeditwidget.cpp @@ -228,7 +228,7 @@ void LineEditWidget::setPrompt(String const &promptText) } } -Vector2i LineEditWidget::cursorPosition() +Vector2i LineEditWidget::cursorPosition() const { de::Rectanglei pos = rule().recti(); return pos.topLeft + Vector2i(d->prompt.size(), 0) + d->lineCursorPos(); @@ -247,7 +247,8 @@ void LineEditWidget::draw() // Temporary buffer for drawing. TextCanvas buf(pos.size()); - TextCanvas::Char::Attribs attr = TextCanvas::Char::Reverse; + TextCanvas::Char::Attribs attr = + (hasFocus()? TextCanvas::Char::Reverse : TextCanvas::Char::DefaultAttributes); buf.clear(TextCanvas::Char(' ', attr)); buf.drawText(Vector2i(0, 0), d->prompt, attr | TextCanvas::Char::Bold); diff --git a/doomsday/libshell/src/textcanvas.cpp b/doomsday/libshell/src/textcanvas.cpp index 44ddbf8df7..b2d9de514e 100644 --- a/doomsday/libshell/src/textcanvas.cpp +++ b/doomsday/libshell/src/textcanvas.cpp @@ -121,6 +121,11 @@ int TextCanvas::height() const return d->size.y; } +Rectanglei TextCanvas::rect() const +{ + return Rectanglei(Vector2i(0, 0), size()); +} + void TextCanvas::resize(Size const &newSize) { d->resize(newSize); @@ -186,6 +191,32 @@ void TextCanvas::drawText(Vector2i const &pos, String const &text, Char::Attribs } } +void TextCanvas::drawLineRect(Rectanglei const &rect, Char::Attribs const &attribs) +{ + Char const corner('+', attribs); + Char const hEdge ('-', attribs); + Char const vEdge ('|', attribs); + + // Horizontal edges. + for(int x = 1; x < rect.width() - 1; ++x) + { + put(rect.topLeft + Vector2i(x, 0), hEdge); + put(rect.bottomLeft() + Vector2i(x, -1), hEdge); + } + + // Vertical edges. + for(int y = 1; y < rect.width() - 1; ++y) + { + put(rect.topLeft + Vector2i(0, y), vEdge); + put(rect.topRight() + Vector2i(-1, y), vEdge); + } + + put(rect.topLeft, corner); + put(rect.topRight() - Vector2i(1, 0), corner); + put(rect.bottomRight - Vector2i(1, 1), corner); + put(rect.bottomLeft() - Vector2i(0, 1), corner); +} + void TextCanvas::draw(TextCanvas const &canvas, Coord const &topLeft) { for(int y = 0; y < canvas.d->size.y; ++y) diff --git a/doomsday/libshell/src/textwidget.cpp b/doomsday/libshell/src/textwidget.cpp index 8b63844447..528b5e973a 100644 --- a/doomsday/libshell/src/textwidget.cpp +++ b/doomsday/libshell/src/textwidget.cpp @@ -35,7 +35,7 @@ struct TextWidget::Instance ~Instance() { - releaseRef(rule); + delete rule; foreach(Action *act, actions) delete act; } }; @@ -70,17 +70,26 @@ TextCanvas &TextWidget::targetCanvas() const return *d->canvas; } +void TextWidget::redraw() +{ + if(hasRoot()) root().requestDraw(); +} + void TextWidget::drawAndShow() { - draw(); - notifyTree(&Widget::draw); - targetCanvas().show(); + if(!isHidden()) + { + draw(); + notifyTree(&Widget::drawIfVisible); + targetCanvas().show(); + } } void TextWidget::setRule(RectangleRule *rule) { - releaseRef(d->rule); - d->rule = holdRef(rule); + DENG2_ASSERT(rule != 0); + delete d->rule; + d->rule = rule; } RectangleRule &TextWidget::rule() @@ -89,7 +98,13 @@ RectangleRule &TextWidget::rule() return *d->rule; } -Vector2i TextWidget::cursorPosition() +RectangleRule const &TextWidget::rule() const +{ + DENG2_ASSERT(d->rule != 0); + return *d->rule; +} + +Vector2i TextWidget::cursorPosition() const { return Vector2i(floor(rule().left()->value()), floor(rule().top()->value())); diff --git a/doomsday/tools/shell/shell-text/src/logwidget.cpp b/doomsday/tools/shell/shell-text/src/logwidget.cpp index 3323eb0568..48ec8e05af 100644 --- a/doomsday/tools/shell/shell-text/src/logwidget.cpp +++ b/doomsday/tools/shell/shell-text/src/logwidget.cpp @@ -160,8 +160,3 @@ void LogWidget::draw() targetCanvas().draw(buf, pos.topLeft); } - -void LogWidget::redraw() -{ - drawAndShow(); -} diff --git a/doomsday/tools/shell/shell-text/src/logwidget.h b/doomsday/tools/shell/shell-text/src/logwidget.h index 76b6e2e4ad..ff441ff41b 100644 --- a/doomsday/tools/shell/shell-text/src/logwidget.h +++ b/doomsday/tools/shell/shell-text/src/logwidget.h @@ -24,8 +24,6 @@ class LogWidget : public de::shell::TextWidget { - Q_OBJECT - public: LogWidget(de::String const &name = ""); virtual ~LogWidget(); @@ -38,9 +36,6 @@ class LogWidget : public de::shell::TextWidget void draw(); -public slots: - void redraw(); - private: struct Instance; Instance *d;