00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #define GETTEXT_DOMAIN "wesnoth-lib"
00017
00018 #include "gui/widgets/text_box.hpp"
00019
00020 #include "font.hpp"
00021 #include "foreach.hpp"
00022 #include "gui/auxiliary/log.hpp"
00023 #include "gui/auxiliary/widget_definition/text_box.hpp"
00024 #include "gui/auxiliary/window_builder/text_box.hpp"
00025 #include "gui/widgets/settings.hpp"
00026 #include "gui/widgets/window.hpp"
00027 #include "game_preferences.hpp"
00028
00029 #include <boost/bind.hpp>
00030
00031 #define LOG_SCOPE_HEADER get_control_type() + " [" + id() + "] " + __func__
00032 #define LOG_HEADER LOG_SCOPE_HEADER + ':'
00033
00034 namespace gui2 {
00035
00036 REGISTER_WIDGET(text_box)
00037
00038 ttext_history ttext_history::get_history(const std::string& id, const bool enabled)
00039 {
00040 std::vector<std::string>* vec = preferences::get_history(id);
00041 return ttext_history(vec, enabled);
00042 }
00043
00044 void ttext_history::push(const std::string& text)
00045 {
00046 if (!enabled_) {
00047 return;
00048 } else {
00049 if (!text.empty() && (history_->empty() || text != history_->back())) {
00050 history_->push_back(text);
00051 }
00052
00053 pos_ = history_->size();
00054 }
00055 }
00056
00057 std::string ttext_history::up(const std::string& text)
00058 {
00059
00060 if (!enabled_) {
00061 return "";
00062 } else if (pos_ == history_->size()) {
00063 unsigned curr = pos_;
00064 push(text);
00065 pos_ = curr;
00066 }
00067
00068 if (pos_ != 0) {
00069 --pos_;
00070 }
00071
00072 return get_value();
00073 }
00074
00075 std::string ttext_history::down(const std::string& text)
00076 {
00077 if (!enabled_) {
00078 return "";
00079 } else if (pos_ == history_->size()) {
00080 push(text);
00081 } else {
00082 pos_++;
00083 }
00084
00085 return get_value();
00086 }
00087
00088 std::string ttext_history::get_value() const
00089 {
00090 if (!enabled_ || pos_ == history_->size()) {
00091 return "";
00092 } else {
00093 return history_->at(pos_);
00094 }
00095 }
00096
00097 ttext_box::ttext_box()
00098 : ttext_()
00099 , history_()
00100 , text_x_offset_(0)
00101 , text_y_offset_(0)
00102 , text_height_(0)
00103 , dragging_(false)
00104 {
00105 set_wants_mouse_left_double_click();
00106
00107 connect_signal<event::MOUSE_MOTION>(boost::bind(
00108 &ttext_box::signal_handler_mouse_motion, this, _2, _3, _5));
00109 connect_signal<event::LEFT_BUTTON_DOWN>(boost::bind(
00110 &ttext_box::signal_handler_left_button_down, this, _2, _3));
00111 connect_signal<event::LEFT_BUTTON_UP>(boost::bind(
00112 &ttext_box::signal_handler_left_button_up, this, _2, _3));
00113 connect_signal<event::LEFT_BUTTON_DOUBLE_CLICK>(boost::bind(&ttext_box
00114 ::signal_handler_left_button_double_click, this, _2, _3));
00115 }
00116
00117 void ttext_box::place(const tpoint& origin, const tpoint& size)
00118 {
00119
00120 tcontrol::place(origin, size);
00121
00122 set_maximum_width(get_text_maximum_width());
00123 set_maximum_height(get_text_maximum_height());
00124
00125 update_offsets();
00126 }
00127
00128 void ttext_box::update_canvas()
00129 {
00130
00131
00132
00133 const unsigned start = get_selection_start();
00134 const int length = get_selection_length();
00135
00136
00137 PangoEllipsizeMode ellipse_mode = PANGO_ELLIPSIZE_NONE;
00138 if(!can_wrap()) {
00139 if((start + length) > (get_length() / 2)) {
00140 ellipse_mode = PANGO_ELLIPSIZE_START;
00141 } else {
00142 ellipse_mode = PANGO_ELLIPSIZE_END;
00143 }
00144 }
00145 set_ellipse_mode(ellipse_mode);
00146
00147
00148 unsigned start_offset = 0;
00149 unsigned end_offset = 0;
00150 if(length == 0) {
00151
00152 } else if(length > 0) {
00153 start_offset = get_cursor_position(start).x;
00154 end_offset = get_cursor_position(start + length).x;
00155 } else {
00156 start_offset = get_cursor_position(start + length).x;
00157 end_offset = get_cursor_position(start).x;
00158 }
00159
00160
00161
00162 const int max_width = get_text_maximum_width();
00163 const int max_height = get_text_maximum_height();
00164
00165 foreach(tcanvas& tmp, canvas()) {
00166
00167 tmp.set_variable("text", variant(get_value()));
00168 tmp.set_variable("text_x_offset", variant(text_x_offset_));
00169 tmp.set_variable("text_y_offset", variant(text_y_offset_));
00170 tmp.set_variable("text_maximum_width", variant(max_width));
00171 tmp.set_variable("text_maximum_height", variant(max_height));
00172
00173 tmp.set_variable("cursor_offset",
00174 variant(get_cursor_position(start + length).x));
00175
00176 tmp.set_variable("selection_offset", variant(start_offset));
00177 tmp.set_variable("selection_width", variant(end_offset - start_offset ));
00178 tmp.set_variable("text_wrap_mode", variant(ellipse_mode));
00179 }
00180 }
00181
00182 void ttext_box::delete_char(const bool before_cursor)
00183 {
00184 if(before_cursor) {
00185 set_cursor(get_selection_start() - 1, false);
00186 }
00187
00188 set_selection_length(1);
00189
00190 delete_selection();
00191 }
00192
00193 void ttext_box::delete_selection()
00194 {
00195 if(get_selection_length() == 0) {
00196 return;
00197 }
00198
00199
00200
00201 int len = get_selection_length();
00202 unsigned start = get_selection_start();
00203 if(len < 0) {
00204 len = - len;
00205 start -= len;
00206 }
00207
00208
00209 wide_string tmp = utils::string_to_wstring(get_value());
00210 tmp.erase(tmp.begin() + start, tmp.begin() + start + len);
00211 const std::string& text = utils::wstring_to_string(tmp);
00212 set_value(text);
00213 set_cursor(start, false);
00214 }
00215
00216 void ttext_box::handle_mouse_selection(tpoint mouse, const bool start_selection)
00217 {
00218 mouse.x -= get_x();
00219 mouse.y -= get_y();
00220
00221 if(mouse.x < static_cast<int>(text_x_offset_) ||
00222 mouse.y < static_cast<int>(text_y_offset_) ||
00223 mouse.y >= static_cast<int>(text_y_offset_ + text_height_)) {
00224 return;
00225 }
00226
00227 int offset = get_column_line(tpoint(
00228 mouse.x - text_x_offset_, mouse.y - text_y_offset_)).x;
00229
00230 if(offset < 0) {
00231 return;
00232 }
00233
00234
00235 set_cursor(offset, !start_selection);
00236 update_canvas();
00237 set_dirty();
00238 dragging_ |= start_selection;
00239 }
00240
00241 void ttext_box::update_offsets()
00242 {
00243 assert(config());
00244
00245 boost::intrusive_ptr<const ttext_box_definition::tresolution> conf =
00246 boost::dynamic_pointer_cast
00247 <const ttext_box_definition::tresolution>(config());
00248
00249 assert(conf);
00250
00251 text_height_ = font::get_max_height(conf->text_font_size);
00252
00253 game_logic::map_formula_callable variables;
00254 variables.add("height", variant(get_height()));
00255 variables.add("width", variant(get_width()));
00256 variables.add("text_font_height", variant(text_height_));
00257
00258 text_x_offset_ = conf->text_x_offset(variables);
00259 text_y_offset_ = conf->text_y_offset(variables);
00260
00261
00262
00263 foreach(tcanvas& tmp, canvas()) {
00264 tmp.set_variable("text_font_height", variant(text_height_));
00265 }
00266
00267
00268 update_canvas();
00269 }
00270
00271 bool ttext_box::history_up()
00272 {
00273 if(!history_.get_enabled()) {
00274 return false;
00275 }
00276
00277 const std::string str = history_.up(get_value());
00278 if(!str.empty()) {
00279 set_value(str);
00280 }
00281 return true;
00282 }
00283
00284 bool ttext_box::history_down()
00285 {
00286 if(!history_.get_enabled()) {
00287 return false;
00288 }
00289
00290 const std::string str = history_.down(get_value());
00291 if(!str.empty()) {
00292 set_value(str);
00293 }
00294 return true;
00295 }
00296
00297 void ttext_box::handle_key_default(
00298 bool& handled, SDLKey key, SDLMod modifier, Uint16 unicode)
00299 {
00300 if(key == SDLK_TAB && (modifier & KMOD_CTRL)) {
00301 if(!(modifier& KMOD_SHIFT)) {
00302 handled = history_up();
00303 } else {
00304 handled = history_down();
00305 }
00306 }
00307
00308 if(!handled) {
00309
00310 ttext_::handle_key_default(handled, key, modifier, unicode);
00311 }
00312 }
00313
00314 void ttext_box::handle_key_clear_line(SDLMod , bool& handled)
00315 {
00316 handled = true;
00317
00318 set_value("");
00319 }
00320
00321 void ttext_box::load_config_extra()
00322 {
00323 assert(config());
00324
00325 boost::intrusive_ptr<const ttext_box_definition::tresolution> conf =
00326 boost::dynamic_pointer_cast
00327 <const ttext_box_definition::tresolution>(config());
00328
00329 assert(conf);
00330
00331 set_font_size(conf->text_font_size);
00332 set_font_style(conf->text_font_style);
00333
00334 update_offsets();
00335 }
00336
00337 const std::string& ttext_box::get_control_type() const
00338 {
00339 static const std::string type = "text_box";
00340 return type;
00341 }
00342
00343 void ttext_box::signal_handler_mouse_motion(
00344 const event::tevent event, bool& handled, const tpoint& coordinate)
00345 {
00346 DBG_GUI_E << get_control_type() << "[" << id() << "]: " << event << ".\n";
00347
00348 if(dragging_) {
00349 handle_mouse_selection(coordinate, false);
00350 }
00351
00352 handled = true;
00353 }
00354
00355 void ttext_box::signal_handler_left_button_down(
00356 const event::tevent event, bool& handled)
00357 {
00358 DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
00359
00360
00361
00362
00363
00364 get_window()->keyboard_capture(this);
00365 get_window()->mouse_capture();
00366
00367 handle_mouse_selection(get_mouse_position(), true);
00368
00369 handled = true;
00370 }
00371
00372 void ttext_box::signal_handler_left_button_up(
00373 const event::tevent event, bool& handled)
00374 {
00375 DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
00376
00377 dragging_ = false;
00378 handled = true;
00379 }
00380
00381 void ttext_box::signal_handler_left_button_double_click(
00382 const event::tevent event, bool& handled)
00383 {
00384 DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
00385
00386 select_all();
00387 handled = true;
00388 }
00389
00390 }
00391