The Battle for Wesnoth  1.17.23+dev
chatbox.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2016 - 2023
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 
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"
35 #include "gettext.hpp"
36 #include "log.hpp"
38 #include "preferences/game.hpp"
39 #include "preferences/lobby.hpp"
41 #include "wml_exception.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  , log_(nullptr)
66 {
67  // We only implement a RECEIVE_KEYBOARD_FOCUS handler; LOSE_KEYBOARD_FOCUS
68  // isn't needed. This handler forwards focus to the input textbox, meaning
69  // if keyboard_focus is called on a chatbox, distributor::keyboard_focus_
70  // will immediately be set to the input textbox, which will then handle focus
71  // loss itself when applicable. Nothing else happens in the interim while
72  // keyboard_focus_ equals `this` to warrent cleanup.
73  connect_signal<event::RECEIVE_KEYBOARD_FOCUS>(
74  std::bind(&chatbox::signal_handler_receive_keyboard_focus, this, std::placeholders::_2));
75 }
76 
78 {
79  roomlistbox_ = find_widget<listbox>(this, "room_list", false, true);
80 
81  // We need to bind a lambda here since switch_to_window is overloaded.
82  // A lambda alone would be more verbose because it'd need to specify all the parameters.
84  std::bind([this]() { switch_to_window(roomlistbox_->get_selected_row()); }));
85 
86  chat_log_container_ = find_widget<multi_page>(this, "chat_log_container", false, true);
87 
88  chat_input_ = find_widget<text_box>(this, "chat_input", false, true);
89 
91  std::bind(&chatbox::chat_input_keypress_callback, this, std::placeholders::_5));
92 }
93 
94 void chatbox::load_log(std::map<std::string, chatroom_log>& log, bool show_lobby)
95 {
96  for(const auto& l : log) {
97  const bool is_lobby = l.first == "lobby";
98 
99  if(!show_lobby && is_lobby && !l.second.whisper) {
100  continue;
101  }
102 
103  find_or_create_window(l.first, l.second.whisper, true, !is_lobby, l.second.log);
104  }
105 
106  log_ = &log;
107 }
108 
110 {
112 
113  // Clear pending messages notification in room listbox
115  find_widget<image>(grid, "pending_messages", false).set_visible(widget::visibility::hidden);
116 
117  t.pending_messages = 0;
118 
121  }
122 }
123 
125 {
127 }
128 
129 void chatbox::switch_to_window(std::size_t id)
130 {
131  active_window_ = id;
132  assert(active_window_ < open_windows_.size());
133 
136 
137  // Grab input focus
139 
141 }
142 
143 void chatbox::chat_input_keypress_callback(const SDL_Keycode key)
144 {
145  std::string input = chat_input_->get_value();
146  if(input.empty() || chat_input_->is_composing()) {
147  return;
148  }
149 
151 
152  switch(key) {
153  case SDLK_RETURN:
154  case SDLK_KP_ENTER: {
155  if(input[0] == '/') {
156  // TODO: refactor do_speak so it uses context information about
157  // opened window, so e.g. /ignore in a whisper session ignores
158  // the other party without having to specify it's nick.
159  chat_handler::do_speak(input);
160  } else {
161  if(t.whisper) {
162  send_whisper(t.name, input);
163  add_whisper_sent(t.name, input);
164  } else {
165  send_chat_room_message(t.name, input);
166  add_chat_room_message_sent(t.name, input);
167  }
168  }
169 
171  chat_input_->set_value("");
172 
173  break;
174  }
175 
176  case SDLK_TAB: {
177  auto* li = mp::get_lobby_info();
178  if(!li) {
179  break;
180  }
181 
182  // TODO: very inefficient! Very! D:
183  std::vector<std::string> matches;
184  for(const auto& ui : li->users()) {
185  if(ui.name != preferences::login()) {
186  matches.push_back(ui.name);
187  }
188  }
189 
190  const bool line_start = utils::word_completion(input, matches);
191 
192  if(matches.empty()) {
193  return;
194  }
195 
196  if(matches.size() == 1) {
197  input.append(line_start ? ": " : " ");
198  } else {
199  std::string completion_list = utils::join(matches, " ");
200  append_to_chatbox(completion_list);
201  }
202 
203  chat_input_->set_value(input);
204 
205  break;
206  }
207 
208  default:
209  break;
210  }
211 }
212 
213 void chatbox::append_to_chatbox(const std::string& text, const bool force_scroll)
214 {
215  append_to_chatbox(text, active_window_, force_scroll);
216 }
217 
218 void chatbox::append_to_chatbox(const std::string& text, std::size_t id, const bool force_scroll)
219 {
221 
222  scroll_label& log = find_widget<scroll_label>(&grid, "log_text", false);
223  const bool chatbox_at_end = log.vertical_scrollbar_at_end();
224  const unsigned chatbox_position = log.get_vertical_scrollbar_item_position();
225 
226  const std::string before_message = log.get_label().empty() ? "" : "\n";
227  const std::string new_text = formatter()
228  << log.get_label() << before_message << "<span color='#bcb088'>" << preferences::get_chat_timestamp(std::time(0)) << text << "</span>";
229 
230  log.set_use_markup(true);
231  log.set_label(new_text);
232 
233  if(log_ != nullptr) {
234  try {
235  const std::string& room_name = open_windows_[id].name;
236  log_->at(room_name).log = new_text;
237  } catch(const std::out_of_range&) {
238  }
239  }
240 
241  if(chatbox_at_end || force_scroll) {
243  } else {
244  log.set_vertical_scrollbar_item_position(chatbox_position);
245  }
246 }
247 
248 void chatbox::send_chat_message(const std::string& message, bool /*allies_only*/)
249 {
250  add_chat_message(std::time(nullptr), preferences::login(), 0, message);
251 
252  ::config c {"message", ::config {"message", message, "sender", preferences::login()}};
253  send_to_server(c);
254 }
255 
257 {
258  const auto id = active_window_;
260  scroll_label& log = find_widget<scroll_label>(&grid, "log_text", false);
261  log.set_label("");
262 }
263 
264 void chatbox::user_relation_changed(const std::string& /*name*/)
265 {
268  }
269 }
270 
271 void chatbox::add_chat_message(const std::time_t& /*time*/,
272  const std::string& speaker,
273  int /*side*/,
274  const std::string& message,
276 {
277  std::string text;
278 
279  // FIXME: the chat_command_handler class (which handles chat commands) dispatches a
280  // message consisting of '/me insert text here' in the case the '/me' or '/emote'
281  // commands are used, so we need to do some manual preprocessing here.
282  if(message.compare(0, 4, "/me ") == 0) {
283  text = formatter() << "<i>" << speaker << " " << font::escape_text(message.substr(4)) << "</i>";
284  } else {
285  text = formatter() << "<b>" << speaker << ":</b> " << font::escape_text(message);
286  }
287 
288  append_to_chatbox(text);
289 }
290 
291 void chatbox::add_whisper_sent(const std::string& receiver, const std::string& message)
292 {
293  if(whisper_window_active(receiver)) {
298  } else {
299  add_active_window_whisper(VGETTEXT("whisper to $receiver", {{"receiver", receiver}}), message, true);
300  }
301 }
302 
303 void chatbox::add_whisper_received(const std::string& sender, const std::string& message)
304 {
305  bool can_go_to_active = !preferences::whisper_friends_only() || preferences::is_friend(sender);
306  bool can_open_new = preferences::auto_open_whisper_windows() && can_go_to_active;
307 
308  if(whisper_window_open(sender, can_open_new)) {
309  if(whisper_window_active(sender)) {
311 
313  } else {
316 
318  }
319  } else if(can_go_to_active) {
322  } else {
323  LOG_LB << "Ignoring whisper from " << sender;
324  }
325 }
326 
327 void chatbox::add_chat_room_message_sent(const std::string& room, const std::string& message)
328 {
329  lobby_chat_window* t = room_window_open(room, false);
330  if(!t) {
331  LOG_LB << "Cannot add sent message to ui for room " << room << ", player not in the room";
332  return;
333  }
334 
335  if(!room_window_active(room)) {
337  }
338 
340 }
341 
342 void chatbox::add_chat_room_message_received(const std::string& room,
343  const std::string& speaker,
344  const std::string& message)
345 {
347 
348  if(room_window_active(room)) {
351  } else {
352  add_room_window_message(room, speaker, message);
355  }
356 
357  if(speaker == "server") {
361  } else if (preferences::is_friend(speaker)) {
363  }
364 
365  do_notify(notify_mode, speaker, message);
366 }
367 
368 bool chatbox::whisper_window_active(const std::string& name)
369 {
371  return t.name == name && t.whisper == true;
372 }
373 
374 bool chatbox::room_window_active(const std::string& room)
375 {
377  return t.name == room && t.whisper == false;
378 }
379 
380 lobby_chat_window* chatbox::room_window_open(const std::string& room, const bool open_new, const bool allow_close)
381 {
382  return find_or_create_window(room, false, open_new, allow_close,
383  VGETTEXT("Joined <i>$name</i>", { { "name", translation::dsgettext("wesnoth-lib", room.c_str()) } }));
384 }
385 
386 lobby_chat_window* chatbox::whisper_window_open(const std::string& name, bool open_new)
387 {
388  return find_or_create_window(name, true, open_new, true,
389  VGETTEXT("Started private message with <i>$name</i>. "
390  "If you do not want to receive messages from this player, type <i>/ignore $name</i>", { { "name", name } }));
391 }
392 
394  const bool whisper,
395  const bool open_new,
396  const bool allow_close,
397  const std::string& initial_text)
398 {
399  for(auto& t : open_windows_) {
400  if(t.name == name && t.whisper == whisper) {
401  return &t;
402  }
403  }
404 
405  if(!open_new) {
406  return nullptr;
407  }
408 
409  open_windows_.emplace_back(name, whisper);
410 
411  //
412  // Add a new chat log page.
413  //
415  item["use_markup"] = "true";
416  item["label"] = initial_text;
417  widget_data data{{"log_text", item}};
418 
419  if(log_ != nullptr) {
420  log_->emplace(name, chatroom_log{item["label"], whisper});
421  }
422 
424 
425  //
426  // Add a new room window tab.
427  //
428  data.clear();
429  item.clear();
430 
431  if(!whisper) {
432  item["label"] = translation::dsgettext("wesnoth-lib", name.c_str());
433  } else {
434  item["label"] = "<" + name + ">";
435  }
436 
437  data.emplace("room", item);
438 
439  grid& row_grid = roomlistbox_->add_row(data);
440 
441  //
442  // Set up the Close Window button.
443  //
444  button& close_button = find_widget<button>(&row_grid, "close_window", false);
445 
446  if(!allow_close) {
448  } else {
449  connect_signal_mouse_left_click(close_button,
450  std::bind(&chatbox::close_window_button_callback, this, open_windows_.back().name, std::placeholders::_3, std::placeholders::_4));
451  }
452 
453  return &open_windows_.back();
454 }
455 
456 void chatbox::close_window_button_callback(std::string room_name, bool& handled, bool& halt)
457 {
458  const int index = std::distance(open_windows_.begin(), std::find_if(open_windows_.begin(), open_windows_.end(),
459  [&room_name](const lobby_chat_window& room) { return room.name == room_name; }
460  ));
461 
463 
464  handled = halt = true;
465 }
466 
467 void chatbox::send_to_server(const ::config& cfg)
468 {
469  mp::send_to_server(cfg);
470 }
471 
472 void chatbox::increment_waiting_whispers(const std::string& name)
473 {
474  if(lobby_chat_window* t = whisper_window_open(name, false)) {
475  ++t->pending_messages;
476 
477  if(t->pending_messages == 1) {
478  DBG_LB << "do whisper pending mark row " << (t - &open_windows_[0]) << " with " << t->name;
479 
481  find_widget<image>(grid, "pending_messages", false).set_visible(widget::visibility::visible);
482  }
483  }
484 }
485 
486 void chatbox::increment_waiting_messages(const std::string& room)
487 {
488  if(lobby_chat_window* t = room_window_open(room, false)) {
489  ++t->pending_messages;
490 
491  if(t->pending_messages == 1) {
492  int idx = t - &open_windows_[0];
493 
494  DBG_LB << "do room pending mark row " << idx << " with " << t->name;
495 
497  find_widget<image>(grid, "pending_messages", false).set_visible(widget::visibility::visible);
498  }
499  }
500 }
501 
502 void chatbox::add_whisper_window_whisper(const std::string& sender, const std::string& message)
503 {
504  lobby_chat_window* t = whisper_window_open(sender, false);
505  if(!t) {
506  ERR_LB << "Whisper window not open in add_whisper_window_whisper for " << sender;
507  return;
508  }
509 
510  const std::string text = formatter() << "<b>" << sender << ":</b> " << font::escape_text(message);
511  append_to_chatbox(text, t - &open_windows_[0], false);
512 }
513 
514 void chatbox::add_active_window_whisper(const std::string& sender,
515  const std::string& message,
516  const bool force_scroll)
517 {
518  const std::string text = formatter() << "<b>" << "whisper: " << sender << ":</b> " << font::escape_text(message);
519  append_to_chatbox(text, force_scroll);
520 }
521 
522 void chatbox::close_window(std::size_t idx)
523 {
524  const lobby_chat_window& t = open_windows_[idx];
525 
526  DBG_LB << "Close window " << idx << " - " << t.name;
527 
528  // Can't close the lobby!
529  if((t.name == "lobby" && t.whisper == false) || open_windows_.size() == 1) {
530  return;
531  }
532 
533  // Check if we're closing the currently-active window.
534  const bool active_changed = idx == active_window_;
535 
536  if(active_window_ == open_windows_.size() - 1) {
537  --active_window_;
538  }
539 
540  if(log_ != nullptr) {
541  log_->erase(t.name);
542  }
543 
544  open_windows_.erase(open_windows_.begin() + idx);
545 
546  roomlistbox_->remove_row(idx);
548 
551 
552  if(active_changed) {
554  }
555 }
556 
557 void chatbox::add_room_window_message(const std::string& room,
558  const std::string& sender,
559  const std::string& message)
560 {
561  lobby_chat_window* t = room_window_open(room, false);
562  if(!t) {
563  ERR_LB << "Room window not open in add_room_window_message for " << room;
564  return;
565  }
566 
567  const std::string text = formatter() << "<b>" << sender << ":</b> " << font::escape_text(message);
568  append_to_chatbox(text, t - &open_windows_[0], false);
569 }
570 
571 void chatbox::add_active_window_message(const std::string& sender,
572  const std::string& message,
573  const bool force_scroll)
574 {
575  const std::string text = formatter() << "<b>" << sender << ":</b> " << font::escape_text(message);
576  append_to_chatbox(text, force_scroll);
577 }
578 
579 void chatbox::process_message(const ::config& data, bool whisper /*= false*/)
580 {
581  std::string sender = data["sender"];
582  DBG_LB << "process message from " << sender << " " << (whisper ? "(w)" : "")
583  << ", len " << data["message"].str().size();
584 
585  if(preferences::is_ignored(sender)) {
586  return;
587  }
588 
589  const std::string& message = data["message"];
590  //preferences::parse_admin_authentication(sender, message); TODO: replace
591 
592  if(whisper) {
593  add_whisper_received(sender, message);
594  } else {
596 
597  std::string room = data["room"];
598 
599  // Attempt to send to the currently active room first.
600  if(room.empty()) {
601  LOG_LB << "Message without a room from " << sender << ", falling back to active window";
602  room = open_windows_[active_window_].name;
603  }
604 
605  // If we still don't have a name, fall back to lobby.
606  if(room.empty()) {
607  LOG_LB << "Message without a room from " << sender << ", assuming lobby";
608  room = "lobby";
609  }
610 
611  if(log_ != nullptr && data["type"].str() == "motd") {
612  if(log_->at("lobby").received_motd == message) {
613  LOG_LB << "Ignoring repeated motd";
614  return;
615  } else {
616  log_->at("lobby").received_motd = message;
617  }
618  }
619 
621  }
622 
623  // Notify plugins about the message
624  ::config plugin_data = data;
625  plugin_data["whisper"] = whisper;
626  plugins_manager::get()->notify_event("chat", plugin_data);
627 }
628 
629 void chatbox::process_network_data(const ::config& data)
630 {
631  if(const auto message = data.optional_child("message")) {
633  } else if(const auto whisper = data.optional_child("whisper")) {
634  process_message(*whisper, true);
635  }
636 }
637 
639 {
640  DBG_GUI_E << LOG_HEADER << ' ' << event << ".";
641 
642  // Forward focus to the input textbox.
644 }
645 
646 // }---------- DEFINITION ---------{
647 
650 {
651  load_resolutions<resolution>(cfg);
652 }
653 
655  : resolution_definition(cfg), grid()
656 {
657  state.emplace_back(VALIDATE_WML_CHILD(cfg, "background", _("Missing required background for chatbox")));
658  state.emplace_back(VALIDATE_WML_CHILD(cfg, "foreground", _("Missing required foreground for chatbox")));
659 
660  auto child = VALIDATE_WML_CHILD(cfg, "grid", _("Missing required grid for chatbox"));
661  grid = std::make_shared<builder_grid>(child);
662 }
663 // }---------- BUILDER -----------{
664 
665 namespace implementation
666 {
667 
668 builder_chatbox::builder_chatbox(const config& cfg)
669  : builder_styled_widget(cfg)
670 {
671 }
672 
673 std::unique_ptr<widget> builder_chatbox::build() const
674 {
675  auto widget = std::make_unique<chatbox>(*this);
676 
677  DBG_GUI_G << "Window builder: placed unit preview pane '" << id
678  << "' with definition '" << definition << "'.";
679 
680  const auto conf = widget->cast_config_to<chatbox_definition>();
681  assert(conf);
682 
683  widget->init_grid(*conf->grid);
684  widget->finalize_setup();
685 
686  return widget;
687 }
688 
689 } // namespace implementation
690 
691 // }------------ END --------------
692 
693 } // namespace gui2
double t
Definition: astarsearch.cpp:65
#define LOG_LB
Definition: chatbox.cpp:45
#define ERR_LB
Definition: chatbox.cpp:46
#define LOG_HEADER
Definition: chatbox.cpp:49
static lg::log_domain log_lobby("lobby")
#define DBG_LB
Definition: chatbox.cpp:44
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:161
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:37
std::map< std::string, chatroom_log > * log_
Definition: chatbox.hpp:137
bool room_window_active(const std::string &room)
Definition: chatbox.cpp:374
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:380
text_box * chat_input_
Definition: chatbox.hpp:129
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:393
virtual void clear_messages() override
Definition: chatbox.cpp:256
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:514
void append_to_chatbox(const std::string &text, const bool force_scroll=false)
Definition: chatbox.cpp:213
virtual void user_relation_changed(const std::string &name) override
Inherited form chat_handler.
Definition: chatbox.cpp:264
virtual void send_chat_message(const std::string &message, bool allies_only) override
Inherited form chat_handler.
Definition: chatbox.cpp:248
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:571
void close_window(std::size_t idx)
Definition: chatbox.cpp:522
void add_whisper_window_whisper(const std::string &sender, const std::string &message)
Add a whisper message to the whisper window.
Definition: chatbox.cpp:502
void close_window_button_callback(std::string room_name, bool &handled, bool &halt)
Definition: chatbox.cpp:456
virtual void add_chat_room_message_sent(const std::string &room, const std::string &message) override
Inherited form chat_handler.
Definition: chatbox.cpp:327
multi_page * chat_log_container_
Definition: chatbox.hpp:127
void process_message(const ::config &data, bool whisper=false)
Definition: chatbox.cpp:579
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:386
void switch_to_window(lobby_chat_window *t)
Switch to the window given by a valid pointer (e.g.
Definition: chatbox.cpp:124
std::size_t active_window_
Definition: chatbox.hpp:133
virtual void add_whisper_sent(const std::string &receiver, const std::string &message) override
Inherited form chat_handler.
Definition: chatbox.cpp:291
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:271
void process_network_data(const ::config &data)
Definition: chatbox.cpp:629
void increment_waiting_whispers(const std::string &name)
Mark the whisper window for "name" as having one more pending message.
Definition: chatbox.cpp:472
std::function< void(void)> active_window_changed_callback_
Definition: chatbox.hpp:135
listbox * roomlistbox_
Definition: chatbox.hpp:125
void increment_waiting_messages(const std::string &room)
Mark the room window for "room" as having one more pending message.
Definition: chatbox.cpp:486
void signal_handler_receive_keyboard_focus(const event::ui_event event)
Definition: chatbox.cpp:638
void send_to_server(const ::config &cfg) override
Definition: chatbox.cpp:467
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:342
void load_log(std::map< std::string, chatroom_log > &log, bool show_lobby)
Definition: chatbox.cpp:94
virtual void add_whisper_received(const std::string &sender, const std::string &message) override
Inherited form chat_handler.
Definition: chatbox.cpp:303
void finalize_setup()
Initializes the internal sub-widget pointers.
Definition: chatbox.cpp:77
void chat_input_keypress_callback(const SDL_Keycode key)
Definition: chatbox.cpp:143
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:557
void active_window_changed()
Definition: chatbox.cpp:109
std::vector< lobby_chat_window > open_windows_
Definition: chatbox.hpp:131
bool whisper_window_active(const std::string &name)
Definition: chatbox.cpp:368
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:62
const grid * get_row_grid(const unsigned row) const
Returns the grid of the wanted row.
Definition: listbox.cpp:233
bool select_row(const unsigned row, const bool select=true)
Selects a row.
Definition: listbox.cpp:246
void remove_row(const unsigned row, unsigned count=1)
Removes a row in the listbox.
Definition: listbox.cpp:82
int get_selected_row() const
Returns the first selected row.
Definition: listbox.cpp:271
const grid & page_grid(const unsigned page) const
Returns the grid for the page.
Definition: multi_page.cpp:120
void remove_page(const unsigned page, unsigned count=1)
Removes a page in the multi page.
Definition: multi_page.cpp:76
grid & add_page(const widget_item &item)
Adds single page to the grid.
Definition: multi_page.cpp:44
void select_page(const unsigned page, const bool select=true)
Selects a page.
Definition: multi_page.cpp:105
Label showing a text.
virtual void set_label(const t_string &label) override
See styled_widget::set_label.
virtual void set_use_markup(bool use_markup) override
See styled_widget::set_use_markup.
@ END
Go to the end position.
Definition: scrollbar.hpp:61
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.
const t_string & get_label() const
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:149
Base class for all widgets.
Definition: widget.hpp:54
void set_visible(const visibility visible)
Definition: widget.cpp:471
const std::string & id() const
Definition: widget.cpp:111
window * get_window()
Get the parent window.
Definition: widget.cpp:118
@ visible
The user sets the widget visible, that means:
@ hidden
The user sets the widget hidden, that means:
void keyboard_capture(widget *widget)
Definition: window.cpp:1224
void notify_event(const std::string &name, const config &data)
Definition: manager.cpp:145
static plugins_manager * get()
Definition: manager.cpp:59
bool empty() const
Definition: tstring.hpp:187
#define VGETTEXT(msgid,...)
Handy wrappers around interpolate_variables_into_string and gettext.
static std::string _(const char *str)
Definition: gettext.hpp:93
#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(const std::string &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:174
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:205
void connect_signal_mouse_left_click(dispatcher &dispatcher, const signal &signal)
Connects a signal handler for a left mouse button click.
Definition: dispatcher.cpp:179
Generic file dialog.
std::map< std::string, widget_item > widget_data
Definition: widget.hpp:35
std::map< std::string, t_string > widget_item
Definition: widget.hpp:32
std::pair< std::string, unsigned > item
Definition: help_impl.hpp:414
Contains the implementation details for lexical_cast and shouldn't be used directly.
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:62
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:155
bool is_ignored(const std::string &nick)
Definition: game.cpp:276
bool whisper_friends_only()
Definition: lobby.cpp:21
std::string get_chat_timestamp(const std::time_t &t)
Definition: game.cpp:863
bool parse_should_show_lobby_join(const std::string &sender, const std::string &message)
Definition: game.cpp:304
std::string login()
bool is_friend(const std::string &nick)
Definition: game.cpp:264
bool auto_open_whisper_windows()
Definition: lobby.cpp:31
std::string dsgettext(const char *domainname, const char *msgid)
Definition: gettext.cpp:436
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:72
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:199
#define REGISTER_WIDGET(id)
Wrapper for REGISTER_WIDGET3.
This file contains the settings handling of the widget library.
chatbox_definition(const config &cfg)
Definition: chatbox.cpp:648
virtual std::unique_ptr< widget > build() const override
Definition: chatbox.cpp:673
std::string definition
Parameters for the styled_widget.
Base class of a resolution, contains the common keys for a resolution.
std::vector< state_definition > state
mock_char c
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)