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/grid_private.hpp"
00019
00020 #include "gui/auxiliary/iterator/walker_grid.hpp"
00021 #include "gui/auxiliary/log.hpp"
00022 #include "gui/auxiliary/layout_exception.hpp"
00023 #include "gui/widgets/control.hpp"
00024
00025 #include <numeric>
00026
00027 #define LOG_SCOPE_HEADER "tgrid [" + id() + "] " + __func__
00028 #define LOG_HEADER LOG_SCOPE_HEADER + ':'
00029 #define LOG_IMPL_HEADER "tgrid [" + grid.id() + "] " + __func__ + ':'
00030
00031 #define LOG_CHILD_SCOPE_HEADER "tgrid::tchild [" \
00032 + (widget_ ? widget_->id() : "-") + "] " + __func__
00033 #define LOG_CHILD_HEADER LOG_CHILD_SCOPE_HEADER + ':'
00034
00035 namespace gui2 {
00036
00037 tgrid::tgrid(const unsigned rows, const unsigned cols)
00038 : rows_(rows)
00039 , cols_(cols)
00040 , row_height_()
00041 , col_width_()
00042 , row_grow_factor_(rows)
00043 , col_grow_factor_(cols)
00044 , children_(rows * cols)
00045 {
00046 }
00047
00048 tgrid::~tgrid()
00049 {
00050
00051
00052 foreach(tchild& child, children_) {
00053 delete child.widget();
00054 }
00055 }
00056
00057 unsigned tgrid::add_row(const unsigned count)
00058 {
00059 assert(count);
00060
00061
00062
00063 unsigned result = rows_;
00064 set_rows_cols(rows_ + count, cols_);
00065 return result;
00066 }
00067
00068 void tgrid::set_child(twidget* widget, const unsigned row,
00069 const unsigned col, const unsigned flags, const unsigned border_size)
00070 {
00071 assert(row < rows_ && col < cols_);
00072 assert(flags & VERTICAL_MASK);
00073 assert(flags & HORIZONTAL_MASK);
00074
00075 tchild& cell = child(row, col);
00076
00077
00078 if(cell.widget()) {
00079
00080 WRN_GUI_G << LOG_HEADER
00081 << " child '" << cell.id()
00082 << "' at cell '" << row << ',' << col
00083 << "' will be replaced.\n";
00084 delete cell.widget();
00085 }
00086
00087
00088 cell.set_flags(flags);
00089 cell.set_border_size(border_size);
00090 cell.set_widget(widget);
00091 if(cell.widget()) {
00092
00093 cell.widget()->set_parent(this);
00094 }
00095 }
00096
00097 twidget* tgrid::swap_child(
00098 const std::string& id, twidget* widget, const bool recurse,
00099 twidget* new_parent)
00100 {
00101 assert(widget);
00102
00103 foreach(tchild& child, children_) {
00104 if(child.id() != id) {
00105
00106 if(recurse) {
00107
00108 tgrid* grid = dynamic_cast<tgrid*>(child.widget());
00109 if(grid) {
00110
00111 twidget* old = grid->swap_child(id, widget, true);
00112 if(old) {
00113 return old;
00114 }
00115 }
00116 }
00117
00118 continue;
00119 }
00120
00121
00122 twidget* old = child.widget();
00123 assert(old);
00124 old->set_parent(new_parent);
00125
00126 widget->set_parent(this);
00127 child.set_widget(widget);
00128
00129 return old;
00130 }
00131
00132 return NULL;
00133 }
00134
00135 void tgrid::remove_child(const unsigned row, const unsigned col)
00136 {
00137 assert(row < rows_ && col < cols_);
00138
00139 tchild& cell = child(row, col);
00140
00141 if(cell.widget()) {
00142 delete cell.widget();
00143 }
00144 cell.set_widget(NULL);
00145 }
00146
00147 void tgrid::remove_child(const std::string& id, const bool find_all)
00148 {
00149 foreach(tchild& child, children_) {
00150
00151 if(child.id() == id) {
00152 delete child.widget();
00153 child.set_widget(NULL);
00154
00155 if(!find_all) {
00156 break;
00157 }
00158 }
00159 }
00160 }
00161
00162 void tgrid::set_active(const bool active)
00163 {
00164 foreach(tchild& child, children_) {
00165
00166 twidget* widget = child.widget();
00167 if(!widget) {
00168 continue;
00169 }
00170
00171 tgrid* grid = dynamic_cast<tgrid*>(widget);
00172 if(grid) {
00173 grid->set_active(active);
00174 continue;
00175 }
00176
00177 tcontrol* control = dynamic_cast<tcontrol*>(widget);
00178 if(control) {
00179 control->set_active(active);
00180 }
00181 }
00182 }
00183
00184 void tgrid::layout_init(const bool full_initialization)
00185 {
00186
00187 twidget::layout_init(full_initialization);
00188
00189
00190 foreach(tchild& child, children_) {
00191
00192 child.layout_init(full_initialization);
00193
00194 }
00195 }
00196
00197 void tgrid::reduce_width(const unsigned maximum_width)
00198 {
00199
00200 log_scope2(log_gui_layout, LOG_SCOPE_HEADER);
00201 DBG_GUI_L << LOG_HEADER << " maximum width " << maximum_width << ".\n";
00202
00203 tpoint size = get_best_size();
00204 if(size.x <= static_cast<int>(maximum_width)) {
00205 DBG_GUI_L << LOG_HEADER << " Already fits.\n";
00206 return;
00207 }
00208
00209
00210
00211 request_reduce_width(maximum_width);
00212
00213 size = get_best_size();
00214 if(size.x <= static_cast<int>(maximum_width)) {
00215 DBG_GUI_L << LOG_HEADER << " Resize request honoured.\n";
00216 return;
00217 }
00218
00219
00220
00221
00222
00223
00224
00225 DBG_GUI_L << LOG_HEADER << " Resizing failed.\n";
00226
00227 throw tlayout_exception_width_resize_failed();
00228 }
00229
00230 void tgrid::request_reduce_width(const unsigned maximum_width)
00231 {
00232 tpoint size = get_best_size();
00233 if(size.x <= static_cast<int>(maximum_width)) {
00234
00235 return;
00236 }
00237
00238 const unsigned too_wide = size.x - maximum_width;
00239 unsigned reduced = 0;
00240 for(size_t col = 0; col < cols_; ++col) {
00241 if(too_wide - reduced >= col_width_[col]) {
00242 DBG_GUI_L << LOG_HEADER
00243 << " column " << col
00244 << " is too small to be reduced.\n";
00245 continue;
00246 }
00247
00248 const unsigned wanted_width = col_width_[col] - (too_wide - reduced);
00249 const unsigned width = tgrid_implementation::
00250 column_request_reduce_width(*this, col, wanted_width);
00251
00252 if(width < col_width_[col]) {
00253 DBG_GUI_L << LOG_HEADER
00254 << " reduced " << col_width_[col] - width
00255 << " pixels for column " << col
00256 << ".\n";
00257
00258 size.x -= col_width_[col] - width;
00259 col_width_[col] = width;
00260 }
00261
00262 if(size.x <= static_cast<int>(maximum_width)) {
00263 break;
00264 }
00265 }
00266
00267 set_layout_size(calculate_best_size());
00268 }
00269
00270 void tgrid::demand_reduce_width(const unsigned )
00271 {
00272
00273 }
00274
00275 void tgrid::reduce_height(const unsigned maximum_height)
00276 {
00277
00278 log_scope2(log_gui_layout, LOG_SCOPE_HEADER);
00279 DBG_GUI_L << LOG_HEADER << " maximum height " << maximum_height << ".\n";
00280
00281 tpoint size = get_best_size();
00282 if(size.y <= static_cast<int>(maximum_height)) {
00283 DBG_GUI_L << LOG_HEADER << " Already fits.\n";
00284 return;
00285 }
00286
00287
00288
00289 request_reduce_height(maximum_height);
00290
00291 size = get_best_size();
00292 if(size.y <= static_cast<int>(maximum_height)) {
00293 DBG_GUI_L << LOG_HEADER << " Resize request honoured.\n";
00294 return;
00295 }
00296
00297
00298
00299
00300
00301
00302
00303 DBG_GUI_L << LOG_HEADER << " Resizing failed.\n";
00304
00305 throw tlayout_exception_height_resize_failed();
00306 }
00307
00308 void tgrid::request_reduce_height(const unsigned maximum_height)
00309 {
00310 tpoint size = get_best_size();
00311 if(size.y <= static_cast<int>(maximum_height)) {
00312
00313 return;
00314 }
00315
00316 const unsigned too_high = size.y - maximum_height;
00317 unsigned reduced = 0;
00318 for(size_t row = 0; row < rows_; ++row) {
00319 unsigned wanted_height = row_height_[row] - (too_high - reduced);
00320
00321
00322
00323
00324
00325
00326
00327 if(too_high - reduced >= row_height_[row]) {
00328 DBG_GUI_L << LOG_HEADER
00329 << " row " << row
00330 << " height " << row_height_[row]
00331 << " want to reduce " << too_high
00332 << " is too small to be reduced fully try 1 pixel.\n";
00333
00334 wanted_height = 1;
00335 }
00336
00337 const unsigned height = tgrid_implementation::
00338 row_request_reduce_height(*this, row, wanted_height);
00339
00340 if(height < row_height_[row]) {
00341 DBG_GUI_L << LOG_HEADER
00342 << " row " << row
00343 << " height " << row_height_[row]
00344 << " want to reduce " << too_high
00345 << " reduced " << row_height_[row] - height
00346 << " pixels.\n";
00347
00348 size.y -= row_height_[row] - height;
00349 row_height_[row] = height;
00350 }
00351
00352 if(size.y <= static_cast<int>(maximum_height)) {
00353 break;
00354 }
00355 }
00356
00357 size = calculate_best_size();
00358
00359 DBG_GUI_L << LOG_HEADER
00360 << " Requested maximum " << maximum_height
00361 << " resulting height " << size.y
00362 << ".\n";
00363
00364 set_layout_size(size);
00365 }
00366
00367 void tgrid::demand_reduce_height(const unsigned )
00368 {
00369
00370 }
00371
00372 tpoint tgrid::recalculate_best_size()
00373 {
00374 tpoint best_size = calculate_best_size();
00375 set_layout_size(best_size);
00376 return best_size;
00377 }
00378
00379 tpoint tgrid::calculate_best_size() const
00380 {
00381 log_scope2(log_gui_layout, LOG_SCOPE_HEADER);
00382
00383
00384 row_height_.clear();
00385 row_height_.resize(rows_, 0);
00386 col_width_.clear();
00387 col_width_.resize(cols_, 0);
00388
00389
00390 for(unsigned row = 0; row < rows_; ++row) {
00391 for(unsigned col = 0; col < cols_; ++col) {
00392
00393 const tpoint size = child(row, col).get_best_size();
00394
00395 if(size.x > static_cast<int>(col_width_[col])) {
00396 col_width_[col] = size.x;
00397 }
00398
00399 if(size.y > static_cast<int>(row_height_[row])) {
00400 row_height_[row] = size.y;
00401 }
00402
00403 }
00404 }
00405
00406 for(unsigned row = 0; row < rows_; ++row) {
00407 DBG_GUI_L << LOG_HEADER
00408 << " the row_height_ for row " << row
00409 << " will be " << row_height_[row]
00410 << ".\n";
00411 }
00412
00413 for(unsigned col = 0; col < cols_; ++col) {
00414 DBG_GUI_L << LOG_HEADER
00415 << " the col_width_ for column " << col
00416 << " will be " << col_width_[col]
00417 << ".\n";
00418 }
00419
00420 const tpoint result(
00421 std::accumulate(col_width_.begin(), col_width_.end(), 0),
00422 std::accumulate(row_height_.begin(), row_height_.end(), 0));
00423
00424 DBG_GUI_L << LOG_HEADER << " returning " << result << ".\n";
00425 return result;
00426 }
00427
00428 bool tgrid::can_wrap() const
00429 {
00430 foreach(const tchild& child, children_) {
00431 if(child.can_wrap()) {
00432 return true;
00433 }
00434 }
00435
00436
00437 return twidget::can_wrap();
00438 }
00439
00440 void tgrid::place(const tpoint& origin, const tpoint& size)
00441 {
00442 log_scope2(log_gui_layout, LOG_SCOPE_HEADER);
00443
00444
00445
00446 twidget::place(origin, size);
00447
00448 if(!rows_ || !cols_) {
00449 return;
00450 }
00451
00452
00453 const tpoint best_size = calculate_best_size();
00454
00455 assert(row_height_.size() == rows_);
00456 assert(col_width_.size() == cols_);
00457 assert(row_grow_factor_.size() == rows_);
00458 assert(col_grow_factor_.size() == cols_);
00459
00460 DBG_GUI_L << LOG_HEADER
00461 << " best size " << best_size
00462 << " available size " << size
00463 << ".\n";
00464
00465
00466
00467 if(best_size == size) {
00468 layout(origin);
00469 return;
00470 }
00471
00472
00473 if(best_size.x <= size.x && best_size.y <= size.y) {
00474
00475
00476 if(size.x > best_size.x) {
00477 const unsigned w = size.x - best_size.x;
00478 unsigned w_size = std::accumulate(
00479 col_grow_factor_.begin(), col_grow_factor_.end(), 0);
00480
00481 DBG_GUI_L << LOG_HEADER
00482 << " extra width " << w
00483 << " will be divided amount " << w_size
00484 << " units in " << cols_
00485 << " columns.\n";
00486
00487 if(w_size == 0) {
00488
00489 foreach(unsigned& val, col_grow_factor_) {
00490 val = 1;
00491 }
00492 w_size = cols_;
00493 }
00494
00495
00496 const unsigned w_normal = w / w_size;
00497 for(unsigned i = 0; i < cols_; ++i) {
00498 col_width_[i] += w_normal * col_grow_factor_[i];
00499 DBG_GUI_L << LOG_HEADER
00500 << " column " << i
00501 << " with grow factor " << col_grow_factor_[i]
00502 << " set width to " << col_width_[i]
00503 << ".\n";
00504 }
00505
00506 }
00507
00508 if(size.y > best_size.y) {
00509 const unsigned h = size.y - best_size.y;
00510 unsigned h_size = std::accumulate(
00511 row_grow_factor_.begin(), row_grow_factor_.end(), 0);
00512 DBG_GUI_L << LOG_HEADER
00513 << " extra height " << h
00514 << " will be divided amount " << h_size
00515 << " units in " << rows_
00516 << " rows.\n";
00517
00518 if(h_size == 0) {
00519
00520 foreach(unsigned& val, row_grow_factor_) {
00521 val = 1;
00522 }
00523 h_size = rows_;
00524 }
00525
00526
00527 const unsigned h_normal = h / h_size;
00528 for(unsigned i = 0; i < rows_; ++i) {
00529 row_height_[i] += h_normal * row_grow_factor_[i];
00530 DBG_GUI_L << LOG_HEADER
00531 << " row " << i
00532 << " with grow factor " << row_grow_factor_[i]
00533 << " set height to " << row_height_[i]
00534 << ".\n";
00535 }
00536 }
00537
00538 layout(origin);
00539 return;
00540 }
00541
00542
00543 assert(false);
00544 }
00545
00546 void tgrid::set_origin(const tpoint& origin)
00547 {
00548 const tpoint movement = tpoint(
00549 origin.x - get_x(),
00550 origin.y - get_y());
00551
00552
00553 twidget::set_origin(origin);
00554
00555 foreach(tchild& child, children_) {
00556
00557 twidget* widget = child.widget();
00558 assert(widget);
00559
00560 widget->set_origin(tpoint(
00561 widget->get_x() + movement.x,
00562 widget->get_y() + movement.y));
00563 }
00564 }
00565
00566 void tgrid::set_visible_area(const SDL_Rect& area)
00567 {
00568
00569 twidget::set_visible_area(area);
00570
00571 foreach(tchild& child, children_) {
00572
00573 twidget* widget = child.widget();
00574 assert(widget);
00575
00576 widget->set_visible_area(area);
00577 }
00578 }
00579
00580 void tgrid::layout_children()
00581 {
00582 foreach(tchild& child, children_) {
00583 assert(child.widget());
00584 child.widget()->layout_children();
00585 }
00586 }
00587
00588 void tgrid::child_populate_dirty_list(twindow& caller,
00589 const std::vector<twidget*>& call_stack)
00590 {
00591 assert(!call_stack.empty() && call_stack.back() == this);
00592
00593 foreach(tchild& child, children_) {
00594
00595 assert(child.widget());
00596
00597 std::vector<twidget*> child_call_stack = call_stack;
00598 child.widget()->populate_dirty_list(caller, child_call_stack);
00599 }
00600 }
00601
00602 twidget* tgrid::find_at(const tpoint& coordinate,
00603 const bool must_be_active)
00604 {
00605 return tgrid_implementation::find_at<twidget>(
00606 *this, coordinate, must_be_active);
00607 }
00608
00609 const twidget* tgrid::find_at(const tpoint& coordinate,
00610 const bool must_be_active) const
00611 {
00612 return tgrid_implementation::find_at<const twidget>(
00613 *this, coordinate, must_be_active);
00614 }
00615
00616 twidget* tgrid::find(const std::string& id, const bool must_be_active)
00617 {
00618 return tgrid_implementation::find<twidget>(
00619 *this, id, must_be_active);
00620 }
00621
00622 const twidget* tgrid::find(const std::string& id,
00623 const bool must_be_active) const
00624 {
00625 return tgrid_implementation::find<const twidget>(
00626 *this, id, must_be_active);
00627 }
00628
00629 bool tgrid::has_widget(const twidget* widget) const
00630 {
00631 if(twidget::has_widget(widget)) {
00632 return true;
00633 }
00634
00635 foreach(const tchild& child, children_) {
00636 if(child.widget()->has_widget(widget)) {
00637 return true;
00638 }
00639 }
00640 return false;
00641 }
00642
00643 bool tgrid::disable_click_dismiss() const
00644 {
00645 if(get_visible() != twidget::VISIBLE) {
00646 return false;
00647 }
00648
00649 foreach(const tchild& child, children_) {
00650 const twidget* widget = child.widget();
00651 assert(widget);
00652
00653 if(widget->disable_click_dismiss()) {
00654 return true;
00655 }
00656 }
00657 return false;
00658 }
00659
00660 iterator::twalker_* tgrid::create_walker()
00661 {
00662 return new gui2::iterator::tgrid(*this);
00663 }
00664
00665 void tgrid::set_rows(const unsigned rows)
00666 {
00667 if(rows == rows_) {
00668 return;
00669 }
00670
00671 set_rows_cols(rows, cols_);
00672 }
00673
00674 void tgrid::set_cols(const unsigned cols)
00675 {
00676 if(cols == cols_) {
00677 return;
00678 }
00679
00680 set_rows_cols(rows_, cols);
00681 }
00682
00683 void tgrid::set_rows_cols(const unsigned rows, const unsigned cols)
00684 {
00685 if(rows == rows_ && cols == cols_) {
00686 return;
00687 }
00688
00689 if(!children_.empty()) {
00690 WRN_GUI_G << LOG_HEADER << " resizing a non-empty grid "
00691 << " may give unexpected problems.\n";
00692 }
00693
00694 rows_ = rows;
00695 cols_ = cols;
00696 row_grow_factor_.resize(rows);
00697 col_grow_factor_.resize(cols);
00698 children_.resize(rows_ * cols_);
00699 }
00700
00701 tpoint tgrid::tchild::get_best_size() const
00702 {
00703 log_scope2(log_gui_layout, LOG_CHILD_SCOPE_HEADER)
00704
00705 if(!widget_) {
00706 DBG_GUI_L << LOG_CHILD_HEADER
00707 << " has widget " << false
00708 << " returning " << border_space()
00709 << ".\n";
00710 return border_space();
00711 }
00712
00713 if(widget_->get_visible() == twidget::INVISIBLE) {
00714 DBG_GUI_L << LOG_CHILD_HEADER
00715 << " has widget " << true
00716 << " widget visible " << false
00717 << " returning 0,0"
00718 << ".\n";
00719 return tpoint(0, 0);
00720 }
00721
00722 const tpoint best_size = widget_->get_best_size() + border_space();
00723
00724 DBG_GUI_L << LOG_CHILD_HEADER
00725 << " has widget " << true
00726 << " widget visible " << true
00727 << " returning " << best_size
00728 << ".\n";
00729 return best_size;
00730 }
00731
00732 void tgrid::tchild::place(tpoint origin, tpoint size)
00733 {
00734 assert(widget());
00735 if(widget()->get_visible() == twidget::INVISIBLE) {
00736 return;
00737 }
00738
00739 if(border_size_) {
00740 if(flags_ & BORDER_TOP) {
00741 origin.y += border_size_;
00742 size.y -= border_size_;
00743 }
00744 if(flags_ & BORDER_BOTTOM) {
00745 size.y -= border_size_;
00746 }
00747
00748 if(flags_ & BORDER_LEFT) {
00749 origin.x += border_size_;
00750 size.x -= border_size_;
00751 }
00752 if(flags_ & BORDER_RIGHT) {
00753 size.x -= border_size_;
00754 }
00755 }
00756
00757
00758
00759 const tpoint best_size = widget()->get_best_size();
00760 if(size <= best_size) {
00761 DBG_GUI_L << LOG_CHILD_HEADER
00762 << " in best size range setting widget to "
00763 << origin << " x " << size
00764 << ".\n";
00765
00766 widget()->place(origin, size);
00767 return;
00768 }
00769
00770 const tcontrol* control = dynamic_cast<const tcontrol*>(widget());
00771 const tpoint maximum_size = control
00772 ? control->get_config_maximum_size()
00773 : tpoint(0, 0);
00774
00775 if((flags_ & (HORIZONTAL_MASK | VERTICAL_MASK))
00776 == (HORIZONTAL_GROW_SEND_TO_CLIENT | VERTICAL_GROW_SEND_TO_CLIENT)) {
00777
00778 if(maximum_size == tpoint(0,0) || size <= maximum_size) {
00779
00780 DBG_GUI_L << LOG_CHILD_HEADER
00781 << " in maximum size range setting widget to "
00782 << origin << " x " << size
00783 << ".\n";
00784
00785 widget()->place(origin, size);
00786 return;
00787
00788 }
00789 }
00790
00791 tpoint widget_size = tpoint(
00792 std::min(size.x, best_size.x),
00793 std::min(size.y, best_size.y));
00794 tpoint widget_orig = origin;
00795
00796 const unsigned v_flag = flags_ & VERTICAL_MASK;
00797
00798 if(v_flag == VERTICAL_GROW_SEND_TO_CLIENT) {
00799 if(maximum_size.y) {
00800 widget_size.y = std::min(size.y, maximum_size.y);
00801 } else {
00802 widget_size.y = size.y;
00803 }
00804 DBG_GUI_L << LOG_CHILD_HEADER
00805 << " vertical growing from " << best_size.y
00806 << " to " << widget_size.y
00807 << ".\n";
00808
00809 } else if(v_flag == VERTICAL_ALIGN_TOP) {
00810
00811
00812 DBG_GUI_L << LOG_CHILD_HEADER << " vertically aligned at the top.\n";
00813
00814 } else if(v_flag == VERTICAL_ALIGN_CENTER) {
00815
00816 widget_orig.y += (size.y - widget_size.y) / 2;
00817 DBG_GUI_L << LOG_CHILD_HEADER << " vertically centred.\n";
00818
00819 } else if(v_flag == VERTICAL_ALIGN_BOTTOM) {
00820
00821 widget_orig.y += (size.y - widget_size.y);
00822 DBG_GUI_L << LOG_CHILD_HEADER << " vertically aligned at the bottom.\n";
00823
00824 } else {
00825 ERR_GUI_L << LOG_CHILD_HEADER
00826 << " Invalid vertical alignment '"
00827 << v_flag << "' specified.\n";
00828 assert(false);
00829 }
00830
00831 const unsigned h_flag = flags_ & HORIZONTAL_MASK;
00832
00833 if(h_flag == HORIZONTAL_GROW_SEND_TO_CLIENT) {
00834 if(maximum_size.x) {
00835 widget_size.x = std::min(size.x, maximum_size.x);
00836 } else {
00837 widget_size.x = size.x;
00838 }
00839 DBG_GUI_L << LOG_CHILD_HEADER
00840 << " horizontal growing from " << best_size.x
00841 << " to " << widget_size.x
00842 << ".\n";
00843
00844 } else if(h_flag == HORIZONTAL_ALIGN_LEFT) {
00845
00846 DBG_GUI_L << LOG_CHILD_HEADER << " horizontally aligned at the left.\n";
00847
00848 } else if(h_flag == HORIZONTAL_ALIGN_CENTER) {
00849
00850 widget_orig.x += (size.x - widget_size.x) / 2;
00851 DBG_GUI_L << LOG_CHILD_HEADER << " horizontally centred.\n";
00852
00853 } else if(h_flag == HORIZONTAL_ALIGN_RIGHT) {
00854
00855 widget_orig.x += (size.x - widget_size.x);
00856 DBG_GUI_L << LOG_CHILD_HEADER
00857 << " horizontally aligned at the right.\n";
00858
00859 } else {
00860 ERR_GUI_L << LOG_CHILD_HEADER
00861 << " No horizontal alignment '" << h_flag
00862 << "' specified.\n";
00863 assert(false);
00864 }
00865
00866 DBG_GUI_L << LOG_CHILD_HEADER
00867 << " resize widget to " << widget_orig << " x " << widget_size
00868 << ".\n";
00869
00870 widget()->place(widget_orig, widget_size);
00871 }
00872
00873 void tgrid::tchild::layout_init(const bool full_initialization)
00874 {
00875 assert(widget_);
00876
00877 if(widget_->get_visible() != twidget::INVISIBLE) {
00878 widget_->layout_init(full_initialization);
00879 }
00880 }
00881
00882 const std::string& tgrid::tchild::id() const
00883 {
00884 assert(widget_);
00885 return widget_->id();
00886 }
00887
00888 tpoint tgrid::tchild::border_space() const
00889 {
00890 tpoint result(0, 0);
00891
00892 if(border_size_) {
00893
00894 if(flags_ & BORDER_TOP) result.y += border_size_;
00895 if(flags_ & BORDER_BOTTOM) result.y += border_size_;
00896
00897 if(flags_ & BORDER_LEFT) result.x += border_size_;
00898 if(flags_ & BORDER_RIGHT) result.x += border_size_;
00899 }
00900
00901 return result;
00902 }
00903
00904 void tgrid::layout(const tpoint& origin)
00905 {
00906 tpoint orig = origin;
00907 for(unsigned row = 0; row < rows_; ++row) {
00908 for(unsigned col = 0; col < cols_; ++col) {
00909
00910 const tpoint size(col_width_[col], row_height_[row]);
00911 DBG_GUI_L << LOG_HEADER
00912 << " set widget at " << row << ',' << col
00913 << " at origin " << orig
00914 << " with size " << size
00915 << ".\n";
00916
00917 if(child(row, col).widget()) {
00918 child(row, col).place(orig, size);
00919 }
00920
00921 orig.x += col_width_[col];
00922 }
00923 orig.y += row_height_[row];
00924 orig.x = origin.x;
00925 }
00926 }
00927
00928 void tgrid::impl_draw_children(surface& frame_buffer)
00929 {
00930
00931
00932
00933
00934
00935
00936
00937
00938
00939 SDL_PumpEvents();
00940
00941 assert(get_visible() == twidget::VISIBLE);
00942 set_dirty(false);
00943
00944 foreach(tchild& child, children_) {
00945
00946 twidget* widget = child.widget();
00947 assert(widget);
00948
00949 if(widget->get_visible() != twidget::VISIBLE) {
00950 continue;
00951 }
00952
00953 if(widget->get_drawing_action() == twidget::NOT_DRAWN) {
00954 continue;
00955 }
00956
00957 widget->draw_background(frame_buffer);
00958 widget->draw_children(frame_buffer);
00959 widget->draw_foreground(frame_buffer);
00960 widget->set_dirty(false);
00961 }
00962 }
00963
00964 void tgrid::impl_draw_children(
00965 surface& frame_buffer
00966 , int x_offset
00967 , int y_offset)
00968 {
00969
00970
00971
00972
00973
00974
00975
00976
00977
00978 SDL_PumpEvents();
00979
00980 assert(get_visible() == twidget::VISIBLE);
00981 set_dirty(false);
00982
00983 foreach(tchild& child, children_) {
00984
00985 twidget* widget = child.widget();
00986 assert(widget);
00987
00988 if(widget->get_visible() != twidget::VISIBLE) {
00989 continue;
00990 }
00991
00992 if(widget->get_drawing_action() == twidget::NOT_DRAWN) {
00993 continue;
00994 }
00995
00996 widget->draw_background(frame_buffer, x_offset, y_offset);
00997 widget->draw_children(frame_buffer, x_offset, y_offset);
00998 widget->draw_foreground(frame_buffer, x_offset, y_offset);
00999 widget->set_dirty(false);
01000 }
01001 }
01002
01003 unsigned tgrid_implementation::row_request_reduce_height(tgrid& grid,
01004 const unsigned row, const unsigned maximum_height)
01005 {
01006
01007 unsigned required_height = 0;
01008
01009 for(size_t x = 0; x < grid.cols_; ++x) {
01010 tgrid::tchild& cell = grid.child(row, x);
01011 cell_request_reduce_height(cell, maximum_height);
01012
01013 const tpoint size(cell.get_best_size());
01014
01015 if(required_height == 0
01016 || static_cast<size_t>(size.y) > required_height) {
01017
01018 required_height = size.y;
01019 }
01020 }
01021
01022 DBG_GUI_L << LOG_IMPL_HEADER
01023 << " maximum row height " << maximum_height
01024 << " returning " << required_height
01025 << ".\n";
01026
01027 return required_height;
01028 }
01029
01030 unsigned tgrid_implementation::column_request_reduce_width(tgrid& grid,
01031 const unsigned column, const unsigned maximum_width)
01032 {
01033
01034 unsigned required_width = 0;
01035
01036 for(size_t y = 0; y < grid.rows_; ++y) {
01037 tgrid::tchild& cell = grid.child(y, column);
01038 cell_request_reduce_width(cell, maximum_width);
01039
01040 const tpoint size(cell.get_best_size());
01041
01042 if(required_width == 0
01043 || static_cast<size_t>(size.x) > required_width) {
01044
01045 required_width = size.x;
01046 }
01047 }
01048
01049 DBG_GUI_L << LOG_IMPL_HEADER
01050 << " maximum column width " << maximum_width
01051 << " returning " << required_width
01052 << ".\n";
01053
01054 return required_width;
01055 }
01056
01057 void tgrid_implementation::cell_request_reduce_height(
01058 tgrid::tchild& child, const unsigned maximum_height)
01059 {
01060 assert(child.widget_);
01061
01062 if(child.widget_->get_visible() == twidget::INVISIBLE) {
01063 return;
01064 }
01065
01066 child.widget_->request_reduce_height(
01067 maximum_height - child.border_space().y);
01068 }
01069
01070 void tgrid_implementation::cell_request_reduce_width(
01071 tgrid::tchild& child, const unsigned maximum_width)
01072 {
01073 assert(child.widget_);
01074
01075 if(child.widget_->get_visible() == twidget::INVISIBLE) {
01076 return;
01077 }
01078
01079 child.widget_->request_reduce_width(
01080 maximum_width - child.border_space().x);
01081 }
01082
01083 void set_single_child(tgrid& grid, twidget* widget)
01084 {
01085 grid.set_rows_cols(1, 1);
01086 grid.set_child(widget
01087 , 0
01088 , 0
01089 , tgrid::HORIZONTAL_GROW_SEND_TO_CLIENT
01090 | tgrid::VERTICAL_GROW_SEND_TO_CLIENT
01091 , 0);
01092 }
01093
01094 }
01095
01096
01097
01098
01099
01100
01101
01102
01103
01104
01105
01106
01107
01108
01109
01110
01111
01112
01113
01114
01115
01116
01117
01118
01119
01120
01121
01122
01123
01124
01125
01126
01127
01128
01129
01130
01131
01132
01133
01134
01135
01136
01137
01138
01139
01140
01141
01142
01143
01144
01145
01146
01147
01148
01149
01150
01151
01152
01153
01154
01155
01156
01157
01158
01159
01160
01161
01162
01163
01164
01165
01166
01167
01168
01169
01170
01171
01172
01173
01174
01175
01176
01177
01178
01179
01180
01181
01182
01183
01184
01185
01186
01187
01188
01189
01190
01191
01192
01193
01194
01195
01196
01197
01198
01199
01200
01201
01202
01203
01204
01205
01206
01207
01208
01209
01210
01211
01212
01213
01214
01215
01216
01217
01218
01219
01220
01221
01222
01223
01224
01225
01226
01227
01228
01229
01230
01231
01232
01233
01234
01235
01236
01237
01238
01239
01240
01241
01242
01243
01244
01245
01246
01247
01248
01249
01250
01251
01252
01253
01254
01255
01256
01257
01258
01259
01260
01261
01262
01263
01264
01265
01266
01267
01268
01269
01270
01271
01272
01273
01274
01275
01276
01277
01278
01279
01280
01281
01282
01283
01284
01285
01286
01287
01288
01289
01290
01291
01292
01293
01294
01295
01296
01297
01298
01299
01300
01301