Skip to content

Commit

Permalink
UI|Multiplayer: Improved MPSelectionWidget
Browse files Browse the repository at this point in the history
The multiplayer game selection widget can now notify an audience
when the selection has been made, and the click-to-join feature can
be disabled. This allows the widget to function as a part of another
dialog.

Also, the discovery mode for the widget can be configured.
  • Loading branch information
skyjake committed Mar 2, 2014
1 parent af3daf1 commit fd39af2
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 48 deletions.
36 changes: 35 additions & 1 deletion doomsday/client/include/ui/widgets/mpselectionwidget.h
Expand Up @@ -20,6 +20,7 @@
#define DENG_CLIENT_MPSELECTIONWIDGET_H

#include <de/MenuWidget>
#include "network/net_main.h"

/**
* Menu that populates itself with available multiplayer games.
Expand All @@ -31,10 +32,43 @@ class MPSelectionWidget : public de::MenuWidget
Q_OBJECT

public:
MPSelectionWidget();
DENG2_DEFINE_AUDIENCE(Selection, void gameSelected(serverinfo_t const &info))

enum DiscoveryMode {
NoDiscovery,
DiscoverUsingMaster,
DirectDiscoveryOnly
};

/**
* Action for joining a game on a multiplayer server.
*/
class JoinAction : public de::Action
{
public:
JoinAction(serverinfo_t const &sv);
void trigger();

private:
DENG2_PRIVATE(d)
};

public:
MPSelectionWidget(DiscoveryMode discovery = NoDiscovery);

/**
* Enables or disables joining games by pressing the menu items in the widget.
* By default, this is enabled. If disabled, one will only get a notification
* about the selection.
*
* @param enableJoin @c true to allow automatic joining, @c false to disallow.
*/
void setJoinGameWhenSelected(bool enableJoin);

void setColumns(int numberOfColumns);

serverinfo_t const &serverInfo(de::ui::DataPos pos) const;

signals:
void availabilityChanged();
void gameSelected();
Expand Down
2 changes: 1 addition & 1 deletion doomsday/client/src/ui/widgets/gameselectionwidget.cpp
Expand Up @@ -109,7 +109,7 @@ DENG_GUI_PIMPL(GameSelectionWidget)
break;

