Skip to content

Commit

Permalink
Client|UI: Added a basic implementation of NotificationWidget
Browse files Browse the repository at this point in the history
This will act as a common notification area.

Also added changeRef() to aid in changing the value of a reference
counted pointer, and safe type casting for Widget-based classes.
  • Loading branch information
skyjake committed Jul 8, 2013
1 parent 5a5830b commit eaaf07e
Show file tree
Hide file tree
Showing 5 changed files with 230 additions and 0 deletions.
2 changes: 2 additions & 0 deletions doomsday/client/client.pro
Expand Up @@ -346,6 +346,7 @@ DENG_HEADERS += \
include/ui/widgets/lineeditwidget.h \
include/ui/widgets/logwidget.h \
include/ui/widgets/menuwidget.h \
include/ui/widgets/notificationwidget.h \
include/ui/widgets/popupmenuwidget.h \
include/ui/widgets/popupwidget.h \
include/ui/widgets/scrollareawidget.h \
Expand Down Expand Up @@ -637,6 +638,7 @@ SOURCES += \
src/ui/widgets/lineeditwidget.cpp \
src/ui/widgets/logwidget.cpp \
src/ui/widgets/menuwidget.cpp \
src/ui/widgets/notificationwidget.cpp \
src/ui/widgets/popupmenuwidget.cpp \
src/ui/widgets/popupwidget.cpp \
src/ui/widgets/scrollareawidget.cpp \
Expand Down
53 changes: 53 additions & 0 deletions doomsday/client/include/ui/widgets/notificationwidget.h
@@ -0,0 +1,53 @@
/** @file notificationwidget.h Notifiction area.
*
* @authors Copyright (c) 2013 Jaakko Keränen <jaakko.keranen@iki.fi>
*
* @par License
* GPL: http://www.gnu.org/licenses/gpl.html
*
* <small>This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. This program is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details. You should have received a copy of the GNU
* General Public License along with this program; if not, see:
* http://www.gnu.org/licenses</small>
*/

#ifndef DENG_CLIENT_NOTIFICATIONWIDGET_H
#define DENG_CLIENT_NOTIFICATIONWIDGET_H

#include "guiwidget.h"

/**
* Notification area.
*
* Children the widget are expected to size themselves and allow unrestricted,
* automatical positioning inside the area. Children can be added and removed
* dynamically. The notification area is dismissed if there are no visible
* notifications.
*
* The client window owns an instance of NotificationWidget. Other widgets and
* subsystems are expected to give ownership of their notifications to the
* window's NotificationWidget.
*/
class NotificationWidget : public GuiWidget
{
public:
NotificationWidget(de::String const &name = "");

// Events.
void viewResized();
void drawContent();

protected:
void glInit();
void glDeinit();

private:
DENG2_PRIVATE(d)
};

#endif // DENG_CLIENT_NOTIFICATIONWIDGET_H
149 changes: 149 additions & 0 deletions doomsday/client/src/ui/widgets/notificationwidget.cpp
@@ -0,0 +1,149 @@
/** @file notificationwidget.cpp Notification area.
*
* @authors Copyright (c) 2013 Jaakko Keränen <jaakko.keranen@iki.fi>
*
* @par License
* GPL: http://www.gnu.org/licenses/gpl.html
*
* <small>This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. This program is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details. You should have received a copy of the GNU
* General Public License along with this program; if not, see:
* http://www.gnu.org/licenses</small>
*/

#include "ui/widgets/notificationwidget.h"
#include "ui/widgets/guirootwidget.h"

#include <de/Drawable>
#include <de/Matrix>

using namespace de;

