The Battle for Wesnoth  1.15.1+dev
chatbox.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2016 - 2018 The Battle for Wesnoth Project https://www.wesnoth.org/
3 
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or
7  (at your option) any later version.
8  This program is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY.
10 
11  See the COPYING file for more details.
12 */
13 
14 #define GETTEXT_DOMAIN "wesnoth-lib"
15 
16 #include "gui/widgets/chatbox.hpp"
17 
19 
21 #include "gui/widgets/button.hpp"
22 #include "gui/widgets/image.hpp"
23 #include "gui/widgets/label.hpp"
24 #include "gui/widgets/listbox.hpp"
27 #include "gui/widgets/settings.hpp"
28 #include "gui/widgets/text_box.hpp"
29 #include "gui/widgets/window.hpp"
30 
31 #include "font/pango/escape.hpp"
32 #include "formatter.hpp"
33 #include "formula/string_utils.hpp"
34 #include "gettext.hpp"
35 #include "log.hpp"
37 #include "preferences/game.hpp"
38 #include "preferences/lobby.hpp"
40 #include "wesnothd_connection.hpp"
41 
42 static lg::log_domain log_lobby("lobby");
43 #define DBG_LB LOG_STREAM(debug, log_lobby)
44 #define LOG_LB LOG_STREAM(info, log_lobby)
45 #define ERR_LB LOG_STREAM(err, log_lobby)
46 
47 #define LOG_SCOPE_HEADER get_control_type() + " [" + id() + "] " + __func__
48 #define LOG_HEADER LOG_SCOPE_HEADER + ':'
49 
50 namespace gui2
51 {
52 
53 // ------------ WIDGET -----------{
54 
55 REGISTER_WIDGET(chatbox)
56 
57 chatbox::chatbox(const implementation::builder_chatbox& builder)
58  : container_base(builder, type())
59  , roomlistbox_(nullptr)
60  , chat_log_container_(nullptr)
61  , chat_input_(nullptr)
62  , active_window_(0)
63  , active_window_changed_callback_()
64  , lobby_info_(nullptr)
65  , wesnothd_connection_(nullptr)
66  , log_(nullptr)
67 {
68  // We only implement a RECEIVE_KEYBOARD_FOCUS handler; LOSE_KEYBOARD_FOCUS
69  // isn't needed. This handler forwards focus to the input textbox, meaning
70  // if keyboard_focus is called on a chatbox, distributor::keyboard_focus_
71  // will immediately be set to the input textbox, which will then handle focus
72  // loss itself when applicable. Nothing else happens in the interim while
73  // keyboard_focus_ equals `this` to warrent cleanup.
74  connect_signal<event::RECEIVE_KEYBOARD_FOCUS>(
76 }
77 
79 {
80  roomlistbox_ = find_widget<listbox>(this, "room_list", false, true);
81 
82  // We need to bind a lambda here since switch_to_window is overloaded.
83  // A lambda alone would be more verbose because it'd need to specify all the parameters.
85  std::bind([this]() { switch_to_window(roomlistbox_->get_selected_row()); }));
86 
87  chat_log_container_ = find_widget<multi_page>(this, "chat_log_container", false, true);
88 
89  chat_input_ = find_widget<text_box>(this, "chat_input", false, true);
90 
91  connect_signal_pre_key_press(*chat_input_,
92  std::bind(&chatbox::chat_input_keypress_callback, this, _5));
93 }
94 
95 void chatbox::load_log(std::map<std::string, chatroom_log>& log, bool show_lobby)
96 {
97  for(const auto& l : log) {
98  const bool is_lobby = l.first == "lobby";
99 
100  if(!show_lobby && is_lobby && !l.second.whisper) {
101  continue;
102  }
103 
104  find_or_create_window(l.first, l.second.whisper, true, !is_lobby, l.second.log);
105  }
106 
107  log_ = &log;
108 }
109 
111 {
113 
114  // Clear pending messages notification in room listbox
116  find_widget<image>(grid, "pending_messages", false).set_visible(widget::visibility::hidden);
117 
118  t.pending_messages = 0;
119 
122  }
123 }
124 
126 {
128 }
129 
130 void chatbox::switch_to_window(std::size_t id)
131 {
132  active_window_ = id;
133  assert(active_window_ < open_windows_.size());
134 
137 
138  // Grab input focus
140 
142 }
143 
144 void chatbox::chat_input_keypress_callback(const SDL_Keycode key)
145 {
146  std::string input = chat_input_->get_value();
147  if(input.empty() || chat_input_->is_composing()) {
148  return;
149  }
150 
151  switch(key) {
152  case SDLK_RETURN:
153  case SDLK_KP_ENTER: {
154  if(input[0] == '/') {
155  // TODO: refactor do_speak so it uses context information about
156  // opened window, so e.g. /ignore in a whisper session ignores
157  // the other party without having to specify it's nick.
158  chat_handler::do_speak(input);
159  } else {
161 
162  if(t.whisper) {
163  send_whisper(t.name, input);
164  add_whisper_sent(t.name, input);
165  } else {
166  send_chat_room_message(t.name, input);
168  }
169  }
170 
172  chat_input_->set_value("");
173 
174  break;
175  }
176 
177  case SDLK_TAB: {
178  // TODO: very inefficient! Very! D:
179  std::vector<std::string> matches;
180  for(const auto& ui : lobby_info_->users()) {
181  if(ui.name != preferences::login()) {
182  matches.push_back(ui.name);
183  }
184  }
185 
186  const bool line_start = utils::word_completion(input, matches);
187 
188  if(matches.empty()) {
189  return;
190  }
191 
192  if(matches.size() == 1) {
193  input.append(line_start ? ": " : " ");
194  } else {
195  std::string completion_list = utils::join(matches, " ");
196  append_to_chatbox(completion_list);
197  }
198 
199  chat_input_->set_value(input);
200 
201  break;
202  }
203 
204  default:
205  break;
206  }
207 }
208 
209 void chatbox::append_to_chatbox(const std::string& text, const bool force_scroll)
210 {
211  append_to_chatbox(text, active_window_, force_scroll);
212 }
213 
214 void chatbox::append_to_chatbox(const std::string& text, std::size_t id, const bool force_scroll)
215 {
217 
218  scroll_label& log = find_widget<scroll_label>(&grid, "log_text", false);
219  const bool chatbox_at_end = log.vertical_scrollbar_at_end();
220  const unsigned chatbox_position = log.get_vertical_scrollbar_item_position();
221 
222  const std::string new_text = formatter()
223  << log.get_label() << "\n" << "<span color='#bcb088'>" << preferences::get_chat_timestamp(std::time(0)) << text << "</span>";
224 
225  log.set_use_markup(true);
226  log.set_label(new_text);
227 
228  if(log_ != nullptr) {
229  try {
230  const std::string& room_name = open_windows_[id].name;
231  log_->at(room_name).log = new_text;
232  } catch(const std::out_of_range&) {
233  }
234  }
235 
236  if(chatbox_at_end || force_scroll) {
238  } else {
239  log.set_vertical_scrollbar_item_position(chatbox_position);
240  }
241 }
242 
243 void chatbox::send_chat_message(const std::string& message, bool /*allies_only*/)
244 {
245  add_chat_message(std::time(nullptr), preferences::login(), 0, message);
246 
247  ::config c {"message", ::config {"message", message, "sender", preferences::login()}};
248  send_to_server(c);
249 }
250 
251 void chatbox::user_relation_changed(const std::string& /*name*/)
252 {
255  }
256 }
257 
258 void chatbox::add_chat_message(const std::time_t& /*time*/,
259  const std::string& speaker,
260  int /*side*/,
261  const std::string& message,
263 {
264  std::string text;
265 
266  // FIXME: the chat_command_handler class (which handles chat commands) dispatches a
267  // message consisting of '/me insert text here' in the case the '/me' or '/emote'
268  // commands are used, so we need to do some manual preprocessing here.
269  if(message.compare(0, 4, "/me ") == 0) {
270  text = formatter() << "<i>" << speaker << " " << font::escape_text(message.substr(4)) << "</i>";
271  } else {
272  text = formatter() << "<b>" << speaker << ":</b> " << font::escape_text(message);
273  }
274 
275  append_to_chatbox(text);
276 }
277 
278 void chatbox::add_whisper_sent(const std::string& receiver, const std::string& message)
279 {
280  if(whisper_window_active(receiver)) {
285  } else {
286  add_active_window_whisper(VGETTEXT("whisper to $receiver", {{"receiver", receiver}}), message, true);
287  }
288 
290 }
291 
292 void chatbox::add_whisper_received(const std::string& sender, const std::string& message)
293 {
294  bool can_go_to_active = !preferences::whisper_friends_only() || preferences::is_friend(sender);
295  bool can_open_new = preferences::auto_open_whisper_windows() && can_go_to_active;
296 
297  lobby_info_->get_whisper_log(sender).add_message(sender, message);
298 
299  if(whisper_window_open(sender, can_open_new)) {
300  if(whisper_window_active(sender)) {
301  add_active_window_message(sender, message);
302 
303  do_notify(mp::NOTIFY_WHISPER, sender, message);
304  } else {
305  add_whisper_window_whisper(sender, message);
307 
308  do_notify(mp::NOTIFY_WHISPER_OTHER_WINDOW, sender, message);
309  }
310  } else if(can_go_to_active) {
311  add_active_window_whisper(sender, message);
312  do_notify(mp::NOTIFY_WHISPER, sender, message);
313  } else {
314  LOG_LB << "Ignoring whisper from " << sender << "\n";
315  }
316 }
317 
318 void chatbox::add_chat_room_message_sent(const std::string& room, const std::string& message)
319 {
320  lobby_chat_window* t = room_window_open(room, false);
321  if(!t) {
322  LOG_LB << "Cannot add sent message to ui for room " << room << ", player not in the room\n";
323  return;
324  }
325 
326  // Do not open room window here. The player should be in the room before sending messages
327  mp::room_info* ri = lobby_info_->get_room(room);
328  assert(ri);
329 
330  if(!room_window_active(room)) {
331  switch_to_window(t);
332  }
333 
334  ri->log().add_message(preferences::login(), message);
336 }
337 
338 void chatbox::add_chat_room_message_received(const std::string& room,
339  const std::string& speaker,
340  const std::string& message)
341 {
342  mp::room_info* ri = lobby_info_->get_room(room);
343  if(!ri) {
344  LOG_LB << "Discarding message to room " << room << " from " << speaker << " (room not open)\n";
345  return;
346  }
347 
349  ri->log().add_message(speaker, message);
350 
351  if(room_window_active(room)) {
352  add_active_window_message(speaker, message);
353  notify_mode = mp::NOTIFY_MESSAGE;
354  } else {
355  add_room_window_message(room, speaker, message);
357  notify_mode = mp::NOTIFY_MESSAGE_OTHER_WINDOW;
358  }
359 
360  if(speaker == "server") {
361  notify_mode = mp::NOTIFY_SERVER_MESSAGE;
362  } else if (utils::word_match(message, preferences::login())) {
363  notify_mode = mp::NOTIFY_OWN_NICK;
364  } else if (preferences::is_friend(speaker)) {
365  notify_mode = mp::NOTIFY_FRIEND_MESSAGE;
366  }
367 
368  do_notify(notify_mode, speaker, message);
369 }
370 
371 bool chatbox::whisper_window_active(const std::string& name)
372 {
374  return t.name == name && t.whisper == true;
375 }
376 
377 bool chatbox::room_window_active(const std::string& room)
378 {
380  return t.name == room && t.whisper == false;
381 }
382 
383 lobby_chat_window* chatbox::room_window_open(const std::string& room, const bool open_new, const bool allow_close)
384 {
385  return find_or_create_window(room, false, open_new, allow_close,
386  VGETTEXT("Room <i>“$name”</i> joined", { { "name", translation::dsgettext("wesnoth-lib", room.c_str()) } }));
387 }
388 
389 lobby_chat_window* chatbox::whisper_window_open(const std::string& name, bool open_new)
390 {
391  return find_or_create_window(name, true, open_new, true,
392  VGETTEXT("Whisper session with <i>“$name”</i> started. "
393  "If you do not want to receive messages from this user, type <i>/ignore $name</i>", { { "name", name } }));
394 }
395 
397  const bool whisper,
398  const bool open_new,
399  const bool allow_close,
400  const std::string& initial_text)
401 {
402  for(auto& t : open_windows_) {
403  if(t.name == name && t.whisper == whisper) {
404  return &t;
405  }
406  }
407 
408  if(!open_new) {
409  return nullptr;
410  }
411 
412  open_windows_.emplace_back(name, whisper);
413 
414  //
415  // Add a new chat log page.
416  //
418  item["use_markup"] = "true";
419  item["label"] = initial_text;
420  std::map<std::string, string_map> data{{"log_text", item}};
421 
422  if(!whisper) {
423  lobby_info_->open_room(name);
424  }
425 
426  if(log_ != nullptr) {
427  log_->emplace(name, chatroom_log{item["label"], whisper});
428  }
429 
431 
432  //
433  // Add a new room window tab.
434  //
435  data.clear();
436  item.clear();
437 
438  if(!whisper) {
439  item["label"] = translation::dsgettext("wesnoth-lib", name.c_str());
440  } else {
441  item["label"] = "<" + name + ">";
442  }
443 
444  data.emplace("room", item);
445 
446  grid& row_grid = roomlistbox_->add_row(data);
447 
448  //
449  // Set up the Close Window button.
450  //
451  button& close_button = find_widget<button>(&row_grid, "close_window", false);
452 
453  if(!allow_close) {
455  } else {
456  connect_signal_mouse_left_click(close_button,
457  std::bind(&chatbox::close_window_button_callback, this, open_windows_.back().name, _3, _4));
458  }
459 
460  return &open_windows_.back();
461 }
462 
463 void chatbox::close_window_button_callback(std::string room_name, bool& handled, bool& halt)
464 {
465  const int index = std::distance(open_windows_.begin(), std::find_if(open_windows_.begin(), open_windows_.end(),
466  [&room_name](const lobby_chat_window& room) { return room.name == room_name; }
467  ));
468 
469  close_window(index);
470 
471  handled = halt = true;
472 }
473 
474 void chatbox::send_to_server(const ::config& cfg)
475 {
478  }
479 }
480 
482 {
483  if(lobby_chat_window* t = whisper_window_open(name, false)) {
484  ++t->pending_messages;
485 
486  if(t->pending_messages == 1) {
487  DBG_LB << "do whisper pending mark row " << (t - &open_windows_[0]) << " with " << t->name << "\n";
488 
490  find_widget<image>(grid, "pending_messages", false).set_visible(widget::visibility::visible);
491  }
492  }
493 }
494 
495 void chatbox::increment_waiting_messages(const std::string& room)
496 {
497  if(lobby_chat_window* t = room_window_open(room, false)) {
498  ++t->pending_messages;
499 
500  if(t->pending_messages == 1) {
501  int idx = t - &open_windows_[0];
502 
503  DBG_LB << "do room pending mark row " << idx << " with " << t->name << "\n";
504 
506  find_widget<image>(grid, "pending_messages", false).set_visible(widget::visibility::visible);
507  }
508  }
509 }
510 
511 void chatbox::add_whisper_window_whisper(const std::string& sender, const std::string& message)
512 {
513  lobby_chat_window* t = whisper_window_open(sender, false);
514  if(!t) {
515  ERR_LB << "Whisper window not open in add_whisper_window_whisper for " << sender << "\n";
516  return;
517  }
518 
519  const std::string text = formatter() << "<b>" << sender << ":</b> " << font::escape_text(message);
520  append_to_chatbox(text, t - &open_windows_[0], false);
521 }
522 
523 void chatbox::add_active_window_whisper(const std::string& sender,
524  const std::string& message,
525  const bool force_scroll)
526 {
527  const std::string text = formatter() << "<b>" << "whisper: " << sender << ":</b> " << font::escape_text(message);
528  append_to_chatbox(text, force_scroll);
529 }
530 
531 void chatbox::close_window(std::size_t idx)
532 {
533  const lobby_chat_window& t = open_windows_[idx];
534 
535  DBG_LB << "Close window " << idx << " - " << t.name << "\n";
536 
537  // Can't close the lobby!
538  if((t.name == "lobby" && t.whisper == false) || open_windows_.size() == 1) {
539  return;
540  }
541 
542  if(t.whisper == false) {
543  // closing a room window -- send a part to the server
544  ::config data, msg;
545  msg["room"] = t.name;
546  msg["player"] = preferences::login();
547  data.add_child("room_part", std::move(msg));
548 
549  send_to_server(data);
550  }
551 
552  // Check if we're closing the currently-active window.
553  const bool active_changed = idx == active_window_;
554 
555  if(active_window_ == open_windows_.size() - 1) {
556  --active_window_;
557  }
558 
559  if(t.whisper) {
561  } else {
563  }
564 
565  if(log_ != nullptr) {
566  log_->erase(t.name);
567  }
568 
569  open_windows_.erase(open_windows_.begin() + idx);
570 
571  roomlistbox_->remove_row(idx);
573 
576 
577  if(active_changed) {
579  }
580 }
581 
582 void chatbox::add_room_window_message(const std::string& room,
583  const std::string& sender,
584  const std::string& message)
585 {
586  lobby_chat_window* t = room_window_open(room, false);
587  if(!t) {
588  ERR_LB << "Room window not open in add_room_window_message for " << room << "\n";
589  return;
590  }
591 
592  const std::string text = formatter() << "<b>" << sender << ":</b> " << font::escape_text(message);
593  append_to_chatbox(text, t - &open_windows_[0], false);
594 }
595 
596 void chatbox::add_active_window_message(const std::string& sender,
597  const std::string& message,
598  const bool force_scroll)
599 {
600  const std::string text = formatter() << "<b>" << sender << ":</b> " << font::escape_text(message);
601  append_to_chatbox(text, force_scroll);
602 }
603 
605 {
607  if(t.whisper) {
608  return nullptr;
609  }
610 
611  return lobby_info_->get_room(t.name);
612 }
613 
614 void chatbox::process_room_join(const ::config& data)
615 {
616  const std::string& room = data["room"];
617  const std::string& player = data["player"];
618 
619  DBG_LB << "room join: " << room << " " << player << "\n";
620 
621  mp::room_info* r = lobby_info_->get_room(room);
622  if(r) {
623  if(player == preferences::login()) {
624  if(const auto& members = data.child("members")) {
625  r->process_room_members(members);
626  }
627  } else {
628  r->add_member(player);
629 
630  /* TODO: add/use preference */
631  add_room_window_message(room, "server", VGETTEXT("$player has entered the room", {{"player", player}}));
632  }
633 
634  if(r == active_window_room()) {
636  }
637  } else {
638  if(player == preferences::login()) {
639  lobby_chat_window* t = room_window_open(room, true);
640 
641  lobby_info_->open_room(room);
642  r = lobby_info_->get_room(room);
643  assert(r);
644 
645  if(const auto& members = data.child("members")) {
646  r->process_room_members(members);
647  }
648 
649  switch_to_window(t);
650 
651  const std::string& topic = data["topic"];
652  if(!topic.empty()) {
653  add_chat_room_message_received("room", "server", room + ": " + topic);
654  }
655  } else {
656  LOG_LB << "Discarding join info for a room the player is not in\n";
657  }
658  }
659 }
660 
661 void chatbox::process_room_part(const ::config& data)
662 {
663  // TODO: close room window when the part message is sent
664  const std::string& room = data["room"];
665  const std::string& player = data["player"];
666 
667  DBG_LB << "Room part: " << room << " " << player << "\n";
668 
669  if(mp::room_info* r = lobby_info_->get_room(room)) {
670  r->remove_member(player);
671 
672  /* TODO: add/use preference */
673  add_room_window_message(room, "server", VGETTEXT("$player has left the room", {{"player", player}}));
674  if(active_window_room() == r) {
676  }
677  } else {
678  LOG_LB << "Discarding part info for a room the player is not in\n";
679  }
680 }
681 
682 void chatbox::process_room_query_response(const ::config& data)
683 {
684  const std::string& room = data["room"];
685  const std::string& message = data["message"];
686 
687  DBG_LB << "room query response: " << room << " " << message << "\n";
688 
689  if(room.empty()) {
690  if(!message.empty()) {
691  add_active_window_message("server", message);
692  }
693 
694  if(const ::config& rooms = data.child("rooms")) {
695  // TODO: this should really open a nice join room dialog instead
696  std::stringstream ss;
697  ss << "Rooms:";
698 
699  for(const auto & r : rooms.child_range("room")) {
700  ss << " " << r["name"];
701  }
702 
703  add_active_window_message("server", ss.str());
704  }
705  } else {
706  if(room_window_open(room, false)) {
707  if(!message.empty()) {
708  add_chat_room_message_received(room, "server", message);
709  }
710 
711  if(const ::config& members = data.child("members")) {
712  mp::room_info* r = lobby_info_->get_room(room);
713  assert(r);
714  r->process_room_members(members);
715  if(r == active_window_room()) {
717  }
718  }
719  } else {
720  if(!message.empty()) {
721  add_active_window_message("server", room + ": " + message);
722  }
723  }
724  }
725 }
726 
727 void chatbox::process_message(const ::config& data, bool whisper /*= false*/)
728 {
729  std::string sender = data["sender"];
730  DBG_LB << "process message from " << sender << " " << (whisper ? "(w)" : "")
731  << ", len " << data["message"].str().size() << '\n';
732 
733  if(preferences::is_ignored(sender)) {
734  return;
735  }
736 
737  const std::string& message = data["message"];
739 
740  if(whisper) {
741  add_whisper_received(sender, message);
742  } else {
743  std::string room = data["room"];
744 
745  // Attempt to send to the currently active room first.
746  if(room.empty()) {
747  LOG_LB << "Message without a room from " << sender << ", falling back to active window\n";
748  room = open_windows_[active_window_].name;
749  }
750 
751  // If we still don't have a name, fall back to lobby.
752  if(room.empty()) {
753  LOG_LB << "Message without a room from " << sender << ", assuming lobby\n";
754  room = "lobby";
755  }
756 
757  add_chat_room_message_received(room, sender, message);
758  }
759 
760  // Notify plugins about the message
761  ::config plugin_data = data;
762  plugin_data["whisper"] = whisper;
763  plugins_manager::get()->notify_event("chat", plugin_data);
764 }
765 
766 void chatbox::process_network_data(const ::config& data)
767 {
768  if(const ::config& message = data.child("message")) {
770  } else if(const ::config& whisper = data.child("whisper")) {
771  process_message(whisper, true);
772  } else if(const ::config& room_join = data.child("room_join")) {
773  process_room_join(room_join);
774  } else if(const ::config& room_part = data.child("room_part")) {
775  process_room_part(room_part);
776  } else if(const ::config& room_query_response = data.child("room_query_response")) {
777  process_room_query_response(room_query_response);
778  }
779 }
780 
782 {
783  DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
784 
785  // Forward focus to the input textbox.
787 }
788 
789 // }---------- DEFINITION ---------{
790 
793 {
794  load_resolutions<resolution>(cfg);
795 }
796 
798  : resolution_definition(cfg), grid()
799 {
800  state.emplace_back(cfg.child("background"));
801  state.emplace_back(cfg.child("foreground"));
802 
803  const config& child = cfg.child("grid");
804  VALIDATE(child, _("No grid defined."));
805 
806  grid = std::make_shared<builder_grid>(child);
807 }
808 // }---------- BUILDER -----------{
809 
810 namespace implementation
811 {
812 
813 builder_chatbox::builder_chatbox(const config& cfg)
814  : builder_styled_widget(cfg)
815 {
816 }
817 
819 {
820  chatbox* widget = new chatbox(*this);
821 
822  DBG_GUI_G << "Window builder: placed unit preview pane '" << id
823  << "' with definition '" << definition << "'.\n";
824 
825  const auto conf = widget->cast_config_to<chatbox_definition>();
826  assert(conf);
827 
828  widget->init_grid(conf->grid);
829  widget->finalize_setup();
830 
831  return widget;
832 }
833 
834 } // namespace implementation
835 
836 // }------------ END --------------
837 
838 } // namespace gui2
bool is_composing() const
void send_data(const configr_of &request)
void switch_to_window(lobby_chat_window *t)
Switch to the window given by a valid pointer (e.g.
Definition: chatbox.cpp:125
void active_window_changed()
Definition: chatbox.cpp:110
Base class of a resolution, contains the common keys for a resolution.
void keyboard_capture(widget *widget)
Definition: window.cpp:1282
#define LOG_HEADER
Definition: chatbox.cpp:48
wesnothd_connection * wesnothd_connection_
Definition: chatbox.hpp:149
void increment_waiting_messages(const std::string &room)
Mark the room window for "room" as having one more pending message.
Definition: chatbox.cpp:495
config & child(config_key_type 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:420
void add_message(const std::time_t &timestamp, const std::string &user, const std::string &message)
Definition: lobby_data.cpp:63
multi_page * chat_log_container_
Definition: chatbox.hpp:137
std::vector< state_definition > state
virtual void set_use_markup(bool use_markup) override
See styled_widget::set_use_markup.
bool room_window_active(const std::string &room)
Definition: chatbox.cpp:377
std::string join(const T &v, const std::string &s=",")
Generates a new string joining container items in a list.
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: chatbox.cpp:582
void signal_handler_receive_keyboard_focus(const event::ui_event event)
Definition: chatbox.cpp:781
#define LOG_LB
Definition: chatbox.cpp:44
Main class to show messages to the user.
Definition: message.hpp:34
grid & add_page(const string_map &item)
Adds single page to the grid.
Definition: multi_page.cpp:43
chatbox_definition(const config &cfg)
Definition: chatbox.cpp:791
const std::string & id() const
Definition: widget.cpp:107
std::string get_value() const
This file contains the window object, this object is a top level container which has the event manage...
Base class for all widgets.
Definition: widget.hpp:47
std::map< std::string, chatroom_log > * log_
Definition: chatbox.hpp:151
void parse_admin_authentication(const std::string &sender, const std::string &message)
Definition: game.cpp:188
void remove_page(const unsigned page, unsigned count=1)
Removes a page in the multi page.
Definition: multi_page.cpp:77
void save_to_history()
Saves the text in the widget to the history.
Definition: text_box.hpp:129
std::vector< lobby_chat_window > open_windows_
Definition: chatbox.hpp:141
static void msg(const char *act, debug_info &i, const char *to="", const char *result="")
Definition: debugger.cpp:109
void process_room_query_response(const ::config &data)
Definition: chatbox.cpp:682
void send_to_server(const ::config &cfg) override
Definition: chatbox.cpp:474
int get_selected_row() const
Returns the first selected row.
Definition: listbox.cpp:272
bool whisper_window_active(const std::string &name)
Definition: chatbox.cpp:371
const chat_session & log() const
Definition: lobby_data.hpp:85
std::size_t active_window_
Definition: chatbox.hpp:143
std::string dsgettext(const char *domainname, const char *msgid)
Definition: gettext.cpp:404
room_info * get_room(const std::string &name)
Returns info on room with the given name, or nullptr if it doesn&#39;t exist.
Definition: lobby_info.cpp:287
bool whisper_friends_only()
Definition: lobby.cpp:20
bool select_row(const unsigned row, const bool select=true)
Selects a row.
Definition: listbox.cpp:250
text_box * chat_input_
Definition: chatbox.hpp:139
void process_room_part(const ::config &data)
Definition: chatbox.cpp:661
virtual void set_label(const t_string &label) override
See styled_widget::set_label.
Generic file dialog.
Definition: field-fwd.hpp:22
Go to the end position.
Definition: scrollbar.hpp:60
#define DBG_LB
Definition: chatbox.cpp:43
static const char * name(const std::vector< SDL_Joystick *> &joysticks, const std::size_t index)
Definition: joystick.cpp:48
void process_message(const ::config &data, bool whisper=false)
Definition: chatbox.cpp:727
Base container class.
Definition: grid.hpp:30
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:91
std::string definition
Parameters for the styled_widget.
void do_notify(notify_mode mode, const std::string &sender, const std::string &message)
Definition: lobby_info.cpp:53
bool auto_open_whisper_windows()
Definition: lobby.cpp:30
virtual void add_chat_message(const std::time_t &time, const std::string &speaker, int side, const std::string &message, events::chat_handler::MESSAGE_TYPE type=events::chat_handler::MESSAGE_PRIVATE) override
Inherited form chat_handler.
Definition: chatbox.cpp:258
virtual void send_whisper(const std::string &receiver, const std::string &message)
void close_window_button_callback(std::string room_name, bool &handled, bool &halt)
Definition: chatbox.cpp:463
void connect_signal_notify_modified(dispatcher &dispatcher, const signal_notification_function &signal)
Connects a signal handler for getting a notification upon modification.
Definition: dispatcher.cpp:248
#define ERR_LB
Definition: chatbox.cpp:45
bool is_friend(const std::string &nick)
Definition: game.cpp:306
#define VALIDATE(cond, message)
The macro to use for the validation of WML.
This file contains the settings handling of the widget library.
const grid & page_grid(const unsigned page) const
Returns the grid for the page.
Definition: multi_page.cpp:118
std::ostringstream wrapper.
Definition: formatter.hpp:38
void set_visible(const visibility visible)
Definition: widget.cpp:473
void connect_signal_mouse_left_click(dispatcher &dispatcher, const signal_function &signal)
Connects a signal handler for a left mouse button click.
Definition: dispatcher.cpp:233
mp::lobby_info * lobby_info_
Definition: chatbox.hpp:147
lobby_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: chatbox.cpp:389
virtual void send_chat_message(const std::string &message, bool allies_only) override
Inherited form chat_handler.
Definition: chatbox.cpp:243
std::function< void(void)> active_window_changed_callback_
Definition: chatbox.hpp:145
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: chatbox.cpp:596
void load_log(std::map< std::string, chatroom_log > &log, bool show_lobby)
Definition: chatbox.cpp:95
Label showing a text.
void init_grid(const std::shared_ptr< builder_grid > &grid_builder)
Initializes and builds the grid.
void process_room_join(const ::config &data)
Definition: chatbox.cpp:614
listbox * roomlistbox_
Definition: chatbox.hpp:135
bool is_ignored(const std::string &nick)
Definition: game.cpp:319
#define REGISTER_WIDGET(id)
Wrapper for REGISTER_WIDGET3.
mp::room_info * active_window_room()
Get the room* corresponding to the currently active window, or nullptr if a whisper window is active ...
Definition: chatbox.cpp:604
void process_network_data(const ::config &data)
Definition: chatbox.cpp:766
static lg::log_domain log_lobby("lobby")
std::string login()
virtual void user_relation_changed(const std::string &name) override
Inherited form chat_handler.
Definition: chatbox.cpp:251
std::string escape_text(const std::string &text)
Escapes the pango markup characters in a text.
Definition: escape.hpp:32
#define DBG_GUI_E
Definition: log.hpp:34
std::shared_ptr< const typename T::resolution > cast_config_to() const
Casts the current resolution definition config to the respective type of a derived widget...
void increment_waiting_whispers(const std::string &name)
Mark the whisper window for "name" as having one more pending message.
Definition: chatbox.cpp:481
void set_vertical_scrollbar_item_position(const unsigned position)
Move the vertical scrollbar to a position.
void chat_input_keypress_callback(const SDL_Keycode key)
Definition: chatbox.cpp:144
virtual void add_whisper_received(const std::string &sender, const std::string &message) override
Inherited form chat_handler.
Definition: chatbox.cpp:292
void select_page(const unsigned page, const bool select=true)
Selectes a page.
Definition: multi_page.cpp:106
window * get_window()
Get the parent window.
Definition: widget.cpp:114
void scroll_vertical_scrollbar(const scrollbar_base::scroll_mode scroll)
Scrolls the vertical scrollbar.
std::map< std::string, t_string > string_map
Definition: widget.hpp:24
grid & 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:66
This class represents the information a client has about a room.
Definition: lobby_data.hpp:67
std::size_t index(const std::string &str, const std::size_t index)
Codepoint index corresponding to the nth character in a UTF-8 string.
Definition: unicode.cpp:71
#define VGETTEXT(msgid,...)
Handy wrappers around interpolate_variables_into_string and gettext.
A generic container base class.
config & add_child(config_key_type key)
Definition: config.cpp:476
std::string get_chat_timestamp(const std::time_t &t)
Definition: game.cpp:906
bool grid()
Definition: general.cpp:505
virtual void add_chat_room_message_received(const std::string &room, const std::string &speaker, const std::string &message) override
Inherited form chat_handler.
Definition: chatbox.cpp:338
const grid * get_row_grid(const unsigned row) const
Returns the grid of the wanted row.
Definition: listbox.cpp:237
virtual void set_value(const std::string &text)
The set_value is virtual for the password_box class.
const t_string & get_label() const
void append_to_chatbox(const std::string &text, const bool force_scroll=false)
Definition: chatbox.cpp:209
The user sets the widget visible, that means:
void close_room(const std::string &name)
Close the chat room with the given name.
Definition: lobby_info.cpp:332
void connect_signal_pre_key_press(dispatcher &dispatcher, const signal_keyboard_function &signal)
Connects the signal for &#39;snooping&#39; on the keypress.
Definition: dispatcher.cpp:228
double t
Definition: astarsearch.cpp:64
The user sets the widget hidden, that means:
virtual void add_chat_room_message_sent(const std::string &room, const std::string &message) override
Inherited form chat_handler.
Definition: chatbox.cpp:318
chat_session & get_whisper_log(const std::string &name)
Definition: lobby_info.hpp:113
Simple push button.
Definition: button.hpp:35
Standard logging facilities (interface).
void remove_row(const unsigned row, unsigned count=1)
Removes a row in the listbox.
Definition: listbox.cpp:86
unsigned get_vertical_scrollbar_item_position() const
Returns current position of the vertical scrollbar.
notify_mode
Definition: lobby_info.hpp:175
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: chatbox.cpp:523
lobby_chat_window * find_or_create_window(const std::string &name, const bool whisper, const bool open_new, const bool allow_close, const std::string &initial_text)
Helper function to find and open a new window, used by *_window_open.
Definition: chatbox.cpp:396
const std::vector< user_info > & users() const
Definition: lobby_info.hpp:135
virtual void add_whisper_sent(const std::string &receiver, const std::string &message) override
Inherited form chat_handler.
Definition: chatbox.cpp:278
void open_room(const std::string &name)
Open a new chat room with the given name.
Definition: lobby_info.cpp:325
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:92
void notify_event(const std::string &name, const config &data)
Definition: manager.cpp:144
mock_char c
void finalize_setup()
Initializes the internal sub-widget pointers.
Definition: chatbox.cpp:78
#define DBG_GUI_G
Definition: log.hpp:40
virtual void send_chat_room_message(const std::string &room, const std::string &message)
bool word_completion(std::string &text, std::vector< std::string > &wordlist)
Try to complete the last word of &#39;text&#39; with the &#39;wordlist&#39;.
lobby_chat_window * room_window_open(const std::string &room, const bool open_new, const bool allow_close=true)
Check if a room window for "room" is open, if open_new is true then it will be created if not found...
Definition: chatbox.cpp:383
Contains the implementation details for lexical_cast and shouldn&#39;t be used directly.
ui_event
The event send to the dispatcher.
Definition: handler.hpp:55
static plugins_manager * get()
Definition: manager.cpp:58
std::pair< std::string, unsigned > item
Definition: help_impl.hpp:371
void process_room_members(const config &data)
Definition: lobby_data.cpp:100
bool word_match(const std::string &message, const std::string &word)
Check if a message contains a word.
void close_window(std::size_t idx)
Definition: chatbox.cpp:531
void add_whisper_window_whisper(const std::string &sender, const std::string &message)
Add a whisper message to the whisper window.
Definition: chatbox.cpp:511
void add_member(const std::string &user)
Definition: lobby_data.cpp:90