The Battle for Wesnoth  1.19.13+dev
chatbox.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2016 - 2025
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 #include "gui/widgets/button.hpp"
21 #include "gui/widgets/image.hpp"
22 #include "gui/widgets/listbox.hpp"
25 #include "gui/widgets/text_box.hpp"
26 #include "gui/widgets/window.hpp"
27 
28 #include "font/pango/escape.hpp"
29 #include "formatter.hpp"
30 #include "formula/string_utils.hpp"
32 #include "gettext.hpp"
33 #include "log.hpp"
36 #include "serialization/markup.hpp"
37 #include "wml_exception.hpp"
38 
39 static lg::log_domain log_lobby("lobby");
40 #define DBG_LB LOG_STREAM(debug, log_lobby)
41 #define LOG_LB LOG_STREAM(info, log_lobby)
42 #define ERR_LB LOG_STREAM(err, log_lobby)
43 
44 #define LOG_SCOPE_HEADER get_control_type() + " [" + id() + "] " + __func__
45 #define LOG_HEADER LOG_SCOPE_HEADER + ':'
46 
47 namespace gui2
48 {
49 
50 // ------------ WIDGET -----------{
51 
52 REGISTER_WIDGET(chatbox)
53 
54 chatbox::chatbox(const implementation::builder_chatbox& builder)
55  : container_base(builder, type())
56  , roomlistbox_(nullptr)
57  , chat_log_container_(nullptr)
58  , chat_input_(nullptr)
59  , active_window_(0)
60  , active_window_changed_callback_()
61  , log_(nullptr)
62 {
63  // We only implement a RECEIVE_KEYBOARD_FOCUS handler; LOSE_KEYBOARD_FOCUS
64  // isn't needed. This handler forwards focus to the input textbox, meaning
65  // if keyboard_focus is called on a chatbox, distributor::keyboard_focus_
66  // will immediately be set to the input textbox, which will then handle focus
67  // loss itself when applicable. Nothing else happens in the interim while
68  // keyboard_focus_ equals `this` to warrent cleanup.
69  connect_signal<event::RECEIVE_KEYBOARD_FOCUS>(
70  std::bind(&chatbox::signal_handler_receive_keyboard_focus, this, std::placeholders::_2));
71 }
72 
74 {
75  roomlistbox_ = find_widget<listbox>("room_list", false, true);
76 
77  // We need to bind a lambda here since switch_to_window is overloaded.
78  // A lambda alone would be more verbose because it'd need to specify all the parameters.
80  [this](auto&&...) { switch_to_window(roomlistbox_->get_selected_row()); });
81 
82  chat_log_container_ = find_widget<multi_page>("chat_log_container", false, true);
83 
84  chat_input_ = find_widget<text_box>("chat_input", false, true);
85 
87  std::bind(&chatbox::chat_input_keypress_callback, this, std::placeholders::_5));
88 }
89 
90 void chatbox::load_log(std::map<std::string, chatroom_log>& log, bool show_lobby)
91 {
92  const std::string new_tip = formatter()
93  << "\n"
94  // TRANSLATORS: This is the new chat text indicator
95  << markup::span_color("#FF0000", "============", _("NEW"), "============");
96 
97  for(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  const std::size_t new_tip_index = l.second.log.find(new_tip);
105 
106  if(new_tip_index != std::string::npos) {
107  l.second.log.replace(new_tip_index, new_tip.length(), "");
108  }
109  find_or_create_window(l.first, l.second.whisper, true, !is_lobby, l.second.log + new_tip);
110  }
111 
112  log_ = &log;
113 }
114 
116 {
118 
119  // Clear pending messages notification in room listbox
122 
123  t.pending_messages = 0;
124 
127  }
128 }
129 
131 {
133 }
134 
135 void chatbox::switch_to_window(std::size_t id)
136 {
137  active_window_ = id;
138  assert(active_window_ < open_windows_.size());
139 
142 
143  // Grab input focus
145 
147 }
148 
149 void chatbox::chat_input_keypress_callback(const SDL_Keycode key)
150 {
151  std::string input = chat_input_->get_value();
152  if(input.empty() || chat_input_->is_composing()) {
153  return;
154  }
155 
157 
158  switch(key) {
159  case SDLK_RETURN:
160  case SDLK_KP_ENTER: {
161  if(input[0] == '/') {
162  // TODO: refactor do_speak so it uses context information about
163  // opened window, so e.g. /ignore in a whisper session ignores
164  // the other party without having to specify it's nick.
165  chat_handler::do_speak(input);
166  } else {
167  if(t.whisper) {
168  send_whisper(t.name, input);
169  add_whisper_sent(t.name, input);
170  } else {
171  send_chat_room_message(t.name, input);
172  add_chat_room_message_sent(t.name, input);
173  }
174  }
175 
177  chat_input_->set_value("");
178 
179  break;
180  }
181 
182  case SDLK_TAB: {
183  auto* li = mp::get_lobby_info();
184  if(!li) {
185  break;
186  }
187 
188  std::vector<std::string> matches;
189  for(const auto& ui : li->users()) {
190  if(ui.name != prefs::get().login()) {
191  matches.push_back(ui.name);
192  }
193  }
194 
195  const bool line_start = utils::word_completion(input, matches);
196 
197  if(matches.empty()) {
198  return;
199  }
200 
201  if(matches.size() == 1) {
202  input.append(line_start ? ": " : " ");
203  } else {
204  std::string completion_list = utils::join(matches, " ");
205  append_to_chatbox(completion_list);
206  }
207 
208  chat_input_->set_value(input);
209 
210  break;
211  }
212 
213  default:
214  break;
215  }
216 }
217 
218 void chatbox::append_to_chatbox(const std::string& text, const bool force_scroll)
219 {
220  append_to_chatbox(text, active_window_, force_scroll);
221 }
222 
223 void chatbox::append_to_chatbox(const std::string& text, std::size_t id, const bool force_scroll)
224 {
226  scroll_text& log = grid.find_widget<scroll_text>("log_text");
227 
228  const bool chatbox_at_end = log.vertical_scrollbar_at_end();
229  const unsigned chatbox_position = log.get_vertical_scrollbar_item_position();
230 
231  const std::string before_message = log.get_value().empty() ? "" : "\n";
232  const std::string new_text = formatter()
233  << log.get_value() << before_message << markup::span_color("#bcb088", prefs::get().get_chat_timestamp(std::chrono::system_clock::now()), text);
234 
235  log.set_use_markup(true);
236  log.set_value(new_text);
237 
238  if(log_ != nullptr) {
239  try {
240  const std::string& room_name = open_windows_[id].name;
241  log_->at(room_name).log = new_text;
242  } catch(const std::out_of_range&) {
243  }
244  }
245 
246  if(chatbox_at_end || force_scroll) {
248  } else {
249  log.set_vertical_scrollbar_item_position(chatbox_position);
250  }
251 }
252 
253 void chatbox::send_chat_message(const std::string& message, bool /*allies_only*/)
254 {
255  add_chat_message(std::chrono::system_clock::now(), prefs::get().login(), 0, message);
256  send_to_server(::config{"message", ::config{"message", message, "sender", prefs::get().login()}});
257 }
258 
260 {
261  const auto id = active_window_;
263  scroll_text& log = grid.find_widget<scroll_text>("log_text");
264  log.set_label("");
265 }
266 
267 void chatbox::user_relation_changed(const std::string& /*name*/)
268 {
271  }
272 }
273 
274 void chatbox::add_chat_message(const std::chrono::system_clock::time_point& /*time*/,
275  const std::string& speaker,
276  int /*side*/,
277  const std::string& message,
279 {
280  std::string text;
281  if(message.compare(0, 4, "/me ") == 0) {
282  text = formatter() << markup::italic(speaker, " ", font::escape_text(message.substr(4)));
283  } else {
284  text = formatter() << markup::bold(speaker, ":") << font::escape_text(message);
285  }
286 
287  append_to_chatbox(text);
288 }
289 
290 void chatbox::add_whisper_sent(const std::string& receiver, const std::string& message)
291 {
292  if(whisper_window_active(receiver)) {
293  add_active_window_message(prefs::get().login(), message, true);
294  } else if(lobby_chat_window* t = whisper_window_open(receiver, prefs::get().auto_open_whisper_windows())) {
296  add_active_window_message(prefs::get().login(), message, true);
297  } else {
298  add_active_window_whisper(VGETTEXT("whisper to $receiver", {{"receiver", receiver}}), message, true);
299  }
300 }
301 
302 void chatbox::add_whisper_received(const std::string& sender, const std::string& message)
303 {
304  bool can_go_to_active = !prefs::get().lobby_whisper_friends_only() || prefs::get().is_friend(sender);
305  bool can_open_new = prefs::get().auto_open_whisper_windows() && can_go_to_active;
306 
307  if(whisper_window_open(sender, can_open_new)) {
308  if(whisper_window_active(sender)) {
310 
312  } else {
315 
317  }
318  } else if(can_go_to_active) {
321  } else {
322  LOG_LB << "Ignoring whisper from " << sender;
323  }
324 }
325 
326 void chatbox::add_chat_room_message_sent(const std::string& room, const std::string& message)
327 {
328  lobby_chat_window* t = room_window_open(room, false);
329  if(!t) {
330  LOG_LB << "Cannot add sent message to ui for room " << room << ", player not in the room";
331  return;
332  }
333 
334  if(!room_window_active(room)) {
336  }
337 
338  add_active_window_message(prefs::get().login(), message, true);
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 {
346 
347  if(room_window_active(room)) {
350  } else {
351  add_room_window_message(room, speaker, message);
354  }
355 
356  if(speaker == "server") {
358  } else if (utils::word_match(message, prefs::get().login())) {
360  } else if (prefs::get().is_friend(speaker)) {
362  }
363 
364  do_notify(notify_mode, speaker, message);
365 }
366 
367 bool chatbox::whisper_window_active(const std::string& name)
368 {
370  return t.name == name && t.whisper == true;
371 }
372 
373 bool chatbox::room_window_active(const std::string& room)
374 {
376  return t.name == room && t.whisper == false;
377 }
378 
379 lobby_chat_window* chatbox::room_window_open(const std::string& room, const bool open_new, const bool allow_close)
380 {
381  return find_or_create_window(room, false, open_new, allow_close,
382  VGETTEXT("Joined <i>$name</i>", { { "name", translation::dsgettext("wesnoth-lib", room.c_str()) } }));
383 }
384 
385 lobby_chat_window* chatbox::whisper_window_open(const std::string& name, bool open_new)
386 {
387  return find_or_create_window(name, true, open_new, true,
388  VGETTEXT("Started private message with <i>$name</i>. "
389  "If you do not want to receive messages from this player, type <i>/ignore $name</i>", { { "name", name } }));
390 }
391 
393  const bool whisper,
394  const bool open_new,
395  const bool allow_close,
396  const std::string& initial_text)
397 {
398  for(auto& t : open_windows_) {
399  if(t.name == name && t.whisper == whisper) {
400  return &t;
401  }
402  }
403 
404  if(!open_new) {
405  return nullptr;
406  }
407 
408  open_windows_.emplace_back(name, whisper);
409 
410  //
411  // Add a new chat log page.
412  //
413  widget_item item;
414  item["use_markup"] = "true";
415  item["label"] = initial_text;
416  widget_data data{{"log_text", item}};
417 
418  if(log_ != nullptr) {
419  log_->emplace(name, chatroom_log{item["label"], whisper});
420  }
421 
423 
424  //
425  // Add a new room window tab.
426  //
427  data.clear();
428  item.clear();
429 
430  if(!whisper) {
431  item["label"] = translation::dsgettext("wesnoth-lib", name.c_str());
432  } else {
433  item["label"] = "<" + name + ">";
434  }
435 
436  data.emplace("room", item);
437 
438  grid& row_grid = roomlistbox_->add_row(data);
439 
440  //
441  // Set up the Close Window button.
442  //
443  button& close_button = row_grid.find_widget<button>("close_window");
444 
445  if(!allow_close) {
447  } else {
448  connect_signal_mouse_left_click(close_button,
449  std::bind(&chatbox::close_window_button_callback, this, open_windows_.back().name, std::placeholders::_3, std::placeholders::_4));
450  }
451 
452  return &open_windows_.back();
453 }
454 
455 void chatbox::close_window_button_callback(std::string room_name, bool& handled, bool& halt)
456 {
457  const int index = std::distance(open_windows_.begin(), std::find_if(open_windows_.begin(), open_windows_.end(),
458  [&room_name](const lobby_chat_window& room) { return room.name == room_name; }
459  ));
460 
462 
463  handled = halt = true;
464 }
465 
466 void chatbox::send_to_server(const ::config& cfg)
467 {
469 }
470 
471 void chatbox::increment_waiting_whispers(const std::string& name)
472 {
473  if(lobby_chat_window* t = whisper_window_open(name, false)) {
474  ++t->pending_messages;
475 
476  if(t->pending_messages == 1) {
477  DBG_LB << "do whisper pending mark row " << (t - &open_windows_[0]) << " with " << t->name;
478 
481  }
482  }
483 }
484 
485 void chatbox::increment_waiting_messages(const std::string& room)
486 {
487  if(lobby_chat_window* t = room_window_open(room, false)) {
488  ++t->pending_messages;
489 
490  if(t->pending_messages == 1) {
491  int idx = t - &open_windows_[0];
492 
493  DBG_LB << "do room pending mark row " << idx << " with " << t->name;
494 
497  }
498  }
499 }
500 
501 void chatbox::add_whisper_window_whisper(const std::string& sender, const std::string& message)
502 {
503  lobby_chat_window* t = whisper_window_open(sender, false);
504  if(!t) {
505  ERR_LB << "Whisper window not open in add_whisper_window_whisper for " << sender;
506  return;
507  }
508 
509  const std::string text = formatter() << markup::bold(sender, ": ") << font::escape_text(message);
510  append_to_chatbox(text, t - &open_windows_[0], false);
511 }
512 
513 void chatbox::add_active_window_whisper(const std::string& sender,
514  const std::string& message,
515  const bool force_scroll)
516 {
517  const std::string text = formatter() << markup::bold("whisper: ", sender, ": ") << font::escape_text(message);
518  append_to_chatbox(text, force_scroll);
519 }
520 
521 void chatbox::close_window(std::size_t idx)
522 {
523  const lobby_chat_window& t = open_windows_[idx];
524 
525  DBG_LB << "Close window " << idx << " - " << t.name;
526 
527  // Can't close the lobby!
528  if((t.name == "lobby" && t.whisper == false) || open_windows_.size() == 1) {
529  return;
530  }
531 
532  // Check if we're closing the currently-active window.
533  const bool active_changed = idx == active_window_;
534 
535  if(active_window_ == open_windows_.size() - 1) {
536  --active_window_;
537  }
538 
539  if(log_ != nullptr) {
540  log_->erase(t.name);
541  }
542 
543  open_windows_.erase(open_windows_.begin() + idx);
544 
545  roomlistbox_->remove_row(idx);
547 
550 
551  if(active_changed) {
553  }
554 }
555 
556 void chatbox::add_room_window_message(const std::string& room,
557  const std::string& sender,
558  const std::string& message)
559 {
560  lobby_chat_window* t = room_window_open(room, false);
561  if(!t) {
562  ERR_LB << "Room window not open in add_room_window_message for " << room;
563  return;
564  }
565 
566  const std::string text = formatter() << markup::bold(sender, ": ") << font::escape_text(message);
567  append_to_chatbox(text, t - &open_windows_[0], false);
568 }
569 
570 void chatbox::add_active_window_message(const std::string& sender,
571  const std::string& message,
572  const bool force_scroll)
573 {
574  const std::string text = formatter() << markup::bold(sender, ": ") << font::escape_text(message);
575  append_to_chatbox(text, force_scroll);
576 }
577 
578 void chatbox::process_message(const ::config& data, bool whisper /*= false*/)
579 {
580  std::string sender = data["sender"];
581  DBG_LB << "process message from " << sender << " " << (whisper ? "(w)" : "")
582  << ", len " << data["message"].str().size();
583 
584  if(prefs::get().is_ignored(sender)) {
585  return;
586  }
587 
588  const std::string& message = data["message"];
589  //prefs::get().parse_admin_authentication(sender, message); TODO: replace
590 
591  if(whisper) {
592  add_whisper_received(sender, message);
593  } else {
594  if (!prefs::get().parse_should_show_lobby_join(sender, message)) return;
595 
596  std::string room = data["room"];
597 
598  // Attempt to send to the currently active room first.
599  if(room.empty()) {
600  LOG_LB << "Message without a room from " << sender << ", falling back to active window";
601  room = open_windows_[active_window_].name;
602  }
603 
604  // If we still don't have a name, fall back to lobby.
605  if(room.empty()) {
606  LOG_LB << "Message without a room from " << sender << ", assuming lobby";
607  room = "lobby";
608  }
609 
610  if(log_ != nullptr && data["type"].str() == "motd") {
611  if(log_->at("lobby").received_motd == message) {
612  LOG_LB << "Ignoring repeated motd";
613  return;
614  } else {
615  log_->at("lobby").received_motd = message;
616  }
617  }
618 
620  }
621 
622  // Notify plugins about the message
623  ::config plugin_data = data;
624  plugin_data["whisper"] = whisper;
625  plugins_manager::get()->notify_event("chat", plugin_data);
626 }
627 
628 void chatbox::process_network_data(const ::config& data)
629 {
630  if(const auto message = data.optional_child("message")) {
632  } else if(const auto whisper = data.optional_child("whisper")) {
633  process_message(*whisper, true);
634  }
635 }
636 
638 {
639  DBG_GUI_E << LOG_HEADER << ' ' << event << ".";
640 
641  // Forward focus to the input textbox.
643 }
644 
645 // }---------- DEFINITION ---------{
646 
649 {
650  load_resolutions<resolution>(cfg);
651 }
652 
655 {
656  state.emplace_back(VALIDATE_WML_CHILD(cfg, "background", missing_mandatory_wml_tag("chatbox_definition][resolution", "background")));
657  state.emplace_back(VALIDATE_WML_CHILD(cfg, "foreground", missing_mandatory_wml_tag("chatbox_definition][resolution", "foreground")));
658 
659  auto child = VALIDATE_WML_CHILD(cfg, "grid", missing_mandatory_wml_tag("chatbox_definition][resolution", "grid"));
660  grid = std::make_shared<builder_grid>(child);
661 }
662 // }---------- BUILDER -----------{
663 
664 namespace implementation
665 {
666 
667 builder_chatbox::builder_chatbox(const config& cfg)
669 {
670 }
671 
672 std::unique_ptr<widget> builder_chatbox::build() const
673 {
674  auto widget = std::make_unique<chatbox>(*this);
675 
676  DBG_GUI_G << "Window builder: placed unit preview pane '" << id
677  << "' with definition '" << definition << "'.";
678 
679  const auto conf = widget->cast_config_to<chatbox_definition>();
680  assert(conf);
681 
682  widget->init_grid(*conf->grid);
683  widget->finalize_setup();
684 
685  return widget;
686 }
687 
688 } // namespace implementation
689 
690 // }------------ END --------------
691 
692 } // namespace gui2
double t
Definition: astarsearch.cpp:63
#define LOG_LB
Definition: chatbox.cpp:41
#define ERR_LB
Definition: chatbox.cpp:42
#define LOG_HEADER
Definition: chatbox.cpp:45
static lg::log_domain log_lobby("lobby")
#define DBG_LB
Definition: chatbox.cpp:40
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:158
virtual void send_chat_room_message(const std::string &room, const std::string &message)
virtual void send_whisper(const std::string &receiver, const std::string &message)
std::ostringstream wrapper.
Definition: formatter.hpp:40
Simple push button.
Definition: button.hpp:36
std::map< std::string, chatroom_log > * log_
Definition: chatbox.hpp:136
bool room_window_active(const std::string &room)
Definition: chatbox.cpp:373
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:379
text_box * chat_input_
Definition: chatbox.hpp:128
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:392
virtual void clear_messages() override
Definition: chatbox.cpp:259
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:513
void append_to_chatbox(const std::string &text, const bool force_scroll=false)
Definition: chatbox.cpp:218
virtual void user_relation_changed(const std::string &name) override
Inherited form chat_handler.
Definition: chatbox.cpp:267
virtual void send_chat_message(const std::string &message, bool allies_only) override
Inherited form chat_handler.
Definition: chatbox.cpp:253
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:570
void close_window(std::size_t idx)
Definition: chatbox.cpp:521
void add_whisper_window_whisper(const std::string &sender, const std::string &message)
Add a whisper message to the whisper window.
Definition: chatbox.cpp:501
void close_window_button_callback(std::string room_name, bool &handled, bool &halt)
Definition: chatbox.cpp:455
virtual void add_chat_room_message_sent(const std::string &room, const std::string &message) override
Inherited form chat_handler.
Definition: chatbox.cpp:326
multi_page * chat_log_container_
Definition: chatbox.hpp:126
void process_message(const ::config &data, bool whisper=false)
Definition: chatbox.cpp:578
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:385
void switch_to_window(lobby_chat_window *t)
Switch to the window given by a valid pointer (e.g.
Definition: chatbox.cpp:130
std::size_t active_window_
Definition: chatbox.hpp:132
virtual void add_whisper_sent(const std::string &receiver, const std::string &message) override
Inherited form chat_handler.
Definition: chatbox.cpp:290
void process_network_data(const ::config &data)
Definition: chatbox.cpp:628
void increment_waiting_whispers(const std::string &name)
Mark the whisper window for "name" as having one more pending message.
Definition: chatbox.cpp:471
std::function< void(void)> active_window_changed_callback_
Definition: chatbox.hpp:134
listbox * roomlistbox_
Definition: chatbox.hpp:124
void increment_waiting_messages(const std::string &room)
Mark the room window for "room" as having one more pending message.
Definition: chatbox.cpp:485
void signal_handler_receive_keyboard_focus(const event::ui_event event)
Definition: chatbox.cpp:637
void send_to_server(const ::config &cfg) override
Definition: chatbox.cpp:466
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
void load_log(std::map< std::string, chatroom_log > &log, bool show_lobby)
Definition: chatbox.cpp:90
virtual void add_whisper_received(const std::string &sender, const std::string &message) override
Inherited form chat_handler.
Definition: chatbox.cpp:302
virtual void add_chat_message(const std::chrono::system_clock::time_point &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:274
void finalize_setup()
Initializes the internal sub-widget pointers.
Definition: chatbox.cpp:73
void chat_input_keypress_callback(const SDL_Keycode key)
Definition: chatbox.cpp:149
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:556
void active_window_changed()
Definition: chatbox.cpp:115
std::vector< lobby_chat_window > open_windows_
Definition: chatbox.hpp:130
bool whisper_window_active(const std::string &name)
Definition: chatbox.cpp:367
A generic container base class.
Main class to show messages to the user.
Definition: message.hpp:36
Base container class.
Definition: grid.hpp:32
grid & add_row(const widget_item &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:92
const grid * get_row_grid(const unsigned row) const
Returns the grid of the wanted row.
Definition: listbox.cpp:256
bool select_row(const unsigned row, const bool select=true)
Selects a row.
Definition: listbox.cpp:267
void remove_row(const unsigned row, unsigned count=1)
Removes a row in the listbox.
Definition: listbox.cpp:108
int get_selected_row() const
Returns the first selected row.
Definition: listbox.cpp:289
const grid & page_grid(const unsigned page) const
Returns the grid for the page.
Definition: multi_page.cpp:134
void remove_page(const unsigned page, unsigned count=1)
Removes a page in the multi page.
Definition: multi_page.cpp:90
grid & add_page(const widget_item &item)
Adds single page to the grid.
Definition: multi_page.cpp:58
void select_page(const unsigned page, const bool select=true)
Selects a page.
Definition: multi_page.cpp:119
std::string get_value()
Definition: scroll_text.cpp:76
virtual void set_label(const t_string &label) override
Definition: scroll_text.cpp:62
void set_value(const t_string &label)
Definition: scroll_text.hpp:47
@ END
Go to the end position.
Definition: scrollbar.hpp:58
void scroll_vertical_scrollbar(const scrollbar_base::scroll_mode scroll)
Scrolls the vertical scrollbar.
unsigned get_vertical_scrollbar_item_position() const
Returns current position of the vertical scrollbar.
void set_vertical_scrollbar_item_position(const unsigned position)
Move the vertical scrollbar to a position.
virtual void set_use_markup(bool use_markup)
std::string get_value() const
virtual void set_value(const std::string &text)
The set_value is virtual for the password_box class.
bool is_composing() const
void save_to_history()
Saves the text in the widget to the history.
Definition: text_box.hpp:132
Base class for all widgets.
Definition: widget.hpp:55
void set_visible(const visibility visible)
Definition: widget.cpp:479
const std::string & id() const
Definition: widget.cpp:110
window * get_window()
Get the parent window.
Definition: widget.cpp:117
@ visible
The user sets the widget visible, that means:
@ hidden
The user sets the widget hidden, that means:
T * find_widget(const std::string_view id, const bool must_be_active, const bool must_exist)
Gets a widget with the wanted id.
Definition: widget.hpp:747
void keyboard_capture(widget *widget)
Definition: window.cpp:1201
void notify_event(const std::string &name, const config &data)
Definition: manager.cpp:144
static plugins_manager * get()
Definition: manager.cpp:58
static prefs & get()
bool is_ignored(const std::string &nick)
bool is_friend(const std::string &nick)
std::string login()
bool auto_open_whisper_windows()
const config * cfg
#define VGETTEXT(msgid,...)
Handy wrappers around interpolate_variables_into_string and gettext.
static std::string _(const char *str)
Definition: gettext.hpp:97
#define DBG_GUI_G
Definition: log.hpp:41
#define DBG_GUI_E
Definition: log.hpp:35
This file contains the window object, this object is a top level container which has the event manage...
Standard logging facilities (interface).
std::string escape_text(std::string_view text)
Escapes the pango markup characters in a text.
Definition: escape.hpp:33
void connect_signal_pre_key_press(dispatcher &dispatcher, const signal_keyboard &signal)
Connects the signal for 'snooping' on the keypress.
Definition: dispatcher.cpp:158
ui_event
The event sent to the dispatcher.
Definition: handler.hpp:115
void connect_signal_notify_modified(dispatcher &dispatcher, const signal_notification &signal)
Connects a signal handler for getting a notification upon modification.
Definition: dispatcher.cpp:189
void connect_signal_mouse_left_click(dispatcher &dispatcher, const signal &signal)
Connects a signal handler for a left mouse button click.
Definition: dispatcher.cpp:163
Generic file dialog.
std::map< std::string, widget_item > widget_data
Definition: widget.hpp:36
std::map< std::string, t_string > widget_item
Definition: widget.hpp:33
Functions to load and save images from/to disk.
Contains the implementation details for lexical_cast and shouldn't be used directly.
std::string italic(Args &&... data)
Applies italic Pango markup to the input.
Definition: markup.hpp:176
std::string bold(Args &&... data)
Applies bold Pango markup to the input.
Definition: markup.hpp:161
std::string span_color(const color_t &color, Args &&... data)
Applies Pango markup to the input specifying its display color.
Definition: markup.hpp:110
lobby_info * get_lobby_info()
Returns the lobby_info object for the given session.
void do_notify(notify_mode mode, const std::string &sender, const std::string &message)
Definition: lobby_info.cpp:58
void send_to_server(const config &data)
Attempts to send given data to server if a connection is open.
notify_mode
Definition: lobby_info.hpp:154
std::string dsgettext(const char *domainname, const char *msgid)
Definition: gettext.cpp:434
std::size_t index(std::string_view str, const std::size_t index)
Codepoint index corresponding to the nth character in a UTF-8 string.
Definition: unicode.cpp:70
std::string join(const T &v, const std::string &s=",")
Generates a new string joining container items in a list.
bool word_match(const std::string &message, const std::string &word)
Check if a message contains a word.
bool word_completion(std::string &text, std::vector< std::string > &wordlist)
Try to complete the last word of 'text' with the 'wordlist'.
std::string_view data
Definition: picture.cpp:188
#define REGISTER_WIDGET(id)
Wrapper for REGISTER_WIDGET3.
chatbox_definition(const config &cfg)
Definition: chatbox.cpp:647
virtual std::unique_ptr< widget > build() const override
Definition: chatbox.cpp:672
std::string definition
Parameters for the styled_widget.
std::vector< state_definition > state
std::string missing_mandatory_wml_tag(const std::string &section, const std::string &tag)
Returns a standard message for a missing wml child (tag).
Add a special kind of assert to validate whether the input from WML doesn't contain any problems that...
#define VALIDATE_WML_CHILD(cfg, key, message)