DENG2_PIMPL(NotificationWidget)
{
// GL objects:
typedef DefaultVertexBuf VertexBuf;
Drawable drawable;
GLUniform uMvpMatrix;
GLUniform uColor;

Instance(Public *i)
: Base(i),
uMvpMatrix("uMvpMatrix", GLUniform::Mat4),
uColor ("uColor", GLUniform::Vec4)
{
updateStyle();
}

void updateStyle()
{
self.set(Background(self.style().colors().colorf("background")));
}

void glInit()
{
drawable.addBuffer(new VertexBuf);

self.root().shaders().build(drawable.program(), "generic.color_ucolor")
<< uMvpMatrix << uColor;
}

void glDeinit()
{
drawable.clear();
}

void updateGeometry()
{
Rectanglei pos;
if(self.hasChangedPlace(pos) || self.geometryRequested())
{
self.requestGeometry(false);

VertexBuf::Builder verts;
self.glMakeGeometry(verts);
drawable.buffer<VertexBuf>().setVertices(gl::TriangleStrip, verts, gl::Static);
}
}

void updateChildLayout()
{
Rule const &outer = self.style().rules().rule("gap");
Rule const &inner = self.style().rules().rule("unit");

Rule const *totalWidth = 0;
Rule const *totalHeight = 0;

WidgetList const children = self.Widget::children();
for(int i = 0; i < children.size(); ++i)
{
GuiWidget &w = children[i]->as<GuiWidget>();

// The children are laid out simply in a row from right to left.
w.rule().setInput(Rule::Top, self.rule().top() + outer);
if(i > 0)
{
w.rule().setInput(Rule::Right, children[i - 1]->as<GuiWidget>().rule().left() - inner);
changeRef(totalWidth, *totalWidth + inner + w.rule().width());
}
else
{
w.rule().setInput(Rule::Right, self.rule().right() - outer);
totalWidth = holdRef(w.rule().width());
}

if(!totalHeight)
{
totalHeight = holdRef(w.rule().height());
}
else
{
changeRef(totalHeight, OperatorRule::maximum(*totalHeight, w.rule().height()));
}
}

// Update the total size of the notification area.
self.rule()
.setInput(Rule::Width, *totalWidth + outer * 2)
.setInput(Rule::Height, *totalHeight + outer * 2);

releaseRef(totalWidth);
releaseRef(totalHeight);
}
};

NotificationWidget::NotificationWidget(String const &name) : d(new Instance(this))
{
// Initially the widget is empty.
rule().setSize(Const(0), Const(0));
hide();
}

void NotificationWidget::viewResized()
{
d->uMvpMatrix = root().projMatrix2D();
}

void NotificationWidget::drawContent()
{
d->updateGeometry();

d->uColor = Vector4f(1, 1, 1, visibleOpacity());
d->drawable.draw();
}

void NotificationWidget::glInit()
{
d->glInit();
}

void NotificationWidget::glDeinit()
{
d->glDeinit();
}

14 changes: 14 additions & 0 deletions doomsday/libdeng2/include/de/data/counted.h
Expand Up @@ -160,6 +160,20 @@ inline CountedType const *holdRef(CountedType const &counted) {
return counted.template ref<CountedType>();
}

template <typename CountedType1, typename CountedType2>
inline void changeRef(CountedType1 const *&counted, CountedType2 const *newRef) {
CountedType1 const *old = counted;
counted = holdRef(newRef);
releaseRef(old);
}

template <typename CountedType1, typename CountedType2>
inline void changeRef(CountedType1 const *&counted, CountedType2 const &newRef) {
CountedType1 const *old = counted;
counted = holdRef(newRef);
releaseRef(old);
}

/**
* Releases a reference to a Counted object. Afterwards, the pointer is cleared
* to NULL.
Expand Down
12 changes: 12 additions & 0 deletions doomsday/libdeng2/include/de/widgets/widget.h
Expand Up @@ -85,6 +85,18 @@ class DENG2_PUBLIC Widget
Widget(String const &name = "");
virtual ~Widget();

template <typename Type>
Type &as() {
DENG2_ASSERT(dynamic_cast<Type *>(this) != 0);
return *static_cast<Type *>(this);
}

template <typename Type>
Type const &as() const {
DENG2_ASSERT(dynamic_cast<Type const *>(this) != 0);
return *static_cast<Type const *>(this);
}

/**
* Returns the automatically generated, unique identifier of the widget.
*/
Expand Down

0 comments on commit eaaf07e

Please sign in to comment.