1 #pragma once 2 #ifndef CATA_SRC_STRING_INPUT_POPUP_H 3 #define CATA_SRC_STRING_INPUT_POPUP_H 4 5 #include <cstddef> 6 #include <cstdint> 7 #include <functional> 8 #include <iosfwd> 9 #include <map> 10 #include <memory> 11 #include <vector> 12 13 #include "color.h" 14 #include "cursesdef.h" 15 16 class input_context; 17 class utf8_wrapper; 18 struct point; 19 20 /** 21 * Shows a window querying the user for input. 22 * 23 * Returns the input that was entered. If the user cancels the input (e.g. by pressing Escape), 24 * an empty string is returned. An empty string may also be returned when the user does not enter 25 * any text and confirms the input (by pressing ENTER). 26 * 27 * Examples: 28 * \code 29 input = string_input_popup().title("Enter something").query(); 30 // shows the input field in window w at coordinates (10,20) up to (30,20). 31 input = string_input_popup().window(w, 10, 20, 30).query(); 32 * \endcode 33 * 34 * @param title The displayed title, describing what to enter. @ref color_tags can be used. 35 * @param width Width of the input area where the user input appears. 36 * @param input The initially display input. The user can change this. 37 * @param desc An optional text (e.h. help or formatting information) which is displayed 38 * above the input. Color tags can be used. 39 * @param identifier If not empty, this is used to store and retrieve previously entered 40 * text. All calls with the same `identifier` share this history, the history is also stored 41 * when saving the game (see @ref uistate). 42 * @param max_length The maximal length of the text the user can input. More input is simply 43 * ignored and the returned string is never longer than this. 44 * @param only_digits Whether to only allow digits in the string. 45 */ 46 class string_input_popup // NOLINT(cata-xy) 47 { 48 private: 49 std::string _title; 50 std::string _text; 51 std::string _description; 52 std::string _identifier; 53 std::string _session_str_entered; 54 nc_color _title_color = c_light_red; 55 nc_color _desc_color = c_green; 56 nc_color _string_color = c_magenta; 57 nc_color _cursor_color = h_light_gray; 58 nc_color _underscore_color = c_light_gray; 59 int _width = 0; 60 int _max_length = -1; 61 bool _only_digits = false; 62 bool _hist_use_uilist = true; 63 bool _ignore_custom_actions = true; 64 int _startx = 0; 65 int _starty = 0; 66 int _endx = 0; 67 int _position = -1; 68 // in output (console) cells, not characters of the string! 69 int shift = 0; 70 int _hist_str_ind = 0; 71 //Counts only when @_hist_use_uilist is false 72 const size_t _hist_max_size = 100; 73 74 // Cache when using the default window 75 int w_width = 0; 76 int w_height = 0; 77 std::vector<std::string> descformatted; 78 std::vector<std::string> title_split; 79 int titlesize = 0; 80 81 bool custom_window = false; 82 catacurses::window w; 83 84 std::unique_ptr<input_context> ctxt_ptr; 85 input_context *ctxt = nullptr; 86 87 bool _canceled = false; 88 bool _confirmed = false; 89 bool _handled = false; 90 91 void create_window(); 92 void create_context(); 93 94 void show_history( utf8_wrapper &ret ); 95 void add_to_history( const std::string &value ) const; 96 void update_input_history( utf8_wrapper &ret, bool up ); 97 void draw( const utf8_wrapper &ret, const utf8_wrapper &edit ) const; 98 99 public: 100 string_input_popup(); 101 ~string_input_popup(); 102 /** 103 * The title: short string before the actual input field. 104 * It's optional, default is an empty string. 105 */ title(const std::string & value)106 string_input_popup &title( const std::string &value ) { 107 _title = value; 108 return *this; 109 } 110 /** 111 * Set / get the text that can be modified by the user. 112 * Note that canceling the query makes this an empty string. 113 * It's optional default is an empty string. 114 */ 115 /**@{*/ 116 string_input_popup &text( const std::string &value ); text()117 const std::string &text() const { 118 return _text; 119 } 120 /**@}*/ 121 /** 122 * Additional help text, shown below the input box. 123 * It's optional, default is an empty text. 124 */ description(const std::string & value)125 string_input_popup &description( const std::string &value ) { 126 _description = value; 127 return *this; 128 } 129 /** 130 * An identifier to be used to store / get the input 131 * history. If empty (the default), no history will be 132 * available, otherwise the history associated with 133 * the identifier will be available. 134 * If the input is not canceled, the new input is 135 * added to the history. 136 */ identifier(const std::string & value)137 string_input_popup &identifier( const std::string &value ) { 138 _identifier = value; 139 return *this; 140 } 141 /** 142 * Width (in console cells) of the input field itself. 143 */ width(int value)144 string_input_popup &width( int value ) { 145 _width = value; 146 return *this; 147 } 148 /** 149 * Maximal amount of Unicode characters that can be 150 * given by the user. The default is something like 1000. 151 */ max_length(int value)152 string_input_popup &max_length( int value ) { 153 _max_length = value; 154 return *this; 155 } 156 /** 157 * If true, any non-digit input cancels the input. Default is false. 158 */ only_digits(bool value)159 string_input_popup &only_digits( bool value ) { 160 _only_digits = value; 161 return *this; 162 } 163 /** 164 * Make any difference only if @identifier is used. 165 * If true, create UiList window with query history, otherwise use arrow keys at string input to move through history. 166 * Default is true. 167 */ hist_use_uilist(bool value)168 string_input_popup &hist_use_uilist( bool value ) { 169 _hist_use_uilist = value; 170 return *this; 171 } 172 /** 173 * If true and the custom input context returns an input action, the 174 * action is not handled at all and left to be handled by the caller. 175 * Otherwise the action is always handled as an input event to the popup. 176 * The caller can use @ref handled to check whether the last input is handled. 177 */ ignore_custom_actions(const bool value)178 string_input_popup &ignore_custom_actions( const bool value ) { 179 _ignore_custom_actions = value; 180 return *this; 181 } 182 /** 183 * Set the window area where to display the input text. If this is set, 184 * the class will not create a separate window and *only* the editable 185 * text will be printed at the given part of the given window. 186 * Integer parameters define the area (one line) where the editable 187 * text is printed. 188 * 189 * This method only has effect before the default window is initialized. 190 * After that calls to this method are just ignored. 191 */ 192 string_input_popup &window( const catacurses::window &w, const point &start, int endx ); 193 /** 194 * Set / get the input context that is used to gather user input. 195 * The class will create its own context if none is set here. 196 */ 197 /**@{*/ 198 string_input_popup &context( input_context &ctxt ); context()199 input_context &context() const { 200 return *ctxt; 201 } 202 /** 203 * Set / get the foreground color of the title. 204 * Optional, default value is c_light_red. 205 */ title_color(const nc_color & color)206 string_input_popup &title_color( const nc_color &color ) { 207 _title_color = color; 208 return *this; 209 } 210 /** 211 * Set / get the foreground color of the description. 212 * Optional, default value is c_green. 213 */ desc_color(const nc_color & color)214 string_input_popup &desc_color( const nc_color &color ) { 215 _desc_color = color; 216 return *this; 217 } 218 /** 219 * Set / get the foreground color of the input string. 220 * Optional, default value is c_magenta. 221 */ string_color(const nc_color & color)222 string_input_popup &string_color( const nc_color &color ) { 223 _string_color = color; 224 return *this; 225 } 226 /** 227 * Set / get the foreground color of the caret. 228 * Optional, default value is h_light_gray. 229 */ cursor_color(const nc_color & color)230 string_input_popup &cursor_color( const nc_color &color ) { 231 _cursor_color = color; 232 return *this; 233 } 234 /** 235 * Set / get the foreground color of the dashed line. 236 * Optional, default value is c_light_gray. 237 */ underscore_color(const nc_color & color)238 string_input_popup &underscore_color( const nc_color &color ) { 239 _underscore_color = color; 240 return *this; 241 } 242 /**@}*/ 243 /** 244 * Draws the input box, waits for input (if \p loop is true). 245 * @return @ref text() 246 */ 247 /**@{*/ 248 void query( bool loop = true, bool draw_only = false ); 249 int query_int( bool loop = true, bool draw_only = false ); 250 int64_t query_int64_t( bool loop = true, bool draw_only = false ); 251 const std::string &query_string( bool loop = true, bool draw_only = false ); 252 /**@}*/ 253 /** 254 * Whether the input box was canceled via the ESCAPE key (or similar) 255 * If the input was finished via the ENTER key (or similar), this will 256 * return `false`. 257 */ canceled()258 bool canceled() const { 259 return _canceled; 260 } 261 /** 262 * Returns true if query was finished via the ENTER key. 263 */ confirmed()264 bool confirmed() const { 265 return _confirmed; 266 } 267 /** 268 * Returns false if the last input was unhandled. Useful to avoid handling 269 * input already handled by the popup itself. 270 */ handled()271 bool handled() const { 272 return _handled; 273 } 274 /** 275 * Edit values in place. This combines: calls to @ref text to set the 276 * current value, @ref query to get user input and setting the 277 * value back into the parameter object (when the popup was not 278 * canceled). Canceling the popup keeps the value unmodified. 279 */ 280 /**@{*/ 281 void edit( std::string &value ); 282 // Acceptable to use long as part of overload set 283 // NOLINTNEXTLINE(cata-no-long) 284 void edit( long &value ); 285 void edit( int &value ); 286 /**@}*/ 287 288 std::map<long, std::function<bool()>> callbacks; 289 }; 290 291 #endif // CATA_SRC_STRING_INPUT_POPUP_H 292