The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
mp_change_control.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2011 - 2016 by Lukasz Dobrogowski
4  Part of the Battle for Wesnoth Project http://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 #define GETTEXT_DOMAIN "wesnoth-lib"
17 
19 
21 #include "gui/dialogs/helper.hpp"
22 #include "gui/widgets/button.hpp"
23 #ifdef GUI2_EXPERIMENTAL_LISTBOX
24 #include "gui/widgets/list.hpp"
25 #else
26 #include "gui/widgets/listbox.hpp"
27 #endif
28 #include "gui/widgets/settings.hpp"
29 #include "gui/widgets/window.hpp"
30 
31 #include "formula/string_utils.hpp"
32 #include "game_display.hpp"
33 #include "game_preferences.hpp"
34 #include "log.hpp"
35 #include "marked-up_text.hpp"
36 #include "resources.hpp"
37 #include "team.hpp"
38 
39 #include <vector>
40 #include "utils/functional.hpp"
41 #include <boost/shared_ptr.hpp>
42 
43 static lg::log_domain log_gui("gui/dialogs/mp_change_control");
44 #define ERR_GUI LOG_STREAM(err, log_gui)
45 #define WRN_GUI LOG_STREAM(warn, log_gui)
46 #define LOG_GUI LOG_STREAM(info, log_gui)
47 #define DBG_GUI LOG_STREAM(debug, log_gui)
48 
49 namespace gui2
50 {
51 
52 /*WIKI
53  * @page = GUIWindowDefinitionWML
54  * @order = 2_mp_change_control
55  *
56  * == Change control dialog ==
57  *
58  * This shows the multiplayer change control dialog.
59  *
60  * @begin{table}{dialog_widgets}
61  * sides_list & & listbox & m &
62  * List of sides participating in the MP game. $
63  *
64  * nicks_list & & listbox & m &
65  * List of nicks of all clients playing or observing the MP game. $
66  *
67  * @end{table}
68  *
69  */
70 
71 template <class D, class V, void (V::*fptr)(twindow&)>
72 void dialog_view_callback(twidget& caller)
73 {
74  D* dialog = dynamic_cast<D*>(caller.dialog());
75  assert(dialog);
76  twindow* window = dynamic_cast<twindow*>(caller.get_window());
77  assert(window);
78  (*(dialog->get_view()).*fptr)(*window);
79 }
80 
81 /**
82  * The model is an interface defining the data to be displayed or otherwise
83  * acted upon in the user interface.
84  */
86 {
87 public:
88  model() : sides_list(nullptr), nicks_list(nullptr), sides(), nicks()
89  {
90  }
91 
94 
95  // contains the mapping from listbox labels to actual sides
96  // (note that due to hidden= attribute nth list item doesn't have to be nth
97  // side)
98  std::vector<int> sides;
99  // contains the mapping from listbox labels to actual nicks
100  std::vector<std::string> nicks;
101 
102  void clear_sides()
103  {
104  DBG_GUI << "Sides list: clearing\n";
105  sides_list->clear();
106  sides.clear();
107  }
108 
109  void add_side(int side_num, const std::string& label)
110  {
111  sides.push_back(side_num);
112  DBG_GUI << "Sides list: adding item (side_num: \"" << side_num
113  << "\" label: \"" << label << "\")\n";
114  std::map<std::string, string_map> data;
115  string_map item;
116  item["id"] = std::string("side_") + std::to_string(side_num);
117  item["label"] = label;
118  item["use_markup"] = "true";
119  data.insert(std::make_pair("side", item));
120  sides_list->add_row(data);
121  }
122 
123  void clear_nicks()
124  {
125  DBG_GUI << "Nicks list: clearing\n";
126  nicks_list->clear();
127  nicks.clear();
128  }
129 
130  void add_nick(const std::string& nick, const std::string& label)
131  {
132  DBG_GUI << "Nicks list: adding item (nick: \"" << nick << "\" label: \""
133  << label << "\")\n";
134  nicks.push_back(nick);
135  std::map<std::string, string_map> data;
136  string_map item;
137  item["id"] = nick;
138  item["label"] = label;
139  item["use_markup"] = "true";
140  data.insert(std::make_pair("nick", item));
141  nicks_list->add_row(data);
142  }
143 };
144 
146 {
147 public:
150  int side_number)
151  : model_(m), name_(name), side_number_(side_number)
152  {
153  }
154 
156  {
157  }
158 
160  {
161  return name_;
162  }
163 
164  int side_number() const
165  {
166  return side_number_;
167  }
168 
170  {
171  DBG_GUI << "Nicks list: showing for side " << side_number_ << '\n';
172  // model_.selected_side = side_number_;
174 
175  std::set<std::string> nicks;
176  for(std::vector<team>::const_iterator it = resources::teams->begin();
177  it != resources::teams->end();
178  ++it) {
179  if(!it->is_local_ai() && !it->is_network_ai() && !it->is_idle()
180  && !it->is_empty() && !it->current_player().empty())
181  nicks.insert(it->current_player());
182  }
183 
184  const std::set<std::string>& observers = resources::screen->observers();
185 
186  nicks.insert(observers.begin(), observers.end());
187  nicks.insert(preferences::login()); // in case we are an observer, it
188  // isn't in the observers set then
189  // and has to be added manually
190 
191  int i = 0; // because we need to know which row contains the controlling
192  // player
193 
194  for(const auto & nick : nicks)
195  {
196  if(side_number_ <= static_cast<int>(resources::teams->size())
197  && resources::teams->at(side_number_ - 1).current_player()
198  == nick) {
199  std::string label_str = "<b>" + nick + "</b>";
200  model_.add_nick(nick, label_str);
202  } else
203  model_.add_nick(nick, nick);
204  ++i;
205  }
206  }
208  {
210  DBG_GUI << "Nicks list: row " << selected << " selected, it contains "
211  << model_.nicks[selected] << '\n';
212  }
214  {
215  show_nicks_list();
216  }
217 
218 private:
222 };
223 
224 /**
225  * The controller acts upon the model.
226  *
227  * It retrieves data from repositories, persists it, manipulates it, and
228  * determines how it will be displayed in the view.
229  */
231 {
232 public:
233  typedef std::vector<boost::shared_ptr<side_controller> >
236  {
237  }
238 
240  {
241  DBG_GUI << "Sides list: filling\n";
243  int sides = resources::teams
244  ? static_cast<int>((*resources::teams).size())
245  : 0;
246  for(int side = 1; side <= sides; ++side) {
247  if(!resources::teams->at(side - 1).hidden()) {
248  string_map symbols;
249  symbols["side"] = std::to_string(side);
250  std::string side_str = vgettext("Side $side", symbols);
251  side_str = font::span_color(team::get_side_color(side))
252  + side_str + "</span>";
253  model_.add_side(side, side_str);
255  new side_controller(side_str, model_, side)));
256  }
257  }
258  }
259 
261  {
263  if(selected < 0 || selected
264  >= static_cast<int>(side_controllers_.size()))
265  return boost::shared_ptr<side_controller>(); // null pointer
266  else
267  return side_controllers_.at(selected);
268  }
269 
271  {
273  DBG_GUI << "Sides list: selected row: " << selected << " for side "
274  << model_.sides[selected] << '\n';
275  if(get_side_controller())
276  get_side_controller()->update_view_from_model();
277  }
278 
280  {
282  DBG_GUI << "Nicks list: selected row: " << selected << " with nick "
283  << model_.nicks[selected] << '\n';
284  if(get_side_controller())
285  get_side_controller()->handle_nicks_list_selection();
286  }
287 
289  {
290  if(get_side_controller())
291  get_side_controller()->update_view_from_model();
292  }
293 
295  {
296  int selected_side = model_.sides_list->get_selected_row();
297  int selected_nick = model_.nicks_list->get_selected_row();
298  DBG_GUI << "Main: changing control of side "
299  << model_.sides[selected_side] << " to nick "
300  << model_.nicks[selected_nick] << '\n';
301  if(mh) // since in unit tests we pass a null pointer to it
302  mh->request_control_change(model_.sides[selected_side],
303  model_.nicks[selected_nick]);
304  }
305 
306 private:
309 };
310 
311 
312 /**
313  * The view is an interface that displays data (the model) and routes user
314  * commands to the controller to act upon that data.
315  */
317 {
318 public:
320  {
321  }
322 
323  void pre_show(twindow& window)
324  {
329  window.invalidate_layout(); // workaround for assertion failure
330  }
331 
333  {
335  window.invalidate_layout(); // workaround for assertion failure
336  }
337 
339  {
341  window.invalidate_layout(); // workaround for assertion failure
342  }
343 
344  void bind(twindow& window)
345  {
346  DBG_GUI << "Main: Binding widgets and callbacks\n";
348  = &find_widget<tlistbox>(&window, "sides_list", false);
350  = &find_widget<tlistbox>(&window, "nicks_list", false);
351 
352 #ifdef GUI2_EXPERIMENTAL_LISTBOX
355  std::bind(&tmp_change_control::view::
357  this,
358  std::ref(window)));
359 
362  std::bind(&tmp_change_control::view::
364  this,
365  std::ref(window)));
366 #else
371  handle_sides_list_item_clicked>);
372 
377  handle_nicks_list_item_clicked>);
378 #endif
379  }
380 
381  void post_show(int retval, events::menu_handler* mh)
382  {
383  if(retval == twindow::OK) {
385  }
386  }
387 
388 private:
391 };
392 
393 REGISTER_DIALOG(mp_change_control)
394 
396  : menu_handler_(mh), view_(new view)
397 {
398 }
399 
401 {
402  return view_;
403 }
404 
406 {
407  view_->bind(window);
408  view_->pre_show(window);
409 }
410 
412 {
413  view_->post_show(get_retval(), menu_handler_);
414 }
415 
416 } // end of namespace gui2
std::vector< boost::shared_ptr< side_controller > > side_controller_ptr_vector
side_controller(const std::string &name, tmp_change_control::model &m, int side_number)
void post_show(int retval, events::menu_handler *mh)
void add_nick(const std::string &nick, const std::string &label)
int get_retval() const
Definition: dialog.hpp:161
std::vector< std::string > nicks
void connect_signal_notify_modified(tdispatcher &dispatcher, const tsignal_notification_function &signal)
Connects a signal handler for getting a notification upon modification.
Definition: dispatcher.hpp:725
game_display * screen
Definition: resources.cpp:27
This file contains the window object, this object is a top level container which has the event manage...
bool select_row(const unsigned row, const bool select=true)
Selectes a row.
Definition: listbox.cpp:228
REGISTER_DIALOG(label_settings)
void request_control_change(int side_num, const std::string &player)
-file sdl_utils.hpp
GLint GLenum GLsizei GLint GLsizei const GLvoid * data
Definition: glew.h:1347
std::string span_color(const SDL_Color &color)
Creates pango markup of a color.
base class of top level items, the only item which needs to store the final canvases to draw on ...
Definition: window.hpp:62
events::menu_handler * menu_handler_
A class inherited from ttext_box that displays its input as stars.
Definition: field-fwd.hpp:23
void change_control(events::menu_handler *mh)
tmp_change_control::model & model_
static std::string at(const std::string &file, int line)
The controller acts upon the model.
Dialog is closed with ok button.
Definition: window.hpp:125
void handle_sides_list_item_clicked(twindow &window)
std::vector< team > * teams
Definition: resources.cpp:29
This file contains the settings handling of the widget library.
void add_row(const string_map &item, const int index=-1)
When an item in the list is selected by the user we need to update the state.
Definition: listbox.cpp:74
#define DBG_GUI
std::string selected
Definition: game_config.cpp:84
side_controller_ptr_vector side_controllers_
void handle_nicks_list_item_clicked(twindow &window)
std::string name() const
std::map< std::string, t_string > string_map
Definition: generator.hpp:23
std::string login()
void dialog_view_callback(twidget &caller)
Template for dialog callbacks for dialogs using model-view-controller architecture pattern...
void post_show(twindow &window)
Actions to be taken after the window has been shown.
boost::shared_ptr< side_controller > get_side_controller()
void pre_show(twindow &window)
Inherited from tdialog.
The listbox class.
Definition: listbox.hpp:39
size_t i
Definition: function.cpp:1057
static SDL_Color get_side_color(int side)
Definition: team.cpp:828
static lg::log_domain log_gui("gui/dialogs/mp_change_control")
std::string vgettext(const char *msgid, const utils::string_map &symbols)
Handling of system events.
Definition: manager.hpp:42
GLuint const GLchar * name
Definition: glew.h:1782
GLsizeiptr size
Definition: glew.h:1649
GLenum GLint ref
Definition: glew.h:1813
const GLdouble * m
Definition: glew.h:6968
boost::shared_ptr< view > view_
const std::set< std::string > & observers() const
Standard logging facilities (interface).
The model is an interface defining the data to be displayed or otherwise acted upon in the user inter...
void set_callback_value_change(const std::function< void(twidget &)> &callback)
Definition: listbox.hpp:225
void add_side(int side_num, const std::string &label)
int get_selected_row() const
Returns the first selected row.
Definition: listbox.cpp:237
GLsizei const GLcharARB ** string
Definition: glew.h:4503
The view is an interface that displays data (the model) and routes user commands to the controller to...
void clear()
Removes all the rows in the listbox, clearing it.
Definition: listbox.cpp:131
void invalidate_layout()
Updates the size of the window.
Definition: window.cpp:941
boost::shared_ptr< view > get_view()