Skip to content

Commit

Permalink
UI|Client|DialogWidget: Non-modal dialogs
Browse files Browse the repository at this point in the history
DialogWidget can now also be opened in a non-modal manner.
  • Loading branch information
skyjake committed Aug 22, 2013
1 parent 8389717 commit 33a1777
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 17 deletions.
10 changes: 7 additions & 3 deletions doomsday/client/include/ui/widgets/dialogwidget.h
Expand Up @@ -51,7 +51,7 @@ class DialogWidget : public PopupWidget
*/
enum Modality {
Modal,
Nonmodal
NonModal
};

enum RoleFlag {
Expand Down Expand Up @@ -97,8 +97,6 @@ class DialogWidget : public PopupWidget
public:
DialogWidget(de::String const &name = "");

void setModality(Modality modality);

Modality modality() const;

ScrollAreaWidget &area();
Expand All @@ -116,6 +114,12 @@ class DialogWidget : public PopupWidget
*/
int exec(GuiRootWidget &root);

/**
* Opens the dialog as non-modal. The dialog must already be added to the
* widget tree. Use accept() or reject() to close the dialog.
*/
void open();

// Events.
void update();
bool handleEvent(de::Event const &event);
Expand Down
74 changes: 62 additions & 12 deletions doomsday/client/src/ui/widgets/dialogwidget.cpp
Expand Up @@ -69,17 +69,20 @@ static bool dialogButtonOrder(ui::Item const &a, ui::Item const &b)
DENG2_PIMPL(DialogWidget),
DENG2_OBSERVES(ContextWidgetOrganizer, WidgetCreation),
DENG2_OBSERVES(ContextWidgetOrganizer, WidgetUpdate),
DENG2_OBSERVES(Widget, ChildAddition) // for styling the contents
DENG2_OBSERVES(Widget, ChildAddition), // for styling the contents
DENG2_OBSERVES(ui::Context, Addition),
DENG2_OBSERVES(ui::Context, Removal)
{
Modality modality;
ScrollAreaWidget *area;
MenuWidget *buttons;
QEventLoop subloop;
Animation glow;
bool needButtonUpdate;
float normalGlow;
bool animatingGlow;

Instance(Public *i) : Base(i), modality(Modal), animatingGlow(false)
Instance(Public *i) : Base(i), modality(Modal), needButtonUpdate(false), animatingGlow(false)
{
// Initialize the border glow.
normalGlow = self.style().colors().colorf("glow").w;
Expand All @@ -93,6 +96,8 @@ DENG2_OBSERVES(Widget, ChildAddition) // for styling the contents
area->audienceForChildAddition += this;

buttons = new MenuWidget("buttons");
buttons->items().audienceForAddition += this;
buttons->items().audienceForRemoval += this;
buttons->organizer().audienceForWidgetCreation += this;
buttons->organizer().audienceForWidgetUpdate += this;

Expand Down Expand Up @@ -133,6 +138,24 @@ DENG2_OBSERVES(Widget, ChildAddition) // for styling the contents
buttons->rule().height()));
}

void contextItemAdded(ui::Context::Pos, ui::Item const &)
{
needButtonUpdate = true;
}

void contextItemRemoved(ui::Context::Pos, ui::Item &)
{
needButtonUpdate = true;
}

void updateButtonLayout()
{
buttons->items().sort(dialogButtonOrder);
buttons->updateLayout();

needButtonUpdate = false;
}

void widgetCreatedForItem(GuiWidget &widget, ui::Item const &item)
{
// Make sure all label-based widgets in the button area
Expand Down Expand Up @@ -272,11 +295,6 @@ DialogWidget::DialogWidget(String const &name)
set(bg);
}

void DialogWidget::setModality(DialogWidget::Modality modality)
{
d->modality = modality;
}

DialogWidget::Modality DialogWidget::modality() const
{
return d->modality;
Expand All @@ -294,8 +312,7 @@ MenuWidget &DialogWidget::buttons()

int DialogWidget::exec(GuiRootWidget &root)
{
/// @todo Non-modal dialogs shouldn't be run with a subloop.
DENG2_ASSERT(modality() == Modal);
d->modality = Modal;

// The widget is added to the root temporarily (as top child).
DENG2_ASSERT(!hasRoot());
Expand All @@ -311,10 +328,23 @@ int DialogWidget::exec(GuiRootWidget &root)
return result;
}

void DialogWidget::open()
{
d->modality = NonModal;

DENG2_ASSERT(hasRoot());
prepare();
}

void DialogWidget::update()
{
PopupWidget::update();

if(d->needButtonUpdate)
{
d->updateButtonLayout();
}

if(d->animatingGlow)
{
d->updateBorderFlash();
Expand Down Expand Up @@ -360,6 +390,15 @@ bool DialogWidget::handleEvent(Event const &event)
}
return true;
}
else
{
if(event.type() == Event::MouseButton &&
hitTest(event.as<MouseEvent>().pos()))
{
// Non-modal dialogs eat mouse clicks inside the dialog.
return true;
}
}

return PopupWidget::handleEvent(event);
}
Expand All @@ -368,18 +407,30 @@ void DialogWidget::accept(int result)
{
if(d->subloop.isRunning())
{
DENG2_ASSERT(d->modality == Modal);
d->subloop.exit(result);
emit accepted(result);
}
else if(d->modality == NonModal)
{
emit accepted(result);
finish(result);
}
}

void DialogWidget::reject(int result)
{
if(d->subloop.isRunning())
{
DENG2_ASSERT(d->modality == Modal);
d->subloop.exit(result);
emit rejected(result);
}
else if(d->modality == NonModal)
{
emit rejected(result);
finish(result);
}
}

void DialogWidget::prepare()
Expand All @@ -396,10 +447,9 @@ void DialogWidget::prepare()
viewResized();
notifyTree(&Widget::viewResized);

d->buttons->items().sort(dialogButtonOrder);
d->buttons->updateLayout();
//d->updateButtonLayout();

open();
PopupWidget::open();
}

void DialogWidget::preparePopupForOpening()
Expand Down
4 changes: 2 additions & 2 deletions doomsday/client/src/updater/updateavailabledialog.cpp
Expand Up @@ -76,8 +76,8 @@ DENG2_OBSERVES(ToggleWidget, Toggle)
if(show)
{
// Set up a cancel button.
self.buttons().items().clear();
self.buttons().items() << new DialogButtonItem(DialogWidget::Reject);
self.buttons().items().clear()
<< new DialogButtonItem(DialogWidget::Reject);
}
}

Expand Down

0 comments on commit 33a1777

Please sign in to comment.