case MultiplayerGames:
menu = new MPSelectionWidget;
menu = new MPSelectionWidget(MPSelectionWidget::DiscoverUsingMaster);
QObject::connect(menu, SIGNAL(gameSelected()), owner->thisPublic, SIGNAL(gameSessionSelected()));
QObject::connect(menu, SIGNAL(availabilityChanged()), owner->thisPublic, SLOT(updateSubsetLayout()));
break;
Expand Down
123 changes: 77 additions & 46 deletions doomsday/client/src/ui/widgets/mpselectionwidget.cpp
Expand Up @@ -75,33 +75,6 @@ DENG_GUI_PIMPL(MPSelectionWidget)
*/
struct ServerWidget : public GameSessionWidget
{
struct JoinAction : public Action
{
public:
JoinAction(serverinfo_t const &sv, ButtonWidget &owner)
: _owner(&owner)
{
_gameId = sv.gameIdentityKey;
_cmd = String("connect %1 %2").arg(sv.address).arg(sv.port);
}

void trigger()
{
Action::trigger();

BusyMode_FreezeGameForBusyMode();
ClientWindow::main().taskBar().close();

App_ChangeGame(App_Games().byIdentityKey(_gameId), false /*no reload*/);
Con_Execute(CMDS_DDAY, _cmd.toLatin1(), false, false);
}

private:
ButtonWidget *_owner;
String _gameId;
String _cmd;
};

ServerWidget()
{
loadButton().disable();
Expand All @@ -124,10 +97,10 @@ DENG_GUI_PIMPL(MPSelectionWidget)
loadButton().enable(sv.canJoin);
if(sv.canJoin)
{
loadButton().setAction(new JoinAction(sv, loadButton()));
loadButton().setAction(new JoinAction(sv));
}

loadButton().setText(String(_E(1) "%1 " _E(.)_E(2) "(%5/%6)" _E(.) "\n%2"
loadButton().setText(String(_E(1) "%1 " _E(.)_E(2) "(%5/%6)" _E(.) " "DENG2_CHAR_MDASH" %2"
_E(D)_E(l) "\n%7 %4")
.arg(sv.name)
.arg(svGame.title())
Expand All @@ -146,7 +119,13 @@ DENG_GUI_PIMPL(MPSelectionWidget)
}
};

Instance(Public *i) : Base(i)
ServerLink::FoundMask mask;
bool joinWhenSelected;

Instance(Public *i)
: Base(i)
, mask(ServerLink::Any)
, joinWhenSelected(true)
{
self.organizer().setWidgetFactory(*this);
link().audienceForDiscoveryUpdate += this;
Expand All @@ -171,11 +150,27 @@ DENG_GUI_PIMPL(MPSelectionWidget)

void updateItemWidget(GuiWidget &widget, ui::Item const &item)
{
widget.as<ServerWidget>().updateFromItem(item.as<ServerListItem>());
ServerWidget &sv = widget.as<ServerWidget>();
sv.updateFromItem(item.as<ServerListItem>());

if(!joinWhenSelected)
{
// Only send notification.
sv.loadButton().setAction(0);
}
}

void buttonPressed(ButtonWidget &)
void buttonPressed(ButtonWidget &loadButton)
{
if(ServerListItem const *it = self.organizer().findItemForWidget(
loadButton.parentWidget()->as<GuiWidget>())->maybeAs<ServerListItem>())
{
DENG2_FOR_PUBLIC_AUDIENCE(Selection, i)
{
i->gameSelected(it->info());
}
}

// A load button has been pressed.
emit self.gameSelected();
}
Expand All @@ -188,18 +183,18 @@ DENG_GUI_PIMPL(MPSelectionWidget)
for(ui::Data::Pos idx = 0; idx < self.items().size(); ++idx)
{
String const id = self.items().at(idx).data().toString();
if(!link.isFound(Address::parse(id)))
if(!link.isFound(Address::parse(id), mask))
{
self.items().remove(idx--);
changed = true;
}
}

// Add new entries and update existing ones.
foreach(de::Address const &host, link.foundServers())
foreach(de::Address const &host, link.foundServers(mask))
{
serverinfo_t info;
if(!link.foundServerInfo(host, &info)) continue;
if(!link.foundServerInfo(host, &info, mask)) continue;

ui::Data::Pos found = self.items().findData(hostId(info));
if(found == ui::Data::InvalidPos)
Expand All @@ -224,12 +219,30 @@ DENG_GUI_PIMPL(MPSelectionWidget)
}
};

MPSelectionWidget::MPSelectionWidget()
MPSelectionWidget::MPSelectionWidget(DiscoveryMode discovery)
: MenuWidget("mp-selection"), d(new Instance(this))
{
setGridSize(3, ui::Filled, 0, ui::Expand);

d->link().discoverUsingMaster();
switch(discovery)
{
case DiscoverUsingMaster:
d->link().discoverUsingMaster();
break;

case DirectDiscoveryOnly:
// Only show servers found via direct connection.
d->mask = ServerLink::Direct;
break;

default:
break;
}
}

void MPSelectionWidget::setJoinGameWhenSelected(bool enableJoin)
{
d->joinWhenSelected = enableJoin;
}

void MPSelectionWidget::setColumns(int numberOfColumns)
Expand All @@ -239,15 +252,33 @@ void MPSelectionWidget::setColumns(int numberOfColumns)
setGridSize(numberOfColumns, ui::Filled, 0, ui::Expand);
}
}
/*
void MPSelectionWidget::update()

serverinfo_t const &MPSelectionWidget::serverInfo(ui::DataPos pos) const
{
MenuWidget::update();
DENG2_ASSERT(pos < items().size());
return items().at(pos).as<Instance::ServerListItem>().info();
}

Rectanglei rect;
if(hasChangedPlace(rect))
{
d->updateLayoutForWidth(rect.width());
}
DENG2_PIMPL_NOREF(MPSelectionWidget::JoinAction)
{
String gameId;
String cmd;
};

MPSelectionWidget::JoinAction::JoinAction(serverinfo_t const &sv)
: d(new Instance)
{
d->gameId = sv.gameIdentityKey;
d->cmd = String("connect %1 %2").arg(sv.address).arg(sv.port);
}

void MPSelectionWidget::JoinAction::trigger()
{
Action::trigger();

BusyMode_FreezeGameForBusyMode();
ClientWindow::main().taskBar().close();

App_ChangeGame(App_Games().byIdentityKey(d->gameId), false /*no reload*/);
Con_Execute(CMDS_DDAY, d->cmd.toLatin1(), false, false);
}
*/

0 comments on commit fd39af2

Please sign in to comment.