The Battle for Wesnoth  1.19.24+dev
floating_textbox.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2006 - 2025
3  by Joerg Hinrichs <joerg.hinrichs@alice-dsl.de>
4  Copyright (C) 2003 by David White <dave@whitevine.net>
5  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
6 
7  This program is free software; you can redistribute it and/or modify
8  it under the terms of the GNU General Public License as published by
9  the Free Software Foundation; either version 2 of the License, or
10  (at your option) any later version.
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY.
13 
14  See the COPYING file for more details.
15 */
16 
17 #include "floating_textbox.hpp"
18 
19 #include "display_chat_manager.hpp"
20 #include "floating_label.hpp"
21 #include "font/standard_colors.hpp"
22 #include "game_display.hpp"
24 #include "video.hpp"
25 #include "log.hpp"
26 
27 #include <SDL3/SDL_keyboard.h>
28 #include <ctime>
29 
30 static lg::log_domain log_display("display");
31 #define ERR_DP LOG_STREAM(err, log_display)
32 
33 namespace gui
34 {
36  box_(nullptr),
37  check_(nullptr),
38  mode_(TEXTBOX_NONE),
39  label_string_(),
40  label_(0),
41  command_history_()
42 {}
43 
45 {
46  if(!active()) {
47  return;
48  }
49 
50  if(check_ != nullptr && mode_ == TEXTBOX_MESSAGE) {
52  }
53  box_.reset(nullptr);
54  check_.reset(nullptr);
57 
58 #if defined(__ANDROID__) || defined(__IPHONEOS__)
59  // Hide onscreen keyboard
60  SDL_StopTextInput(video::get_window());
61 #endif
62 }
63 
65 {
66  if(box_ == nullptr) {
67  return;
68  }
69 
70  const rect& area = gui.map_outside_area();
71 
72  const int border_size = 10;
73 
74 #ifdef __ANDROID__
75  // On Android the Onscreen keyboard hides this box if aligned to bottom,
76  // so we align it to top instead.
77  const int ypos = area.y + border_size - (check_ != nullptr ? check_->height() + border_size : 0);
78 #else
79  const int ypos = area.y + area.h - 30 - (check_ != nullptr ? check_->height() + border_size : 0);
80 #endif
81 
82  if(label_ != 0) {
84  }
85 
88  flabel.set_position(area.x + border_size, ypos);
90  flabel.set_clip_rect(area);
91 
93 
94  if(label_ == 0) {
95  return;
96  }
97 
98  const rect& label_area = font::get_floating_label_rect(label_);
99  const int textbox_width = area.w - label_area.w - border_size * 3;
100 
101  if(textbox_width <= 0) {
103  return;
104  }
105 
106  if(box_ != nullptr) {
107  const rect rect {
108  area.x + label_area.w + border_size * 2
109  , ypos
110  , textbox_width
111  , box_->height()
112  };
113 
114  box_->set_location(rect);
115  }
116 
117  if(check_ != nullptr) {
118  check_->set_location(box_->location().x,box_->location().y + box_->location().h + border_size);
119  }
120 }
121 
123  gui::TEXTBOX_MODE mode, const std::string& label,
124  const std::string& check_label, bool checked, game_display& gui)
125 {
126  close();
127 
129  mode_ = mode;
130 
131  if(!check_label.empty()) {
132  check_.reset(new gui::button(check_label,gui::button::TYPE_CHECK));
133  check_->set_check(checked);
134  }
135 
136  box_.reset(new gui::textbox(100,"",true,256,font::SIZE_NORMAL,0.8,0.6));
137 
139 
140 #if defined(__ANDROID__) || defined(__IPHONEOS__)
141  // Show onscreen keyboard
142  SDL_StartTextInput(video::get_window());
143 #endif
144 }
145 
146 void floating_textbox::tab(const std::set<std::string>& dictionary)
147 {
148  if(active() == false) {
149  return;
150  }
151 
152  std::string text = box_->text();
153  std::vector<std::string> matches(dictionary.begin(), dictionary.end());
154  const bool line_start = utils::word_completion(text, matches);
155 
156  if(matches.empty()) {
157  return;
158  }
159 
160  if(matches.size() == 1 && mode_ == gui::TEXTBOX_MESSAGE) {
161  text.append(line_start ? ": " : " ");
162  } else if(matches.size() > 1) {
163  std::string completion_list = utils::join(matches, " ");
165  std::chrono::system_clock::now(), "", 0, completion_list, events::chat_handler::MESSAGE_PRIVATE, false);
166  }
167  box_->set_text(text);
168 }
169 
170 void floating_textbox::memorize_command(const std::string& command)
171 {
172  if(command.empty()) {
173  return;
174  }
175 
176  auto prev = std::find(command_history_.begin(), command_history_.end(), command);
177 
178  if(prev != command_history_.end()) {
179  command_history_.erase(prev);
180  }
181  command_history_.emplace_back(command);
182 }
183 }
map_location prev
Definition: astarsearch.cpp:64
void add_chat_message(const std::chrono::system_clock::time_point &time, const std::string &speaker, int side, const std::string &msg, events::chat_handler::MESSAGE_TYPE type, bool bell)
void set_position(double xpos, double ypos)
void set_alignment(ALIGN align)
void set_color(const color_t &color)
void set_clip_rect(const rect &r)
static game_display * get_singleton()
display_chat_manager & get_chat_manager()
@ TYPE_CHECK
Definition: button.hpp:29
void show(gui::TEXTBOX_MODE mode, const std::string &label, const std::string &check_label, bool checked, game_display &gui)
void memorize_command(const std::string &command)
TEXTBOX_MODE mode() const
void update_location(game_display &gui)
void tab(const std::set< std::string > &dictionary)
std::unique_ptr< gui::button > check_
std::vector< std::string > command_history_
std::unique_ptr< gui::textbox > box_
static prefs & get()
void set_message_private(bool value)
static lg::log_domain log_display("display")
std::string label
What to show in the filter's drop-down list.
Definition: manager.cpp:201
Standard logging facilities (interface).
const color_t YELLOW_COLOR
int add_floating_label(const floating_label &flabel)
add a label floating on the screen above everything else.
rect get_floating_label_rect(int handle)
void remove_floating_label(int handle, const std::chrono::milliseconds &fadeout)
removes the floating label given by 'handle' from the screen
const int SIZE_NORMAL
Definition: constants.cpp:20
General purpose widgets.
@ TEXTBOX_MESSAGE
std::string join(const Range &v, const std::string &s=",")
Generates a new string joining container items in a list.
bool word_completion(std::string &text, std::vector< std::string > &wordlist)
Try to complete the last word of 'text' with the 'wordlist'.
auto * find(Container &container, const Value &value)
Convenience wrapper for using find on a container without needing to comare to end()
Definition: general.hpp:141
SDL_Window * get_window()
Definition: video.cpp:697
An abstract description of a rectangle with integer coordinates.
Definition: rect.hpp:49