grid.cpp

Go to the documentation of this file.
00001 /* $Id: grid.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/grid.hpp"
00016 
00017 #include "foreach.hpp"
00018 #include "log.hpp"
00019 
00020 #include <cassert>
00021 #include <numeric>
00022 
00023 #define DBG_G LOG_STREAM_INDENT(debug, gui)
00024 #define LOG_G LOG_STREAM_INDENT(info, gui)
00025 #define WRN_G LOG_STREAM_INDENT(warn, gui)
00026 #define ERR_G LOG_STREAM_INDENT(err, gui)
00027 
00028 #define DBG_G_D LOG_STREAM_INDENT(debug, gui_draw)
00029 #define LOG_G_D LOG_STREAM_INDENT(info, gui_draw)
00030 #define WRN_G_D LOG_STREAM_INDENT(warn, gui_draw)
00031 #define ERR_G_D LOG_STREAM_INDENT(err, gui_draw)
00032 
00033 #define DBG_G_E LOG_STREAM_INDENT(debug, gui_event)
00034 #define LOG_G_E LOG_STREAM_INDENT(info, gui_event)
00035 #define WRN_G_E LOG_STREAM_INDENT(warn, gui_event)
00036 #define ERR_G_E LOG_STREAM_INDENT(err, gui_event)
00037 
00038 #define DBG_G_P LOG_STREAM_INDENT(debug, gui_parse)
00039 #define LOG_G_P LOG_STREAM_INDENT(info, gui_parse)
00040 #define WRN_G_P LOG_STREAM_INDENT(warn, gui_parse)
00041 #define ERR_G_P LOG_STREAM_INDENT(err, gui_parse)
00042 
00043 
00044 namespace gui2 {
00045 
00046 tgrid::tgrid(const unsigned rows, const unsigned cols) :
00047     rows_(rows),
00048     cols_(cols),
00049     best_row_height_(),
00050     best_col_width_(),
00051     minimum_row_height_(),
00052     minimum_col_width_(),
00053     row_height_(),
00054     col_width_(),
00055     row_grow_factor_(rows),
00056     col_grow_factor_(cols),
00057     children_(rows * cols)
00058 {
00059 }
00060 
00061 tgrid::~tgrid()
00062 {
00063     for(std::vector<tchild>::iterator itor = children_.begin();
00064             itor != children_.end(); ++itor) {
00065 
00066         if(itor->widget()) {
00067             delete itor->widget();
00068         }
00069     }
00070 }
00071 
00072 void tgrid::add_child(twidget* widget, const unsigned row, 
00073         const unsigned col, const unsigned flags, const unsigned border_size) 
00074 {
00075     assert(row < rows_ && col < cols_);
00076 
00077     tchild& cell = child(row, col);
00078 
00079     // clear old child if any
00080     if(cell.widget()) {
00081         // free a child when overwriting it
00082         WRN_G << "Grid: child '" << cell.id() 
00083             << "' at cell '" << row << ',' << col << "' will be replaced.\n";
00084         delete cell.widget();
00085     }
00086 
00087     // copy data
00088     cell.set_flags(flags);
00089     cell.set_border_size(border_size);
00090     cell.set_widget(widget);
00091     if(cell.widget()) {
00092         // make sure the new child is valid before deferring
00093         cell.set_id(cell.widget()->id());
00094         cell.widget()->set_parent(this);
00095     } else {
00096         cell.set_id("");
00097     }
00098 
00099     clear_cache();
00100 }
00101 
00102 void tgrid::set_rows(const unsigned rows)
00103 {
00104     if(rows == rows_) {
00105         return;
00106     }
00107 
00108     set_rows_cols(rows, cols_);
00109 }
00110 
00111 unsigned tgrid::add_row(const unsigned count)
00112 {
00113     assert(count);
00114 
00115     //FIXME the warning in set_rows_cols should be killed.
00116     
00117     unsigned result = rows_;
00118     set_rows_cols(rows_ + count, cols_);
00119     return result;
00120 }
00121 
00122 void tgrid::set_cols(const unsigned cols)
00123 {
00124     if(cols == cols_) {
00125         return;
00126     }
00127 
00128     set_rows_cols(rows_, cols);
00129 }
00130 
00131 void tgrid::set_rows_cols(const unsigned rows, const unsigned cols)
00132 {
00133     if(rows == rows_ && cols == cols_) {
00134         return;
00135     }
00136 
00137     if(!children_.empty()) {
00138         WRN_G << "Grid: resizing a non-empty grid may give unexpected problems.\n";
00139     }
00140 
00141     rows_ = rows;
00142     cols_ = cols;
00143     row_grow_factor_.resize(rows);
00144     col_grow_factor_.resize(cols);
00145     children_.resize(rows_ * cols_);
00146     clear_cache();
00147 }
00148 
00149 void tgrid::remove_child(const unsigned row, const unsigned col)
00150 {
00151     assert(row < rows_ && col < cols_);
00152 
00153     tchild& cell = child(row, col);
00154 
00155     cell.set_id("");
00156     cell.set_widget(0);
00157     clear_cache();
00158 }
00159 
00160 void tgrid::remove_child(const std::string& id, const bool find_all)
00161 {
00162     for(std::vector<tchild>::iterator itor = children_.begin();
00163             itor != children_.end(); ++itor) {
00164 
00165         if(itor->id() == id) {
00166             itor->set_id("");
00167             itor->set_widget(0);
00168             clear_cache();
00169 
00170             if(!find_all) {
00171                 break;
00172             }
00173         }
00174     }
00175 }
00176 
00177 void tgrid::set_active(const bool active)
00178 {
00179     for(std::vector<tchild>::iterator itor = children_.begin();
00180             itor != children_.end(); ++itor) {
00181 
00182         twidget* widget = itor->widget();
00183         if(!widget) {
00184             continue;
00185         }
00186 
00187         tgrid* grid = dynamic_cast<tgrid*>(widget);
00188         if(grid) {
00189             grid->set_active(active);
00190             continue;
00191         }
00192 
00193         tcontrol* control =  dynamic_cast<tcontrol*>(widget);
00194         if(control) {
00195             control->set_active(active);
00196         }
00197     }
00198 }
00199 
00200 bool tgrid::has_vertical_scrollbar() const 
00201 {
00202     for(std::vector<tchild>::const_iterator itor = children_.begin();
00203             itor != children_.end(); ++itor) {
00204         // FIXME we should check per row and the entire row
00205         // should have the flag!!!!
00206         if(itor->widget() && itor->widget()->has_vertical_scrollbar()) {
00207             return true;
00208         } 
00209 
00210     }
00211     
00212     // Inherit
00213     return twidget::has_vertical_scrollbar();
00214 }
00215 
00216 tpoint tgrid::get_minimum_size() const
00217 {
00218     return get_size("minimum", minimum_col_width_, 
00219         minimum_row_height_, &tchild::get_minimum_size);
00220 }
00221 
00222 tpoint tgrid::get_maximum_size() const
00223 {
00224     // A grid doesn't have a maximum size.
00225     return tpoint(0,0);
00226 }
00227 
00228 tpoint tgrid::get_best_size() const
00229 {
00230     return get_size("best", best_col_width_, 
00231         best_row_height_, &tchild::get_best_size);
00232 }
00233 
00234 //! Helper function to get the best or minimum size.
00235 //!
00236 //! @param id                     Name to use in debug output.
00237 //! @param width                  Reference to the vector width cache for the 
00238 //!                               size function of the caller.
00239 //! @param height                 Reference to the vector height cache for the 
00240 //!                               size function of the caller.
00241 //! @param size_proc              The function to call on the cells in order to
00242 //!                               get their sizes.
00243 //!
00244 //! @return                       The wanted size.
00245 tpoint tgrid::get_size(const std::string& id, std::vector<unsigned>& width, 
00246         std::vector<unsigned>& height, tpoint (tchild::*size_proc)() const) const
00247 {
00248     if(height.empty() || width.empty()) {
00249 
00250         DBG_G << "Grid: calculate " << id << " size.\n";
00251 
00252         height.resize(rows_, 0);
00253         width.resize(cols_, 0);
00254         
00255         // First get the sizes for all items.
00256         for(unsigned row = 0; row < rows_; ++row) {
00257             for(unsigned col = 0; col < cols_; ++col) {
00258 
00259                 const tpoint size = (child(row, col).*size_proc)();
00260 
00261                 if(size.x > width[col]) {
00262                     width[col] = size.x;
00263                 }
00264 
00265                 if(size.y > height[row]) {
00266                     height[row] = size.y;
00267                 }
00268 
00269             }
00270         }
00271     } else {
00272         DBG_G << "Grid: used cached " << id << " size.\n";
00273     }
00274 
00275     for(unsigned row = 0; row < rows_; ++row) {
00276         DBG_G << "Grid: the " << id << " height for row " << row 
00277             << " will be " << height[row] << ".\n";
00278     }
00279 
00280     for(unsigned col = 0; col < cols_; ++col) {
00281         DBG_G << "Grid: the " << id << " width for col " << col 
00282             << " will be " << width[col]  << ".\n";
00283     }
00284 
00285     return tpoint(
00286         std::accumulate(width.begin(), width.end(), 0),
00287         std::accumulate(height.begin(), height.end(), 0));
00288 }
00289 
00290 void tgrid::set_size(const SDL_Rect& rect)
00291 {
00292     log_scope2(gui, "Grid: set size");
00293 
00294     twidget::set_size(rect);
00295 
00296     if(!rows_ || !cols_) {
00297         return;
00298     }
00299 
00300     const tpoint orig(rect.x, rect.y);
00301     const tpoint size(rect.w, rect.h);
00302 
00303     const tpoint best_size = get_best_size();
00304     row_height_ = best_row_height_;
00305     col_width_ = best_col_width_;
00306 
00307     assert(row_height_.size() == rows_);
00308     assert(col_width_.size() == cols_);
00309     assert(row_grow_factor_.size() == rows_);
00310     assert(col_grow_factor_.size() == cols_);
00311     DBG_G << "Grid: best size " << best_size << " available size " << size << ".\n";
00312 
00313     if(best_size == size) {
00314         row_height_ = best_row_height_;
00315         col_width_ = best_col_width_;
00316 
00317         layout(orig);
00318         return;
00319     }
00320 
00321     if(best_size < size) {
00322         row_height_ = best_row_height_;
00323         col_width_ = best_col_width_;
00324 
00325         // expand it.
00326         if(size.x > best_size.x) {
00327             const unsigned w = size.x - best_size.x;
00328             unsigned w_size = 
00329                 std::accumulate(col_grow_factor_.begin(), col_grow_factor_.end(), 0);
00330             DBG_G << "Grid: extra width " << w << " will be divided amount " 
00331                 << w_size << " units in " << cols_ << " columns.\n";
00332 
00333             if(w_size == 0) {
00334                 // If all sizes are 0 reset them to 1
00335                 foreach(unsigned& val, col_grow_factor_) {
00336                     val = 1;
00337                 }
00338                 w_size = cols_;
00339             }
00340             // We might have a bit 'extra' if the division doesn't fix exactly
00341             // but we ignore that part for now.
00342             const unsigned w_normal = w / w_size;
00343             for(unsigned i = 0; i < cols_; ++i) {
00344                 col_width_[i] += w_normal * col_grow_factor_[i];
00345                 DBG_G << "Grid: column " << i << " with grow factor " 
00346                     << col_grow_factor_[i] << " set width to " << col_width_[i] << ".\n";
00347             }
00348 
00349         }
00350 
00351         if(size.y > best_size.y) {
00352             const unsigned h = size.y - best_size.y;
00353             unsigned h_size = 
00354                 std::accumulate(row_grow_factor_.begin(), row_grow_factor_.end(), 0);
00355             DBG_G << "Grid: extra height " << h << " will be divided amount " 
00356                 << h_size << " units in " << rows_ << " rows.\n";
00357 
00358             if(h_size == 0) {
00359                 // If all sizes are 0 reset them to 1
00360                 foreach(unsigned& val, row_grow_factor_) {
00361                     val = 1;
00362                 }
00363                 h_size = rows_;
00364             }
00365             // We might have a bit 'extra' if the division doesn't fix exactly
00366             // but we ignore that part for now.
00367             const unsigned h_normal = h / h_size;
00368             for(unsigned i = 0; i < rows_; ++i) {
00369                 row_height_[i] += h_normal * row_grow_factor_[i];
00370                 DBG_G << "Grid: row " << i  << " with grow factor "
00371                     << row_grow_factor_[i] << " set height to " << row_height_[i] << ".\n";
00372             }
00373         }
00374 
00375         layout(orig);
00376         return;
00377 
00378     }
00379 
00380     if((best_size.x <= size.x /*|| has_horizontal_scrollbar()*/) 
00381             && (best_size.y <= size.y || has_vertical_scrollbar())) {
00382 
00383         // FIXME we only do the height atm, the width will be added when needed.
00384         const unsigned over_shoot = best_size.y - size.y;
00385 
00386         bool set = false;
00387         row_height_ = best_row_height_;
00388         col_width_ = best_col_width_;
00389         // FIXME we assume 1 item per row.
00390         for(unsigned i = 0; i < rows_; ++i) {
00391             twidget* row = widget(i, 0);
00392             if(row && row->has_vertical_scrollbar()) {
00393                 row_height_[i] -= over_shoot; // Assume this row can be resized enough
00394                 set = true;
00395                 break;
00396             }
00397             
00398         }
00399 
00400         assert(set);
00401         layout(orig);
00402         return;
00403     }
00404 
00405 
00406 
00407 
00408     // FIXME make other cases work as well
00409     assert(false);
00410 /*
00411     const tpoint minimum_size = get_minimum_size();
00412     if(minimum_size == size) {
00413 */      
00414 }
00415 
00416 twidget* tgrid::find_widget(const tpoint& coordinate, const bool must_be_active) 
00417 {
00418     for(std::vector<tchild>::iterator itor = children_.begin(); 
00419             itor != children_.end(); ++itor) {
00420 
00421         twidget* widget = itor->widget();
00422         if(!widget) {
00423             continue;
00424         }
00425 
00426         widget = widget->find_widget(coordinate, must_be_active);
00427         if(widget) { 
00428             clear_cache();
00429             return widget;
00430         }
00431         
00432     }
00433     
00434     return 0;
00435 }
00436 
00437 const twidget* tgrid::find_widget(const tpoint& coordinate, 
00438         const bool must_be_active) const
00439 {   
00440     for(std::vector<tchild>::const_iterator itor = children_.begin(); 
00441             itor != children_.end(); ++itor) {
00442 
00443         const twidget* widget = itor->widget();
00444         if(!widget) {
00445             continue;
00446         }
00447 
00448         widget = widget->find_widget(coordinate, must_be_active);
00449         if(widget) { 
00450             return widget;
00451         }
00452         
00453     }
00454     
00455     return 0;
00456 }
00457 
00458 twidget* tgrid::find_widget(const std::string& id, const bool must_be_active)
00459 {
00460     for(std::vector<tchild>::iterator itor = children_.begin(); 
00461             itor != children_.end(); ++itor) {
00462 
00463         twidget* widget = itor->widget();
00464         if(!widget) {
00465             continue;
00466         }
00467 
00468         widget = widget->find_widget(id, must_be_active);
00469         if(widget) { 
00470             clear_cache();
00471             return widget;
00472         }
00473         
00474     }
00475     
00476     return 0;
00477 }
00478 
00479 const twidget* tgrid::find_widget(const std::string& id, 
00480         const bool must_be_active) const
00481 {
00482     for(std::vector<tchild>::const_iterator itor = children_.begin(); 
00483             itor != children_.end(); ++itor) {
00484 
00485         const twidget* widget = itor->widget();
00486         if(!widget) {
00487             continue;
00488         }
00489 
00490         widget = widget->find_widget(id, must_be_active);
00491         if(widget) { 
00492             return widget;
00493         }
00494         
00495     }
00496     
00497     return 0;
00498 }
00499 
00500 bool tgrid::has_widget(const twidget* widget) const
00501 {
00502     for(std::vector<tchild>::const_iterator itor = children_.begin();
00503             itor != children_.end(); ++itor) {
00504     
00505         if(itor->widget() == widget) {
00506             return true;
00507         }
00508     }
00509     return false;
00510 }
00511 
00512 void tgrid::draw(surface& surface)
00513 {
00514     for(iterator itor = begin(); itor != end(); ++itor) {
00515         if(! *itor || !itor->dirty()) {
00516             continue;
00517         }
00518 
00519         log_scope2(gui_draw, "Grid: draw child.");
00520 
00521         itor->draw(surface);
00522     }
00523 
00524     set_dirty(false);
00525 }
00526 
00527 void tgrid::clear_cache()
00528 {
00529     best_row_height_.clear();
00530     best_col_width_.clear();
00531 
00532     minimum_row_height_.clear();
00533     minimum_col_width_.clear();
00534 }
00535 
00536 void tgrid::layout(const tpoint& origin)
00537 {
00538     tpoint orig = origin;
00539     for(unsigned row = 0; row < rows_; ++row) {
00540         for(unsigned col = 0; col < cols_; ++col) {
00541 
00542             const tpoint size(col_width_[col], row_height_[row]);
00543             DBG_G << "Grid: set widget at " << row << ',' << col 
00544                 << " at origin " << orig << " with size " << size << ".\n";
00545 
00546             if(child(row, col).widget()) {
00547                 child(row, col).set_size(orig, size);
00548             }
00549 
00550             orig.x += col_width_[col];
00551         }
00552         orig.y += row_height_[row];
00553         orig.x = origin.x;
00554     }
00555 }
00556 
00557 tpoint tgrid::tchild::get_best_size() const
00558 {
00559     if(!widget_) {
00560         return border_space();
00561     }
00562 
00563     if(widget_->dirty() || best_size_ == tpoint(0, 0)) {
00564         best_size_ = widget_->get_best_size() + border_space();
00565     }
00566 
00567     return best_size_;
00568 }
00569 
00570 tpoint tgrid::tchild::get_minimum_size() const
00571 {
00572     if(!widget_) {
00573         return border_space();
00574     }
00575 
00576     if(widget_->dirty() || minimum_size_ == tpoint(0, 0)) {
00577         minimum_size_ = widget_->get_minimum_size() + border_space();
00578     }
00579 
00580     return minimum_size_;
00581 }
00582 
00583 tpoint tgrid::tchild::get_maximum_size() const
00584 {
00585     if(!widget_) {
00586         return tpoint(0, 0);
00587     }
00588 
00589     if(widget_->dirty() || maximum_size_ == tpoint(0, 0)) {
00590         maximum_size_ = widget_->get_maximum_size();
00591 
00592         // If the widget has no maximum return that 
00593         // else we need to add the border.
00594         if(maximum_size_ != tpoint(0, 0)) {
00595             maximum_size_ += border_space();
00596         }
00597     }
00598 
00599     return maximum_size_;
00600 }
00601 
00602 tpoint tgrid::tchild::border_space() const
00603 {
00604     tpoint result(0, 0);
00605 
00606     if(border_size_) {
00607 
00608         if(flags_ & BORDER_TOP) result.y += border_size_;
00609         if(flags_ & BORDER_BOTTOM) result.y += border_size_;
00610                 
00611         if(flags_ & BORDER_LEFT) result.x += border_size_;
00612         if(flags_ & BORDER_RIGHT) result.x += border_size_;
00613     }
00614 
00615     return result;
00616 }
00617 
00618 void tgrid::tchild::set_size(tpoint orig, tpoint size)
00619 {
00620     assert(widget());
00621 
00622     if(border_size_) {
00623         if(flags_ & BORDER_TOP) {
00624             orig.y += border_size_;
00625             size.y -= border_size_;
00626         }
00627         if(flags_ & BORDER_BOTTOM) {
00628             size.y -= border_size_;
00629         }
00630                 
00631         if(flags_ & BORDER_LEFT) {
00632             orig.x += border_size_;
00633             size.x -= border_size_;
00634         }
00635         if(flags_ & BORDER_RIGHT) {
00636             size.x -= border_size_;
00637         }
00638     }
00639 
00640     // If size smaller or equal to best size set that size.
00641     // No need to check > min size since this is what we got.
00642     const tpoint best_size = widget()->get_best_size();
00643     if(size <= best_size) {
00644         DBG_G << "Grid cell: in best size range setting widget to " 
00645             << orig << " x " << size << ".\n";
00646 
00647         widget()->set_size(create_rect(orig, size));
00648         return;
00649     }
00650 
00651     const tpoint maximum_size = widget()->get_maximum_size();
00652     if(flags_ & (HORIZONTAL_GROW_SEND_TO_CLIENT | HORIZONTAL_GROW_SEND_TO_CLIENT)) {
00653         if(maximum_size == tpoint(0,0) || size <= maximum_size) {
00654     
00655             DBG_G << "Grid cell: in maximum size range setting widget to " 
00656                 << orig << " x " << size << ".\n";
00657 
00658             widget()->set_size(create_rect(orig, size));
00659             return;
00660     
00661         }
00662     }
00663 
00664     tpoint widget_size = best_size;
00665     tpoint widget_orig = orig;
00666 
00667     if(flags_ & HORIZONTAL_GROW_SEND_TO_CLIENT) {
00668         if(maximum_size.x) {
00669             widget_size.x = std::min(size.x, maximum_size.x);
00670         } else {
00671             widget_size.x = size.x;
00672         }
00673         DBG_G << "Grid cell: horizontal growing from " 
00674             << best_size.x << " to " << widget_size.x << ".\n";
00675     }
00676 
00677     if(flags_ & VERTICAL_GROW_SEND_TO_CLIENT) {
00678         if(maximum_size.y) {
00679             widget_size.y = std::min(size.y, maximum_size.y);
00680         } else {
00681             widget_size.y = size.y;
00682         }
00683         DBG_G << "Grid cell: vertical growing from " 
00684             << best_size.y << " to " << widget_size.y << ".\n";
00685     }
00686 
00687     if((flags_ & VERTICAL_ALIGN_TOP) == VERTICAL_ALIGN_TOP) {
00688         // Do nothing.
00689         
00690         DBG_G << "Grid cell: vertically aligned at the top.\n";
00691 
00692     } else if((flags_ & VERTICAL_ALIGN_CENTER) == VERTICAL_ALIGN_CENTER) {
00693         
00694         widget_orig.y += (size.y - widget_size.y) / 2;
00695         DBG_G << "Grid cell: vertically centred.\n";
00696 
00697     } else if((flags_ & VERTICAL_ALIGN_BOTTOM) == VERTICAL_ALIGN_BOTTOM) {
00698 
00699         widget_orig.y += (size.y - widget_size.y);
00700         DBG_G << "Grid cell: vertically aligned at the bottom.\n";
00701 
00702     } else {
00703         assert(false);
00704     }
00705     
00706     if((flags_ & HORIZONTAL_ALIGN_LEFT) == HORIZONTAL_ALIGN_LEFT) {
00707         // Do nothing.
00708         DBG_G << "Grid cell: horizontally aligned at the left.\n";
00709 
00710     } else if((flags_ & HORIZONTAL_ALIGN_CENTER) == HORIZONTAL_ALIGN_CENTER) {
00711         
00712         widget_orig.x += (size.x - widget_size.x) / 2;
00713         DBG_G << "Grid cell: horizontally centred.\n";
00714 
00715     } else if((flags_ & HORIZONTAL_ALIGN_RIGHT) == HORIZONTAL_ALIGN_RIGHT) {
00716 
00717         widget_orig.x += (size.x - widget_size.x);
00718         DBG_G << "Grid cell: horizontally aligned at the right.\n";
00719 
00720     } else {
00721         assert(false);
00722     }
00723 
00724     DBG_G << "Grid cell: resize widget to " 
00725         << widget_orig << " x " << widget_size << ".\n";
00726 
00727 
00728     widget()->set_size(create_rect(widget_orig, widget_size));
00729 }
00730 
00731 } // namespace gui2
00732 
00733 
00734 /*WIKI
00735  * @page = GUILayout
00736  * 
00737  * = Abstract =
00738  *
00739  * In the widget library the placement and sizes of elements is determined by
00740  * a grid. Therefore most widgets have no fixed size.
00741  *
00742  *
00743  * = Theory =
00744  *
00745  * We have two examples for the addon dialog, the first example the lower 
00746  * buttons are in one grid, that means if the remove button gets wider 
00747  * (due to translations) the connect button (4.1 - 2.2) will be aligned 
00748  * to the left of the remove button. In the second example the connect
00749  * button will be partial underneath the remove button.
00750  *
00751  * A grid exists of x rows and y columns for all rows the number of columns
00752  * needs to be the same, there is no column (nor row) span. If spanning is
00753  * required place a nested grid to do so. In the examples every row has 1 column
00754  * but rows 3, 4 (and in the second 5) have a nested grid to add more elements
00755  * per row. 
00756  *
00757  * In the grid every cell needs to have a widget, if no widget is wanted place
00758  * the special widget ''spacer''. This is a non-visible item which normally
00759  * shouldn't have a size. It is possible to give a spacer a size as well but
00760  * that is discussed elsewhere.
00761  *
00762  * Every row and column has a ''grow_factor'', since all columns in a grid are
00763  * aligned only the columns in the first row need to define their grow factor.
00764  * The grow factor is used to determine with the extra size available in a
00765  * dialog. The algorithm determines the extra size work like this:
00766  *
00767  * * determine the extra size
00768  * * determine the sum of the grow factors
00769  * * if this sum is 0 set the grow factor for every item to 1 and sum to sum of items.
00770  * * divide the extra size with the sum of grow factors
00771  * * for every item multiply the grow factor with the division value
00772  * 
00773  * eg
00774  *  extra size 100
00775  *  grow factors 1, 1, 2, 1
00776  *  sum 5
00777  *  division 100 / 5 = 20
00778  *  extra sizes 20, 20, 40, 20
00779  *
00780  * Since we force the factors to 1 if all zero it's not possible to have non
00781  * growing cells. This can be solved by adding an extra cell with a spacer and a
00782  * grow factor of 1. This is used for the buttons in the examples.
00783  * 
00784  * Every cell has a ''border_size'' and ''border'' the ''border_size'' is the
00785  * number of pixels in the cell which aren't available for the widget. This is
00786  * used to make sure the items in different cells aren't put side to side. With
00787  * ''border'' it can be determined which sides get the border. So a border is
00788  * either 0 or ''border_size''.
00789  *
00790  * If the widget doesn't grow when there's more space available the alignment
00791  * determines where in the cell the widget is placed.
00792  *
00793  * == Examples ==
00794  *
00795  *  |---------------------------------------|
00796  *  | 1.1                                   |
00797  *  |---------------------------------------|
00798  *  | 2.1                                   |
00799  *  |---------------------------------------|
00800  *  | |-----------------------------------| |
00801  *  | | 3.1 - 1.1          | 3.1 - 1.2    | |
00802  *  | |-----------------------------------| |
00803  *  |---------------------------------------|
00804  *  | |-----------------------------------| |
00805  *  | | 4.1 - 1.1 | 4.1 - 1.2 | 4.1 - 1.3 | |
00806  *  | |-----------------------------------| |
00807  *  | | 4.1 - 2.1 | 4.1 - 2.2 | 4.1 - 2.3 | |
00808  *  | |-----------------------------------| |
00809  *  |---------------------------------------| 
00810  *
00811  *
00812  *  1.1       label : title 
00813  *  2.1       label : description 
00814  *  3.1 - 1.1 label : server
00815  *  3.1 - 1.2 text box : server to connect to
00816  *  4.1 - 1.1 spacer
00817  *  4.1 - 1.2 spacer
00818  *  4.1 - 1.3 button : remove addon
00819  *  4.2 - 2.1 spacer
00820  *  4.2 - 2.2 button : connect
00821  *  4.2 - 2.3 button : cancel
00822  *
00823  *
00824  *  |---------------------------------------|
00825  *  | 1.1                                   |
00826  *  |---------------------------------------|
00827  *  | 2.1                                   |
00828  *  |---------------------------------------|
00829  *  | |-----------------------------------| |
00830  *  | | 3.1 - 1.1          | 3.1 - 1.2    | |
00831  *  | |-----------------------------------| |
00832  *  |---------------------------------------|
00833  *  | |-----------------------------------| |
00834  *  | | 4.1 - 1.1         | 4.1 - 1.2     | |
00835  *  | |-----------------------------------| |
00836  *  |---------------------------------------|
00837  *  | |-----------------------------------| |
00838  *  | | 5.1 - 1.1 | 5.1 - 1.2 | 5.1 - 2.3 | |
00839  *  | |-----------------------------------| |
00840  *  |---------------------------------------| 
00841  *
00842  *
00843  *  1.1       label : title 
00844  *  2.1       label : description 
00845  *  3.1 - 1.1 label : server
00846  *  3.1 - 1.2 text box : server to connect to
00847  *  4.1 - 1.1 spacer
00848  *  4.1 - 1.2 button : remove addon
00849  *  5.2 - 1.1 spacer
00850  *  5.2 - 1.2 button : connect
00851  *  5.2 - 1.3 button : cancel
00852  *
00853  *  = Praxis =
00854  *
00855  * This is the code needed to create the skeleton for the structure the extra
00856  * flags are ommitted. 
00857  *
00858  *      [grid]
00859  *          [row]
00860  *              [column]
00861  *                  [label] 
00862  *                      # 1.1
00863  *                  [/label]
00864  *              [/column]
00865  *          [/row]
00866  *          [row]
00867  *              [column]
00868  *                  [label]
00869  *                      # 2.1
00870  *                  [/label]
00871  *              [/column]
00872  *          [/row]
00873  *          [row]
00874  *              [column]
00875  *                  [grid]
00876  *                      [row]
00877  *                          [column]
00878  *                              [label]
00879  *                                  # 3.1 - 1.1
00880  *                              [/label]
00881  *                          [/column]
00882  *                          [column]
00883  *                              [text_box]
00884  *                                  # 3.1 - 1.2
00885  *                              [/text_box]
00886  *                          [/column]
00887  *                      [/row]
00888  *                  [/grid]
00889  *              [/column]
00890  *          [/row]
00891  *          [row]
00892  *              [column]
00893  *                  [grid]
00894  *                      [row]
00895  *                          [column]
00896  *                              [spacer]
00897  *                                  # 4.1 - 1.1
00898  *                              [/spacer]
00899  *                          [/column]
00900  *                          [column]
00901  *                              [spacer]
00902  *                                  # 4.1 - 1.2
00903  *                              [/spacer]
00904  *                          [/column]
00905  *                          [column]
00906  *                              [button]
00907  *                                  # 4.1 - 1.3
00908  *                              [/button]
00909  *                          [/column]
00910  *                      [/row]
00911  *                      [row]
00912  *                          [column]
00913  *                              [spacer]
00914  *                                  # 4.1 - 2.1
00915  *                              [/spacer]
00916  *                          [/column]
00917  *                          [column]
00918  *                              [button]
00919  *                                  # 4.1 - 2.2
00920  *                              [/button]
00921  *                          [/column]
00922  *                          [column]
00923  *                              [button]
00924  *                                  # 4.1 - 2.3
00925  *                              [/button]
00926  *                          [/column]
00927  *                      [/row]
00928  *                  [/grid]
00929  *              [/column]
00930  *          [/row]
00931  *      [/grid]
00932  *
00933  *
00934  * [[Category:WML Reference]]
00935  * [[Category:Generated]]
00936  */

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