control.cpp

Go to the documentation of this file.
00001 /* $Id: control.cpp 26698 2008-05-18 14:25:08Z mordante $ */
00002 /*
00003    copyright (C) 2008 by mark de wever <koraq@xs4all.nl>
00004    part of the battle for wesnoth project http://www.wesnoth.org/
00005 
00006    this program is free software; you can redistribute it and/or modify
00007    it under the terms of the gnu general public license version 2
00008    or at your option any later version.
00009    this program is distributed in the hope that it will be useful,
00010    but without any warranty.
00011 
00012    see the copying file for more details.
00013 */
00014 
00015 #include "gui/widgets/control.hpp"
00016 
00017 #include "font.hpp"
00018 #include "foreach.hpp"
00019 #include "gui/widgets/helper.hpp"
00020 #include "gui/widgets/window.hpp"
00021 #include "log.hpp"
00022 #include "marked-up_text.hpp"
00023 #include "util.hpp"
00024 #include "sdl_utils.hpp"
00025 
00026 #define DBG_G LOG_STREAM_INDENT(debug, gui)
00027 #define LOG_G LOG_STREAM_INDENT(info, gui)
00028 #define WRN_G LOG_STREAM_INDENT(warn, gui)
00029 #define ERR_G LOG_STREAM_INDENT(err, gui)
00030 
00031 #define DBG_G_D LOG_STREAM_INDENT(debug, gui_draw)
00032 #define LOG_G_D LOG_STREAM_INDENT(info, gui_draw)
00033 #define WRN_G_D LOG_STREAM_INDENT(warn, gui_draw)
00034 #define ERR_G_D LOG_STREAM_INDENT(err, gui_draw)
00035 
00036 #define DBG_G_E LOG_STREAM_INDENT(debug, gui_event)
00037 #define LOG_G_E LOG_STREAM_INDENT(info, gui_event)
00038 #define WRN_G_E LOG_STREAM_INDENT(warn, gui_event)
00039 #define ERR_G_E LOG_STREAM_INDENT(err, gui_event)
00040 
00041 #define DBG_G_P LOG_STREAM_INDENT(debug, gui_parse)
00042 #define LOG_G_P LOG_STREAM_INDENT(info, gui_parse)
00043 #define WRN_G_P LOG_STREAM_INDENT(warn, gui_parse)
00044 #define ERR_G_P LOG_STREAM_INDENT(err, gui_parse)
00045 
00046 namespace gui2 {
00047 
00048 tcontrol::tcontrol(const unsigned canvas_count) :
00049     visible_(true),
00050     multiline_label_(false),
00051     wrapped_label_(),
00052     label_(),
00053     tooltip_(),
00054     help_message_(),
00055     canvas_(canvas_count),
00056     restorer_(),
00057     config_(0)
00058 {
00059 }
00060 
00061 void tcontrol::mouse_hover(tevent_handler& event)
00062 {
00063     DBG_G_E << "Control: mouse hover.\n"; 
00064     event.show_tooltip(tooltip_, settings::popup_show_time);
00065 }
00066 
00067 void tcontrol::help_key(tevent_handler& event)
00068 {
00069     DBG_G_E << "Control: help key.\n"; 
00070     event.show_help_popup(help_message_, settings::help_show_time);
00071 }
00072 
00073 void tcontrol::set_size(const SDL_Rect& rect)
00074 {
00075     // resize canvasses
00076     foreach(tcanvas& canvas, canvas_) {
00077         canvas.set_width(rect.w);
00078         canvas.set_height(rect.h);
00079     }
00080 
00081     // clear the cache.
00082     wrapped_label_.clear();
00083     
00084     // inherited
00085     twidget::set_size(rect);
00086 }
00087 
00088 void tcontrol::set_label(const t_string& label)
00089 {
00090     if(label == label_) {
00091         return;
00092     }
00093 
00094     label_ = label;
00095     wrapped_label_.clear();
00096     set_canvas_text();
00097     set_dirty();
00098 }
00099 
00100 tpoint tcontrol::get_minimum_size() const
00101 {
00102     assert(config_);
00103     const tpoint min_size(config_->min_width, config_->min_height);
00104     if(label_.empty()) {
00105         return min_size;
00106     }
00107 
00108     if(!multiline_label_) {
00109         return get_single_line_best_size(min_size);
00110     } else {
00111         return get_multi_line_best_size(min_size);
00112     }
00113 }
00114 
00115 tpoint tcontrol::get_best_size() const
00116 {
00117     assert(config_);
00118 
00119     // Return default on an empty label.
00120     const tpoint default_size(config_->default_width, config_->default_height);
00121     if(label_.empty()) {
00122         return default_size;
00123     }
00124 
00125     if(!multiline_label_) {
00126         return get_single_line_best_size(default_size);
00127     } else {
00128         return get_multi_line_best_size(default_size);
00129     }
00130 }
00131 
00132 tpoint tcontrol::get_maximum_size() const
00133 {
00134     assert(config_);
00135     return tpoint(config_->max_width, config_->max_height);
00136 }
00137 
00138 tpoint tcontrol::get_single_line_best_size(const tpoint& config_size) const
00139 {
00140     assert(!label_.empty());
00141 
00142     // Get the best size depending on the label.
00143     SDL_Rect rect = font::line_size(label_, config_->text_font_size, config_->text_font_style);
00144     const tpoint text_size(rect.w + config_->text_extra_width, rect.h + config_->text_extra_height);
00145 
00146     // Get the best size if default has a 0 value always use the size of the text.
00147     tpoint size(0, 0);
00148     if(config_size == size) { // config_size == 0,0
00149         size = text_size;
00150     } else if(!config_size.x) {
00151         size = tpoint(text_size.x, maximum(config_size.y, text_size.y));
00152     } else if(!config_size.y) {
00153         size = tpoint(maximum(config_size.x, text_size.x), text_size.y);
00154     } else {
00155         size = maximum(config_size, text_size);
00156     }
00157 
00158     // Honour the maximum.
00159     const tpoint maximum_size(config_->max_width, config_->max_height);
00160     if(maximum_size.x && size.x > maximum_size.x) {
00161         size.x = maximum_size.x;
00162     }
00163     if(maximum_size.y && size.y > maximum_size.y) {
00164         size.y = maximum_size.y;
00165     }
00166     return size;
00167 }
00168 
00169 tpoint tcontrol::get_multi_line_best_size(const tpoint& config_size) const
00170 {
00171     assert(!label_.empty());
00172 
00173     // In multiline mode we only expect a fixed width and no
00174     // fixed height so we ignore the height ;-)
00175     const tpoint maximum_size(config_->max_width, config_->max_height);
00176     if(config_size.y || maximum_size.y) {
00177         WRN_G << "Control: Multiline items don't respect the wanted height.\n";
00178     }
00179     unsigned width = 0;
00180     if(!config_size.x && !maximum_size.x) {
00181         // FIMXE implement
00182 /*      const twindow* window = get_window();
00183         if(window) {
00184             const SDL_Rect rect = window->get_client_rect();
00185             LOG_G << "Control: Multiline items want a width, falling back to window size.\n";
00186             width = rect.w;
00187         } else {
00188 */          ERR_G << "Control: Multiline items want a width, no window setting hardcoded.\n";
00189             width = 100;
00190 //      }
00191     } else {
00192 
00193         if(!config_size.x) {
00194             width = maximum_size.x;
00195         } else if(!maximum_size.x) {
00196             width = config_size.x;
00197         } else {
00198             width = minimum(config_size.x, maximum_size.x);
00199         }
00200     }
00201 
00202     static const SDL_Color col = {0, 0, 0, 0};
00203     const std::string& wrapped_message = font::word_wrap_text(label_, config_->text_font_size, width);
00204     surface surf = font::get_rendered_text(wrapped_message, config_->text_font_size, col);
00205     assert(surf);
00206 
00207     return tpoint(surf->w + config_->text_extra_width, surf->h + config_->text_extra_height);
00208 }
00209 
00210 //! Does the widget need to restore the surface before (re)painting?
00211 bool tcontrol::full_redraw() const
00212 {
00213     assert(config());
00214     return config()->state[get_state()].full_redraw;
00215 }
00216 
00217 //! Sets the text variable for the canvases.
00218 void tcontrol::set_canvas_text()
00219 {
00220     // set label in canvases
00221     foreach(tcanvas& canvas, canvas_) {
00222         canvas.set_variable("text", variant(label_));
00223     }
00224 }
00225 
00226 void tcontrol::set_definition(const std::string& definition)
00227 {
00228     assert(!config());
00229     twidget::set_definition(definition);
00230     load_config();
00231     assert(config());
00232 }
00233 
00234 void tcontrol::draw(surface& surface)
00235 {
00236     assert(config_);
00237 
00238     set_dirty(false);
00239     SDL_Rect rect = get_rect();
00240 
00241     if(!visible_) {
00242         // When not visible we first restore our original surface.
00243         // Next time when visible we grab the background again.
00244         if(restorer_) {
00245             DBG_G_D << "Control: drawing setting invisible.\n";
00246             restore_background(surface);
00247             restorer_ = 0;
00248         }
00249         return;
00250     }
00251 
00252     DBG_G_D << "Control: drawing.\n";
00253     if(!restorer_) {
00254         save_background(surface);
00255     } else if(full_redraw()) {
00256         restore_background(surface);
00257     }
00258 
00259     if(multiline_label_) {
00260         // Set the text hardcoded in multiline mode.
00261         if(wrapped_label_.empty()) {
00262             wrapped_label_ = font::word_wrap_text(label_, config_->text_font_size, get_width());
00263         }
00264         canvas(get_state()).set_variable("text", variant(wrapped_label_));
00265     }
00266 
00267     canvas(get_state()).draw(true);
00268     blit_surface(canvas(get_state()).surf(), 0, surface, &rect);
00269 }
00270 
00271 //! Saves the portion of the background.
00272 //!
00273 //! We expect an empty restorer and copy the part in get_rect() to the new 
00274 //! surface. We copy the data since we want to put it back 1:1 and not a blit
00275 //! so can't use get_surface_portion.
00276 //!
00277 //! @param src          background to save.
00278 void tcontrol::save_background(const surface& src)
00279 {
00280     assert(!restorer_);
00281 
00282     restorer_ = gui2::save_background(src, get_rect());
00283 }
00284 
00285 //! Restores a portion of the background.
00286 //!
00287 //! See save_background for more info.
00288 //! 
00289 //! @param dst          Background to restore.
00290 void tcontrol::restore_background(surface& dst)
00291 {
00292     gui2::restore_background(restorer_, dst, get_rect());
00293 }
00294 
00295 //! Inherited from twidget.
00296 //!
00297 //! All classes which use this class as base should call this function in
00298 //! their constructor. Abstract classes shouldn't call this routine. The 
00299 //! classes which call this routine should also define get_control_type().
00300 void tcontrol::load_config()
00301 {
00302     if(!config()) {
00303         set_config(get_control(get_control_type(), definition()));
00304 
00305         assert(canvas().size() == config()->state.size());
00306         for(size_t i = 0; i < canvas().size(); ++i) {
00307             canvas(i) = config()->state[i].canvas;
00308         }
00309 
00310         set_canvas_text();
00311 
00312         load_config_extra();
00313     }
00314 }
00315 
00316 } // namespace gui2
00317 
00318 

Generated by doxygen 1.5.5 on 23 May 2008 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs