The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
lobby.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2009 - 2016 by Tomasz Sniatowski <[email protected]>
3  Part of the Battle for Wesnoth Project http://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 #define GETTEXT_DOMAIN "wesnoth-lib"
15 
16 #include "gui/auxiliary/field.hpp"
20 #include "gui/dialogs/helper.hpp"
21 
22 #include "gui/core/log.hpp"
23 #include "gui/core/timer.hpp"
24 #include "gui/widgets/button.hpp"
25 #include "gui/widgets/image.hpp"
26 #include "gui/widgets/label.hpp"
27 #ifdef GUI2_EXPERIMENTAL_LISTBOX
28 #include "gui/widgets/list.hpp"
29 #else
30 #include "gui/widgets/listbox.hpp"
31 #endif
32 #include "gui/widgets/minimap.hpp"
35 #include "gui/widgets/settings.hpp"
36 #include "gui/widgets/text_box.hpp"
40 
41 #include "formula/string_utils.hpp"
42 #include "game_preferences.hpp"
43 #include "gettext.hpp"
44 #include "lobby_preferences.hpp"
45 #include "log.hpp"
46 #include "wesnothd_connection.hpp"
47 #include "playmp_controller.hpp"
48 #include "mp_ui_alerts.hpp"
49 
50 #include "utils/functional.hpp"
51 
52 static lg::log_domain log_network("network");
53 #define DBG_NW LOG_STREAM(debug, log_network)
54 #define LOG_NW LOG_STREAM(info, log_network)
55 #define ERR_NW LOG_STREAM(err, log_network)
56 
57 static lg::log_domain log_engine("engine");
58 #define LOG_NG LOG_STREAM(info, log_engine)
59 #define ERR_NG LOG_STREAM(err, log_engine)
60 
61 static lg::log_domain log_config("config");
62 #define ERR_CF LOG_STREAM(err, log_config)
63 
64 static lg::log_domain log_lobby("lobby");
65 #define DBG_LB LOG_STREAM(debug, log_lobby)
66 #define LOG_LB LOG_STREAM(info, log_lobby)
67 #define ERR_LB LOG_STREAM(err, log_lobby)
68 #define SCOPE_LB log_scope2(log_lobby, __func__)
69 
70 
71 namespace gui2
72 {
73 
74 REGISTER_DIALOG(lobby_main)
75 
76 void tsub_player_list::init(gui2::twindow& w, const std::string& id)
77 {
78  list = find_widget<tlistbox>(&w, id, false, true);
79  show_toggle
80  = find_widget<ttoggle_button>(&w, id + "_show_toggle", false, true);
81  show_toggle->set_icon_name("lobby/group-expanded.png");
82  show_toggle->set_callback_state_change(
83  std::bind(&tsub_player_list::show_toggle_callback, this, _1));
84  count = find_widget<tlabel>(&w, id + "_count", false, true);
85  label = find_widget<tlabel>(&w, id + "_label", false, true);
86 
87  ttree_view& parent_tree = find_widget<ttree_view>(&w, "player_tree", false);
88 
89  string_map tree_group_field;
90  std::map<std::string, string_map> tree_group_item;
91 
92  tree_group_field["label"] = id;
93  tree_group_item["tree_view_node_label"] = tree_group_field;
94  tree = &parent_tree.add_node("player_group", tree_group_item);
95 
96  tree_label = find_widget<tlabel>(tree, "tree_view_node_label", false, true);
97 
98  tree_label->set_label(label->label());
99 }
100 
102 {
103  if(show_toggle->get_value()) {
105  show_toggle->set_icon_name("lobby/group-folded.png");
106  } else {
108  show_toggle->set_icon_name("lobby/group-expanded.png");
109  }
110 }
111 
113 {
114  assert(tree);
115  assert(tree_label);
116  if(tree->empty()) {
117  /**
118  * @todo Make sure setting visible resizes the widget.
119  *
120  * It doesn't work here since invalidate_layout is blocked, but the
121  * widget should also be able to handle it itself. Once done the
122  * setting of the label text can also be removed.
123  */
124  assert(label);
125  tree_label->set_label(label->label() + " (0)");
126  // tree_label->set_visible(twidget::tvisible::invisible);
127  } else {
128  assert(label);
129  std::stringstream ss;
130  ss << label->label() << " (" << tree->size() << ")";
131  tree_label->set_label(ss.str());
132  // tree_label->set_visible(twidget::tvisible::visible);
133  }
134 }
135 
137 {
138  active_game.init(w, "active_game");
139  active_room.init(w, "active_room");
140  other_rooms.init(w, "other_rooms");
141  other_games.init(w, "other_games");
142  sort_by_name = find_widget<ttoggle_button>(
143  &w, "player_list_sort_name", false, true);
144  sort_by_relation = find_widget<ttoggle_button>(
145  &w, "player_list_sort_relation", false, true);
146 
147  tree = find_widget<ttree_view>(&w, "player_tree", false, true);
148 
149  find_widget<twidget>(&w, "old_player_list", false)
150  .set_visible(twidget::tvisible::invisible);
151 }
152 
154 {
155  if(sort_by_name->get_value()) {
156  sort_by_name->set_icon_name("lobby/sort-az.png");
157  } else {
158  sort_by_name->set_icon_name("lobby/sort-az-off.png");
159  }
160  if(sort_by_relation->get_value()) {
161  sort_by_relation->set_icon_name("lobby/sort-friend.png");
162  } else {
163  sort_by_relation->set_icon_name("lobby/sort-friend-off.png");
164  }
165 }
167  bool /*allies_only*/)
168 {
169  config data, msg;
170  msg["message"] = message;
171  msg["sender"] = preferences::login();
172  data.add_child("message", msg);
173 
174  add_chat_message(time(nullptr), preferences::login(), 0, message); // local
175  // echo
177 }
178 
180 {
181  player_list_dirty_ = true;
182 }
183 
184 void tlobby_main::add_chat_message(const time_t& /*time*/,
185  const std::string& speaker,
186  int /*side*/,
187  const std::string& message,
189 {
190  std::stringstream ss;
191  ss << "<b>" << speaker << ":</b> ";
192  ss << font::escape_text(message);
193  append_to_chatbox(ss.str());
194 }
195 
196 
198  const std::string& message)
199 {
200  if(whisper_window_active(receiver)) {
206  } else {
207  utils::string_map symbols;
208  symbols["receiver"] = receiver;
209  add_active_window_whisper(VGETTEXT("whisper to $receiver", symbols),
210  message, true);
211  }
212  lobby_info_.get_whisper_log(receiver)
213  .add_message(preferences::login(), message);
214 }
215 
217  const std::string& message)
218 {
219  bool can_go_to_active = !preferences::whisper_friends_only()
220  || preferences::is_friend(sender);
221  bool can_open_new = preferences::auto_open_whisper_windows()
222  && can_go_to_active;
223  lobby_info_.get_whisper_log(sender).add_message(sender, message);
224  if(whisper_window_open(sender, can_open_new)) {
225  if(whisper_window_active(sender)) {
226  add_active_window_message(sender, message);
227  do_notify(NOTIFY_WHISPER, sender, message);
228  } else {
229  add_whisper_window_whisper(sender, message);
231  do_notify(NOTIFY_WHISPER_OTHER_WINDOW, sender, message);
232  }
233  } else if(can_go_to_active) {
234  add_active_window_whisper(sender, message);
235  do_notify(NOTIFY_WHISPER, sender, message);
236  } else {
237  LOG_LB << "Ignoring whisper from " << sender << "\n";
238  }
239 }
240 
242  const std::string& message)
243 {
244  // do not open room window here, player should be in the room before sending
245  // messages yo it should be allowed to happen
246  if(tlobby_chat_window* t = room_window_open(room, false)) {
247  room_info* ri = lobby_info_.get_room(room);
248  assert(ri);
249  if(!room_window_active(room)) {
251  }
252  ri->log().add_message(preferences::login(), message);
254  } else {
255  LOG_LB << "Cannot add sent message to ui for room " << room
256  << ", player not in the room\n";
257  }
258 }
259 
261  const std::string& speaker,
262  const std::string& message)
263 {
264  if(room_info* ri = lobby_info_.get_room(room)) {
265  t_notify_mode notify_mode = NOTIFY_NONE;
266  ri->log().add_message(speaker, message);
267  if(room_window_active(room)) {
268  add_active_window_message(speaker, message);
269  notify_mode = NOTIFY_MESSAGE;
270  } else {
271  add_room_window_message(room, speaker, message);
273  notify_mode = NOTIFY_MESSAGE_OTHER_WINDOW;
274  }
275  if(speaker == "server") {
276  notify_mode = NOTIFY_SERVER_MESSAGE;
277  } else if(utils::word_match(message, preferences::login())) {
278  notify_mode = NOTIFY_OWN_NICK;
279  } else if(preferences::is_friend(speaker)) {
280  notify_mode = NOTIFY_FRIEND_MESSAGE;
281  }
282  do_notify(notify_mode, speaker, message);
283  } else {
284  LOG_LB << "Discarding message to room " << room << " from " << speaker
285  << " (room not open)\n";
286  }
287 }
288 
289 void tlobby_main::append_to_chatbox(const std::string& text, const bool force_scroll)
290 {
291  append_to_chatbox(text, active_window_, force_scroll);
292 }
293 
294 void tlobby_main::append_to_chatbox(const std::string& text, size_t id, const bool force_scroll)
295 {
297  tscroll_label& log = find_widget<tscroll_label>(&grid, "log_text", false);
298  const bool chatbox_at_end = log.vertical_scrollbar_at_end();
299  const unsigned chatbox_position = log.get_vertical_scrollbar_item_position();
300  log.set_use_markup(true);
301  log.set_label(log.label() + "\n" +
302  "<span color='#bcb088'>" + preferences::get_chat_timestamp(time(0)) + text + "</span>");
303 
304  if(chatbox_at_end || force_scroll) {
306  } else {
307  log.set_vertical_scrollbar_item_position(chatbox_position);
308  }
309 }
310 
312 {
313  switch(mode) {
314  case NOTIFY_WHISPER:
316  case NOTIFY_OWN_NICK:
317  mp_ui_alerts::private_message(true, sender, message);
318  break;
320  mp_ui_alerts::friend_message(true, sender, message);
321  break;
323  mp_ui_alerts::server_message(true, sender, message);
324  break;
325  case NOTIFY_LOBBY_QUIT:
327  break;
328  case NOTIFY_LOBBY_JOIN:
330  break;
331  case NOTIFY_MESSAGE:
332  mp_ui_alerts::public_message(true, sender, message);
333  break;
334  default:
335  break;
336  }
337 }
338 
340  lobby_info& info,
341  CVideo& video, twesnothd_connection &wesnothd_connection)
342  : legacy_result_(QUIT)
343  , game_config_(game_config)
344  , gamelistbox_(nullptr)
345  , userlistbox_(nullptr)
346  , roomlistbox_(nullptr)
347  , chat_log_container_(nullptr)
348  , chat_input_(nullptr)
349  , window_(nullptr)
350  , lobby_info_(info)
351  , preferences_callback_()
352  , open_windows_()
353  , active_window_(0)
354  , filter_friends_(nullptr)
355  , filter_ignored_(nullptr)
356  , filter_slots_(nullptr)
357  , filter_invert_(nullptr)
358  , filter_text_(nullptr)
359  , selected_game_id_()
360  , player_list_()
361  , player_list_dirty_(false)
362  , gamelist_dirty_(false)
363  , last_gamelist_update_(0)
364  , gamelist_diff_update_(true)
365  , video_(video)
366  , wesnothd_connection_(wesnothd_connection)
367  , lobby_update_timer_(0)
368  , preferences_wrapper_()
369  , gamelist_id_at_row_()
370  , delay_playerlist_update_(false)
371  , delay_gamelist_update_(false)
372 {
373 }
374 
376 {
378  {
379  l.delay_gamelist_update_ = true;
380  }
382  {
383  l.delay_gamelist_update_ = false;
384  }
386 };
387 
388 void tlobby_main::set_preferences_callback(std::function<void()> cb)
389 {
391 }
392 
394 {
395  if(lobby_update_timer_) {
397  }
398 }
399 
400 static bool fullscreen(CVideo& video)
401 {
403 
404 
405  return true;
406 }
407 
409 {
410  /** @todo Should become a global hotkey after 1.8, then remove it here. */
412  std::bind(fullscreen, std::ref(window.video())));
413 
414  /*** Local hotkeys. ***/
417  this,
418  std::ref(window));
419 
420  window.register_hotkey(
422  std::bind(function_wrapper<bool, std::function<void()> >,
423  true,
424  boost::cref(preferences_wrapper_)));
425 }
426 
427 namespace
428 {
429 
430 void add_label_data(std::map<std::string, string_map>& map,
431  const std::string& key,
432  const std::string& label)
433 {
434  string_map item;
435  item["label"] = label;
436  item["use_markup"] = "true";
437  map.insert(std::make_pair(key, item));
438 }
439 
440 void add_tooltip_data(std::map<std::string, string_map>& map,
441  const std::string& key,
442  const std::string& label)
443 {
444  string_map item;
445  item["tooltip"] = label;
446  map.insert(std::make_pair(key, item));
447 }
448 
449 void modify_grid_with_data(tgrid* grid,
450  const std::map<std::string, string_map>& map)
451 {
452  for(const auto & v : map)
453  {
454  const std::string& key = v.first;
455  const string_map& strmap = v.second;
456  twidget* w = grid->find(key, false);
457  if(w == nullptr)
458  continue;
459  tcontrol* c = dynamic_cast<tcontrol*>(w);
460  if(c == nullptr)
461  continue;
462  for(const auto & vv : strmap)
463  {
464  if(vv.first == "label") {
465  c->set_label(vv.second);
466  } else if(vv.first == "tooltip") {
467  c->set_tooltip(vv.second);
468  }
469  }
470  }
471 }
472 
473 void set_visible_if_exists(tgrid* grid, const char* id, bool visible)
474 {
475  twidget* w = grid->find(id, false);
476  if(w) {
477  w->set_visible(visible ? twidget::tvisible::visible
479  }
480 }
481 
482 std::string colorize(const std::string& str, const std::string& color)
483 {
484  return "<span color=\"" + color + "\">" + str + "</span>";
485 }
486 
487 std::string tag(const std::string& str, const std::string& tag)
488 {
489  return "<" + tag + ">" + str + "</" + tag + ">";
490 }
491 
492 } // end anonymous namespace
493 
495 {
496  SCOPE_LB;
497  gamelistbox_->clear();
498  gamelist_id_at_row_.clear();
500  int select_row = -1;
501  for(unsigned i = 0; i < lobby_info_.games().size(); ++i) {
502  const game_info& game = *lobby_info_.games()[i];
503  if(game.id == selected_game_id_) {
504  select_row = i;
505  }
506  gamelist_id_at_row_.push_back(game.id);
507  LOG_LB << "Adding game to listbox (1)" << game.id << "\n";
510  - 1);
512  game, gamelistbox_->get_item_count() - 1, grid);
513  }
514  if(select_row >= 0 && select_row != gamelistbox_->get_selected_row()) {
515  gamelistbox_->select_row(select_row);
516  }
518  gamelist_dirty_ = false;
519  last_gamelist_update_ = SDL_GetTicks();
524 }
525 
527 {
528  SCOPE_LB;
530  int select_row = -1;
531  unsigned list_i = 0;
532  int list_rows_deleted = 0;
533  std::vector<int> next_gamelist_id_at_row;
534  for(unsigned i = 0; i < lobby_info_.games().size(); ++i) {
535  const game_info& game = *lobby_info_.games()[i];
536  if(game.display_status == game_info::NEW) {
537  LOG_LB << "Adding game to listbox " << game.id << "\n";
538  if(list_i != gamelistbox_->get_item_count()) {
539  gamelistbox_->add_row(make_game_row_data(game), list_i);
540  DBG_LB << "Added a game listbox row not at the end" << list_i
541  << " " << gamelistbox_->get_item_count() << "\n";
542  list_rows_deleted--;
543  } else {
545  }
549  game, gamelistbox_->get_item_count() - 1, grid);
550  list_i++;
551  next_gamelist_id_at_row.push_back(game.id);
552  } else {
553  if(list_i >= gamelistbox_->get_item_count()) {
554  ERR_LB << "Ran out of listbox items -- triggering a full "
555  "refresh\n";
556  wesnothd_connection_.send_data(config("refresh_lobby"));
557  return;
558  }
559  if(list_i + list_rows_deleted >= gamelist_id_at_row_.size()) {
560  ERR_LB << "gamelist_id_at_row_ overflow! " << list_i << " + "
561  << list_rows_deleted
562  << " >= " << gamelist_id_at_row_.size()
563  << " -- triggering a full refresh\n";
564  wesnothd_connection_.send_data(config("refresh_lobby"));
565  return;
566  }
567  int listbox_game_id
568  = gamelist_id_at_row_[list_i + list_rows_deleted];
569  if(game.id != listbox_game_id) {
570  ERR_LB << "Listbox game id does not match expected id "
571  << listbox_game_id << " " << game.id << " (row "
572  << list_i << ")\n";
573  wesnothd_connection_.send_data(config("refresh_lobby"));
574  return;
575  }
576  if(game.display_status == game_info::UPDATED) {
577  LOG_LB << "Modifying game in listbox " << game.id << " (row "
578  << list_i << ")\n";
579  tgrid* grid = gamelistbox_->get_row_grid(list_i);
580  modify_grid_with_data(grid, make_game_row_data(game));
581  adjust_game_row_contents(game, list_i, grid);
582  ++list_i;
583  next_gamelist_id_at_row.push_back(game.id);
584  } else if(game.display_status == game_info::DELETED) {
585  LOG_LB << "Deleting game from listbox " << game.id << " (row "
586  << list_i << ")\n";
587  gamelistbox_->remove_row(list_i);
588  ++list_rows_deleted;
589  } else {
590  // clean
591  LOG_LB << "Clean game in listbox " << game.id << " (row "
592  << list_i << ")\n";
593  next_gamelist_id_at_row.push_back(game.id);
594  ++list_i;
595  }
596  }
597  }
598  for(unsigned i = 0; i < next_gamelist_id_at_row.size(); ++i) {
599  if(next_gamelist_id_at_row[i] == selected_game_id_) {
600  select_row = i;
601  }
602  }
603  next_gamelist_id_at_row.swap(gamelist_id_at_row_);
604  if(select_row >= static_cast<int>(gamelistbox_->get_item_count())) {
605  ERR_LB << "Would select a row beyond the listbox" << select_row << " "
606  << gamelistbox_->get_item_count() << "\n";
607  select_row = gamelistbox_->get_item_count() - 1;
608  }
609  if(select_row >= 0 && select_row != gamelistbox_->get_selected_row()) {
610  gamelistbox_->select_row(select_row);
611  }
613  gamelist_dirty_ = false;
614  last_gamelist_update_ = SDL_GetTicks();
619 }
620 
622 {
623 #ifndef GUI2_EXPERIMENTAL_LISTBOX
624  utils::string_map symbols;
625  symbols["num_shown"]
626  = std::to_string(lobby_info_.games_filtered().size());
627  symbols["num_total"]
628  = std::to_string(lobby_info_.games().size());
629  std::string games_string
630  = VGETTEXT("Games: showing $num_shown out of $num_total", symbols);
631  find_widget<tlabel>(gamelistbox_, "map", false).set_label(games_string);
632 #endif
633 }
634 
635 std::map<std::string, string_map>
637 {
638  std::map<std::string, string_map> data;
639 
640  const char* color_string;
641  if(game.vacant_slots > 0) {
642  if(game.reloaded || game.started) {
643  color_string = "yellow";
644  } else {
645  color_string = "green";
646  }
647  } else {
648  if(game.observers) {
649  color_string = "#ddd";
650  } else {
651  color_string = "red";
652  }
653  }
654  if(!game.have_era && (game.vacant_slots > 0 || game.observers)) {
655  color_string = "#444";
656  }
657 
658  add_label_data(data, "status", colorize(game.status, color_string));
659  add_label_data(data, "name", colorize(game.name, color_string));
660 
661  add_label_data(data, "era", game.era);
662  add_label_data(data, "era_short", game.era_short);
663  add_label_data(data, "map_info", game.map_info);
664  add_label_data(data, "scenario", game.scenario);
665  add_label_data(data, "map_size_text", game.map_size_info);
666  add_label_data(data, "time_limit", game.time_limit);
667  add_label_data(data, "gold_text", game.gold);
668  add_label_data(data, "xp_text", game.xp);
669  add_label_data(data, "vision_text", game.vision);
670  add_label_data(data, "time_limit_text", game.time_limit);
671  add_label_data(data, "status", game.status);
672  if(game.observers) {
673  add_label_data(data, "observer_icon", "misc/eye.png");
674  add_tooltip_data(data, "observer_icon", _("Observers allowed"));
675  } else {
676  add_label_data(data, "observer_icon", "misc/no_observer.png");
677  add_tooltip_data(data, "observer_icon", _("Observers not allowed"));
678  }
679 
680  const char* vision_icon;
681  if(game.fog) {
682  if(game.shroud) {
683  vision_icon = "misc/vision-fog-shroud.png";
684  } else {
685  vision_icon = "misc/vision-fog.png";
686  }
687  } else {
688  if(game.shroud) {
689  vision_icon = "misc/vision-shroud.png";
690  } else {
691  vision_icon = "misc/vision-none.png";
692  }
693  }
694  add_label_data(data, "vision_icon", vision_icon);
695  add_tooltip_data(data, "vision_icon", game.vision);
696  return data;
697 }
698 
700  int idx,
701  tgrid* grid)
702 {
703  find_widget<tcontrol>(grid, "name", false).set_use_markup(true);
704 
705  find_widget<tcontrol>(grid, "status", false).set_use_markup(true);
706 
707  ttoggle_panel& row_panel = find_widget<ttoggle_panel>(grid, "panel", false);
708 
710  std::bind(&tlobby_main::join_or_observe, this, idx));
711 
712  set_visible_if_exists(grid, "time_limit_icon", !game.time_limit.empty());
713  set_visible_if_exists(grid, "vision_fog", game.fog);
714  set_visible_if_exists(grid, "vision_shroud", game.shroud);
715  set_visible_if_exists(grid, "vision_none", !(game.fog || game.shroud));
716  set_visible_if_exists(grid, "observers_yes", game.observers);
717  set_visible_if_exists(grid, "shuffle_sides_icon", game.shuffle_sides);
718  set_visible_if_exists(grid, "observers_no", !game.observers);
719  set_visible_if_exists(grid, "needs_password", game.password_required);
720  set_visible_if_exists(grid, "reloaded", game.reloaded);
721  set_visible_if_exists(grid, "started", game.started);
722  set_visible_if_exists(grid, "use_map_settings", game.use_map_settings);
723  set_visible_if_exists(grid, "no_era", !game.have_era);
724 
725 
726  tbutton* join_button = dynamic_cast<tbutton*>(grid->find("join", false));
727  if(join_button) {
729  *join_button,
731  this,
732  std::ref(*window_)));
733  join_button->set_active(game.can_join());
734  }
735  tbutton* observe_button
736  = dynamic_cast<tbutton*>(grid->find("observe", false));
737  if(observe_button) {
739  *observe_button,
741  this,
742  std::ref(*window_)));
743  observe_button->set_active(game.can_observe());
744  }
745  tminimap* minimap = dynamic_cast<tminimap*>(grid->find("minimap", false));
746  if(minimap) {
747  minimap->set_config(&game_config_);
748  minimap->set_map_data(game.map_data);
749  }
750 }
751 
753 {
754  DBG_LB << "tlobby_main::update_gamelist_filter\n";
756  DBG_LB << "Games in lobby_info: " << lobby_info_.games().size()
757  << ", games in listbox: " << gamelistbox_->get_item_count() << "\n";
758  assert(lobby_info_.games().size() == gamelistbox_->get_item_count());
760 }
761 
762 
764 {
766  return;
767  SCOPE_LB;
768  DBG_LB << "Playerlist update: " << lobby_info_.users().size() << "\n";
772 
773  bool lobby = false;
774  if(room_info* ri = active_window_room()) {
775  if(ri->name() == "lobby") {
776  lobby = true;
777  }
778  }
783 
784  assert(player_list_.active_game.tree);
785  assert(player_list_.active_room.tree);
786  assert(player_list_.other_games.tree);
787  assert(player_list_.other_rooms.tree);
788 
793 
794  for(auto userptr : lobby_info_.users_sorted())
795  {
796  user_info& user = *userptr;
797  tsub_player_list* target_list(nullptr);
798  std::map<std::string, string_map> data;
799  std::stringstream icon_ss;
800  std::string name = user.name;
801  icon_ss << "lobby/status";
802  switch(user.state) {
803  case user_info::SEL_ROOM:
804  icon_ss << "-lobby";
805  target_list = &player_list_.active_room;
806  if(lobby) {
807  target_list = &player_list_.other_rooms;
808  }
809  break;
810  case user_info::LOBBY:
811  icon_ss << "-lobby";
812  target_list = &player_list_.other_rooms;
813  break;
814  case user_info::SEL_GAME:
815  name = colorize(name, "cyan");
816  icon_ss << (user.observing ? "-obs" : "-playing");
817  target_list = &player_list_.active_game;
818  break;
819  case user_info::GAME:
820  name = colorize(name, "red");
821  icon_ss << (user.observing ? "-obs" : "-playing");
822  target_list = &player_list_.other_games;
823  break;
824  default:
825  ERR_LB << "Bad user state in lobby: " << user.name << ": "
826  << user.state << "\n";
827  continue;
828  }
829  switch(user.relation) {
830  case user_info::ME:
831  /* fall through */
832  case user_info::NEUTRAL:
833  icon_ss << "-n";
834  break;
835  case user_info::FRIEND:
836  icon_ss << "-f";
837  break;
838  case user_info::IGNORED:
839  icon_ss << "-i";
840  break;
841  default:
842  ERR_LB << "Bad user relation in lobby: " << user.relation
843  << "\n";
844  }
845  if(user.registered) {
846  name = tag(name, "b");
847  }
848  icon_ss << ".png";
849  add_label_data(data, "player", name);
850  add_label_data(data, "main_icon", icon_ss.str());
852  target_list = &player_list_.other_rooms;
853  }
854 
855  assert(target_list->tree);
856 
857  string_map tree_group_field;
858  std::map<std::string, string_map> tree_group_item;
859 
860  /*** Add tree item ***/
861  tree_group_field["label"] = icon_ss.str();
862  tree_group_item["icon"] = tree_group_field;
863 
864  tree_group_field["label"] = name;
865  tree_group_field["use_markup"] = "true";
866  tree_group_item["name"] = tree_group_field;
867 
868  ttree_view_node& player
869  = target_list->tree->add_child("player", tree_group_item);
870 
871  find_widget<ttoggle_panel>(&player, "tree_view_node_label", false)
872  .set_callback_mouse_left_double_click(std::bind(
873  &tlobby_main::user_dialog_callback, this, userptr));
874  }
879 
880  player_list_dirty_ = false;
881 }
882 
884 {
885  int idx = gamelistbox_->get_selected_row();
886  bool can_join = false, can_observe = false;
887  if(idx >= 0) {
888  const game_info& game = *lobby_info_.games()[idx];
889  can_observe = game.can_observe();
890  can_join = game.can_join();
891  selected_game_id_ = game.id;
892  } else {
893  selected_game_id_ = 0;
894  }
895  find_widget<tbutton>(window_, "observe_global", false)
896  .set_active(can_observe);
897 
898  find_widget<tbutton>(window_, "join_global", false).set_active(can_join);
899 
900  player_list_dirty_ = true;
901 }
902 
904 {
905  SCOPE_LB;
906  roomlistbox_ = find_widget<tlistbox>(&window, "room_list", false, true);
907 #ifdef GUI2_EXPERIMENTAL_LISTBOX
909  *roomlistbox_,
911  *this,
912  std::ref(window)));
913 #else
915  dialog_callback<tlobby_main, &tlobby_main::room_switch_callback>);
916 #endif
917 
918  gamelistbox_ = find_widget<tlistbox>(&window, "game_list", false, true);
919 #ifdef GUI2_EXPERIMENTAL_LISTBOX
921  *gamelistbox_,
923  *this,
924  std::ref(window)));
925 #else
929 #endif
930 
931  player_list_.init(window);
932 
937 
939  std::bind(&tlobby_main::player_filter_callback, this, _1));
941  std::bind(&tlobby_main::player_filter_callback, this, _1));
942 
943  chat_log_container_ = find_widget<tmulti_page>(
944  &window, "chat_log_container", false, true);
945 
946  window.set_enter_disabled(true);
947 
948  window_ = &window;
949 
950  chat_input_ = find_widget<ttext_box>(&window, "chat_input", false, true);
951  assert(chat_input_);
953  *chat_input_,
955  this,
956  _3,
957  _4,
958  _5,
959  std::ref(window)));
960 
962  find_widget<tbutton>(&window, "create", false),
964  this,
965  std::ref(window)));
966 
968  find_widget<tbutton>(&window, "refresh", false),
970  this,
971  std::ref(window)));
972 
974  find_widget<tbutton>(&window, "show_preferences", false),
976  this,
977  std::ref(window)));
978 
980  find_widget<tbutton>(&window, "join_global", false),
982  this,
983  std::ref(window)));
984  find_widget<tbutton>(&window, "join_global", false).set_active(false);
985 
987  find_widget<tbutton>(&window, "observe_global", false),
989  this,
990  std::ref(window)));
991  find_widget<tbutton>(&window, "observe_global", false).set_active(false);
992 
993  ttoggle_button& skip_replay
994  = find_widget<ttoggle_button>(&window, "skip_replay", false);
995  skip_replay.set_value(preferences::skip_mp_replay());
996  skip_replay.set_callback_state_change(
997  std::bind(&tlobby_main::skip_replay_changed_callback, this, _1));
998 
999  filter_friends_ = find_widget<ttoggle_button>(
1000  &window, "filter_with_friends", false, true);
1001  filter_ignored_ = find_widget<ttoggle_button>(
1002  &window, "filter_without_ignored", false, true);
1003  filter_slots_ = find_widget<ttoggle_button>(
1004  &window, "filter_vacant_slots", false, true);
1005  filter_invert_ = find_widget<ttoggle_button>(
1006  &window, "filter_invert", false, true);
1007  filter_text_ = find_widget<ttext_box>(&window, "filter_text", false, true);
1008 
1010  std::bind(&tlobby_main::game_filter_change_callback, this, _1));
1011  filter_ignored_->set_callback_state_change(
1012  std::bind(&tlobby_main::game_filter_change_callback, this, _1));
1013  filter_slots_->set_callback_state_change(
1014  std::bind(&tlobby_main::game_filter_change_callback, this, _1));
1015  filter_invert_->set_callback_state_change(
1016  std::bind(&tlobby_main::game_filter_change_callback, this, _1));
1018  *filter_text_,
1019  std::bind(&tlobby_main::game_filter_keypress_callback, this, _5));
1020 
1021  room_window_open("lobby", true);
1024 
1025  // Force first update to be directly.
1029  std::bind(&tlobby_main::network_handler, this),
1030  true);
1031 }
1032 
1034 {
1035  window_ = nullptr;
1037  lobby_update_timer_ = 0;
1038 }
1039 
1041 {
1043  if(t.whisper)
1044  return nullptr;
1045  return lobby_info_.get_room(t.name);
1046 }
1047 
1049  bool open_new)
1050 {
1051  return search_create_window(room, false, open_new);
1052 }
1053 
1055  bool open_new)
1056 {
1057  return search_create_window(name, true, open_new);
1058 }
1059 
1061  bool whisper,
1062  bool open_new)
1063 {
1064  for(auto & t : open_windows_)
1065  {
1066  if(t.name == name && t.whisper == whisper)
1067  return &t;
1068  }
1069  if(open_new) {
1070  open_windows_.push_back(tlobby_chat_window(name, whisper));
1071  std::map<std::string, string_map> data;
1072  utils::string_map symbols;
1073  symbols["name"] = name;
1074  if(whisper) {
1075  add_label_data(data,
1076  "log_text",
1077  VGETTEXT("Whisper session with $name started. "
1078  "If you don’t want to receive messages "
1079  "from this user, "
1080  "type /ignore $name\n",
1081  symbols));
1082  } else {
1083  add_label_data(
1084  data, "log_text", VGETTEXT("<i>Room $name joined</i>", symbols));
1085  lobby_info_.open_room(name);
1086  }
1088  std::map<std::string, string_map> data2;
1089  add_label_data(data2, "room", whisper ? "<" + name + ">" : name);
1090  roomlistbox_->add_row(data2);
1091 
1092  const int row_index = roomlistbox_->get_item_count() - 1;
1093  tbutton& close_button = find_widget<tbutton>(roomlistbox_->get_row_grid(row_index), "close_window", false);
1094  connect_signal_mouse_left_click(close_button,
1096  this, row_index));
1097 
1098  if(name == "lobby") {
1100  }
1101 
1102  return &open_windows_.back();
1103  }
1104  return nullptr;
1105 }
1106 
1108 {
1110  return t.name == name && t.whisper == true;
1111 }
1112 
1114 {
1116  return t.name == room && t.whisper == false;
1117 }
1118 
1120 {
1121  if(tlobby_chat_window* t = whisper_window_open(name, false)) {
1122  t->pending_messages++;
1123  if(t->pending_messages == 1) {
1124  DBG_LB << "do whisper pending mark row " << (t - &open_windows_[0])
1125  << " with " << t->name << "\n";
1126  tgrid* grid = roomlistbox_->get_row_grid(t - &open_windows_[0]);
1127  // this breaks for some reason
1128  // tlabel& label = grid->get_widget<tlabel>("room", false);
1129  // label.set_use_markup(true);
1130  // label.set_label(colorize("<" + t->name + ">", "red"));
1131  find_widget<timage>(grid, "pending_messages", false)
1132  .set_visible(twidget::tvisible::visible);
1133  }
1134  }
1135 }
1136 
1138 {
1139  if(tlobby_chat_window* t = room_window_open(room, false)) {
1140  t->pending_messages++;
1141  if(t->pending_messages == 1) {
1142  int idx = t - &open_windows_[0];
1143  DBG_LB << "do room pending mark row " << idx << " with " << t->name
1144  << "\n";
1145  tgrid* grid = roomlistbox_->get_row_grid(idx);
1146  // this breaks for some reason
1147  // tlabel& label = grid->get_widget<tlabel>("room", false);
1148  // label.set_use_markup(true);
1149  // label.set_label(colorize(t->name, "red"));
1150  find_widget<timage>(grid, "pending_messages", false)
1151  .set_visible(twidget::tvisible::visible);
1152  }
1153  }
1154 }
1155 
1157  const std::string& message)
1158 {
1159  std::stringstream ss;
1160  ss << "<" << sender << "> " << message;
1161  tlobby_chat_window* t = whisper_window_open(sender, false);
1162  if(!t) {
1163  ERR_LB << "Whisper window not open in add_whisper_window_whisper for "
1164  << sender << "\n";
1165  return;
1166  }
1167  append_to_chatbox(ss.str(), t - &open_windows_[0], false);
1168 }
1169 
1171  const std::string& message,
1172  const bool force_scroll)
1173 {
1174  std::stringstream ss;
1175  ss << "<b>"
1176  << "whisper: " << sender << ":</b> " << font::escape_text(message);
1177  append_to_chatbox(ss.str(), force_scroll);
1178 }
1179 
1181  const std::string& sender,
1182  const std::string& message)
1183 {
1184  std::stringstream ss;
1185  ss << "<b>" << sender << ":</b> " << font::escape_text(message);
1186  tlobby_chat_window* t = room_window_open(room, false);
1187  if(!t) {
1188  ERR_LB << "Room window not open in add_room_window_message for " << room
1189  << "\n";
1190  return;
1191  }
1192  append_to_chatbox(ss.str(), t - &open_windows_[0], false);
1193 }
1194 
1196  const std::string& message,
1197  const bool force_scroll)
1198 {
1199  std::stringstream ss;
1200  ss << "<b>" << sender << ":</b> " << font::escape_text(message);
1201  append_to_chatbox(ss.str(), force_scroll);
1202 }
1203 
1205 {
1207 }
1208 
1210 {
1211  active_window_ = id;
1212  assert(active_window_ < open_windows_.size());
1216 }
1217 
1219 {
1221 
1222  DBG_LB << "active window changed to " << active_window_ << " "
1223  << (t.whisper ? "w" : "r") << " " << t.name << "\n";
1224 
1225  // clear pending messages notification in room listbox
1227  find_widget<timage>(grid, "pending_messages", false)
1228  .set_visible(twidget::tvisible::hidden);
1229  t.pending_messages = 0;
1230 
1231  player_list_dirty_ = true;
1232 }
1233 
1234 
1236 {
1237  DBG_LB << "Close window button clicked\n";
1238  return close_window(active_window_);
1239 }
1240 
1242 {
1243  const tlobby_chat_window& t = open_windows_[idx];
1244  bool active_changed = idx == active_window_;
1245  DBG_LB << "Close window " << idx << " - " << t.name << "\n";
1246  if(t.name == "lobby" && t.whisper == false)
1247  return;
1248  if(open_windows_.size() == 1)
1249  return;
1250  if(t.whisper == false) {
1251  // closing a room window -- send a part to the server
1252  config data, msg;
1253  msg["room"] = t.name;
1254  msg["player"] = preferences::login();
1255  data.add_child("room_part", msg);
1257  }
1258  if(active_window_ == open_windows_.size() - 1) {
1259  active_window_--;
1260  }
1261  if(t.whisper) {
1263  } else {
1265  }
1266  open_windows_.erase(open_windows_.begin() + idx);
1267  roomlistbox_->remove_row(idx);
1271  if(active_changed)
1273 }
1274 
1276 {
1278  && (SDL_GetTicks() - last_gamelist_update_
1280  if(gamelist_diff_update_) {
1282  } else {
1283  update_gamelist();
1284  gamelist_diff_update_ = true;
1285  }
1286  }
1287  if(player_list_dirty_) {
1290  }
1291  try
1292  {
1293  config data;
1295  process_network_data(data);
1296  }
1297  }
1298  catch(wesnothd_error& e)
1299  {
1300  LOG_LB << "caught wesnothd_error in network_handler: " << e.message
1301  << "\n";
1302  throw;
1303  }
1304 }
1305 
1307 {
1308  if(const config& c = data.child("error")) {
1309  throw wesnothd_error(c["message"]);
1310  } else if(const config& c = data.child("message")) {
1311  process_message(c);
1312  } else if(const config& c = data.child("whisper")) {
1313  process_message(c, true);
1314  } else if(data.child("gamelist")) {
1315  process_gamelist(data);
1316  } else if(const config& c = data.child("gamelist_diff")) {
1318  } else if(const config& c = data.child("room_join")) {
1319  process_room_join(c);
1320  } else if(const config& c = data.child("room_part")) {
1321  process_room_part(c);
1322  } else if(const config& c = data.child("room_query_response")) {
1324  }
1325 }
1326 
1327 void tlobby_main::process_message(const config& data, bool whisper /*= false*/)
1328 {
1329  std::string sender = data["sender"];
1330  DBG_LB << "process message from " << sender << " " << (whisper ? "(w)" : "")
1331  << ", len " << data["message"].str().size() << '\n';
1332  if(preferences::is_ignored(sender))
1333  return;
1334  const std::string& message = data["message"];
1335  preferences::parse_admin_authentication(sender, message);
1336  if(whisper) {
1337  add_whisper_received(sender, message);
1338  } else {
1339  std::string room = data["room"];
1340  if(room.empty()) {
1341  LOG_LB << "Message without a room from " << sender
1342  << ", assuming lobby\n";
1343  room = "lobby";
1344  }
1345  add_chat_room_message_received(room, sender, message);
1346  }
1347 }
1348 
1350 {
1352  DBG_LB << "Received gamelist\n";
1353  gamelist_dirty_ = true;
1354  gamelist_diff_update_ = false;
1355 }
1356 
1358 {
1360  DBG_LB << "Received gamelist diff\n";
1361  gamelist_dirty_ = true;
1362  } else {
1363  ERR_LB << "process_gamelist_diff failed!" << std::endl;
1364  }
1365  int joined = data.child_count("insert_child");
1366  int left = data.child_count("remove_child");
1367  if(joined > 0 || left > 0) {
1368  if(left > joined) {
1370  } else {
1372  }
1373  }
1374 }
1375 
1377 {
1378  const std::string& room = data["room"];
1379  const std::string& player = data["player"];
1380  room_info* r = lobby_info_.get_room(room);
1381  DBG_LB << "room join: " << room << " " << player << " "
1382  << static_cast<void*>(r) << "\n";
1383 
1384  if(r) {
1385  if(player == preferences::login()) {
1386  if(const config& members = data.child("members")) {
1387  r->process_room_members(members);
1388  }
1389  } else {
1390  r->add_member(player);
1391  /* TODO: add/use preference */
1392  utils::string_map symbols;
1393  symbols["player"] = player;
1395  room,
1396  "server",
1397  VGETTEXT("$player has entered the room", symbols));
1398  }
1399  if(r == active_window_room()) {
1400  player_list_dirty_ = true;
1401  }
1402  } else {
1403  if(player == preferences::login()) {
1404  tlobby_chat_window* t = room_window_open(room, true);
1405  lobby_info_.open_room(room);
1406  r = lobby_info_.get_room(room);
1407  assert(r);
1408  if(const config& members = data.child("members")) {
1409  r->process_room_members(members);
1410  }
1411  switch_to_window(t);
1412 
1413  const std::string& topic = data["topic"];
1414  if(!topic.empty()) {
1416  "room", "server", room + ": " + topic);
1417  }
1418  } else {
1419  LOG_LB << "Discarding join info for a room the player is not in\n";
1420  }
1421  }
1422 }
1423 
1425 {
1426  // todo close room window when the part message is sent
1427  const std::string& room = data["room"];
1428  const std::string& player = data["player"];
1429  DBG_LB << "Room part: " << room << " " << player << "\n";
1430  room_info* r = lobby_info_.get_room(room);
1431  if(r) {
1432  r->remove_member(player);
1433  /* TODO: add/use preference */
1434  utils::string_map symbols;
1435  symbols["player"] = player;
1437  room, "server", VGETTEXT("$player has left the room", symbols));
1438  if(active_window_room() == r) {
1439  player_list_dirty_ = true;
1440  }
1441  } else {
1442  LOG_LB << "Discarding part info for a room the player is not in\n";
1443  }
1444 }
1445 
1447 {
1448  const std::string& room = data["room"];
1449  const std::string& message = data["message"];
1450  DBG_LB << "room query response: " << room << " " << message << "\n";
1451  if(room.empty()) {
1452  if(!message.empty()) {
1453  add_active_window_message("server", message);
1454  }
1455  if(const config& rooms = data.child("rooms")) {
1456  // TODO: this should really open a nice join room dialog instead
1457  std::stringstream ss;
1458  ss << "Rooms:";
1459  for(const auto & r : rooms.child_range("room"))
1460  {
1461  ss << " " << r["name"];
1462  }
1463  add_active_window_message("server", ss.str());
1464  }
1465  } else {
1466  if(room_window_open(room, false)) {
1467  if(!message.empty()) {
1468  add_chat_room_message_received(room, "server", message);
1469  }
1470  if(const config& members = data.child("members")) {
1471  room_info* r = lobby_info_.get_room(room);
1472  assert(r);
1473  r->process_room_members(members);
1474  if(r == active_window_room()) {
1475  player_list_dirty_ = true;
1476  }
1477  }
1478  } else {
1479  if(!message.empty()) {
1480  add_active_window_message("server", room + ": " + message);
1481  }
1482  }
1483  }
1484 }
1485 
1487 {
1488  LOG_LB << "join_button_callback\n";
1490 }
1491 
1493 {
1494  LOG_LB << "observe_button_callback\n";
1496 }
1497 
1499 {
1500  LOG_LB << "observe_global_button_callback\n";
1503  window.close();
1504  }
1505 }
1506 
1508 {
1509  LOG_LB << "join_global_button_callback\n";
1510  if(do_game_join(gamelistbox_->get_selected_row(), false)) {
1511  legacy_result_ = JOIN;
1512  window.close();
1513  }
1514 }
1515 
1517 {
1518  const game_info& game = *lobby_info_.games()[idx];
1519  if(do_game_join(idx, !game.can_join())) {
1520  legacy_result_ = game.can_join() ? JOIN : OBSERVE;
1521  window_->close();
1522  }
1523 }
1524 
1525 bool tlobby_main::do_game_join(int idx, bool observe)
1526 {
1527  if(idx < 0 || idx > static_cast<int>(lobby_info_.games().size())) {
1528  ERR_LB << "Requested join/observe of a game with index out of range: "
1529  << idx << ", games size is " << lobby_info_.games().size()
1530  << "\n";
1531  return false;
1532  }
1533  const game_info& game = *lobby_info_.games()[idx];
1534  if(observe) {
1535  if(!game.can_observe()) {
1536  ERR_LB << "Requested observe of a game with observers disabled"
1537  << std::endl;
1538  return false;
1539  }
1540  } else {
1541  if(!game.can_join()) {
1542  ERR_LB << "Requested join to a game with no vacant slots"
1543  << std::endl;
1544  return false;
1545  }
1546  }
1547  config response;
1548  config& join = response.add_child("join");
1549  join["id"] = std::to_string(game.id);
1550  join["observe"] = observe;
1551  if(join && !observe && game.password_required) {
1554  return false;
1555  }
1556 
1557  join["password"] = password;
1558  }
1559  wesnothd_connection_.send_data(response);
1560  if(observe && game.started) {
1561  // playmp_controller::set_replay_last_turn(game.current_turn);
1562  }
1563  return true;
1564 }
1565 
1567 {
1568  const std::string& input = chat_input_->get_value();
1569  if(input.empty())
1570  return;
1571  if(input[0] == '/') {
1572  // TODO: refactor do_speak so it uses context information about
1573  // opened window, so e.g. /ignore in a whisper session ignores
1574  // the other party without having to specify it's nick.
1575  chat_handler::do_speak(input);
1576  } else {
1577  config msg;
1579  }
1581  chat_input_->set_value("");
1582 }
1583 
1585 {
1587  if(t.whisper) {
1588  send_whisper(t.name, input);
1589  add_whisper_sent(t.name, input);
1590  } else {
1591  send_chat_room_message(t.name, input);
1592  add_chat_room_message_sent(t.name, input);
1593  }
1594 }
1595 
1597 {
1598  close_window(idx);
1599 }
1600 
1602 {
1604  window.close();
1605 }
1606 
1608 {
1609  wesnothd_connection_.send_data(config("refresh_lobby"));
1610 }
1611 
1612 
1614 {
1615  if(preferences_callback_) {
1617 
1618  /**
1619  * The screen size might have changed force an update of the size.
1620  *
1621  * @todo This might no longer be needed when gui2 is done.
1622  */
1623  window.invalidate_layout();
1624 
1625  wesnothd_connection_.send_data(config("refresh_lobby"));
1626  }
1627 }
1628 
1630 {
1632 }
1633 
1635  bool& halt,
1636  const SDLKey key,
1637  twindow& window)
1638 {
1639  if(key == SDLK_RETURN || key == SDLK_KP_ENTER) {
1641  handled = true;
1642  halt = true;
1643  } else if(key == SDLK_TAB) {
1644  std::string text = chat_input_->get_value();
1645  const std::vector<user_info>& match_infos = lobby_info_.users();
1646  std::vector<std::string> matches;
1647 
1648  for(const auto & ui : match_infos)
1649  {
1650  if(ui.name != preferences::login()) {
1651  matches.push_back(ui.name);
1652  }
1653  }
1654  const bool line_start = utils::word_completion(text, matches);
1655 
1656  if(matches.empty()) {
1657  return;
1658  }
1659 
1660  if(matches.size() == 1) {
1661  text.append(line_start ? ": " : " ");
1662  } else {
1663  std::string completion_list = utils::join(matches, " ");
1664  append_to_chatbox(completion_list);
1665  }
1666  chat_input_->set_value(text);
1667  handled = true;
1668  halt = true;
1669  }
1670 }
1671 
1673 {
1675 
1676  for(const auto & s : utils::split(filter_text_->get_value(), ' '))
1677  {
1679  }
1680  // TODO: make changing friend/ignore lists trigger a refresh
1681  if(filter_friends_->get_value()) {
1684  }
1685  if(filter_ignored_->get_value()) {
1688  }
1689  if(filter_slots_->get_value()) {
1691  new game_filter_value<size_t,
1693  std::greater<size_t> >(0));
1694  }
1696 }
1697 
1699 {
1700  if(key == SDLK_RETURN || key == SDLK_KP_ENTER) {
1703  }
1704 }
1705 
1707 {
1710 }
1711 
1713 {
1715 }
1716 
1718 {
1724  player_list_dirty_ = true;
1725  // window_->invalidate_layout();
1726 }
1727 
1729 {
1730  tlobby_player_info dlg(*this, *info, lobby_info_);
1732  dlg.show(window_->video());
1733  delay_playerlist_update_ = true;
1734  if(dlg.result_open_whisper()) {
1735  tlobby_chat_window* t = whisper_window_open(info->name, true);
1736  switch_to_window(t);
1738  }
1739  selected_game_id_ = info->game_id;
1740  // the commented out code below should be enough, but that'd delete the
1741  // playerlist and the widget calling this callback, so instead the game
1742  // will be selected on the next gamelist update.
1743  /*
1744  if (info->game_id != 0) {
1745  for (unsigned i = 0; i < lobby_info_.games_filtered().size(); ++i) {
1746  game_info& g = *lobby_info_.games_filtered()[i];
1747  if (info->game_id == g.id) {
1748  gamelistbox_->select_row(i);
1749  update_selected_game();
1750  break;
1751  }
1752  }
1753  }
1754  */
1755  // do not update here as it can cause issues with removing the widget
1756  // from within it's event handler. Should get updated as soon as possible
1757  // update_gamelist();
1758  delay_playerlist_update_ = false;
1759  player_list_dirty_ = true;
1760  wesnothd_connection_.send_data(config("refresh_lobby"));
1761 }
1762 
1764 {
1765  ttoggle_button& tb = dynamic_cast<ttoggle_button&>(w);
1767 }
1769 {
1771 }
1772 
1773 } // namespace gui2
Define the common log macros for the gui toolkit.
void close_room(const std::string &name)
Definition: info.cpp:291
#define DBG_LB
Definition: lobby.cpp:65
void set_vertical_scrollbar_item_position(const unsigned position)
Move the vertical scrollbar to a position.
An error occured during when trying to coommunicate with the wesnothd server.
std::string status
Definition: data.hpp:158
void add_active_window_whisper(const std::string &sender, const std::string &message, const bool force_scroll=false)
Add a whisper message to the current window which is not the whisper window for "name".
Definition: lobby.cpp:1170
virtual void set_active(const bool active) override
See tcontrol::set_active.
Definition: button.cpp:58
bool fog
Definition: data.hpp:165
void connect_signal_pre_key_press(tdispatcher &dispatcher, const tsignal_keyboard_function &signal)
Connects the signal for 'snooping' on the keypress.
Definition: dispatcher.hpp:703
tplayer_list player_list_
Definition: lobby.hpp:409
size_t size() const
The "size" of the widget.
room_info * active_window_room()
Get the room* corresponding to the currently active window, or nullptr if a whisper window is active ...
Definition: lobby.cpp:1040
tlistbox * list
Definition: lobby.hpp:65
void close_active_window()
Definition: lobby.cpp:1235
bool room_window_active(const std::string &room)
Definition: lobby.cpp:1113
std::function< void()> preferences_wrapper_
Wrapper for the preferences hotkey.
Definition: lobby.hpp:427
std::string map_info
Definition: data.hpp:149
bool started
Definition: data.hpp:164
void observe_global_button_callback(twindow &window)
Definition: lobby.cpp:1498
This class represents the information a client has about a room.
Definition: data.hpp:65
GLvoid **typedef void(GLAPIENTRY *PFNGLGETVERTEXATTRIBDVPROC)(GLuint
Definition: glew.h:1806
void set_row_shown(const unsigned row, const bool shown)
Makes a row visible or invisible.
Definition: listbox.cpp:150
bool player_list_dirty_
Definition: lobby.hpp:411
void update_gamelist_filter()
Definition: lobby.cpp:752
ttoggle_button * sort_by_name
Definition: lobby.hpp:79
void update_gamelist()
Definition: lobby.cpp:494
The basic minimap class.
Definition: minimap.hpp:36
void remove_row(const unsigned row, unsigned count=1)
Removes a row in the listbox.
Definition: listbox.cpp:94
bool empty() const
Does the node have children?
void close_window(size_t idx)
Definition: lobby.cpp:1241
const chat_log & log() const
Definition: data.hpp:83
const GLfloat * c
Definition: glew.h:12741
CVideo & video()
Definition: window.hpp:411
void set_icon_name(const std::string &icon_name)
virtual void add_whisper_received(const std::string &sender, const std::string &message)
inherited form chat_handler
Definition: lobby.cpp:216
size_t active_window_
Definition: lobby.hpp:395
bool do_game_join(int idx, bool observe)
Assemble and send a game join request.
Definition: lobby.cpp:1525
bool show(CVideo &video, const unsigned auto_close_time=0)
Shows the window.
Definition: dialog.cpp:34
void set_preferences_callback(std::function< void()> f)
Set the callback used to show the preferences.
Definition: lobby.cpp:388
void active_window_changed()
Definition: lobby.cpp:1218
const std::vector< bool > & games_visibility() const
Definition: info.hpp:87
logger & info()
Definition: log.cpp:91
void adjust_game_row_contents(const game_info &game, int idx, tgrid *grid)
Definition: lobby.cpp:699
Definition: video.hpp:58
std::string gold
Definition: data.hpp:154
void add_room_window_message(const std::string &room, const std::string &sender, const std::string &message)
Add a message to the window for room "room".
Definition: lobby.cpp:1180
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
bool delay_gamelist_update_
Definition: lobby.hpp:433
void increment_waiting_whsipers(const std::string &name)
Mark the whisper window for "name" as having one more pending message.
Definition: lobby.cpp:1119
Base container class.
Definition: grid.hpp:29
ttoggle_button * filter_slots_
Definition: lobby.hpp:401
GLenum GLenum GLenum input
Definition: glew.h:10668
R function_wrapper(const R result, const F &function)
Helper for function wrappers.
Definition: helper.hpp:172
#define ERR_LB
Definition: lobby.cpp:67
static lg::log_domain log_config("config")
std::string time_limit
Definition: data.hpp:159
bool select_row(const unsigned row, const bool select=true)
Selectes a row.
Definition: listbox.cpp:228
REGISTER_DIALOG(label_settings)
void clear()
Definition: data.cpp:66
This class represents the collective information the client has about the players and games on the se...
Definition: info.hpp:25
void scroll_vertical_scrollbar(const tscrollbar_::tscroll scroll)
Scrolls the vertical scrollbar.
void set_playerlist_sort_name(bool v)
void parse_admin_authentication(const std::string &sender, const std::string &message)
bool receive_data(config &result)
virtual void set_label(const t_string &label)
Definition: control.cpp:330
void open_room(const std::string &name)
Definition: info.cpp:284
void process_gamelist(const config &data)
Definition: lobby.cpp:1349
bool remove_timer(const size_t id)
Removes a timer.
Definition: timer.cpp:144
Go to the end position.
Definition: scrollbar.hpp:61
lobby_delay_gamelist_update_guard(tlobby_main &l)
Definition: lobby.cpp:377
std::map< std::string, string_map > make_game_row_data(const game_info &game)
Definition: lobby.cpp:636
ttoggle_button * show_toggle
Definition: lobby.hpp:64
bool password_required
Definition: data.hpp:171
void send_to_server(const config &cfg) override
Definition: lobby.cpp:1768
void connect_signal_mouse_left_click(tdispatcher &dispatcher, const tsignal_function &signal)
Connects a signal handler for a left mouse button click.
Definition: dispatcher.hpp:710
void update_gamelist_header()
Definition: lobby.cpp:621
void register_hotkey(const hotkey::HOTKEY_COMMAND id, const thotkey_function &function)
Registers a hotkey.
Definition: dispatcher.cpp:303
bool can_observe() const
Definition: data.cpp:363
virtual void add_whisper_sent(const std::string &receiver, const std::string &message)
inherited form chat_handler
Definition: lobby.cpp:197
STL namespace.
void process_gamelist_diff(const config &data)
Definition: lobby.cpp:1357
void skip_replay_changed_callback(twidget &w)
Definition: lobby.cpp:1763
virtual void set_use_markup(bool use_markup) override
See tcontrol::set_use_markup.
void process_room_join(const config &data)
Definition: lobby.cpp:1376
void pre_show(twindow &window)
Inherited from tdialog.
Definition: lobby.cpp:903
const std::vector< game_info * > & games_filtered() const
Definition: info.cpp:301
game_display_status display_status
Definition: data.hpp:184
Implements some helper classes to ease adding fields to a dialog and hide the synchronization needed...
GLint GLenum GLsizei GLint GLsizei const GLvoid * data
Definition: glew.h:1347
bool shroud
Definition: data.hpp:166
GLenum mode
Definition: glew.h:2390
tlobby_chat_window * search_create_window(const std::string &name, bool whisper, bool open_new)
Helper function to find and open a new window, used by *_window_open.
Definition: lobby.cpp:1060
tlistbox * gamelistbox_
Definition: lobby.hpp:373
GLdouble GLdouble t
Definition: glew.h:1366
ttree_view_node & add_child(const std::string &id, const std::map< std::string, string_map > &data, const int index=-1)
Adds a child item to the list of child nodes.
const tgrid & page_grid(const unsigned page) const
Returns the grid for the page.
Definition: multi_page.cpp:96
unsigned get_vertical_scrollbar_item_position() const
Returns current position of the vertical scrollbar.
std::string get_value() const
Definition: text.hpp:76
void init(twindow &w)
Definition: lobby.cpp:136
This class represents the information a client has about another player.
Definition: data.hpp:102
virtual void set_value(const std::string &text)
The set_value is virtual for the tpassword_box class.
Definition: text.cpp:95
#define SDLKey
Definition: compat.hpp:29
void process_network_data(const config &data)
Definition: lobby.cpp:1306
void set_game_filter_invert(bool value)
Definition: info.cpp:316
bool whisper_friends_only()
void join_button_callback(twindow &window)
Definition: lobby.cpp:1486
user_relation relation
Definition: data.hpp:127
void update_sort_icons()
Definition: lobby.cpp:153
GLdouble l
Definition: glew.h:6966
base class of top level items, the only item which needs to store the final canvases to draw on ...
Definition: window.hpp:62
bool gamelist_diff_update_
Definition: lobby.hpp:417
virtual void add_chat_room_message_sent(const std::string &room, const std::string &message)
inherited form chat_handler
Definition: lobby.cpp:241
Class for a toggle button.
A class inherited from ttext_box that displays its input as stars.
Definition: field-fwd.hpp:23
#define SCOPE_LB
Definition: lobby.cpp:68
std::string vision
Definition: data.hpp:157
void set_playerlist_sort_relation(bool v)
void send_data(const configr_of &request)
Simple push button.
Definition: button.hpp:32
std::string scenario
Definition: data.hpp:147
void set_callback_mouse_left_double_click(std::function< void(twidget &)> callback)
void increment_waiting_messages(const std::string &room)
Mark the room window for "room" as having one more pending message.
Definition: lobby.cpp:1137
bool observers
Definition: data.hpp:167
void send_message_button_callback(twindow &window)
Definition: lobby.cpp:1566
std::string name
Definition: lobby.hpp:50
The user set the widget invisible, that means:
Definition: widget.hpp:103
void friend_message(bool is_lobby, const std::string &sender, const std::string &message)
legacy_result legacy_result_
Result flag for interfacing with other MP dialogs.
Definition: lobby.hpp:193
std::vector< int > gamelist_id_at_row_
Definition: lobby.hpp:429
bool have_era
Definition: data.hpp:172
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:82
std::string map_size_info
Definition: data.hpp:150
virtual void set_label(const t_string &label) override
See tcontrol::set_label.
bool auto_open_whisper_windows()
user_state state
Definition: data.hpp:128
static lg::log_domain log_lobby("lobby")
virtual void send_whisper(const std::string &receiver, const std::string &message)
ttoggle_button * filter_friends_
Definition: lobby.hpp:397
std::map< std::string, t_string > string_map
bool is_friend(const std::string &nick)
A class that represents a TCP/IP connection to the wesnothd server.
void process_message(const config &data, bool whisper=false)
Definition: lobby.cpp:1327
void join_global_button_callback(twindow &window)
Definition: lobby.cpp:1507
This file contains the settings handling of the widget library.
static lg::log_domain log_network("network")
unsigned get_item_count() const
Returns the number of items in the listbox.
Definition: listbox.cpp:138
void init(twindow &w, const std::string &id)
Definition: lobby.cpp:76
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
void private_message(bool is_lobby, const std::string &sender, const std::string &message)
unsigned lobby_network_timer
Definition: game_config.cpp:45
void update_selected_game()
Definition: lobby.cpp:883
void set_callback_state_change(std::function< void(twidget &)> callback)
Inherited from tselectable_.
void post_show(twindow &window)
Inherited from tdialog.
Definition: lobby.cpp:1033
bool get_value_bool() const
Definition: selectable.hpp:48
bool fullscreen()
GLubyte GLubyte GLubyte GLubyte w
Definition: glew.h:1858
const GLdouble * v
Definition: glew.h:1359
void send_message_to_active_window(const std::string &input)
Definition: lobby.cpp:1584
ttoggle_button * sort_by_relation
Definition: lobby.hpp:80
virtual void send_chat_message(const std::string &message, bool)
inherited form chat_handler
Definition: lobby.cpp:166
void process_room_part(const config &data)
Definition: lobby.cpp:1424
const config & game_config_
Definition: lobby.hpp:371
bool delay_playerlist_update_
Definition: lobby.hpp:431
config & add_child(const std::string &key)
Definition: config.cpp:743
virtual void user_relation_changed(const std::string &name)
Called when a processed command results in a relation (friend/ignore) change for a user whose name is...
Definition: lobby.cpp:179
int game_id
Definition: data.hpp:126
The user sets the widget hidden, that means:
Definition: widget.hpp:91
void add_page(const string_map &item)
Adds single page to the grid.
Definition: multi_page.cpp:42
std::string xp
Definition: data.hpp:156
void update_user_statuses(int game_id, const room_info *room)
Definition: info.cpp:350
int selected_game_id_
Definition: lobby.hpp:407
std::vector< tlobby_chat_window > open_windows_
This represents the open chat windows (rooms and whispers at the moment) with 1 to 1 correspondence t...
Definition: lobby.hpp:393
void switch_to_window(tlobby_chat_window *t)
Switch to the window given by a valid pointer (e.g.
Definition: lobby.cpp:1204
void room_switch_callback(twindow &window)
Definition: lobby.cpp:1629
tsub_player_list active_room
Definition: lobby.hpp:75
const t_string & label() const
Definition: control.hpp:248
static size_t id
Ids for the timers.
Definition: timer.cpp:39
ttext_box * chat_input_
Definition: lobby.hpp:381
std::function< void()> preferences_callback_
Definition: lobby.hpp:387
void close()
Requests to close the window.
Definition: window.hpp:235
void show_preferences_button_callback(twindow &window)
Definition: lobby.cpp:1613
bool init()
Initializes the gui subsystems.
Definition: helper.cpp:37
unsigned get_value() const override
Inherited from tselectable_.
Label showing a text.
void chat_input_keypress_callback(bool &handled, bool &halt, const SDLKey key, twindow &window)
Definition: lobby.cpp:1634
tsub_player_list other_rooms
Definition: lobby.hpp:76
std::string map_data
Definition: data.hpp:145
ttoggle_button * filter_invert_
Definition: lobby.hpp:403
GLuint GLuint GLsizei count
Definition: glew.h:1221
GLuint color
Definition: glew.h:5801
bool is_ignored(const std::string &nick)
void refresh_button_callback(twindow &window)
Definition: lobby.cpp:1607
void observe_button_callback(twindow &window)
Definition: lobby.cpp:1492
size_t vacant_slots
Definition: data.hpp:160
std::map< std::string, t_string > string_map
Definition: generator.hpp:23
void apply_game_filter()
Definition: info.cpp:332
std::string join(T const &v, const std::string &s=",")
Generates a new string joining container items in a list.
void sync_games_display_status()
Definition: info.cpp:225
std::string login()
void add_member(const std::string &user)
Definition: data.cpp:80
int id
Definition: data.hpp:144
void save_to_history()
Saves the text in the widget to the history.
Definition: text_box.hpp:124
void game_filter_reload()
Definition: lobby.cpp:1672
bool playerlist_sort_relation()
bool whisper_window_active(const std::string &name)
Definition: lobby.cpp:1107
std::string escape_text(const std::string &text)
Escapes the markup characters in a text.
Definition: text.cpp:75
void make_games_vector()
Definition: info.cpp:321
lobby_info & lobby_info_
Definition: lobby.hpp:385
The user sets the widget visible, that means:
Definition: widget.hpp:79
void add_message(const time_t &timestamp, const std::string &user, const std::string &message)
Definition: data.cpp:53
GLint left
Definition: glew.h:5907
chat_log & get_whisper_log(const std::string &name)
Definition: info.cpp:279
static bool fullscreen(CVideo &video)
Definition: lobby.cpp:400
void close_window_button_callback(size_t idx)
Definition: lobby.cpp:1596
bool gamelist_dirty_
Definition: lobby.hpp:413
bool registered
Definition: data.hpp:129
bool reloaded
Definition: data.hpp:163
Game configuration data as global variables.
Definition: build_info.cpp:38
size_t lobby_update_timer_
Timer for updating the lobby.
Definition: lobby.hpp:424
#define VGETTEXT(msgid, symbols)
bool observing
Definition: data.hpp:130
virtual void add_chat_room_message_received(const std::string &room, const std::string &speaker, const std::string &message)
inherited form chat_handler
Definition: lobby.cpp:260
void public_message(bool is_lobby, const std::string &sender, const std::string &message)
static bool execute(std::string &password, CVideo &video)
The execute function – see tdialog for more information.
void remove_page(const unsigned page, unsigned count=1)
Removes a page in the multi page.
Definition: multi_page.cpp:55
std::string era_short
Definition: data.hpp:152
void network_handler()
Network polling callback.
Definition: lobby.cpp:1275
void update_gamelist_diff()
Definition: lobby.cpp:526
size_t i
Definition: function.cpp:1057
Contains the gui2 timer routines.
static void msg(const char *act, debug_info &i, const char *to="", const char *result="")
Definition: debugger.cpp:112
void set_fullscreen(bool ison)
Definition: video.cpp:670
tlabel * tree_label
Definition: lobby.hpp:67
virtual void post_build(twindow &window)
Inherited from tdialog.
Definition: lobby.cpp:408
twindow * window_
Definition: lobby.hpp:383
CVideo & video_
Definition: lobby.hpp:419
void server_message(bool is_lobby, const std::string &sender, const std::string &message)
bool shuffle_sides
Definition: data.hpp:168
void set_skip_mp_replay(bool value)
GLdouble GLdouble GLdouble r
Definition: glew.h:1374
bool result_open_whisper() const
Definition: player_info.hpp:38
void game_filter_keypress_callback(const SDLKey key)
Definition: lobby.cpp:1698
const std::vector< user_info > & users() const
Definition: info.hpp:92
tlobby_main(const config &game_config, lobby_info &info, CVideo &video, twesnothd_connection &wesnothd_connection)
Definition: lobby.cpp:339
unsigned child_count(const std::string &key) const
Definition: config.cpp:635
tlobby_chat_window * whisper_window_open(const std::string &name, bool open_new)
Check if a whisper window for user "name" is open, if open_new is true then it will be created if not...
Definition: lobby.cpp:1054
void process_room_members(const config &data)
Definition: data.cpp:90
void create_button_callback(twindow &window)
Definition: lobby.cpp:1601
GLuint const GLchar * name
Definition: glew.h:1782
void player_leaves(bool is_lobby)
void select_page(const unsigned page, const bool select=true)
Selectes a page.
Definition: multi_page.cpp:84
std::string name
Definition: data.hpp:125
void update_playerlist()
Definition: lobby.cpp:763
void remove_member(const std::string &user)
Definition: data.cpp:85
void clear_game_filter()
Definition: info.cpp:311
bool use_map_settings
Definition: data.hpp:169
void game_filter_change_callback(twidget &widget)
Definition: lobby.cpp:1706
void add_game_filter(game_filter_base *f)
Definition: info.cpp:306
GLenum GLint ref
Definition: glew.h:1813
void sort_users(bool by_name, bool by_relation)
Definition: info.cpp:396
This class represents the info a client has about a game on the server.
Definition: data.hpp:136
#define g
Definition: glew.h:12730
std::string get_chat_timestamp(const time_t &t)
void do_notify(t_notify_mode mode)
Definition: lobby.hpp:142
config & child(const std::string &key, int n=0)
Returns the nth child with the given key, or a reference to an invalid config if there is none...
Definition: config.cpp:658
void process_gamelist(const config &data)
Process a full gamelist.
Definition: info.cpp:102
#define LOG_LB
Definition: lobby.cpp:66
static lg::log_domain log_engine("engine")
tsub_player_list other_games
Definition: lobby.hpp:77
void player_joins(bool is_lobby)
Base class for all widgets.
Definition: widget.hpp:49
unsigned lobby_refresh
Definition: game_config.cpp:46
tmulti_page * chat_log_container_
Definition: lobby.hpp:379
ttree_view * tree
Definition: lobby.hpp:82
std::string message
Definition: exceptions.hpp:29
void player_filter_callback(twidget &widget)
Definition: lobby.cpp:1717
void set_callback_value_change(const std::function< void(twidget &)> &callback)
Definition: listbox.hpp:225
void show_toggle_callback(twidget &widget)
Definition: lobby.cpp:101
GLsizei GLenum GLuint GLuint GLsizei char * message
Definition: glew.h:2499
static void set_label(twindow &window, const std::string &id, const std::string &label)
Definition: unit_attack.cpp:89
void add_active_window_message(const std::string &sender, const std::string &message, const bool force_scroll=false)
Add a message to the window for room "room".
Definition: lobby.cpp:1195
void add_whisper_window_whisper(const std::string &sender, const std::string &message)
Add a whisper message to the whisper window.
Definition: lobby.cpp:1156
std::vector< std::string > split(std::string const &val, const char c, const int flags)
Splits a (comma-)separated string into a vector of pieces.
#define e
void set_config(const ::config *terrain)
Definition: minimap.hpp:77
void process_room_query_response(const config &data)
Definition: lobby.cpp:1446
ttext_box * filter_text_
Definition: lobby.hpp:405
ttoggle_button * filter_ignored_
Definition: lobby.hpp:399
std::string name
Definition: data.hpp:146
tlobby_chat_window * room_window_open(const std::string &room, bool open_new)
Check if a room window for "room" is open, if open_new is true then it will be created if not found...
Definition: lobby.cpp:1048
Class for a toggle button.
void gamelist_change_callback(twindow &window)
Definition: lobby.cpp:1712
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:83
void set_value(const unsigned selected)
Inherited from tselectable_.
tlistbox * roomlistbox_
Definition: lobby.hpp:377
GLdouble s
Definition: glew.h:1358
ttree_view_node * tree
Definition: lobby.hpp:66
int get_selected_row() const
Returns the first selected row.
Definition: listbox.cpp:237
void join_or_observe(int index)
Definition: lobby.cpp:1516
const std::vector< game_info * > & games() const
Definition: info.hpp:83
size_t add_timer(const Uint32 interval, const std::function< void(size_t id)> &callback, const bool repeat)
Adds a new timer.
Definition: timer.cpp:112
void set_visible(const tvisible::scoped_enum visible)
Definition: widget.cpp:445
std::string era
Definition: data.hpp:151
virtual void send_chat_room_message(const std::string &room, const std::string &message)
GLsizei const GLcharARB ** string
Definition: glew.h:4503
room_info * get_room(const std::string &name)
Definition: info.cpp:254
bool word_completion(std::string &text, std::vector< std::string > &wordlist)
Try to complete the last word of 'text' with the 'wordlist'.
void dialog_callback(twidget &caller)
Template for dialog callbacks.
Definition: helper.hpp:31
const std::vector< user_info * > & users_sorted() const
Definition: info.cpp:420
void clear()
Removes all the rows in the listbox, clearing it.
Definition: listbox.cpp:131
bool process_gamelist_diff(const config &data)
Process a gamelist diff.
Definition: info.cpp:120
const tgrid * get_row_grid(const unsigned row) const
Returns the grid of the wanted row.
Definition: listbox.cpp:215
void append_to_chatbox(const std::string &text, const bool force_scroll=false)
Append some text to the active chat log.
Definition: lobby.cpp:289
virtual void add_chat_message(const time_t &time, const std::string &speaker, int side, const std::string &message, events::chat_handler::MESSAGE_TYPE type=events::chat_handler::MESSAGE_PRIVATE)
inherited form chat_handler
Definition: lobby.cpp:184
void user_dialog_callback(user_info *info)
Definition: lobby.cpp:1728
bool can_join() const
Definition: data.cpp:358
void invalidate_layout()
Updates the size of the window.
Definition: window.cpp:941
tsub_player_list active_game
Definition: lobby.hpp:74
bool playerlist_sort_name()
bool playerlist_group_players()
twesnothd_connection & wesnothd_connection_
Definition: lobby.hpp:421
void clear()
Removes all child items from the widget.
bool word_match(const std::string &message, const std::string &word)
Check if a message contains a word.
unsigned last_gamelist_update_
Definition: lobby.hpp:415
void set_map_data(const std::string &map_data)
Definition: minimap.hpp:59