gui/widgets/widget.cpp

Go to the documentation of this file.
00001 /* $Id: widget.cpp 54218 2012-05-19 08:46:15Z mordante $ */
00002 /*
00003    Copyright (C) 2007 - 2012 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 as published by
00008    the Free Software Foundation; either version 2 of the License, or
00009    (at your option) any later version.
00010    This program is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY.
00012 
00013    See the COPYING file for more details.
00014 */
00015 
00016 #define GETTEXT_DOMAIN "wesnoth-lib"
00017 
00018 #include "gui/widgets/settings.hpp"
00019 #include "gui/widgets/window.hpp"
00020 #include "gui/auxiliary/event/message.hpp"
00021 #include "gui/auxiliary/log.hpp"
00022 
00023 namespace gui2 {
00024 
00025 twidget::twidget()
00026     : id_("")
00027     , parent_(NULL)
00028     , x_(-1)
00029     , y_(-1)
00030     , w_(0)
00031     , h_(0)
00032     , dirty_(true)
00033     , visible_(VISIBLE)
00034     , drawing_action_(DRAWN)
00035     , clip_rect_()
00036     , layout_size_(tpoint(0,0))
00037     , linked_group_()
00038 #ifndef LOW_MEM
00039     , debug_border_mode_(0)
00040     , debug_border_color_(0)
00041 #endif
00042 #ifdef DEBUG_WINDOW_LAYOUT_GRAPHS
00043     , last_best_size_(tpoint(0,0))
00044 #endif
00045 {
00046     DBG_GUI_LF << "widget create: " << static_cast<void*>(this) << "\n";
00047 }
00048 
00049 twidget::twidget(const tbuilder_widget& builder)
00050     : id_(builder.id)
00051     , parent_(NULL)
00052     , x_(-1)
00053     , y_(-1)
00054     , w_(0)
00055     , h_(0)
00056     , dirty_(true)
00057     , visible_(VISIBLE)
00058     , drawing_action_(DRAWN)
00059     , clip_rect_()
00060     , layout_size_(tpoint(0,0))
00061     , linked_group_(builder.linked_group)
00062 #ifndef LOW_MEM
00063     , debug_border_mode_(builder.debug_border_mode)
00064     , debug_border_color_(builder.debug_border_color)
00065 #endif
00066 #ifdef DEBUG_WINDOW_LAYOUT_GRAPHS
00067     , last_best_size_(tpoint(0,0))
00068 #endif
00069 {
00070     DBG_GUI_LF << "widget create: " << static_cast<void*>(this) << "\n";
00071 }
00072 
00073 twidget::~twidget()
00074 {
00075     DBG_GUI_LF << "widget destroy: " << static_cast<void*>(this)
00076         << " (id: " << id_ << ")\n";
00077 
00078     twidget* p = parent();
00079     while(p) {
00080         fire(event::NOTIFY_REMOVAL, *p, NULL);
00081         p = p->parent();
00082     }
00083 
00084     if(!linked_group_.empty()) {
00085         if(twindow* window = get_window()) {
00086             window->remove_linked_widget(linked_group_, this);
00087         }
00088     }
00089 }
00090 
00091 void twidget::set_id(const std::string& id)
00092 {
00093     DBG_GUI_LF << "set id of " << static_cast<void*>(this)
00094         << " to '" << id << "' "
00095         << "(was '" << id_ << "'). Widget type: " <<
00096         (dynamic_cast<tcontrol*>(this) ?
00097             dynamic_cast<tcontrol*>(this)->get_control_type()
00098             : typeid(twidget).name())
00099         << "\n";
00100     id_ = id;
00101 }
00102 
00103 
00104 void twidget::layout_init(const bool /*full_initialization*/)
00105 {
00106     assert(visible_ != INVISIBLE);
00107     assert(get_window());
00108 
00109     layout_size_ = tpoint(0,0);
00110     if(!linked_group_.empty()) {
00111         get_window()->add_linked_widget(linked_group_, this);
00112     }
00113 }
00114 
00115 tpoint twidget::get_best_size() const
00116 {
00117     assert(visible_ != INVISIBLE);
00118 
00119     tpoint result = layout_size_;
00120     if(result == tpoint(0, 0)) {
00121         result = calculate_best_size();
00122     }
00123 
00124 #ifdef DEBUG_WINDOW_LAYOUT_GRAPHS
00125     last_best_size_ = result;
00126 #endif
00127     return result;
00128 }
00129 
00130 void twidget::place(const tpoint& origin, const tpoint& size)
00131 {
00132     assert(size.x >= 0);
00133     assert(size.y >= 0);
00134 
00135     x_ = origin.x;
00136     y_ = origin.y;
00137     w_ = size.x;
00138     h_ = size.y;
00139 
00140 #if 0
00141     std::cerr << "Id " << id()
00142         << " rect " << get_rect()
00143         << " parent "
00144             << (parent ? parent->get_x() : 0)
00145             << ','
00146             << (parent ? parent->get_y() : 0)
00147         << " screen origin " << x_ << ',' << y_
00148         << ".\n";
00149 #endif
00150 
00151     set_dirty();
00152 }
00153 
00154 void twidget::set_size(const tpoint& size)
00155 {
00156     assert(size.x >= 0);
00157     assert(size.y >= 0);
00158 
00159     w_ = size.x;
00160     h_ = size.y;
00161 
00162     set_dirty();
00163 }
00164 
00165 twidget* twidget::find_at(const tpoint& coordinate,
00166         const bool must_be_active)
00167 {
00168     return is_at(coordinate, must_be_active) ? this : NULL;
00169 }
00170 
00171 const twidget* twidget::find_at(const tpoint& coordinate,
00172         const bool must_be_active) const
00173 {
00174     return is_at(coordinate, must_be_active) ? this : NULL;
00175 }
00176 
00177 SDL_Rect twidget::get_dirty_rect() const
00178 {
00179     return drawing_action_ == DRAWN
00180             ? get_rect()
00181             : clip_rect_;
00182 }
00183 
00184 void twidget::move(const int x_offset, const int y_offset)
00185 {
00186     x_ += x_offset;
00187     y_ += y_offset;
00188 }
00189 
00190 twindow* twidget::get_window()
00191 {
00192     // Go up into the parent tree until we find the top level
00193     // parent, we can also be the toplevel so start with
00194     // ourselves instead of our parent.
00195     twidget* result = this;
00196     while(result->parent_) {
00197         result = result->parent_;
00198     }
00199 
00200     // on error dynamic_cast return 0 which is what we want.
00201     return dynamic_cast<twindow*>(result);
00202 }
00203 
00204 const twindow* twidget::get_window() const
00205 {
00206     // Go up into the parent tree until we find the top level
00207     // parent, we can also be the toplevel so start with
00208     // ourselves instead of our parent.
00209     const twidget* result = this;
00210     while(result->parent_) {
00211         result = result->parent_;
00212     }
00213 
00214     // on error dynamic_cast return 0 which is what we want.
00215     return dynamic_cast<const twindow*>(result);
00216 }
00217 
00218 tdialog* twidget::dialog()
00219 {
00220     twindow* window = get_window();
00221     return window ? window->dialog() : NULL;
00222 }
00223 
00224 void twidget::populate_dirty_list(twindow& caller,
00225         std::vector<twidget*>& call_stack)
00226 {
00227     assert(call_stack.empty() || call_stack.back() != this);
00228 
00229     if(visible_ != VISIBLE) {
00230         return;
00231     }
00232 
00233     if(get_drawing_action() == NOT_DRAWN) {
00234         return;
00235     }
00236 
00237     call_stack.push_back(this);
00238     if(dirty_) {
00239         caller.add_to_dirty_list(call_stack);
00240     } else {
00241         // virtual function which only does something for container items.
00242         child_populate_dirty_list(caller, call_stack);
00243     }
00244 }
00245 
00246 void twidget::set_visible(const tvisible visible)
00247 {
00248     if(visible == visible_) {
00249         return;
00250     }
00251 
00252     // Switching to or from invisible should invalidate the layout.
00253     const bool need_resize = visible_ == INVISIBLE || visible == INVISIBLE;
00254     visible_ = visible;
00255 
00256     if(need_resize) {
00257         if(new_widgets) {
00258             event::tmessage message;
00259             fire(event::REQUEST_PLACEMENT, *this, message);
00260         } else {
00261             twindow *window = get_window();
00262             if(window) {
00263                 window->invalidate_layout();
00264             }
00265         }
00266     } else {
00267         set_dirty();
00268     }
00269 }
00270 
00271 twidget::tdrawing_action twidget::get_drawing_action() const
00272 {
00273     return (w_ == 0 || h_ == 0)
00274         ? NOT_DRAWN
00275         : drawing_action_;
00276 }
00277 
00278 void twidget::set_visible_area(const SDL_Rect& area)
00279 {
00280     clip_rect_ = intersect_rects(area, get_rect());
00281 
00282     if(clip_rect_ == get_rect()) {
00283         drawing_action_ = DRAWN;
00284     } else if(clip_rect_ == empty_rect) {
00285         drawing_action_ = NOT_DRAWN;
00286     } else {
00287         drawing_action_ = PARTLY_DRAWN;
00288     }
00289 }
00290 
00291 SDL_Rect twidget::calculate_blitting_rectangle(
00292           const int x_offset
00293         , const int y_offset)
00294 {
00295     SDL_Rect result = get_rect();
00296     result.x += x_offset;
00297     result.y += y_offset;
00298     return result;
00299 }
00300 
00301 SDL_Rect twidget::calculate_clipping_rectangle(
00302           const int x_offset
00303         , const int y_offset)
00304 {
00305     SDL_Rect result = clip_rect_;
00306     result.x += x_offset;
00307     result.y += y_offset;
00308     return result;
00309 }
00310 
00311 void twidget::draw_background(surface& frame_buffer)
00312 {
00313     assert(visible_ == VISIBLE);
00314 
00315     if(drawing_action_ == PARTLY_DRAWN) {
00316         clip_rect_setter clip(frame_buffer, &clip_rect_);
00317         draw_debug_border(frame_buffer);
00318         impl_draw_background(frame_buffer);
00319     } else {
00320         draw_debug_border(frame_buffer);
00321         impl_draw_background(frame_buffer);
00322     }
00323 }
00324 
00325 void twidget::draw_background(surface& frame_buffer, int x_offset, int y_offset)
00326 {
00327     assert(visible_ == VISIBLE);
00328 
00329     if(drawing_action_ == PARTLY_DRAWN) {
00330         const SDL_Rect clipping_rectangle =
00331                 calculate_clipping_rectangle(x_offset, y_offset);
00332 
00333         clip_rect_setter clip(frame_buffer, &clipping_rectangle);
00334         draw_debug_border(frame_buffer, x_offset, y_offset);
00335         impl_draw_background(frame_buffer, x_offset, y_offset);
00336     } else {
00337         draw_debug_border(frame_buffer, x_offset, y_offset);
00338         impl_draw_background(frame_buffer, x_offset, y_offset);
00339     }
00340 }
00341 
00342 void twidget::draw_children(surface& frame_buffer)
00343 {
00344     assert(visible_ == VISIBLE);
00345 
00346     if(drawing_action_ == PARTLY_DRAWN) {
00347         clip_rect_setter clip(frame_buffer, &clip_rect_);
00348         impl_draw_children(frame_buffer);
00349     } else {
00350         impl_draw_children(frame_buffer);
00351     }
00352 }
00353 
00354 void twidget::draw_children(surface& frame_buffer, int x_offset, int y_offset)
00355 {
00356     assert(visible_ == VISIBLE);
00357 
00358     if(drawing_action_ == PARTLY_DRAWN) {
00359         const SDL_Rect clipping_rectangle =
00360                 calculate_clipping_rectangle(x_offset, y_offset);
00361 
00362         clip_rect_setter clip(frame_buffer, &clipping_rectangle);
00363         impl_draw_children(frame_buffer, x_offset, y_offset);
00364     } else {
00365         impl_draw_children(frame_buffer, x_offset, y_offset);
00366     }
00367 }
00368 
00369 void twidget::draw_foreground(surface& frame_buffer)
00370 {
00371     assert(visible_ == VISIBLE);
00372 
00373     if(drawing_action_ == PARTLY_DRAWN) {
00374         clip_rect_setter clip(frame_buffer, &clip_rect_);
00375         impl_draw_foreground(frame_buffer);
00376     } else {
00377         impl_draw_foreground(frame_buffer);
00378     }
00379 }
00380 
00381 void twidget::draw_foreground(surface& frame_buffer, int x_offset, int y_offset)
00382 {
00383     assert(visible_ == VISIBLE);
00384 
00385     if(drawing_action_ == PARTLY_DRAWN) {
00386         const SDL_Rect clipping_rectangle =
00387                 calculate_clipping_rectangle(x_offset, y_offset);
00388 
00389         clip_rect_setter clip(frame_buffer, &clipping_rectangle);
00390         impl_draw_foreground(frame_buffer, x_offset, y_offset);
00391     } else {
00392         impl_draw_foreground(frame_buffer, x_offset, y_offset);
00393     }
00394 }
00395 
00396 #ifndef LOW_MEM
00397 void twidget::draw_debug_border(surface& frame_buffer)
00398 {
00399     SDL_Rect r = drawing_action_ == PARTLY_DRAWN
00400         ? clip_rect_
00401         : get_rect();
00402     switch(debug_border_mode_) {
00403         case 0:
00404             /* DO NOTHING */
00405             break;
00406         case 1:
00407             draw_rectangle(r.x, r.y, r.w, r.h
00408                     , debug_border_color_, frame_buffer);
00409             break;
00410         case 2:
00411             sdl_fill_rect(frame_buffer, &r, debug_border_color_);
00412             break;
00413         default:
00414             assert(false);
00415     }
00416 }
00417 
00418 void twidget::draw_debug_border(
00419           surface& frame_buffer
00420         , int x_offset
00421         , int y_offset)
00422 {
00423     SDL_Rect r = drawing_action_ == PARTLY_DRAWN
00424         ? calculate_clipping_rectangle(x_offset, y_offset)
00425         : calculate_blitting_rectangle(x_offset, y_offset);
00426 
00427     switch(debug_border_mode_) {
00428         case 0:
00429             /* DO NOTHING */
00430             break;
00431         case 1:
00432             draw_rectangle(r.x, r.y, r.w, r.h
00433                     , debug_border_color_, frame_buffer);
00434             break;
00435         case 2:
00436             sdl_fill_rect(frame_buffer, &r, debug_border_color_);
00437             break;
00438         default:
00439             assert(false);
00440     }
00441 }
00442 #endif
00443 
00444 bool twidget::is_at(const tpoint& coordinate, const bool must_be_active) const
00445 {
00446     if(visible_ == INVISIBLE
00447             || (visible_ == HIDDEN && must_be_active)) {
00448         return false;
00449     }
00450 
00451     return coordinate.x >= x_
00452             && coordinate.x < (x_ + static_cast<int>(w_))
00453             && coordinate.y >= y_
00454             && coordinate.y < (y_ + static_cast<int>(h_)) ? true : false;
00455 }
00456 } // namespace gui2
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated by doxygen 1.7.1 on Fri May 25 2012 01:03:00 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs