00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #define GETTEXT_DOMAIN "wesnoth-lib"
00016
00017 #include "gui/dialogs/lobby_main.hpp"
00018 #include "gui/dialogs/lobby_player_info.hpp"
00019 #include "gui/dialogs/field.hpp"
00020 #include "gui/dialogs/helper.hpp"
00021
00022 #include "gui/auxiliary/log.hpp"
00023 #include "gui/auxiliary/timer.hpp"
00024 #include "gui/widgets/button.hpp"
00025 #include "gui/widgets/image.hpp"
00026 #include "gui/widgets/label.hpp"
00027 #ifdef GUI2_EXPERIMENTAL_LISTBOX
00028 #include "gui/widgets/list.hpp"
00029 #else
00030 #include "gui/widgets/listbox.hpp"
00031 #endif
00032 #include "gui/widgets/minimap.hpp"
00033 #include "gui/widgets/multi_page.hpp"
00034 #include "gui/widgets/scroll_label.hpp"
00035 #include "gui/widgets/settings.hpp"
00036 #include "gui/widgets/text_box.hpp"
00037 #include "gui/widgets/toggle_button.hpp"
00038 #include "gui/widgets/toggle_panel.hpp"
00039 #include "gui/widgets/tree_view_node.hpp"
00040
00041 #include "foreach.hpp"
00042 #include "formula_string_utils.hpp"
00043 #include "game_preferences.hpp"
00044 #include "gettext.hpp"
00045 #include "lobby_preferences.hpp"
00046 #include "log.hpp"
00047 #include "network.hpp"
00048 #include "playmp_controller.hpp"
00049 #include "preferences_display.hpp"
00050 #include "sound.hpp"
00051
00052 #include <boost/bind.hpp>
00053
00054 static lg::log_domain log_network("network");
00055 #define DBG_NW LOG_STREAM(debug, log_network)
00056 #define LOG_NW LOG_STREAM(info, log_network)
00057 #define ERR_NW LOG_STREAM(err, log_network)
00058
00059 static lg::log_domain log_engine("engine");
00060 #define LOG_NG LOG_STREAM(info, log_engine)
00061 #define ERR_NG LOG_STREAM(err, log_engine)
00062
00063 static lg::log_domain log_config("config");
00064 #define ERR_CF LOG_STREAM(err, log_config)
00065
00066 static lg::log_domain log_lobby("lobby");
00067 #define DBG_LB LOG_STREAM(debug, log_lobby)
00068 #define LOG_LB LOG_STREAM(info, log_lobby)
00069 #define ERR_LB LOG_STREAM(err, log_lobby)
00070 #define SCOPE_LB log_scope2(log_lobby, __func__)
00071
00072
00073 namespace gui2 {
00074
00075 REGISTER_DIALOG(lobby_main)
00076
00077 void tsub_player_list::init(gui2::twindow &w, const std::string &id)
00078 {
00079 list = find_widget<tlistbox>(&w, id, false, true);
00080 show_toggle = find_widget<ttoggle_button>(&w, id + "_show_toggle"
00081 , false, true);
00082 show_toggle->set_icon_name("lobby/group-expanded.png");
00083 show_toggle->set_callback_state_change(
00084 boost::bind(&tsub_player_list::show_toggle_callback, this, _1));
00085 count = find_widget<tlabel>(&w, id + "_count", false, true);
00086 label = find_widget<tlabel>(&w, id + "_label", false, true);
00087
00088 ttree_view& parent_tree = find_widget<ttree_view>(&w
00089 , "player_tree"
00090 , false);
00091
00092 string_map tree_group_field;
00093 std::map<std::string, string_map> tree_group_item;
00094
00095 tree_group_field["label"] = id;
00096 tree_group_item["tree_view_node_label"] = tree_group_field;
00097 tree = &parent_tree.add_node("player_group", tree_group_item);
00098
00099 tree_label = find_widget<tlabel>(tree
00100 , "tree_view_node_label"
00101 , false
00102 , true);
00103
00104 tree_label->set_label(label->label());
00105
00106 }
00107
00108 void tsub_player_list::show_toggle_callback(gui2::twidget* )
00109 {
00110 if (show_toggle->get_value()) {
00111 list->set_visible(twidget::INVISIBLE);
00112 show_toggle->set_icon_name("lobby/group-folded.png");
00113 } else {
00114 list->set_visible(twidget::VISIBLE);
00115 show_toggle->set_icon_name("lobby/group-expanded.png");
00116 }
00117 }
00118
00119 void tsub_player_list::auto_hide()
00120 {
00121 assert(tree);
00122 assert(tree_label);
00123 if(tree->empty()) {
00124
00125
00126
00127
00128
00129
00130
00131 assert(label);
00132 tree_label->set_label(label->label() + " (0)");
00133
00134 } else {
00135 assert(label);
00136 std::stringstream ss;
00137 ss << label->label() << " (" << tree->size() << ")";
00138 tree_label->set_label(ss.str());
00139
00140 }
00141 }
00142
00143 void tplayer_list::init(gui2::twindow &w)
00144 {
00145 active_game.init(w, "active_game");
00146 active_room.init(w, "active_room");
00147 other_rooms.init(w, "other_rooms");
00148 other_games.init(w, "other_games");
00149 sort_by_name = find_widget<ttoggle_button>(&w
00150 , "player_list_sort_name", false, true);
00151 sort_by_relation = find_widget<ttoggle_button>(&w
00152 , "player_list_sort_relation", false, true);
00153
00154 tree = find_widget<ttree_view>(&w
00155 , "player_tree"
00156 , false
00157 , true);
00158
00159 find_widget<twidget>(&w, "old_player_list", false)
00160 .set_visible(twidget::INVISIBLE);
00161
00162
00163
00164
00165
00166
00167 assert(active_room.tree);
00168 find_widget<ttoggle_button>(active_room.tree
00169 , "tree_view_node_icon"
00170 , false).set_value(true);
00171 assert(other_rooms.tree);
00172 find_widget<ttoggle_button>(other_rooms.tree
00173 , "tree_view_node_icon"
00174 , false).set_value(true);
00175 assert(other_games.tree);
00176 find_widget<ttoggle_button>(other_games.tree
00177 , "tree_view_node_icon"
00178 , false).set_value(true);
00179 }
00180
00181 void tplayer_list::update_sort_icons()
00182 {
00183 if (sort_by_name->get_value()) {
00184 sort_by_name->set_icon_name("lobby/sort-az.png");
00185 } else {
00186 sort_by_name->set_icon_name("lobby/sort-az-off.png");
00187 }
00188 if (sort_by_relation->get_value()) {
00189 sort_by_relation->set_icon_name("lobby/sort-friend.png");
00190 } else {
00191 sort_by_relation->set_icon_name("lobby/sort-friend-off.png");
00192 }
00193 }
00194 void tlobby_main::send_chat_message(const std::string& message, bool )
00195 {
00196 config data, msg;
00197 msg["message"] = message;
00198 msg["sender"] = preferences::login();
00199 data.add_child("message", msg);
00200
00201 add_chat_message(time(NULL), preferences::login(), 0, message);
00202 network::send_data(data, 0);
00203 }
00204
00205 void tlobby_main::user_relation_changed(const std::string& )
00206 {
00207 player_list_dirty_ = true;
00208 }
00209
00210 void tlobby_main::add_chat_message(const time_t& , const std::string& speaker,
00211 int , const std::string& message, events::chat_handler::MESSAGE_TYPE )
00212 {
00213 std::stringstream ss;
00214 ss << "<" << speaker << "> ";
00215 ss << message;
00216 append_to_chatbox(ss.str());
00217 }
00218
00219
00220 void tlobby_main::add_whisper_sent(const std::string& receiver, const std::string& message)
00221 {
00222 if (whisper_window_active(receiver)) {
00223 add_active_window_message(preferences::login(), message);
00224 } else if (tlobby_chat_window* t = whisper_window_open(receiver, preferences::auto_open_whisper_windows())) {
00225 switch_to_window(t);
00226 add_active_window_message(preferences::login(), message);
00227 } else {
00228 utils::string_map symbols;
00229 symbols["receiver"] = receiver;
00230 add_active_window_whisper(VGETTEXT("whisper to $receiver", symbols), message);
00231 }
00232 lobby_info_.get_whisper_log(receiver).add_message(preferences::login(), message);
00233 }
00234
00235 void tlobby_main::add_whisper_received(const std::string& sender, const std::string& message)
00236 {
00237 bool can_go_to_active = !preferences::whisper_friends_only() || preferences::is_friend(sender);
00238 bool can_open_new = preferences::auto_open_whisper_windows() && can_go_to_active;
00239 lobby_info_.get_whisper_log(sender).add_message(sender, message);
00240 if (whisper_window_open(sender, can_open_new)) {
00241 if (whisper_window_active(sender)) {
00242 add_active_window_message(sender, message);
00243 do_notify(NOTIFY_WHISPER);
00244 } else {
00245 add_whisper_window_whisper(sender, message);
00246 increment_waiting_whsipers(sender);
00247 do_notify(NOTIFY_WHISPER_OTHER_WINDOW);
00248 }
00249 } else if (can_go_to_active) {
00250 add_active_window_whisper(sender, message);
00251 do_notify(NOTIFY_WHISPER);
00252 } else {
00253 LOG_LB << "Ignoring whisper from " << sender << "\n";
00254 }
00255 }
00256
00257 void tlobby_main::add_chat_room_message_sent(const std::string& room,
00258 const std::string& message)
00259 {
00260
00261
00262 if (tlobby_chat_window* t = room_window_open(room, false)) {
00263 room_info* ri = lobby_info_.get_room(room);
00264 assert(ri);
00265 if (!room_window_active(room)) {
00266 switch_to_window(t);
00267 }
00268 ri->log().add_message(preferences::login(), message);
00269 add_active_window_message(preferences::login(), message);
00270 } else {
00271 LOG_LB << "Cannot add sent message to ui for room " << room
00272 << ", player not in the room\n";
00273 }
00274 }
00275
00276 void tlobby_main::add_chat_room_message_received(const std::string& room,
00277 const std::string& speaker, const std::string& message)
00278 {
00279 if (room_info* ri = lobby_info_.get_room(room)) {
00280 t_notify_mode notify_mode = NOTIFY_NONE;
00281 ri->log().add_message(speaker, message);
00282 if (room_window_active(room)) {
00283 add_active_window_message(speaker, message);
00284 notify_mode = NOTIFY_MESSAGE;
00285 } else {
00286 add_room_window_message(room, speaker, message);
00287 increment_waiting_messages(room);
00288 notify_mode = NOTIFY_MESSAGE_OTHER_WINDOW;
00289 }
00290 if (speaker == "server") {
00291 notify_mode = NOTIFY_SERVER_MESSAGE;
00292 } else if (utils::word_match(message, preferences::login())) {
00293 notify_mode = NOTIFY_OWN_NICK;
00294 } else if (preferences::is_friend(speaker)) {
00295 notify_mode = NOTIFY_FRIEND_MESSAGE;
00296 }
00297 do_notify(notify_mode);
00298 } else {
00299 LOG_LB << "Discarding message to room " << room
00300 << " from " << speaker << " (room not open)\n";
00301 }
00302 }
00303
00304 void tlobby_main::append_to_chatbox(const std::string& text)
00305 {
00306 append_to_chatbox(text, active_window_);
00307 }
00308
00309 void tlobby_main::append_to_chatbox(const std::string& text, size_t id)
00310 {
00311 tgrid& grid = chat_log_container_->page_grid(id);
00312 tscroll_label& log = find_widget<tscroll_label>(&grid, "log_text", false);
00313 log.set_label(log.label() + "\n" + preferences::get_chat_timestamp(time(0)) + text);
00314 log.scroll_vertical_scrollbar(tscrollbar_::END);
00315 }
00316
00317 void tlobby_main::do_notify(t_notify_mode mode)
00318 {
00319 if (preferences::lobby_sounds()) {
00320 switch (mode) {
00321 case NOTIFY_WHISPER:
00322 case NOTIFY_WHISPER_OTHER_WINDOW:
00323 case NOTIFY_OWN_NICK:
00324 sound::play_UI_sound(game_config::sounds::receive_message_highlight);
00325 break;
00326 case NOTIFY_FRIEND_MESSAGE:
00327 sound::play_UI_sound(game_config::sounds::receive_message_friend);
00328 break;
00329 case NOTIFY_SERVER_MESSAGE:
00330 sound::play_UI_sound(game_config::sounds::receive_message_server);
00331 break;
00332 case NOTIFY_LOBBY_QUIT:
00333 sound::play_UI_sound(game_config::sounds::user_leave);
00334 break;
00335 case NOTIFY_LOBBY_JOIN:
00336 sound::play_UI_sound(game_config::sounds::user_arrive);
00337 break;
00338 case NOTIFY_MESSAGE:
00339 break;
00340 default:
00341 break;
00342 }
00343 }
00344 }
00345
00346 tlobby_main::tlobby_main(const config& game_config
00347 , lobby_info& info
00348 , display& disp)
00349 : legacy_result_(QUIT)
00350 , game_config_(game_config)
00351 , gamelistbox_(NULL)
00352 , userlistbox_(NULL)
00353 , roomlistbox_(NULL)
00354 , chat_log_container_(NULL)
00355 , chat_input_(NULL)
00356 , window_(NULL)
00357 , lobby_info_(info)
00358 , preferences_callback_(NULL)
00359 , open_windows_()
00360 , active_window_(0)
00361 , filter_friends_(NULL)
00362 , filter_ignored_(NULL)
00363 , filter_slots_(NULL)
00364 , filter_invert_(NULL)
00365 , filter_text_(NULL)
00366 , selected_game_id_()
00367 , player_list_()
00368 , player_list_dirty_(false)
00369 , gamelist_dirty_(false)
00370 , last_gamelist_update_(0)
00371 , gamelist_diff_update_(true)
00372 , disp_(disp)
00373 , lobby_update_timer_(0)
00374 , preferences_wrapper_()
00375 , gamelist_id_at_row_()
00376 , delay_playerlist_update_(false)
00377 , delay_gamelist_update_(false)
00378 {
00379 }
00380
00381 struct lobby_delay_gamelist_update_guard
00382 {
00383 lobby_delay_gamelist_update_guard(tlobby_main& l) : l(l) {
00384 l.delay_gamelist_update_ = true;
00385 }
00386 ~lobby_delay_gamelist_update_guard() {
00387 l.delay_gamelist_update_ = false;
00388 }
00389 tlobby_main& l;
00390 };
00391
00392 void tlobby_main::set_preferences_callback(boost::function<void ()> cb)
00393 {
00394 preferences_callback_ = cb;
00395 }
00396
00397 tlobby_main::~tlobby_main()
00398 {
00399 if(lobby_update_timer_) {
00400 remove_timer(lobby_update_timer_);
00401 }
00402 }
00403
00404 static void signal_handler_sdl_video_resize(
00405 const event::tevent event
00406 , bool& handled
00407 , bool& halt
00408 , const tpoint& new_size
00409 , CVideo& video)
00410 {
00411 DBG_GUI_E << __func__ << ": " << event << ".\n";
00412
00413 if(new_size.x < preferences::min_allowed_width()
00414 || new_size.y < preferences::min_allowed_height()) {
00415
00416 DBG_GUI_E << __func__ << ": resize aborted, too small.\n";
00417 handled = true;
00418 halt = true;
00419 return;
00420 }
00421
00422 if(new_size.x == static_cast<int>(settings::screen_width)
00423 && new_size.y == static_cast<int>(settings::screen_height)) {
00424
00425 DBG_GUI_E << __func__ << ": resize not needed.\n";
00426 handled = true;
00427 return;
00428 }
00429
00430 if(!preferences::set_resolution(video , new_size.x, new_size.y)) {
00431
00432 LOG_GUI_E << __func__
00433 << ": resize aborted, resize failed.\n";
00434 }
00435 }
00436
00437 static bool fullscreen(CVideo& video)
00438 {
00439 preferences::set_fullscreen(video , !preferences::fullscreen());
00440
00441
00442 const SDL_Rect& rect = screen_area();
00443
00444 SDL_Event event;
00445 event.type = SDL_VIDEORESIZE;
00446 event.resize.type = SDL_VIDEORESIZE;
00447 event.resize.w = rect.w;
00448 event.resize.h = rect.h;
00449
00450 SDL_PushEvent(&event);
00451
00452 return true;
00453 }
00454
00455 void tlobby_main::post_build(CVideo& video, twindow& window)
00456 {
00457
00458 window.register_hotkey(hotkey::HOTKEY_FULLSCREEN
00459 , boost::bind(fullscreen, boost::ref(video)));
00460
00461
00462
00463 window.connect_signal<event::SDL_VIDEO_RESIZE>(
00464 boost::bind(&signal_handler_sdl_video_resize
00465 , _2, _3, _4, _5, boost::ref(video))
00466 , event::tdispatcher::front_child);
00467
00468
00469 preferences_wrapper_ = boost::bind(
00470 &tlobby_main::show_preferences_button_callback
00471 , this
00472 , boost::ref(window));
00473
00474 window.register_hotkey(
00475 hotkey::HOTKEY_PREFERENCES
00476 , boost::bind(function_wrapper<bool, boost::function<void()> >
00477 , true
00478 , boost::cref(preferences_wrapper_)));
00479 }
00480
00481 namespace {
00482
00483 void add_label_data(std::map<std::string, string_map>& map,
00484 const std::string& key, const std::string& label)
00485 {
00486 string_map item;
00487 item["label"] = label;
00488 map.insert(std::make_pair(key, item));
00489 }
00490
00491 void add_tooltip_data(std::map<std::string, string_map>& map,
00492 const std::string& key, const std::string& label)
00493 {
00494 string_map item;
00495 item["tooltip"] = label;
00496 map.insert(std::make_pair(key, item));
00497 }
00498
00499 void modify_grid_with_data(tgrid* grid, const std::map<std::string, string_map>& map)
00500 {
00501 typedef std::map<std::string, string_map> strstrmap;
00502 foreach (const strstrmap::value_type v, map) {
00503 const std::string& key = v.first;
00504 const string_map& strmap = v.second;
00505 twidget* w = grid->find(key, false);
00506 if (w == NULL) continue;
00507 tcontrol* c = dynamic_cast<tcontrol*>(w);
00508 if (c == NULL) continue;
00509 foreach (const string_map::value_type& vv, strmap) {
00510 if (vv.first == "label") {
00511 c->set_label(vv.second);
00512 } else if (vv.first == "tooltip") {
00513 c->set_tooltip(vv.second);
00514 }
00515 }
00516 }
00517 }
00518
00519 void set_visible_if_exists(tgrid* grid, const char* id, bool visible)
00520 {
00521 twidget* w = grid->find(id, false);
00522 if (w) {
00523 w->set_visible(visible ? twidget::VISIBLE : twidget::INVISIBLE);
00524 }
00525 }
00526
00527 std::string colorize(const std::string& str, const std::string& color)
00528 {
00529 return "<span color=\"" + color +"\">" + str + "</span>";
00530 }
00531
00532 std::string tag(const std::string& str, const std::string& tag)
00533 {
00534 return "<" + tag + ">" + str + "</" + tag + ">";
00535 }
00536
00537 }
00538
00539 void tlobby_main::update_gamelist()
00540 {
00541 SCOPE_LB;
00542 gamelistbox_->clear();
00543 gamelist_id_at_row_.clear();
00544 lobby_info_.make_games_vector();
00545 int select_row = -1;
00546 for (unsigned i = 0; i < lobby_info_.games().size(); ++i) {
00547 const game_info& game = *lobby_info_.games()[i];
00548 if (game.id == selected_game_id_) {
00549 select_row = i;
00550 }
00551 gamelist_id_at_row_.push_back(game.id);
00552 LOG_LB << "Adding game to listbox (1)" << game.id << "\n";
00553 gamelistbox_->add_row(make_game_row_data(game));
00554 tgrid* grid = gamelistbox_->get_row_grid(gamelistbox_->get_item_count() - 1);
00555 adjust_game_row_contents(game, gamelistbox_->get_item_count() - 1, grid);
00556 }
00557 if (select_row >= 0 && select_row != gamelistbox_->get_selected_row()) {
00558 gamelistbox_->select_row(select_row);
00559 }
00560 update_selected_game();
00561 gamelist_dirty_ = false;
00562 last_gamelist_update_ = SDL_GetTicks();
00563 lobby_info_.sync_games_display_status();
00564 lobby_info_.apply_game_filter();
00565 update_gamelist_header();
00566 gamelistbox_->set_row_shown(lobby_info_.games_visibility());
00567 }
00568
00569 void tlobby_main::update_gamelist_diff()
00570 {
00571 SCOPE_LB;
00572 lobby_info_.make_games_vector();
00573 int select_row = -1;
00574 unsigned list_i = 0;
00575 int list_rows_deleted = 0;
00576 std::vector<int> next_gamelist_id_at_row;
00577 for (unsigned i = 0; i < lobby_info_.games().size(); ++i) {
00578 const game_info& game = *lobby_info_.games()[i];
00579 if (game.display_status == game_info::NEW) {
00580 LOG_LB << "Adding game to listbox " << game.id << "\n";
00581 if (list_i != gamelistbox_->get_item_count()) {
00582 gamelistbox_->add_row(make_game_row_data(game), list_i);
00583 DBG_LB << "Added a game listbox row not at the end"
00584 << list_i << " " << gamelistbox_->get_item_count() << "\n";
00585 list_rows_deleted--;
00586 } else {
00587 gamelistbox_->add_row(make_game_row_data(game));
00588 }
00589 tgrid* grid = gamelistbox_->get_row_grid(gamelistbox_->get_item_count() - 1);
00590 adjust_game_row_contents(game, gamelistbox_->get_item_count() - 1, grid);
00591 list_i++;
00592 next_gamelist_id_at_row.push_back(game.id);
00593 } else {
00594 if (list_i >= gamelistbox_->get_item_count()) {
00595 ERR_LB << "Ran out of listbox items -- triggering a full refresh\n";
00596 network::send_data(config("refresh_lobby"), 0);
00597 return;
00598 }
00599 if (list_i + list_rows_deleted >= gamelist_id_at_row_.size()) {
00600 ERR_LB << "gamelist_id_at_row_ overflow! "
00601 << list_i << " + " << list_rows_deleted
00602 << " >= " << gamelist_id_at_row_.size()
00603 << " -- triggering a full refresh\n";
00604 network::send_data(config("refresh_lobby"), 0);
00605 return;
00606 }
00607 int listbox_game_id = gamelist_id_at_row_[list_i + list_rows_deleted];
00608 if (game.id != listbox_game_id) {
00609 ERR_LB << "Listbox game id does not match expected id "
00610 << listbox_game_id << " " << game.id << " (row " << list_i << ")\n";
00611 network::send_data(config("refresh_lobby"), 0);
00612 return;
00613 }
00614 if (game.display_status == game_info::UPDATED) {
00615 LOG_LB << "Modyfying game in listbox " << game.id << " (row " << list_i << ")\n";
00616 tgrid* grid = gamelistbox_->get_row_grid(list_i);
00617 modify_grid_with_data(grid, make_game_row_data(game));
00618 adjust_game_row_contents(game, list_i, grid);
00619 ++list_i;
00620 next_gamelist_id_at_row.push_back(game.id);
00621 } else if (game.display_status == game_info::DELETED) {
00622 LOG_LB << "Deleting game from listbox " << game.id << " (row " << list_i << ")\n";
00623 gamelistbox_->remove_row(list_i);
00624 ++list_rows_deleted;
00625 } else {
00626
00627 LOG_LB << "Clean game in listbox " << game.id << " (row " << list_i << ")\n";
00628 next_gamelist_id_at_row.push_back(game.id);
00629 ++list_i;
00630 }
00631 }
00632 }
00633 for (unsigned i = 0; i < next_gamelist_id_at_row.size(); ++i) {
00634 if (next_gamelist_id_at_row[i] == selected_game_id_) {
00635 select_row = i;
00636 }
00637 }
00638 next_gamelist_id_at_row.swap(gamelist_id_at_row_);
00639 if (select_row >= static_cast<int>(gamelistbox_->get_item_count())) {
00640 ERR_LB << "Would select a row beyond the listbox"
00641 << select_row << " " << gamelistbox_->get_item_count() << "\n";
00642 select_row = gamelistbox_->get_item_count() - 1;
00643 }
00644 if (select_row >= 0 && select_row != gamelistbox_->get_selected_row()) {
00645 gamelistbox_->select_row(select_row);
00646 }
00647 update_selected_game();
00648 gamelist_dirty_ = false;
00649 last_gamelist_update_ = SDL_GetTicks();
00650 lobby_info_.sync_games_display_status();
00651 lobby_info_.apply_game_filter();
00652 update_gamelist_header();
00653 gamelistbox_->set_row_shown(lobby_info_.games_visibility());
00654 }
00655
00656 void tlobby_main::update_gamelist_header()
00657 {
00658 #ifndef GUI2_EXPERIMENTAL_LISTBOX
00659 utils::string_map symbols;
00660 symbols["num_shown"] = lexical_cast<std::string>(lobby_info_.games_filtered().size());
00661 symbols["num_total"] = lexical_cast<std::string>(lobby_info_.games().size());
00662 std::string games_string = VGETTEXT("Games: showing $num_shown out of $num_total", symbols);
00663 find_widget<tlabel>(gamelistbox_, "map", false).set_label(games_string);
00664 #endif
00665 }
00666
00667 std::map<std::string, string_map> tlobby_main::make_game_row_data(const game_info& game)
00668 {
00669 std::map<std::string, string_map> data;
00670
00671 const char* color_string;
00672 if (game.vacant_slots > 0) {
00673 if (game.reloaded || game.started) {
00674 color_string = "yellow";
00675 } else {
00676 color_string = "green";
00677 }
00678 } else {
00679 if (game.observers) {
00680 color_string = "#ddd";
00681 } else {
00682 color_string = "red";
00683 }
00684 }
00685 if (!game.have_era && (game.vacant_slots > 0 || game.observers)) {
00686 color_string = "#444";
00687 }
00688
00689 add_label_data(data, "status", colorize(game.status, color_string));
00690 add_label_data(data, "name", colorize(game.name, color_string));
00691
00692 add_label_data(data, "era", game.era);
00693 add_label_data(data, "era_short", game.era_short);
00694 add_label_data(data, "map_info", game.map_info);
00695 add_label_data(data, "scenario", game.scenario);
00696 add_label_data(data, "map_size_text", game.map_size_info);
00697 add_label_data(data, "time_limit", game.time_limit);
00698 add_label_data(data, "gold_text", game.gold);
00699 add_label_data(data, "xp_text", game.xp);
00700 add_label_data(data, "vision_text", game.vision);
00701 add_label_data(data, "time_limit_text", game.time_limit);
00702 add_label_data(data, "status", game.status);
00703 if (game.observers) {
00704 add_label_data(data, "observer_icon", "misc/eye.png");
00705 add_tooltip_data(data, "observer_icon", _("Observers allowed"));
00706 } else {
00707 add_label_data(data, "observer_icon", "misc/no_observer.png");
00708 add_tooltip_data(data, "observer_icon", _("Observers not allowed"));
00709 }
00710
00711 const char* vision_icon;
00712 if (game.fog) {
00713 if (game.shroud) {
00714 vision_icon = "misc/vision-fog-shroud.png";
00715 } else {
00716 vision_icon = "misc/vision-fog.png";
00717 }
00718 } else {
00719 if (game.shroud) {
00720 vision_icon = "misc/vision-shroud.png";
00721 } else {
00722 vision_icon = "misc/vision-none.png";
00723 }
00724 }
00725 add_label_data(data, "vision_icon", vision_icon);
00726 add_tooltip_data(data, "vision_icon", game.vision);
00727 return data;
00728 }
00729
00730 void tlobby_main::adjust_game_row_contents(const game_info& game, int idx, tgrid* grid)
00731 {
00732 find_widget<tcontrol>(grid, "name", false).set_use_markup(true);
00733
00734 find_widget<tcontrol>(grid, "status", false).set_use_markup(true);
00735
00736 ttoggle_panel& row_panel =
00737 find_widget<ttoggle_panel>(grid, "panel", false);
00738
00739 row_panel.set_callback_mouse_left_double_click(boost::bind(
00740 &tlobby_main::join_or_observe, this, idx));
00741
00742 set_visible_if_exists(grid, "time_limit_icon", !game.time_limit.empty());
00743 set_visible_if_exists(grid, "vision_fog", game.fog);
00744 set_visible_if_exists(grid, "vision_shroud", game.shroud);
00745 set_visible_if_exists(grid, "vision_none", !(game.fog || game.shroud));
00746 set_visible_if_exists(grid, "observers_yes", game.observers);
00747 set_visible_if_exists(grid, "shuffle_sides_icon", game.shuffle_sides);
00748 set_visible_if_exists(grid, "observers_no", !game.observers);
00749 set_visible_if_exists(grid, "needs_password", game.password_required);
00750 set_visible_if_exists(grid, "reloaded", game.reloaded);
00751 set_visible_if_exists(grid, "started", game.started);
00752 set_visible_if_exists(grid, "use_map_settings", game.use_map_settings);
00753 set_visible_if_exists(grid, "no_era", !game.have_era);
00754
00755
00756 tbutton* join_button = dynamic_cast<tbutton*>(grid->find("join", false));
00757 if (join_button) {
00758 connect_signal_mouse_left_click(*join_button, boost::bind(
00759 &tlobby_main::join_button_callback
00760 , this
00761 , boost::ref(*window_)));
00762 join_button->set_active(game.can_join());
00763 }
00764 tbutton* observe_button = dynamic_cast<tbutton*>(grid->find("observe", false));
00765 if (observe_button) {
00766 connect_signal_mouse_left_click(*observe_button, boost::bind(
00767 &tlobby_main::observe_button_callback
00768 , this
00769 , boost::ref(*window_)));
00770 observe_button->set_active(game.can_observe());
00771 }
00772 tminimap* minimap = dynamic_cast<tminimap*>(grid->find("minimap", false));
00773 if (minimap) {
00774 minimap->set_config(&game_config_);
00775 minimap->set_map_data(game.map_data);
00776 }
00777 }
00778
00779 void tlobby_main::update_gamelist_filter()
00780 {
00781 DBG_LB << "tlobby_main::update_gamelist_filter\n";
00782 lobby_info_.apply_game_filter();
00783 DBG_LB << "Games in lobby_info: " << lobby_info_.games().size()
00784 << ", games in listbox: " << gamelistbox_->get_item_count() << "\n";
00785 assert(lobby_info_.games().size() == gamelistbox_->get_item_count());
00786 gamelistbox_->set_row_shown(lobby_info_.games_visibility());
00787 }
00788
00789
00790 void tlobby_main::update_playerlist()
00791 {
00792 if (delay_playerlist_update_) return;
00793 SCOPE_LB;
00794 DBG_LB << "Playerlist update: " << lobby_info_.users().size() << "\n";
00795 lobby_info_.update_user_statuses(selected_game_id_, active_window_room());
00796 lobby_info_.sort_users(player_list_.sort_by_name->get_value(), player_list_.sort_by_relation->get_value());
00797
00798 bool lobby = false;
00799 if (room_info* ri = active_window_room()) {
00800 if (ri->name() == "lobby") {
00801 lobby = true;
00802 }
00803 }
00804 player_list_.active_game.list->clear();
00805 player_list_.active_room.list->clear();
00806 player_list_.other_rooms.list->clear();
00807 player_list_.other_games.list->clear();
00808
00809 assert(player_list_.active_game.tree);
00810 assert(player_list_.active_room.tree);
00811 assert(player_list_.other_games.tree);
00812 assert(player_list_.other_rooms.tree);
00813
00814 player_list_.active_game.tree->clear();
00815 player_list_.active_room.tree->clear();
00816 player_list_.other_games.tree->clear();
00817 player_list_.other_rooms.tree->clear();
00818
00819 foreach (user_info* userptr, lobby_info_.users_sorted())
00820 {
00821 user_info& user = *userptr;
00822 tsub_player_list* target_list(NULL);
00823 std::map<std::string, string_map> data;
00824 std::stringstream icon_ss;
00825 std::string name = user.name;
00826 icon_ss << "lobby/status";
00827 switch (user.state) {
00828 case user_info::SEL_ROOM:
00829 icon_ss << "-lobby";
00830 target_list = &player_list_.active_room;
00831 if (lobby) {
00832 target_list = &player_list_.other_rooms;
00833 }
00834 break;
00835 case user_info::LOBBY:
00836 icon_ss << "-lobby";
00837 target_list = &player_list_.other_rooms;
00838 break;
00839 case user_info::SEL_GAME:
00840 name = colorize(name, "cyan");
00841 icon_ss << (user.observing ? "-obs" : "-playing");
00842 target_list = &player_list_.active_game;
00843 break;
00844 case user_info::GAME:
00845 name = colorize(name, "red");
00846 icon_ss << (user.observing ? "-obs" : "-playing");
00847 target_list = &player_list_.other_games;
00848 break;
00849 default:
00850 ERR_LB << "Bad user state in lobby: " << user.name << ": " << user.state << "\n";
00851 continue;
00852 }
00853 switch (user.relation) {
00854 case user_info::ME:
00855
00856 case user_info::NEUTRAL:
00857 icon_ss << "-n";
00858 break;
00859 case user_info::FRIEND:
00860 icon_ss << "-f";
00861 break;
00862 case user_info::IGNORED:
00863 icon_ss << "-i";
00864 break;
00865 default:
00866 ERR_LB << "Bad user relation in lobby: " << user.relation << "\n";
00867 }
00868 if (user.registered) {
00869 name = tag(name, "b");
00870 }
00871 icon_ss << ".png";
00872 add_label_data(data, "player", name);
00873 add_label_data(data, "main_icon", icon_ss.str());
00874 if (!preferences::playerlist_group_players()) {
00875 target_list = &player_list_.other_rooms;
00876 }
00877
00878 assert(target_list->tree);
00879
00880 string_map tree_group_field;
00881 std::map<std::string, string_map> tree_group_item;
00882
00883
00884 tree_group_field["label"] = icon_ss.str();
00885 tree_group_item["icon"] = tree_group_field;
00886
00887 tree_group_field["label"] = name;
00888 tree_group_field["use_markup"] = "true";
00889 tree_group_item["name"] = tree_group_field;
00890
00891 ttree_view_node& player =
00892 target_list->tree->add_child("player", tree_group_item);
00893
00894 find_widget<ttoggle_panel>(&player, "tree_view_node_label", false)
00895 .set_callback_mouse_left_double_click(boost::bind(
00896 &tlobby_main::user_dialog_callback, this, userptr));
00897 }
00898 player_list_.active_game.auto_hide();
00899 player_list_.active_room.auto_hide();
00900 player_list_.other_rooms.auto_hide();
00901 player_list_.other_games.auto_hide();
00902
00903 player_list_dirty_ = false;
00904 }
00905
00906 void tlobby_main::update_selected_game()
00907 {
00908 int idx = gamelistbox_->get_selected_row();
00909 bool can_join = false, can_observe = false;
00910 if (idx >= 0) {
00911 const game_info& game = *lobby_info_.games()[idx];
00912 can_observe = game.can_observe();
00913 can_join = game.can_join();
00914 selected_game_id_ = game.id;
00915 } else {
00916 selected_game_id_ = 0;
00917 }
00918 find_widget<tbutton>(window_, "observe_global", false)
00919 .set_active(can_observe);
00920
00921 find_widget<tbutton>(window_, "join_global", false).set_active(can_join);
00922
00923 player_list_dirty_ = true;
00924 }
00925
00926 void tlobby_main::pre_show(CVideo& , twindow& window)
00927 {
00928 SCOPE_LB;
00929 roomlistbox_ = find_widget<tlistbox>(&window, "room_list", false, true);
00930 #ifdef GUI2_EXPERIMENTAL_LISTBOX
00931 connect_signal_notify_modified(*roomlistbox_, boost::bind(
00932 &tlobby_main::room_switch_callback
00933 , *this
00934 , boost::ref(window)));
00935 #else
00936 roomlistbox_->set_callback_value_change(
00937 dialog_callback<tlobby_main, &tlobby_main::room_switch_callback>);
00938 #endif
00939
00940 gamelistbox_ = find_widget<tlistbox>(&window, "game_list", false, true);
00941 #ifdef GUI2_EXPERIMENTAL_LISTBOX
00942 connect_signal_notify_modified(*gamelistbox_, boost::bind(
00943 &tlobby_main::gamelist_change_callback
00944 , *this
00945 , boost::ref(window)));
00946 #else
00947 gamelistbox_->set_callback_value_change(
00948 dialog_callback<tlobby_main
00949 , &tlobby_main::gamelist_change_callback>);
00950 #endif
00951
00952 player_list_.init(window);
00953
00954 player_list_.sort_by_name->set_value(preferences::playerlist_sort_name());
00955 player_list_.sort_by_relation->set_value(preferences::playerlist_sort_relation());
00956 player_list_.update_sort_icons();
00957
00958 player_list_.sort_by_name->set_callback_state_change(boost::bind(
00959 &tlobby_main::player_filter_callback, this, _1));
00960 player_list_.sort_by_relation->set_callback_state_change(boost::bind(
00961 &tlobby_main::player_filter_callback, this, _1));
00962
00963 chat_log_container_ = find_widget<tmulti_page>(
00964 &window, "chat_log_container", false, true);
00965
00966 window.set_enter_disabled(true);
00967
00968 window_ = &window;
00969
00970 chat_input_ = find_widget<ttext_box>(&window, "chat_input", false, true);
00971 assert(chat_input_);
00972 connect_signal_pre_key_press(*chat_input_, boost::bind(
00973 &tlobby_main::chat_input_keypress_callback
00974 , this
00975 , _3
00976 , _4
00977 , _5
00978 , boost::ref(window)));
00979
00980 connect_signal_mouse_left_click(
00981 find_widget<tbutton>(&window, "send_message", false)
00982 , boost::bind(
00983 &tlobby_main::send_message_button_callback
00984 , this
00985 , boost::ref(window)));
00986
00987 connect_signal_mouse_left_click(
00988 find_widget<tbutton>(&window, "create", false)
00989 , boost::bind(
00990 &tlobby_main::create_button_callback
00991 , this
00992 , boost::ref(window)));
00993
00994 connect_signal_mouse_left_click(
00995 find_widget<tbutton>(&window, "refresh", false)
00996 , boost::bind(
00997 &tlobby_main::refresh_button_callback
00998 , this
00999 , boost::ref(window)));
01000
01001 connect_signal_mouse_left_click(
01002 find_widget<tbutton>(&window, "show_preferences", false)
01003 , boost::bind(
01004 &tlobby_main::show_preferences_button_callback
01005 , this
01006 , boost::ref(window)));
01007
01008 connect_signal_mouse_left_click(
01009 find_widget<tbutton>(&window, "join_global", false)
01010 , boost::bind(
01011 &tlobby_main::join_global_button_callback
01012 , this
01013 , boost::ref(window)));
01014 find_widget<tbutton>(&window, "join_global", false).set_active(false);
01015
01016 connect_signal_mouse_left_click(
01017 find_widget<tbutton>(&window, "observe_global", false)
01018 , boost::bind(
01019 &tlobby_main::observe_global_button_callback
01020 , this
01021 , boost::ref(window)));
01022 find_widget<tbutton>(&window, "observe_global", false).set_active(false);
01023
01024 connect_signal_mouse_left_click(
01025 find_widget<tbutton>(&window, "close_window", false)
01026 , boost::bind(
01027 &tlobby_main::close_window_button_callback
01028 , this
01029 , boost::ref(window)));
01030
01031 ttoggle_button& skip_replay =
01032 find_widget<ttoggle_button>(&window, "skip_replay", false);
01033 skip_replay.set_value(preferences::skip_mp_replay());
01034 skip_replay.set_callback_state_change(boost::bind(&tlobby_main::skip_replay_changed_callback, this, _1));
01035
01036 filter_friends_ = find_widget<ttoggle_button>(
01037 &window, "filter_with_friends", false, true);
01038 filter_ignored_ = find_widget<ttoggle_button>(
01039 &window, "filter_without_ignored", false, true);
01040 filter_slots_ = find_widget<ttoggle_button>(
01041 &window, "filter_vacant_slots", false, true);
01042 filter_invert_ = find_widget<ttoggle_button>(
01043 &window, "filter_invert", false, true);
01044 filter_text_= find_widget<ttext_box>(&window, "filter_text", false, true);
01045
01046 filter_friends_->set_callback_state_change(
01047 boost::bind(&tlobby_main::game_filter_change_callback, this, _1));
01048 filter_ignored_->set_callback_state_change(
01049 boost::bind(&tlobby_main::game_filter_change_callback, this, _1));
01050 filter_slots_->set_callback_state_change(
01051 boost::bind(&tlobby_main::game_filter_change_callback, this, _1));
01052 filter_invert_->set_callback_state_change(
01053 boost::bind(&tlobby_main::game_filter_change_callback, this, _1));
01054 connect_signal_pre_key_press(*filter_text_, boost::bind(
01055 &tlobby_main::game_filter_keypress_callback
01056 , this
01057 , _5));
01058
01059 room_window_open("lobby", true);
01060 active_window_changed();
01061 game_filter_reload();
01062
01063
01064 tlobby_main::network_handler();
01065 lobby_update_timer_ = add_timer(game_config::lobby_network_timer
01066 , boost::bind(&tlobby_main::network_handler, this)
01067 , true);
01068 }
01069
01070 void tlobby_main::post_show(twindow& )
01071 {
01072 window_ = NULL;
01073 remove_timer(lobby_update_timer_);
01074 lobby_update_timer_ = 0;
01075 }
01076
01077 room_info* tlobby_main::active_window_room()
01078 {
01079 const tlobby_chat_window& t = open_windows_[active_window_];
01080 if (t.whisper) return NULL;
01081 return lobby_info_.get_room(t.name);
01082 }
01083
01084 tlobby_chat_window* tlobby_main::room_window_open(const std::string& room, bool open_new)
01085 {
01086 return search_create_window(room, false, open_new);
01087 }
01088
01089 tlobby_chat_window* tlobby_main::whisper_window_open(const std::string& name, bool open_new)
01090 {
01091 return search_create_window(name, true, open_new);
01092 }
01093
01094 tlobby_chat_window* tlobby_main::search_create_window(const std::string& name, bool whisper, bool open_new)
01095 {
01096 foreach (tlobby_chat_window& t, open_windows_) {
01097 if (t.name == name && t.whisper == whisper) return &t;
01098 }
01099 if (open_new) {
01100 open_windows_.push_back(tlobby_chat_window(name, whisper));
01101 std::map<std::string, string_map> data;
01102 utils::string_map symbols;
01103 symbols["name"] = name;
01104 if (whisper) {
01105 add_label_data(data, "log_header", "<" + name + ">");
01106 add_label_data(data, "log_text", VGETTEXT(
01107 "Whisper session with $name started. "
01108 "If you don’t want to receive messages from this user, "
01109 "type /ignore $name\n", symbols));
01110 } else {
01111 add_label_data(data, "log_header", name);
01112 add_label_data(data, "log_text", VGETTEXT(
01113 "Room $name joined", symbols));
01114 lobby_info_.open_room(name);
01115 }
01116 chat_log_container_->add_page(data);
01117 std::map<std::string, string_map> data2;
01118 add_label_data(data2, "room", whisper ? "<" + name + ">" : name);
01119 roomlistbox_->add_row(data2);
01120
01121 return &open_windows_.back();
01122 }
01123 return NULL;
01124 }
01125
01126 bool tlobby_main::whisper_window_active(const std::string& name)
01127 {
01128 const tlobby_chat_window& t = open_windows_[active_window_];
01129 return t.name == name && t.whisper == true;
01130 }
01131
01132 bool tlobby_main::room_window_active(const std::string& room)
01133 {
01134 const tlobby_chat_window& t = open_windows_[active_window_];
01135 return t.name == room && t.whisper == false;
01136 }
01137
01138 void tlobby_main::increment_waiting_whsipers(const std::string& name)
01139 {
01140 if (tlobby_chat_window* t = whisper_window_open(name, false)) {
01141 t->pending_messages++;
01142 if (t->pending_messages == 1) {
01143 DBG_LB << "do whisper pending mark row "
01144 << (t - &open_windows_[0]) << " with " << t->name << "\n";
01145 tgrid* grid = roomlistbox_->get_row_grid(t - &open_windows_[0]);
01146
01147
01148
01149
01150 find_widget<timage>(grid, "pending_messages", false)
01151 .set_visible(twidget::VISIBLE);
01152 }
01153 }
01154 }
01155
01156 void tlobby_main::increment_waiting_messages(const std::string& room)
01157 {
01158 if (tlobby_chat_window* t = room_window_open(room, false)) {
01159 t->pending_messages++;
01160 if (t->pending_messages == 1) {
01161 int idx = t - &open_windows_[0];
01162 DBG_LB << "do room pending mark row "
01163 << idx << " with " << t->name << "\n";
01164 tgrid* grid = roomlistbox_->get_row_grid(idx);
01165
01166
01167
01168
01169 find_widget<timage>(grid, "pending_messages", false)
01170 .set_visible(twidget::VISIBLE);
01171 }
01172 }
01173 }
01174
01175 void tlobby_main::add_whisper_window_whisper(const std::string& sender, const std::string& message)
01176 {
01177 std::stringstream ss;
01178 ss << "<" << sender << ">" << message;
01179 tlobby_chat_window* t = whisper_window_open(sender, false);
01180 if (!t) {
01181 ERR_LB << "Whisper window not open in add_whisper_window_whisper for " << sender << "\n";
01182 return;
01183 }
01184 append_to_chatbox(ss.str(), t - &open_windows_[0]);
01185 }
01186
01187 void tlobby_main::add_active_window_whisper(const std::string& sender, const std::string& message)
01188 {
01189 std::stringstream ss;
01190 ss << "<" << "whisper: " << sender << ">" << message;
01191 append_to_chatbox(ss.str());
01192 }
01193
01194 void tlobby_main::add_room_window_message(const std::string& room,
01195 const std::string& sender, const std::string& message)
01196 {
01197 std::stringstream ss;
01198 ss << "<" << sender << ">" << message;
01199 tlobby_chat_window* t = room_window_open(room, false);
01200 if (!t) {
01201 ERR_LB << "Room window not open in add_room_window_message for " << room << "\n";
01202 return;
01203 }
01204 append_to_chatbox(ss.str(), t - &open_windows_[0]);
01205 }
01206
01207 void tlobby_main::add_active_window_message(const std::string& sender, const std::string& message)
01208 {
01209 std::stringstream ss;
01210 ss << "<" << sender << ">" << message;
01211 append_to_chatbox(ss.str());
01212 }
01213
01214 void tlobby_main::switch_to_window(tlobby_chat_window* t)
01215 {
01216 switch_to_window(t - &open_windows_[0]);
01217 }
01218
01219 void tlobby_main::switch_to_window(size_t id)
01220 {
01221 active_window_ = id;
01222 assert(active_window_ < open_windows_.size());
01223 chat_log_container_->select_page(active_window_);
01224 roomlistbox_->select_row(active_window_);
01225 active_window_changed();
01226 }
01227
01228 void tlobby_main::active_window_changed()
01229 {
01230 tlabel& header = find_widget<tlabel>(
01231 &chat_log_container_->page_grid(active_window_)
01232 , "log_header"
01233 , false);
01234
01235 tlobby_chat_window& t = open_windows_[active_window_];
01236 std::string expected_label;
01237 if (t.whisper) {
01238 expected_label = "<" + t.name + ">";
01239 } else {
01240 expected_label = t.name;
01241 }
01242 if (header.label() != expected_label) {
01243 ERR_LB << "Chat log header not what it should be! "
01244 << header.label() << " vs " << expected_label << "\n";
01245 }
01246
01247 bool close_button_active = (t.whisper || (t.name != "lobby"));
01248
01249 DBG_LB << "active window changed to " << active_window_ << " "
01250 << (t.whisper ? "w" : "r") << " "
01251 << t.name << " " << t.pending_messages << " : "
01252 << expected_label
01253 << " close button:" << close_button_active << "\n";
01254
01255
01256 tgrid* grid = roomlistbox_->get_row_grid(active_window_);
01257
01258
01259
01260 find_widget<timage>(grid, "pending_messages", false)
01261 .set_visible(twidget::HIDDEN);
01262 t.pending_messages = 0;
01263
01264 find_widget<tbutton>(window_, "close_window", false)
01265 .set_active(close_button_active);
01266 player_list_dirty_ = true;
01267 }
01268
01269
01270 void tlobby_main::close_active_window()
01271 {
01272 DBG_LB << "Close window button clicked\n";
01273 return close_window(active_window_);
01274 }
01275
01276 void tlobby_main::close_window(size_t idx)
01277 {
01278 const tlobby_chat_window& t = open_windows_[idx];
01279 bool active_changed = idx == active_window_;
01280 DBG_LB << "Close window " << idx << " - " << t.name << "\n";
01281 if (t.name == "lobby" && t.whisper == false) return;
01282 if (open_windows_.size() == 1) return;
01283 if (t.whisper == false) {
01284
01285 config data, msg;
01286 msg["room"] = t.name;
01287 msg["player"] = preferences::login();
01288 data.add_child("room_part", msg);
01289 network::send_data(data, 0);
01290 }
01291 if (active_window_ == open_windows_.size() - 1) {
01292 active_window_--;
01293 }
01294 if (t.whisper) {
01295 lobby_info_.get_whisper_log(t.name).clear();
01296 } else {
01297 lobby_info_.close_room(t.name);
01298 }
01299 open_windows_.erase(open_windows_.begin() + idx);
01300 roomlistbox_->remove_row(idx);
01301 roomlistbox_->select_row(active_window_);
01302 chat_log_container_->remove_page(idx);
01303 chat_log_container_->select_page(active_window_);
01304 if (active_changed) active_window_changed();
01305 }
01306
01307 void tlobby_main::network_handler()
01308 {
01309 if (gamelist_dirty_ && !delay_gamelist_update_
01310 &&(SDL_GetTicks() - last_gamelist_update_ > game_config::lobby_refresh)) {
01311 if (gamelist_diff_update_) {
01312 update_gamelist_diff();
01313 } else {
01314 update_gamelist();
01315 gamelist_diff_update_ = true;
01316 }
01317 }
01318 if (player_list_dirty_) {
01319 update_gamelist_filter();
01320 update_playerlist();
01321 }
01322 try {
01323 config data;
01324 const network::connection sock = network::receive_data(data);
01325 if(sock) {
01326 process_network_data(data);
01327 }
01328 } catch(network::error& e) {
01329 LOG_LB << "caught network::error in network_handler: " << e.message << "\n";
01330 throw;
01331 }
01332 }
01333
01334 void tlobby_main::process_network_data(const config &data)
01335 {
01336 if (const config &c = data.child("error")) {
01337 throw network::error(c["message"]);
01338 } else if (const config &c = data.child("message")) {
01339 process_message(c);
01340 } else if (const config &c = data.child("whisper")) {
01341 process_message(c, true);
01342 } else if(data.child("gamelist")) {
01343 process_gamelist(data);
01344 } else if (const config &c = data.child("gamelist_diff")) {
01345 process_gamelist_diff(c);
01346 } else if (const config &c = data.child("room_join")) {
01347 process_room_join(c);
01348 } else if (const config &c = data.child("room_part")) {
01349 process_room_part(c);
01350 } else if (const config &c = data.child("room_query_response")) {
01351 process_room_query_response(c);
01352 }
01353 }
01354
01355 void tlobby_main::process_message(const config &data, bool whisper )
01356 {
01357 std::string sender = data["sender"];
01358 DBG_LB << "process message from " << sender << " "
01359 << (whisper ? "(w)" : "") << ", len " << data["message"].str().size() << '\n';
01360 if (preferences::is_ignored(sender)) return;
01361 const std::string& message = data["message"];
01362 preferences::parse_admin_authentication(sender, message);
01363 if (whisper) {
01364 add_whisper_received(sender, message);
01365 } else {
01366 std::string room = data["room"];
01367 if (room.empty()) {
01368 LOG_LB << "Message without a room from " << sender << ", assuming lobby\n";
01369 room = "lobby";
01370 }
01371 add_chat_room_message_received(room, sender, message);
01372 }
01373 }
01374
01375 void tlobby_main::process_gamelist(const config &data)
01376 {
01377 lobby_info_.process_gamelist(data);
01378 DBG_LB << "Received gamelist\n";
01379 gamelist_dirty_ = true;
01380 gamelist_diff_update_ = false;
01381 }
01382
01383 void tlobby_main::process_gamelist_diff(const config &data)
01384 {
01385 if (lobby_info_.process_gamelist_diff(data)) {
01386 DBG_LB << "Received gamelist diff\n";
01387 gamelist_dirty_ = true;
01388 } else {
01389 ERR_LB << "process_gamelist_diff failed!\n";
01390 }
01391 int joined = data.child_count("insert_child");
01392 int left = data.child_count("remove_child");
01393 if (joined > 0 || left > 0) {
01394 if (left > joined) {
01395 do_notify(NOTIFY_LOBBY_QUIT);
01396 } else {
01397 do_notify(NOTIFY_LOBBY_JOIN);
01398 }
01399 }
01400 }
01401
01402 void tlobby_main::process_room_join(const config &data)
01403 {
01404 const std::string& room = data["room"];
01405 const std::string& player = data["player"];
01406 room_info* r = lobby_info_.get_room(room);
01407 DBG_LB << "room join: " << room << " " << player << " "
01408 << static_cast<void*>(r) << "\n";
01409
01410 if (r) {
01411 if (player == preferences::login()) {
01412 if (const config& members = data.child("members")) {
01413 r->process_room_members(members);
01414 }
01415 } else {
01416 r->add_member(player);
01417
01418 utils::string_map symbols;
01419 symbols["player"] = player;
01420 add_room_window_message(room, "server", VGETTEXT("$player has entered the room", symbols));
01421 }
01422 if (r == active_window_room()) {
01423 player_list_dirty_ = true;
01424 }
01425 } else {
01426 if (player == preferences::login()) {
01427 tlobby_chat_window* t = room_window_open(room, true);
01428 lobby_info_.open_room(room);
01429 r = lobby_info_.get_room(room);
01430 assert(r);
01431 if (const config& members = data.child("members")) {
01432 r->process_room_members(members);
01433 }
01434 switch_to_window(t);
01435
01436 const std::string& topic = data["topic"];
01437 if (!topic.empty()) {
01438 add_chat_room_message_received("room", "server", room + ": " + topic);
01439 }
01440 } else {
01441 LOG_LB << "Discarding join info for a room the player is not in\n";
01442 }
01443 }
01444 }
01445
01446 void tlobby_main::process_room_part(const config &data)
01447 {
01448
01449 const std::string& room = data["room"];
01450 const std::string& player = data["player"];
01451 DBG_LB << "Room part: " << room << " " << player << "\n";
01452 room_info* r = lobby_info_.get_room(room);
01453 if (r) {
01454 r->remove_member(player);
01455
01456 utils::string_map symbols;
01457 symbols["player"] = player;
01458 add_room_window_message(room, "server", VGETTEXT("$player has left the room", symbols));
01459 if (active_window_room() == r) {
01460 player_list_dirty_ = true;
01461 }
01462 } else {
01463 LOG_LB << "Discarding part info for a room the player is not in\n";
01464 }
01465 }
01466
01467 void tlobby_main::process_room_query_response(const config& data)
01468 {
01469 const std::string& room = data["room"];
01470 const std::string& message = data["message"];
01471 DBG_LB << "room query response: " << room << " " << message << "\n";
01472 if (room.empty()) {
01473 if (!message.empty()) {
01474 add_active_window_message("server", message);
01475 }
01476 if (const config& rooms = data.child("rooms")) {
01477
01478 std::stringstream ss;
01479 ss << "Rooms:";
01480 foreach (const config& r, rooms.child_range("room")) {
01481 ss << " " << r["name"];
01482 }
01483 add_active_window_message("server", ss.str());
01484 }
01485 } else {
01486 if (room_window_open(room, false)) {
01487 if (!message.empty()) {
01488 add_chat_room_message_received(room, "server", message);
01489 }
01490 if (const config& members = data.child("members")) {
01491 room_info* r = lobby_info_.get_room(room);
01492 assert(r);
01493 r->process_room_members(members);
01494 if (r == active_window_room()) {
01495 player_list_dirty_ = true;
01496 }
01497 }
01498 } else {
01499 if (!message.empty()) {
01500 add_active_window_message("server", room + ": " + message);
01501 }
01502 }
01503 }
01504 }
01505
01506 void tlobby_main::join_button_callback(gui2::twindow &window)
01507 {
01508 LOG_LB << "join_button_callback\n";
01509 join_global_button_callback(window);
01510 }
01511
01512 void tlobby_main::observe_button_callback(gui2::twindow &window)
01513 {
01514 LOG_LB << "observe_button_callback\n";
01515 observe_global_button_callback(window);
01516 }
01517
01518 void tlobby_main::observe_global_button_callback(gui2::twindow &window)
01519 {
01520 LOG_LB << "observe_global_button_callback\n";
01521 if (do_game_join(gamelistbox_->get_selected_row(), true)) {
01522 legacy_result_ = OBSERVE;
01523 window.close();
01524 }
01525 }
01526
01527 void tlobby_main::join_global_button_callback(gui2::twindow &window)
01528 {
01529 LOG_LB << "join_global_button_callback\n";
01530 if (do_game_join(gamelistbox_->get_selected_row(), false)) {
01531 legacy_result_ = JOIN;
01532 window.close();
01533 }
01534 }
01535
01536 void tlobby_main::join_or_observe(int idx)
01537 {
01538 const game_info& game = *lobby_info_.games()[idx];
01539 if (do_game_join(idx, !game.can_join())) {
01540 legacy_result_ = game.can_join() ? JOIN : OBSERVE;
01541 window_->close();
01542 }
01543 }
01544
01545 bool tlobby_main::do_game_join(int idx, bool observe)
01546 {
01547 if (idx < 0 || idx > static_cast<int>(lobby_info_.games().size())) {
01548 ERR_LB << "Requested join/observe of a game with index out of range: "
01549 << idx << ", games size is " << lobby_info_.games().size() << "\n";
01550 return false;
01551 }
01552 const game_info& game = *lobby_info_.games()[idx];
01553 if (observe) {
01554 if (!game.can_observe()) {
01555 ERR_LB << "Requested observe of a game with observers disabled\n";
01556 return false;
01557 }
01558 } else {
01559 if (!game.can_join()) {
01560 ERR_LB << "Requested join to a game with no vacant slots\n";
01561 return false;
01562 }
01563 }
01564 config response;
01565 config& join = response.add_child("join");
01566 join["id"] = lexical_cast<std::string>(game.id);
01567 join["observe"] = observe;
01568 if (join && !observe && game.password_required) {
01569 std::string password;
01570
01571 const int res = gui::show_dialog(disp_, NULL, _("Password Required"),
01572 _("Joining this game requires a password."),
01573 gui::OK_CANCEL, NULL, NULL, _("Password: "), &password);
01574 if (res != 0) {
01575 return false;
01576 }
01577 if(!password.empty()) {
01578 join["password"] = password;
01579 }
01580 }
01581 network::send_data(response, 0);
01582 if (observe && game.started) {
01583 playmp_controller::set_replay_last_turn(game.current_turn);
01584 }
01585 return true;
01586 }
01587
01588 void tlobby_main::send_message_button_callback(gui2::twindow &)
01589 {
01590 const std::string& input = chat_input_->get_value();
01591 if (input.empty()) return;
01592 if (input[0] == '/') {
01593
01594
01595
01596 chat_handler::do_speak(input);
01597 } else {
01598 config msg;
01599 send_message_to_active_window(input);
01600 }
01601 chat_input_->save_to_history();
01602 chat_input_->set_value("");
01603 }
01604
01605 void tlobby_main::send_message_to_active_window(const std::string& input)
01606 {
01607 tlobby_chat_window& t = open_windows_[active_window_];
01608 if (t.whisper) {
01609 send_whisper(t.name, input);
01610 add_whisper_sent(t.name, input);
01611 } else {
01612 send_chat_room_message(t.name, input);
01613 add_chat_room_message_sent(t.name, input);
01614 }
01615 }
01616
01617 void tlobby_main::close_window_button_callback(twindow& )
01618 {
01619 close_active_window();
01620 }
01621
01622 void tlobby_main::create_button_callback(gui2::twindow& window)
01623 {
01624 legacy_result_ = CREATE;
01625 window.close();
01626 }
01627
01628 void tlobby_main::refresh_button_callback(gui2::twindow& )
01629 {
01630 network::send_data(config("refresh_lobby"), 0);
01631 }
01632
01633
01634 void tlobby_main::show_preferences_button_callback(gui2::twindow& window)
01635 {
01636 if (preferences_callback_) {
01637 preferences_callback_();
01638
01639
01640
01641
01642
01643
01644 window.invalidate_layout();
01645
01646 network::send_data(config("refresh_lobby"), 0);
01647 }
01648 }
01649
01650 void tlobby_main::room_switch_callback(twindow& )
01651 {
01652 switch_to_window(roomlistbox_->get_selected_row());
01653 }
01654
01655 void tlobby_main::chat_input_keypress_callback(
01656 bool& handled
01657 , bool& halt
01658 , const SDLKey key
01659 , twindow& window)
01660 {
01661 if (key == SDLK_RETURN || key == SDLK_KP_ENTER) {
01662 send_message_button_callback(window);
01663 handled = true;
01664 halt = true;
01665 } else if(key == SDLK_TAB) {
01666 std::string text = chat_input_->get_value();
01667 const std::vector<user_info>& match_infos = lobby_info_.users();
01668 std::vector<std::string> matches;
01669
01670 foreach(const user_info& ui, match_infos) {
01671 if(ui.name != preferences::login()) {
01672 matches.push_back(ui.name);
01673 }
01674 }
01675 const bool line_start = utils::word_completion(text, matches);
01676
01677 if (matches.empty()) {
01678 return;
01679 }
01680
01681 if (matches.size() == 1) {
01682 text.append(line_start ? ": " : " ");
01683 } else {
01684 std::string completion_list = utils::join(matches, " ");
01685 append_to_chatbox(completion_list);
01686 }
01687 chat_input_->set_value(text);
01688 handled = true;
01689 halt = true;
01690 }
01691 }
01692
01693 void tlobby_main::game_filter_reload()
01694 {
01695 lobby_info_.clear_game_filter();
01696
01697 foreach (const std::string& s, utils::split(filter_text_->get_value(), ' ')) {
01698 lobby_info_.add_game_filter(new game_filter_general_string_part(s));
01699 }
01700
01701 if (filter_friends_->get_value()) {
01702 lobby_info_.add_game_filter(
01703 new game_filter_value<bool, &game_info::has_friends>(true));
01704 }
01705 if (filter_ignored_->get_value()) {
01706 lobby_info_.add_game_filter(
01707 new game_filter_value<bool, &game_info::has_ignored>(false));
01708 }
01709 if (filter_slots_->get_value()) {
01710 lobby_info_.add_game_filter(
01711 new game_filter_value<size_t, &game_info::vacant_slots, std::greater<size_t> >(0));
01712 }
01713 lobby_info_.set_game_filter_invert(filter_invert_->get_value());
01714 }
01715
01716 void tlobby_main::game_filter_keypress_callback(const SDLKey key)
01717 {
01718 if (key == SDLK_RETURN || key == SDLK_KP_ENTER) {
01719 game_filter_reload();
01720 update_gamelist_filter();
01721 }
01722 }
01723
01724 void tlobby_main::game_filter_change_callback(gui2::twidget* )
01725 {
01726 game_filter_reload();
01727 update_gamelist_filter();
01728 }
01729
01730 void tlobby_main::gamelist_change_callback(gui2::twindow &)
01731 {
01732 update_selected_game();
01733 }
01734
01735 void tlobby_main::player_filter_callback(gui2::twidget* )
01736 {
01737 player_list_.update_sort_icons();
01738 preferences::set_playerlist_sort_relation(player_list_.sort_by_relation->get_value());
01739 preferences::set_playerlist_sort_name(player_list_.sort_by_name->get_value());
01740 player_list_dirty_ = true;
01741
01742 }
01743
01744 void tlobby_main::user_dialog_callback(user_info* info)
01745 {
01746 tlobby_player_info dlg(*this, *info, lobby_info_);
01747 lobby_delay_gamelist_update_guard g(*this);
01748 dlg.show(window_->video());
01749 delay_playerlist_update_ = true;
01750 if (dlg.result_open_whisper()) {
01751 tlobby_chat_window* t = whisper_window_open(info->name, true);
01752 switch_to_window(t);
01753 window_->invalidate_layout();
01754 }
01755 selected_game_id_ = info->game_id;
01756
01757
01758
01759
01760
01761
01762
01763
01764
01765
01766
01767
01768
01769
01770
01771
01772
01773
01774 delay_playerlist_update_ = false;
01775 player_list_dirty_ = true;
01776 network::send_data(config("refresh_lobby"), 0);
01777 }
01778
01779 void tlobby_main::skip_replay_changed_callback(twidget* w)
01780 {
01781 ttoggle_button* tb = dynamic_cast<ttoggle_button*>(w);
01782 assert(tb);
01783 preferences::set_skip_mp_replay(tb->get_value());
01784 }
01785
01786 }