The Battle for Wesnoth  1.17.0-dev
chatbox.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2016 - 2021
3  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 #define GETTEXT_DOMAIN "wesnoth-lib"
16 
17 #include "gui/widgets/chatbox.hpp"
18 
20 
22 #include "gui/widgets/button.hpp"
23 #include "gui/widgets/image.hpp"
24 #include "gui/widgets/label.hpp"
25 #include "gui/widgets/listbox.hpp"
28 #include "gui/widgets/settings.hpp"
29 #include "gui/widgets/text_box.hpp"
30 #include "gui/widgets/window.hpp"
31 
32 #include "font/pango/escape.hpp"
33 #include "formatter.hpp"
34 #include "formula/string_utils.hpp"
35 #include "gettext.hpp"
36 #include "log.hpp"
38 #include "preferences/game.hpp"
39 #include "preferences/lobby.hpp"
41 #include "wesnothd_connection.hpp"
42 
43 static lg::log_domain log_lobby("lobby");
44 #define DBG_LB LOG_STREAM(debug, log_lobby)
45 #define LOG_LB LOG_STREAM(info, log_lobby)
46 #define ERR_LB LOG_STREAM(err, log_lobby)
47 
48 #define LOG_SCOPE_HEADER get_control_type() + " [" + id() + "] " + __func__
49 #define LOG_HEADER LOG_SCOPE_HEADER + ':'
50 
51 namespace gui2
52 {
53 
54 // ------------ WIDGET -----------{
55 
56 REGISTER_WIDGET(chatbox)
57 
58 chatbox::chatbox(const implementation::builder_chatbox& builder)
59  : container_base(builder, type())
60  , roomlistbox_(nullptr)
61  , chat_log_container_(nullptr)
62  , chat_input_(nullptr)
63  , active_window_(0)
64  , active_window_changed_callback_()
65  , chat_info_()
66  , wesnothd_connection_(nullptr)
67  , log_(nullptr)
68 {
69  // We only implement a RECEIVE_KEYBOARD_FOCUS handler; LOSE_KEYBOARD_FOCUS
70  // isn't needed. This handler forwards focus to the input textbox, meaning
71  // if keyboard_focus is called on a chatbox, distributor::keyboard_focus_
72  // will immediately be set to the input textbox, which will then handle focus
73  // loss itself when applicable. Nothing else happens in the interim while
74  // keyboard_focus_ equals `this` to warrent cleanup.
75  connect_signal<event::RECEIVE_KEYBOARD_FOCUS>(
76  std::bind(&chatbox::signal_handler_receive_keyboard_focus, this, std::placeholders::_2));
77 }
78 
80 {
81  roomlistbox_ = find_widget<listbox>(this, "room_list", false, true);
82 
83  // We need to bind a lambda here since switch_to_window is overloaded.
84  // A lambda alone would be more verbose because it'd need to specify all the parameters.
86  std::bind([this]() { switch_to_window(roomlistbox_->get_selected_row()); }));
87 
88  chat_log_container_ = find_widget<multi_page>(this, "chat_log_container", false, true);
89 
90  chat_input_ = find_widget<text_box>(this, "chat_input", false, true);
91 
92  connect_signal_pre_key_press(*chat_input_,
93  std::bind(&chatbox::chat_input_keypress_callback, this, std::placeholders::_5));
94 }
95 
96 void chatbox::load_log(std::map<std::string, chatroom_log>& log, bool show_lobby)
97 {
98  for(const auto& l : log) {
99  const bool is_lobby = l.first == "lobby";
100 
101  if(!show_lobby && is_lobby && !l.second.whisper) {
102  continue;
103  }
104 
105  find_or_create_window(l.first, l.second.whisper, true, !is_lobby, l.second.log);
106  }
107 
108  log_ = &log;
109 }
110 
112 {
114 
115  // Clear pending messages notification in room listbox
117  find_widget<image>(grid, "pending_messages", false).set_visible(widget::visibility::hidden);
118 
119  t.pending_messages = 0;
120 
123  }
124 }
125 
127 {
129 }
130 
131 void chatbox::switch_to_window(std::size_t id)
132 {
133  active_window_ = id;
134  assert(active_window_ < open_windows_.size());
135 
138 
139  // Grab input focus
141 
143 }
144 
145 void chatbox::chat_input_keypress_callback(const SDL_Keycode key)
146 {
147  std::string input = chat_input_->get_value();
148  if(input.empty() || chat_input_->is_composing()) {
149  return;
150  }
151 
153 
154  switch(key) {
155  case SDLK_RETURN:
156  case SDLK_KP_ENTER: {
157  if(input[0] == '/') {
158  // TODO: refactor do_speak so it uses context information about
159  // opened window, so e.g. /ignore in a whisper session ignores
160  // the other party without having to specify it's nick.
161  chat_handler::do_speak(input);
162  } else {
163  if(t.whisper) {
164  send_whisper(t.name, input);
165  add_whisper_sent(t.name, input);
166  } else {
167  send_chat_room_message(t.name, input);
169  }
170  }
171 
173  chat_input_->set_value("");
174 
175  break;
176  }
177 
178  case SDLK_TAB: {
180 
181  // TODO: very inefficient! Very! D:
182  std::vector<std::string> matches;
183  for(const std::string& ui : ri->members()) {
184  if(ui != preferences::login()) {
185  matches.push_back(ui);
186  }
187  }
188 
189  const bool line_start = utils::word_completion(input, matches);
190 
191  if(matches.empty()) {
192  return;
193  }
194 
195  if(matches.size() == 1) {
196  input.append(line_start ? ": " : " ");
197  } else {
198  std::string completion_list = utils::join(matches, " ");
199  append_to_chatbox(completion_list);
200  }
201 
202  chat_input_->set_value(input);
203 
204  break;
205  }
206 
207  default:
208  break;
209  }
210 }
211 
212 void chatbox::append_to_chatbox(const std::string& text, const bool force_scroll)
213 {
214  append_to_chatbox(text, active_window_, force_scroll);
215 }
216 
217 void chatbox::append_to_chatbox(const std::string& text, std::size_t id, const bool force_scroll)
218 {
220 
221  scroll_label& log = find_widget<scroll_label>(&grid, "log_text", false);
222  const bool chatbox_at_end = log.vertical_scrollbar_at_end();
223  const unsigned chatbox_position = log.get_vertical_scrollbar_item_position();
224 
225  const std::string new_text = formatter()
226  << log.get_label() << "\n" << "<span color='#bcb088'>" << preferences::get_chat_timestamp(std::time(0)) << text << "</span>";
227 
228  log.set_use_markup(true);
229  log.set_label(new_text);
230 
231  if(log_ != nullptr) {
232  try {
233  const std::string& room_name = open_windows_[id].name;
234  log_->at(room_name).log = new_text;
235  } catch(const std::out_of_range&) {
236  }
237  }
238 
239  if(chatbox_at_end || force_scroll) {
241  } else {
242  log.set_vertical_scrollbar_item_position(chatbox_position);
243  }
244 }
245 
246 void chatbox::send_chat_message(const std::string& message, bool /*allies_only*/)
247 {
248  add_chat_message(std::time(nullptr), preferences::login(), 0, message);
249 
250  ::config c {"message", ::config {"message", message, "sender", preferences::login()}};
251  send_to_server(c);
252 }
253 
254 void chatbox::user_relation_changed(const std::string& /*name*/)
255 {
258  }
259 }
260 
261 void chatbox::add_chat_message(const std::time_t& /*time*/,
262  const std::string& speaker,
263  int /*side*/,
264  const std::string& message,
266 {
267  std::string text;
268 
269  // FIXME: the chat_command_handler class (which handles chat commands) dispatches a
270  // message consisting of '/me insert text here' in the case the '/me' or '/emote'
271  // commands are used, so we need to do some manual preprocessing here.
272  if(message.compare(0, 4, "/me ") == 0) {
273  text = formatter() << "<i>" << speaker << " " << font::escape_text(message.substr(4)) << "</i>";
274  } else {
275  text = formatter() << "<b>" << speaker << ":</b> " << font::escape_text(message);
276  }
277 
278  append_to_chatbox(text);
279 }
280 
281 void chatbox::add_whisper_sent(const std::string& receiver, const std::string& message)
282 {
283  if(whisper_window_active(receiver)) {
288  } else {
289  add_active_window_whisper(VGETTEXT("whisper to $receiver", {{"receiver", receiver}}), message, true);
290  }
291 
293 }
294 
295 void chatbox::add_whisper_received(const std::string& sender, const std::string& message)
296 {
297  bool can_go_to_active = !preferences::whisper_friends_only() || preferences::is_friend(sender);
298  bool can_open_new = preferences::auto_open_whisper_windows() && can_go_to_active;
299 
300  chat_info_.get_whisper_log(sender).add_message(sender, message);
301 
302  if(whisper_window_open(sender, can_open_new)) {
303  if(whisper_window_active(sender)) {
304  add_active_window_message(sender, message);
305 
306  do_notify(mp::NOTIFY_WHISPER, sender, message);
307  } else {
308  add_whisper_window_whisper(sender, message);
310 
311  do_notify(mp::NOTIFY_WHISPER_OTHER_WINDOW, sender, message);
312  }
313  } else if(can_go_to_active) {
314  add_active_window_whisper(sender, message);
315  do_notify(mp::NOTIFY_WHISPER, sender, message);
316  } else {
317  LOG_LB << "Ignoring whisper from " << sender << "\n";
318  }
319 }
320 
321 void chatbox::add_chat_room_message_sent(const std::string& room, const std::string& message)
322 {
323  lobby_chat_window* t = room_window_open(room, false);
324  if(!t) {
325  LOG_LB << "Cannot add sent message to ui for room " << room << ", player not in the room\n";
326  return;
327  }
328 
329  // Do not open room window here. The player should be in the room before sending messages
330  mp::room_info* ri = chat_info_.get_room(room);
331  assert(ri);
332 
333  if(!room_window_active(room)) {
334  switch_to_window(t);
335  }
336 
337  ri->log().add_message(preferences::login(), message);
339 }
340 
341 void chatbox::add_chat_room_message_received(const std::string& room,
342  const std::string& speaker,
343  const std::string& message)
344 {
345  mp::room_info* ri = chat_info_.get_room(room);
346  if(!ri) {
347  LOG_LB << "Discarding message to room " << room << " from " << speaker << " (room not open)\n";
348  return;
349  }
350 
352  ri->log().add_message(speaker, message);
353 
354  if(room_window_active(room)) {
355  add_active_window_message(speaker, message);
356  notify_mode = mp::NOTIFY_MESSAGE;
357  } else {
358  add_room_window_message(room, speaker, message);
360  notify_mode = mp::NOTIFY_MESSAGE_OTHER_WINDOW;
361  }
362 
363  if(speaker == "server") {
364  notify_mode = mp::NOTIFY_SERVER_MESSAGE;
365  } else if (utils::word_match(message, preferences::login())) {
366  notify_mode = mp::NOTIFY_OWN_NICK;
367  } else if (preferences::is_friend(speaker)) {
368  notify_mode = mp::NOTIFY_FRIEND_MESSAGE;
369  }
370 
371  do_notify(notify_mode, speaker, message);
372 }
373 
374 bool chatbox::whisper_window_active(const std::string& name)
375 {
377  return t.name == name && t.whisper == true;
378 }
379 
380 bool chatbox::room_window_active(const std::string& room)
381 {
383  return t.name == room && t.whisper == false;
384 }
385 
386 lobby_chat_window* chatbox::room_window_open(const std::string& room, const bool open_new, const bool allow_close)
387 {
388  return find_or_create_window(room, false, open_new, allow_close,
389  VGETTEXT("Joined <i>$name</i>", { { "name", translation::dsgettext("wesnoth-lib", room.c_str()) } }));
390 }
391 
392 lobby_chat_window* chatbox::whisper_window_open(const std::string& name, bool open_new)
393 {
394  return find_or_create_window(name, true, open_new, true,
395  VGETTEXT("Started private message with <i>$name</i>. "
396  "If you do not want to receive messages from this player, type <i>/ignore $name</i>", { { "name", name } }));
397 }
398 
400  const bool whisper,
401  const bool open_new,
402  const bool allow_close,
403  const std::string& initial_text)
404 {
405  for(auto& t : open_windows_) {
406  if(t.name == name && t.whisper == whisper) {
407  return &t;
408  }
409  }
410 
411  if(!open_new) {
412  return nullptr;
413  }
414 
415  open_windows_.emplace_back(name, whisper);
416 
417  //
418  // Add a new chat log page.
419  //
421  item["use_markup"] = "true";
422  item["label"] = initial_text;
423  std::map<std::string, string_map> data{{"log_text", item}};
424 
425  if(!whisper) {
426  chat_info_.open_room(name);
427  }
428 
429  if(log_ != nullptr) {
430  log_->emplace(name, chatroom_log{item["label"], whisper});
431  }
432 
434 
435  //
436  // Add a new room window tab.
437  //
438  data.clear();
439  item.clear();
440 
441  if(!whisper) {
442  item["label"] = translation::dsgettext("wesnoth-lib", name.c_str());
443  } else {
444  item["label"] = "<" + name + ">";
445  }
446 
447  data.emplace("room", item);
448 
449  grid& row_grid = roomlistbox_->add_row(data);
450 
451  //
452  // Set up the Close Window button.
453  //
454  button& close_button = find_widget<button>(&row_grid, "close_window", false);
455 
456  if(!allow_close) {
458  } else {
459  connect_signal_mouse_left_click(close_button,
460  std::bind(&chatbox::close_window_button_callback, this, open_windows_.back().name, std::placeholders::_3, std::placeholders::_4));
461  }
462 
463  return &open_windows_.back();
464 }
465 
466 void chatbox::close_window_button_callback(std::string room_name, bool& handled, bool& halt)
467 {
468  const int index = std::distance(open_windows_.begin(), std::find_if(open_windows_.begin(), open_windows_.end(),
469  [&room_name](const lobby_chat_window& room) { return room.name == room_name; }
470  ));
471 
472  close_window(index);
473 
474  handled = halt = true;
475 }
476 
477 void chatbox::send_to_server(const ::config& cfg)
478 {
481  }
482 }
483 
484 void chatbox::increment_waiting_whispers(const std::string& name)
485 {
486  if(lobby_chat_window* t = whisper_window_open(name, false)) {
487  ++t->pending_messages;
488 
489  if(t->pending_messages == 1) {
490  DBG_LB << "do whisper pending mark row " << (t - &open_windows_[0]) << " with " << t->name << "\n";
491 
493  find_widget<image>(grid, "pending_messages", false).set_visible(widget::visibility::visible);
494  }
495  }
496 }
497 
498 void chatbox::increment_waiting_messages(const std::string& room)
499 {
500  if(lobby_chat_window* t = room_window_open(room, false)) {
501  ++t->pending_messages;
502 
503  if(t->pending_messages == 1) {
504  int idx = t - &open_windows_[0];
505 
506  DBG_LB << "do room pending mark row " << idx << " with " << t->name << "\n";
507 
509  find_widget<image>(grid, "pending_messages", false).set_visible(widget::visibility::visible);
510  }
511  }
512 }
513 
514 void chatbox::add_whisper_window_whisper(const std::string& sender, const std::string& message)
515 {
516  lobby_chat_window* t = whisper_window_open(sender, false);
517  if(!t) {
518  ERR_LB << "Whisper window not open in add_whisper_window_whisper for " << sender << "\n";
519  return;
520  }
521 
522  const std::string text = formatter() << "<b>" << sender << ":</b> " << font::escape_text(message);
523  append_to_chatbox(text, t - &open_windows_[0], false);
524 }
525 
526 void chatbox::add_active_window_whisper(const std::string& sender,
527  const std::string& message,
528  const bool force_scroll)
529 {
530  const std::string text = formatter() << "<b>" << "whisper: " << sender << ":</b> " << font::escape_text(message);
531  append_to_chatbox(text, force_scroll);
532 }
533 
534 void chatbox::close_window(std::size_t idx)
535 {
536  const lobby_chat_window& t = open_windows_[idx];
537 
538  DBG_LB << "Close window " << idx << " - " << t.name << "\n";
539 
540  // Can't close the lobby!
541  if((t.name == "lobby" && t.whisper == false) || open_windows_.size() == 1) {
542  return;
543  }
544 
545  // Check if we're closing the currently-active window.
546  const bool active_changed = idx == active_window_;
547 
548  if(active_window_ == open_windows_.size() - 1) {
549  --active_window_;
550  }
551 
552  if(t.whisper) {
554  } else {
556  }
557 
558  if(log_ != nullptr) {
559  log_->erase(t.name);
560  }
561 
562  open_windows_.erase(open_windows_.begin() + idx);
563 
564  roomlistbox_->remove_row(idx);
566 
569 
570  if(active_changed) {
572  }
573 }
574 
575 void chatbox::add_room_window_message(const std::string& room,
576  const std::string& sender,
577  const std::string& message)
578 {
579  lobby_chat_window* t = room_window_open(room, false);
580  if(!t) {
581  ERR_LB << "Room window not open in add_room_window_message for " << room << "\n";
582  return;
583  }
584 
585  const std::string text = formatter() << "<b>" << sender << ":</b> " << font::escape_text(message);
586  append_to_chatbox(text, t - &open_windows_[0], false);
587 }
588 
589 void chatbox::add_active_window_message(const std::string& sender,
590  const std::string& message,
591  const bool force_scroll)
592 {
593  const std::string text = formatter() << "<b>" << sender << ":</b> " << font::escape_text(message);
594  append_to_chatbox(text, force_scroll);
595 }
596 
598 {
600  if(t.whisper) {
601  return nullptr;
602  }
603 
604  return chat_info_.get_room(t.name);
605 }
606 
607 void chatbox::process_message(const ::config& data, bool whisper /*= false*/)
608 {
609  std::string sender = data["sender"];
610  DBG_LB << "process message from " << sender << " " << (whisper ? "(w)" : "")
611  << ", len " << data["message"].str().size() << '\n';
612 
613  if(preferences::is_ignored(sender)) {
614  return;
615  }
616 
617  const std::string& message = data["message"];
618  //preferences::parse_admin_authentication(sender, message); TODO: replace
619 
620  if(whisper) {
621  add_whisper_received(sender, message);
622  } else {
623  std::string room = data["room"];
624 
625  // Attempt to send to the currently active room first.
626  if(room.empty()) {
627  LOG_LB << "Message without a room from " << sender << ", falling back to active window\n";
628  room = open_windows_[active_window_].name;
629  }
630 
631  // If we still don't have a name, fall back to lobby.
632  if(room.empty()) {
633  LOG_LB << "Message without a room from " << sender << ", assuming lobby\n";
634  room = "lobby";
635  }
636 
637  if(log_ != nullptr && data["type"].str() == "motd") {
638  if(log_->at("lobby").received_motd == message) {
639  LOG_LB << "Ignoring repeated motd\n";
640  return;
641  } else {
642  log_->at("lobby").received_motd = message;
643  }
644  }
645 
646  add_chat_room_message_received(room, sender, message);
647  }
648 
649  // Notify plugins about the message
650  ::config plugin_data = data;
651  plugin_data["whisper"] = whisper;
652  plugins_manager::get()->notify_event("chat", plugin_data);
653 }
654 
655 void chatbox::process_network_data(const ::config& data)
656 {
657  if(const auto message = data.optional_child("message")) {
659  } else if(const auto whisper = data.optional_child("whisper")) {
660  process_message(*whisper, true);
661  }
662 }
663 
665 {
666  DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
667 
668  // Forward focus to the input textbox.
670 }
671 
672 // }---------- DEFINITION ---------{
673 
676 {
677  load_resolutions<resolution>(cfg);
678 }
679 
681  : resolution_definition(cfg), grid()
682 {
683  state.emplace_back(cfg.child("background"));
684  state.emplace_back(cfg.child("foreground"));
685 
686  const config& child = cfg.child("grid");
687  VALIDATE(child, _("No grid defined."));
688 
689  grid = std::make_shared<builder_grid>(child);
690 }
691 // }---------- BUILDER -----------{
692 
693 namespace implementation
694 {
695 
696 builder_chatbox::builder_chatbox(const config& cfg)
697  : builder_styled_widget(cfg)
698 {
699 }
700 
702 {
703  chatbox* widget = new chatbox(*this);
704 
705  DBG_GUI_G << "Window builder: placed unit preview pane '" << id
706  << "' with definition '" << definition << "'.\n";
707 
708  const auto conf = widget->cast_config_to<chatbox_definition>();
709  assert(conf);
710 
711  widget->init_grid(*conf->grid);
712  widget->finalize_setup();
713 
714  return widget;
715 }
716 
717 } // namespace implementation
718 
719 // }------------ END --------------
720 
721 } // namespace gui2
bool is_composing() const
void send_data(const configr_of &request)
Queues the given data to be sent to the server.
void switch_to_window(lobby_chat_window *t)
Switch to the window given by a valid pointer (e.g.
Definition: chatbox.cpp:126
void active_window_changed()
Definition: chatbox.cpp:111
Base class of a resolution, contains the common keys for a resolution.
void keyboard_capture(widget *widget)
Definition: window.cpp:1275
#define LOG_HEADER
Definition: chatbox.cpp:49
wesnothd_connection * wesnothd_connection_
Definition: chatbox.hpp:145
void increment_waiting_messages(const std::string &room)
Mark the room window for "room" as having one more pending message.
Definition: chatbox.cpp:498
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:417
void add_message(const std::time_t &timestamp, const std::string &user, const std::string &message)
Definition: lobby_data.cpp:64
multi_page * chat_log_container_
Definition: chatbox.hpp:133
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:380
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:575
void signal_handler_receive_keyboard_focus(const event::ui_event event)
Definition: chatbox.cpp:664
#define LOG_LB
Definition: chatbox.cpp:45
Main class to show messages to the user.
Definition: message.hpp:34
virtual widget * build() const override
Definition: chatbox.cpp:701
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:674
const std::string & id() const
Definition: widget.cpp:109
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:48
std::map< std::string, chatroom_log > * log_
Definition: chatbox.hpp:147
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:148
std::vector< lobby_chat_window > open_windows_
Definition: chatbox.hpp:137
void send_to_server(const ::config &cfg) override
Definition: chatbox.cpp:477
int get_selected_row() const
Returns the first selected row.
Definition: listbox.cpp:276
bool whisper_window_active(const std::string &name)
Definition: chatbox.cpp:374
const chat_session & log() const
Definition: lobby_data.hpp:85
std::size_t active_window_
Definition: chatbox.hpp:139
static std::string _(const char *str)
Definition: gettext.hpp:92
std::string dsgettext(const char *domainname, const char *msgid)
Definition: gettext.cpp:400
bool whisper_friends_only()
Definition: lobby.cpp:20
bool select_row(const unsigned row, const bool select=true)
Selects a row.
Definition: listbox.cpp:251
text_box * chat_input_
Definition: chatbox.hpp:135
mp::chat_info chat_info_
Definition: chatbox.hpp:143
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:44
void process_message(const ::config &data, bool whisper=false)
Definition: chatbox.cpp:607
Base container class.
Definition: grid.hpp:30
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:51
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:261
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:466
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:186
chat_session & get_whisper_log(const std::string &name)
Definition: lobby_info.hpp:173
#define ERR_LB
Definition: chatbox.cpp:46
bool is_friend(const std::string &nick)
Definition: game.cpp:277
#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:121
std::ostringstream wrapper.
Definition: formatter.hpp:38
void set_visible(const visibility visible)
Definition: widget.cpp:475
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:171
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:392
void init_grid(const builder_grid &grid_builder)
Initializes and builds the grid.
virtual void send_chat_message(const std::string &message, bool allies_only) override
Inherited form chat_handler.
Definition: chatbox.cpp:246
std::function< void(void)> active_window_changed_callback_
Definition: chatbox.hpp:141
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:589
void load_log(std::map< std::string, chatroom_log > &log, bool show_lobby)
Definition: chatbox.cpp:96
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:285
Label showing a text.
listbox * roomlistbox_
Definition: chatbox.hpp:131
bool is_ignored(const std::string &nick)
Definition: game.cpp:289
#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:597
void process_network_data(const ::config &data)
Definition: chatbox.cpp:655
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:254
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:484
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:145
virtual void add_whisper_received(const std::string &sender, const std::string &message) override
Inherited form chat_handler.
Definition: chatbox.cpp:295
void select_page(const unsigned page, const bool select=true)
Selects a page.
Definition: multi_page.cpp:106
window * get_window()
Get the parent window.
Definition: widget.cpp:116
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:25
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:67
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:69
#define VGETTEXT(msgid,...)
Handy wrappers around interpolate_variables_into_string and gettext.
A generic container base class.
std::string get_chat_timestamp(const std::time_t &t)
Definition: game.cpp:876
bool grid()
Definition: general.cpp:524
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:341
const grid * get_row_grid(const unsigned row) const
Returns the grid of the wanted row.
Definition: listbox.cpp:238
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:212
The user sets the widget visible, that means:
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:166
double t
Definition: astarsearch.cpp:63
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:321
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:87
unsigned get_vertical_scrollbar_item_position() const
Returns current position of the vertical scrollbar.
notify_mode
Definition: lobby_info.hpp:189
void close_room(const std::string &name)
Close the chat room with the given name.
Definition: lobby_info.cpp:325
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:526
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:399
virtual void add_whisper_sent(const std::string &receiver, const std::string &message) override
Inherited form chat_handler.
Definition: chatbox.cpp:281
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:59
void notify_event(const std::string &name, const config &data)
Definition: manager.cpp:144
mock_char c
const std::set< std::string > & members() const
Definition: lobby_data.hpp:76
void finalize_setup()
Initializes the internal sub-widget pointers.
Definition: chatbox.cpp:79
void open_room(const std::string &name)
Open a new chat room with the given name.
Definition: lobby_info.cpp:319
#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:386
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:47
static plugins_manager * get()
Definition: manager.cpp:58
std::pair< std::string, unsigned > item
Definition: help_impl.hpp:409
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:534
void add_whisper_window_whisper(const std::string &sender, const std::string &message)
Add a whisper message to the whisper window.
Definition: chatbox.cpp:514