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/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 )
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
00193
00194
00195 twidget* result = this;
00196 while(result->parent_) {
00197 result = result->parent_;
00198 }
00199
00200
00201 return dynamic_cast<twindow*>(result);
00202 }
00203
00204 const twindow* twidget::get_window() const
00205 {
00206
00207
00208
00209 const twidget* result = this;
00210 while(result->parent_) {
00211 result = result->parent_;
00212 }
00213
00214
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
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
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
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
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 }