window_builder.cpp

Go to the documentation of this file.
00001 /* $Id: window_builder.cpp 26671 2008-05-17 10:37:10Z 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/window_builder.hpp"
00016 
00017 #include "config.hpp"
00018 #include "gettext.hpp"
00019 #include "gui/widgets/button.hpp"
00020 #include "gui/widgets/label.hpp"
00021 #include "gui/widgets/listbox.hpp"
00022 #include "gui/widgets/spacer.hpp"
00023 #include "gui/widgets/text_box.hpp"
00024 #include "gui/widgets/toggle_button.hpp"
00025 #include "gui/widgets/vertical_scrollbar.hpp"
00026 #include "gui/widgets/widget.hpp"
00027 #include "gui/widgets/window.hpp"
00028 #include "log.hpp"
00029 #include "util.hpp"
00030 #include "wml_exception.hpp"
00031 
00032 #include <cassert>
00033 
00034 #define DBG_G LOG_STREAM_INDENT(debug, gui)
00035 #define LOG_G LOG_STREAM_INDENT(info, gui)
00036 #define WRN_G LOG_STREAM_INDENT(warn, gui)
00037 #define ERR_G LOG_STREAM_INDENT(err, gui)
00038 
00039 #define DBG_G_D LOG_STREAM_INDENT(debug, gui_draw)
00040 #define LOG_G_D LOG_STREAM_INDENT(info, gui_draw)
00041 #define WRN_G_D LOG_STREAM_INDENT(warn, gui_draw)
00042 #define ERR_G_D LOG_STREAM_INDENT(err, gui_draw)
00043 
00044 #define DBG_G_E LOG_STREAM_INDENT(debug, gui_event)
00045 #define LOG_G_E LOG_STREAM_INDENT(info, gui_event)
00046 #define WRN_G_E LOG_STREAM_INDENT(warn, gui_event)
00047 #define ERR_G_E LOG_STREAM_INDENT(err, gui_event)
00048 
00049 #define DBG_G_P LOG_STREAM_INDENT(debug, gui_parse)
00050 #define LOG_G_P LOG_STREAM_INDENT(info, gui_parse)
00051 #define WRN_G_P LOG_STREAM_INDENT(warn, gui_parse)
00052 #define ERR_G_P LOG_STREAM_INDENT(err, gui_parse)
00053 
00054 namespace gui2 {
00055 
00056 static unsigned get_v_align(const std::string& v_align);
00057 static unsigned get_h_align(const std::string& h_align);
00058 static unsigned get_border(const std::vector<std::string>& border);
00059 static unsigned read_flags(const config& cfg);
00060 
00061 struct tbuilder_control : public tbuilder_widget
00062 {
00063 private:
00064     tbuilder_control();
00065 public:
00066 
00067     tbuilder_control(const config& cfg);
00068 
00069     void init_control(tcontrol* control) const;
00070 
00071     //! Parameters for the control.
00072     std::string id;
00073     std::string definition;
00074     t_string label;
00075     t_string tooltip;
00076     t_string help;
00077 };
00078 
00079 struct tbuilder_button : public tbuilder_control
00080 {
00081 
00082 private:
00083     tbuilder_button();
00084 public:
00085     tbuilder_button(const config& cfg);
00086 
00087     twidget* build () const;
00088 
00089 private:
00090     int retval_;
00091 };
00092 
00093 struct tbuilder_label : public tbuilder_control
00094 {
00095 
00096 private:
00097     tbuilder_label();
00098 public:
00099 /*WIKI
00100  * @page = GUIToolkitWML
00101  * @order = 3_widget_label
00102  *
00103  * == Label ==
00104  *
00105  * A label has no special fields.
00106  *
00107  */
00108     tbuilder_label(const config& cfg) :
00109         tbuilder_control(cfg)
00110     {}
00111 
00112     twidget* build () const;
00113 
00114 };
00115 
00116 struct tbuilder_listbox : public tbuilder_control
00117 {
00118 
00119 private:
00120     tbuilder_listbox();
00121 public:
00122     tbuilder_listbox(const config& cfg);
00123 
00124     twidget* build () const;
00125 
00126     tbuilder_grid* header;
00127     tbuilder_grid* list;
00128     tbuilder_grid* footer;
00129 
00130     tbuilder_grid* list_builder;
00131 
00132     const bool assume_fixed_row_size;
00133 };
00134 
00135 struct tbuilder_panel : public tbuilder_control
00136 {
00137 
00138 private:
00139     tbuilder_panel();
00140 public:
00141     tbuilder_panel(const config& cfg);
00142 
00143     twidget* build () const;
00144 
00145     tbuilder_grid* grid;
00146 };
00147 
00148 struct tbuilder_spacer : public tbuilder_control
00149 {
00150 
00151 private:
00152     tbuilder_spacer();
00153 public:
00154 /*WIKI
00155  * @page = GUIToolkitWML
00156  * @order = 3_widget_spacer
00157  *
00158  * == Spacer ==
00159  *
00160  * A spacer has no special fields.
00161  *
00162  */
00163     tbuilder_spacer(const config& cfg) :
00164         tbuilder_control(cfg)
00165     {}
00166 
00167     twidget* build () const;
00168 
00169 };
00170 
00171 struct tbuilder_text_box : public tbuilder_control
00172 {
00173 private:
00174     tbuilder_text_box();
00175     std::string history_;
00176 
00177 public:
00178 /*WIKI
00179  * @page = GUIToolkitWML
00180  * @order = 3_widget_text_box
00181  *
00182  * == Text box ==
00183  *
00184  * @start_table = config
00185  *     label (tstring = "")            The initial text of the text box.
00186  *     history (string = "")           The name of the history for the text box.
00187  *                                     A history saves the data entered in a
00188  *                                     text box between the games. With the up
00189  *                                     and down arrow it can be accessed. To
00190  *                                     create a new history item just add a new
00191  *                                     unique name for this field and the engine
00192  *                                     will handle the rest.
00193  * @end_table
00194  *
00195  */
00196     tbuilder_text_box(const config& cfg) :
00197         tbuilder_control(cfg),
00198         history_(cfg["history"])
00199     {}
00200 
00201     twidget* build () const;
00202 };
00203 
00204 struct tbuilder_toggle_button : public tbuilder_control
00205 {
00206 private:
00207     tbuilder_toggle_button();
00208 
00209 public:
00210 /*WIKI
00211  * @page = GUIToolkitWML
00212  * @order = 3_widget_toggle_button
00213  *
00214  * == Toggle button ==
00215  *
00216  * A toggle button has no special fields.
00217  *
00218  */
00219     tbuilder_toggle_button(const config& cfg) :
00220         tbuilder_control(cfg)
00221     {}
00222 
00223     twidget* build () const;
00224 };
00225 
00226 struct tbuilder_vertical_scrollbar : public tbuilder_control
00227 {
00228 private:
00229     tbuilder_vertical_scrollbar();
00230 
00231 public:
00232 /*WIKI
00233  * @page = GUIToolkitWML
00234  * @order = 3_widget_vertical_scrollbar
00235  *
00236  * == Vertical scrollbar ==
00237  *
00238  * A vertical scrollbar has no special fields.
00239  *
00240  */
00241     tbuilder_vertical_scrollbar(const config& cfg) :
00242         tbuilder_control(cfg)
00243     {}
00244 
00245     twidget* build () const;
00246 };
00247 
00248 twindow build(CVideo& video, const std::string& type)
00249 {
00250     std::vector<twindow_builder::tresolution>::const_iterator 
00251         definition = get_window_builder(type);
00252 
00253     // We set the values from the definition since we can only determine the 
00254     // best size (if needed) after all widgets have been placed.
00255     twindow window(video, 
00256         definition->x, definition->y, definition->width, definition->height, 
00257         definition->automatic_placement, 
00258         definition->horizontal_placement, definition->vertical_placement);
00259 
00260     log_scope2(gui, "Window builder: building grid for window");
00261 
00262     const unsigned rows = definition->grid->rows;
00263     const unsigned cols = definition->grid->cols;
00264 
00265     window.set_rows_cols(rows, cols);
00266 
00267     for(unsigned x = 0; x < rows; ++x) {
00268         window.set_row_grow_factor(x, definition->grid->row_grow_factor[x]);
00269         for(unsigned y = 0; y < cols; ++y) {
00270 
00271             if(x == 0) {
00272                 window.set_col_grow_factor(y, definition->grid->col_grow_factor[y]);
00273             }
00274 
00275             twidget* widget = definition->grid->widgets[x * cols + y]->build();
00276             window.add_child(widget, x, y, definition->grid->flags[x * cols + y],  definition->grid->border_size[x * cols + y]);
00277         }
00278     }
00279 
00280     window.recalculate_size();
00281 
00282     return window;
00283 }
00284 
00285 const std::string& twindow_builder::read(const config& cfg)
00286 {
00287 /*WIKI
00288  * @page = GUIToolkitWML
00289  * @order = 1_window
00290  *
00291  * = Window definition =
00292  *
00293  * A window defines how a window looks in the game.
00294  *
00295  * @start_table = config
00296  *     id (string)                   Unique id for this window.
00297  *     description (t_string)        Unique translatable name for this window.
00298  *
00299  *     resolution (section)          The definitions of the window in various
00300  *                                   resolutions.
00301  * @end_table
00302  *
00303  */
00304 
00305     id_ = cfg["id"];
00306     description_ = cfg["description"];
00307 
00308     VALIDATE(!id_.empty(), missing_mandatory_wml_key("window", "id"));
00309     VALIDATE(!description_.empty(), missing_mandatory_wml_key("window", "description"));
00310 
00311     DBG_G_P << "Window builder: reading data for window " << id_ << ".\n";
00312 
00313     const config::child_list& cfgs = cfg.get_children("resolution");
00314     VALIDATE(!cfgs.empty(), _("No resolution defined."));
00315     for(std::vector<config*>::const_iterator itor = cfgs.begin();
00316             itor != cfgs.end(); ++itor) {
00317 
00318         resolutions.push_back(tresolution(**itor));
00319     }
00320 
00321     return id_;
00322 }
00323 
00324 twindow_builder::tresolution::tresolution(const config& cfg) :
00325     window_width(lexical_cast_default<unsigned>(cfg["window_width"])),
00326     window_height(lexical_cast_default<unsigned>(cfg["window_height"])),
00327     automatic_placement(utils::string_bool(cfg["automatic_placement"], true)),
00328     x(lexical_cast_default<unsigned>(cfg["x"])),
00329     y(lexical_cast_default<unsigned>(cfg["y"])),
00330     width(lexical_cast_default<unsigned>(cfg["width"])),
00331     height(lexical_cast_default<unsigned>(cfg["height"])),
00332     vertical_placement(get_v_align(cfg["vertical_placement"])),
00333     horizontal_placement(get_h_align(cfg["horizontal_placement"])),
00334     definition(cfg["definition"]),
00335     grid(0)
00336 {
00337 /*WIKI
00338  * @page = GUIToolkitWML
00339  * @order = 1_window
00340  *
00341  * == Resolution ==
00342  *
00343  * @start_table = config
00344  *     window_width (unsigned = 0)   Width of the application window.
00345  *     window_height (unsigned = 0)  Height of the application window.
00346  *
00347  *     automatic_placement (bool = true)
00348  *                                   Automatically calculate the best size for
00349  *                                   the window and place it. If automatically
00350  *                                   placed ''vertical_placement'' and
00351  *                                   ''horizontal_placement'' can be used to
00352  *                                   modify the final placement. If not
00353  *                                   automatically placed the ''width'' and
00354  *                                   ''height'' are mandatory.
00355  *
00356  *     x (unsigned = 0)              X coordinate of the window to show.
00357  *     y (unsigned = 0)              Y coordinate of the window to show.
00358  *     width (unsigned = 0)          Width of the window to show.
00359  *     height (unsigned = 0)         Height of the window to show.
00360  *
00361  *     vertical_placement (v_align = "")
00362  *                                   The vertical placement of the window.
00363  *     horizontal_placement (h_align = "")
00364  *                                   The horizontal placement of the window.
00365  *
00366  *     definition (string = "default")
00367  *                                   Definition of the window which we want to 
00368  *                                   show.
00369  *
00370  *     grid (section)                The grid with the widgets to show. FIXME 
00371  *                                   the grid needs its own documentation page.
00372  * @end_table
00373  *
00374  */
00375 
00376     VALIDATE(cfg.child("grid"), _("No grid defined."));
00377 
00378     grid = new tbuilder_grid(*(cfg.child("grid")));
00379 
00380     if(!automatic_placement) {
00381         VALIDATE(width, missing_mandatory_wml_key("resulution", "width"));
00382         VALIDATE(height, missing_mandatory_wml_key("resulution", "height"));
00383     }
00384 
00385     DBG_G_P << "Window builder: parsing resolution " 
00386         << window_width << ',' << window_height << '\n';
00387 
00388     if(definition.empty()) {
00389         definition = "default";
00390     }
00391     
00392 }
00393 
00394 static unsigned get_v_align(const std::string& v_align)
00395 {
00396 
00397     if(v_align == "top") {
00398         return tgrid::VERTICAL_ALIGN_TOP;
00399     } else if(v_align == "bottom") {
00400         return tgrid::VERTICAL_ALIGN_BOTTOM;
00401     } else {
00402         if(!v_align.empty() && v_align != "center") {
00403             ERR_G_E << "Invalid vertical alignment '" 
00404                 << v_align << "' falling back to 'center'.\n";
00405         }
00406         return tgrid::VERTICAL_ALIGN_CENTER;
00407     }
00408 }
00409 
00410 static unsigned get_h_align(const std::string& h_align)
00411 {
00412     if(h_align == "left") {
00413         return tgrid::HORIZONTAL_ALIGN_LEFT;
00414     } else if(h_align == "right") {
00415         return tgrid::HORIZONTAL_ALIGN_RIGHT;
00416     } else {
00417         if(!h_align.empty() && h_align != "center") {
00418             ERR_G_E << "Invalid horizontal alignment '" 
00419                 << h_align << "' falling back to 'center'.\n";
00420         }
00421         return tgrid::HORIZONTAL_ALIGN_CENTER;
00422     }
00423 }
00424 
00425 static unsigned get_border(const std::vector<std::string>& border)
00426 {
00427     if(std::find(border.begin(), border.end(), "all") != border.end()) {
00428         return tgrid::BORDER_TOP 
00429             | tgrid::BORDER_BOTTOM | tgrid::BORDER_LEFT | tgrid::BORDER_RIGHT;
00430     } else {
00431         if(std::find(border.begin(), border.end(), "top") != border.end()) {
00432             return tgrid::BORDER_TOP;
00433         }
00434         if(std::find(border.begin(), border.end(), "bottom") != border.end()) {
00435             return tgrid::BORDER_BOTTOM;
00436         }
00437         if(std::find(border.begin(), border.end(), "left") != border.end()) {
00438             return tgrid::BORDER_LEFT;
00439         }
00440         if(std::find(border.begin(), border.end(), "right") != border.end()) {
00441             return tgrid::BORDER_RIGHT;
00442         }
00443     }
00444 
00445     return 0;
00446 }
00447 
00448 static unsigned read_flags(const config& cfg)
00449 {
00450     unsigned flags = 0;
00451 
00452     // Read the flags. FIXME document.
00453     flags |= get_v_align(cfg["vertical_alignment"]);
00454     flags |= get_h_align(cfg["horizontal_alignment"]);
00455     flags |= get_border( utils::split(cfg["border"]));
00456 
00457     if(utils::string_bool(cfg["vertical_grow"])) {
00458         flags |= tgrid::VERTICAL_GROW_SEND_TO_CLIENT;
00459     }
00460 
00461     if(utils::string_bool(cfg["horizontal_grow"])) {
00462         flags |= tgrid::HORIZONTAL_GROW_SEND_TO_CLIENT;
00463     }
00464 
00465     return flags;
00466 }
00467 
00468 tbuilder_grid::tbuilder_grid(const config& cfg) : 
00469     tbuilder_widget(cfg),
00470     rows(0),
00471     cols(0),
00472     row_grow_factor(),
00473     col_grow_factor(),
00474     flags(),
00475     border_size(),
00476     widgets()
00477 {
00478 /*WIKI
00479  * @page = GUIToolkitWML
00480  * @order = 2_cell
00481  *
00482  * = Cell =
00483  *
00484  * Every grid cell has some cell configuration values and one widget in the grid
00485  * cell. Here we describe the what is available more information about the usage
00486  * can be found here [[GUILayout]].
00487  *
00488  * == Row values ==
00489  *
00490  * For every row the following variables are available:
00491  *
00492  * @start_table = config
00493  *     grow_factor (unsigned = 0)      The grow factor for a row.
00494  * @end_table
00495  *
00496  * == Cell values ==
00497  *
00498  * For every column the following variables are available:
00499  * @start_table = config
00500  *     grow_factor (unsigned = 0)      The grow factor for a column, this value
00501  *                                     is only read for the first row.
00502  *
00503  *     border_size (unsigned = 0)      The border size for this grid cell.
00504  *     border (border = "")            Where to place the border in this grid
00505  *                                     cell.
00506  *
00507  *     vertical_alignment (v_align = "")
00508  *                                     The vertical alignment of the widget in
00509  *                                     the grid cell.
00510  *     horizontal_alignment (h_align = "")
00511  *                                     The horizontal alignment of the widget in
00512  *                                     the grid cell.
00513  *    
00514  *     vertical_grow (bool = false)    Does the widget grow in vertical
00515  *                                     direction when the grid cell grows in the
00516  *                                     vertical directon. This is used if the
00517  *                                     grid cell is wider as the best width for
00518  *                                     the widget.
00519  *     horizontal_grow (bool = false)  Does the widget grow in horizontal
00520  *                                     direction when the grid cell grows in the
00521  *                                     horizontal directon. This is used if the
00522  *                                     grid cell is higher as the best width for
00523  *                                     the widget.
00524  * @end_table
00525  *
00526  * == Widget ==
00527  *
00528  * The widget is one of the following items:
00529  * * button a button.
00530  * * grid a grid, this is used to nest items.
00531  * * label a label.
00532  * * listbox a listbox.
00533  * * panel a panel (a grid which can be drawn on).
00534  * * spacer a filler item. 
00535  * * text_box a text box.
00536  * * vertical_scrollbar a vertical scrollbar.
00537  *
00538  * More details about the widgets is in the next section.
00539  *
00540  */
00541     log_scope2(gui_parse, "Window builder: parsing a grid");
00542 
00543     const config::child_list& row_cfgs = cfg.get_children("row");
00544     for(std::vector<config*>::const_iterator row_itor = row_cfgs.begin();
00545             row_itor != row_cfgs.end(); ++row_itor) {
00546 
00547         unsigned col = 0;
00548 
00549         row_grow_factor.push_back(lexical_cast_default<unsigned>((**row_itor)["grow_factor"]));
00550 
00551         const config::child_list& col_cfgs = (**row_itor).get_children("column");
00552         for(std::vector<config*>::const_iterator col_itor = col_cfgs.begin();
00553                 col_itor != col_cfgs.end(); ++col_itor) {
00554 
00555             flags.push_back(read_flags(**col_itor));
00556             border_size.push_back(lexical_cast_default<unsigned>((**col_itor)["border_size"]));
00557             if(rows == 0) {
00558                 col_grow_factor.push_back(lexical_cast_default<unsigned>((**col_itor)["grow_factor"]));
00559             }
00560 
00561             if((**col_itor).child("button")) {
00562                 widgets.push_back(new tbuilder_button(*((**col_itor).child("button"))));
00563             } else if((**col_itor).child("label")) {
00564                 widgets.push_back(new tbuilder_label(*((**col_itor).child("label"))));
00565             } else if((**col_itor).child("listbox")) {
00566                 widgets.push_back(new tbuilder_listbox(*((**col_itor).child("listbox"))));
00567             } else if((**col_itor).child("panel")) {
00568                 widgets.push_back(new tbuilder_panel(*((**col_itor).child("panel"))));
00569             } else if((**col_itor).child("spacer")) {
00570                 widgets.push_back(new tbuilder_spacer(*((**col_itor).child("spacer"))));
00571             } else if((**col_itor).child("text_box")) {
00572                 widgets.push_back(new tbuilder_text_box(*((**col_itor).child("text_box"))));
00573             } else if((**col_itor).child("toggle_button")) {
00574                 widgets.push_back(new tbuilder_toggle_button(*((**col_itor).child("toggle_button"))));
00575             } else if((**col_itor).child("vertical_scrollbar")) {
00576                 widgets.push_back(
00577                     new tbuilder_vertical_scrollbar(*((**col_itor).child("vertical_scrollbar"))));
00578             } else if((**col_itor).child("grid")) {
00579                 widgets.push_back(new tbuilder_grid(*((**col_itor).child("grid"))));
00580             } else {
00581                 assert(false);
00582             }
00583 
00584             ++col;
00585         }
00586 
00587         ++rows;
00588         if(row_itor == row_cfgs.begin()) {
00589             cols = col;
00590         } else {
00591             VALIDATE(col, _("A row must have a column."));
00592             VALIDATE(col == cols, _("Number of columns differ."));
00593         }
00594 
00595     }
00596 
00597     DBG_G_P << "Window builder: grid has " 
00598         << rows << " rows and " << cols << " columns.\n";
00599 }
00600 
00601 tbuilder_control::tbuilder_control(const config& cfg) :
00602     tbuilder_widget(cfg),
00603     id(cfg["id"]),
00604     definition(cfg["definition"]),
00605     label(cfg["label"]),
00606     tooltip(cfg["tooltip"]),
00607     help(cfg["help"])
00608 {
00609 /*WIKI
00610  * @page = GUIToolkitWML
00611  * @order = 3_widget
00612  *
00613  * = Widget =
00614  *
00615  * All widgets placed in the cell have some values in common:
00616  * @start_table = config
00617  *     id (string = "")                This value is used for the engine to
00618  *                                     identify 'special' items. This means that
00619  *                                     for example a text_box can get the proper
00620  *                                     initial value. This value should be
00621  *                                     unique or empty. Those special values are
00622  *                                     documented at the window definition that
00623  *                                     uses them. NOTE items starting with an
00624  *                                     underscore are used for composed witdgets
00625  *                                     and these should be unique per composed
00626  *                                     widget.
00627  *
00628  *     definition (string = "default") The id of the widget definition to use.
00629  *                                     This way it's possible to select a
00630  *                                     specific version of the widget eg a title
00631  *                                     label when the label is used as title.
00632  *
00633  *     label (tstring = "")            Most widgets have some text accosiated
00634  *                                     with them, this field contain the value
00635  *                                     of that text. Some widgets use this value
00636  *                                     for other purposes, this is documented
00637  *                                     at the widget.
00638  *
00639  *     tooptip (tstring = "")          If you hover over a widget a while (the 
00640  *                                     time it takes can differ per widget) a
00641  *                                     short help can show up.This defines the
00642  *                                     text of that message.
00643  *
00644  *
00645  *     help (tstring = "")             If you hover over a widget and press F1 a
00646  *                                     help message can show up. This help
00647  *                                     message might be the same as the tooltip
00648  *                                     but in general (if used) this message
00649  *                                     should show more help. This defines the
00650  *                                     text of that message.
00651  * @end_table
00652  *
00653  */
00654 
00655     if(definition.empty()) {
00656         definition = "default";
00657     }
00658 
00659 
00660     DBG_G_P << "Window builder: found control with id '" 
00661         << id << "' and definition '" << definition << "'.\n";
00662 }
00663 
00664 void tbuilder_control::init_control(tcontrol* control) const
00665 {
00666     assert(control);
00667 
00668     control->set_id(id);
00669     control->set_definition(definition);
00670     control->set_label(label);
00671     control->set_tooltip(tooltip);
00672     control->set_help_message(help);
00673 }
00674 
00675 tbuilder_button::tbuilder_button(const config& cfg) :
00676     tbuilder_control(cfg),
00677     retval_(lexical_cast_default<int>(cfg["return_value"]))
00678 {
00679 /*WIKI
00680  * @page = GUIToolkitWML
00681  * @order = 3_widget_button
00682  *
00683  * == Button ==
00684  *
00685  * Definition of a button. When a button has a return value it sets the retour
00686  * value for the window. Normally this closes the window and returns this value
00687  * to the caller. The return value can either be defined by the user or
00688  * determined from the id of the button. The return value has a higher
00689  * precedence as the one defined by the id. (Of course it's weird to give a
00690  * button an id and then override it's return value.)
00691  *
00692  * List with the button specific variables:
00693  * @start_table = config
00694  *     return_value (int = 0)          The return value.
00695  *
00696  * @end_table
00697  *
00698  */
00699 }
00700 
00701 twidget* tbuilder_button::build() const
00702 {
00703     tbutton* button = new tbutton();
00704 
00705     init_control(button);
00706 
00707     if(retval_) {
00708         button->set_retval(retval_);
00709     } else {
00710         button->set_retval(tbutton::get_retval_by_id(id));
00711     }
00712 
00713     DBG_G << "Window builder: placed button '" << id << "' with defintion '" 
00714         << definition << "'.\n";
00715 
00716     return button;
00717 }
00718 
00719 twidget* tbuilder_label::build() const
00720 {
00721     tlabel* tmp_label = new tlabel();
00722 
00723     init_control(tmp_label);
00724 
00725     DBG_G << "Window builder: placed label '" << id << "' with defintion '" 
00726         << definition << "'.\n";
00727 
00728     return tmp_label;
00729 }
00730 
00731 tbuilder_listbox::tbuilder_listbox(const config& cfg) :
00732     tbuilder_control(cfg),
00733     header(cfg.child("header") ? new tbuilder_grid(*(cfg.child("header"))) : 0),
00734     list(0),
00735     footer(cfg.child("footer") ? new tbuilder_grid(*(cfg.child("footer"))) : 0),
00736     list_builder(0),
00737     assume_fixed_row_size(utils::string_bool(cfg["assume_fixed_row_size"]))
00738 {
00739 /*WIKI
00740  * @page = GUIToolkitWML
00741  * @order = 3_widget_listbox
00742  *
00743  * == Listbox ==
00744  *
00745  * Definition of a listbox. 
00746  *
00747  * List with the listbox specific variables:
00748  * @start_table = config
00749  *     scrollbar_mode (foo)            The mode for the scrollbar
00750  *                                     @* always_show the srollbar is always 
00751  *                                     shown even if all items can be shown. The
00752  *                                     scrollbar will be disabled in this case.
00753  *                                     @* auto_show the scrollbar is shown if
00754  *                                     more items are in the listbox as can be
00755  *                                     shown.  
00756  *                                     @* never_show the scrollbar is
00757  *                                     never shown even not if more items are
00758  *                                     available as visible.
00759  *     header (section = [])           Defines the grid for the optional header.
00760  *     list (section)                  Defines the grid for the list data.
00761  *     footer (section = [])           Defines the grid for the optional footer.
00762  *    
00763  *     list_definition (section)       The list can be a hardcoded list (uses
00764  *                                     list) or a definition is which case the
00765  *                                     engine knows how to 'build' the widget.
00766  *                                     When both exist [list] and
00767  *                                     [list_definition] the results are
00768  *                                     unexpected.
00769  *
00770  *     assume_fixed_row_size (bool = true)    
00771  *                                     If not all rows can be shown this value
00772  *                                     becomes important. If fixed size we
00773  *                                     always show X rows and no half rows are
00774  *                                     shown. This doesn't mean the rows need to
00775  *                                     be fixed size eg the addon dialog might
00776  *                                     get the option to show verbose info in
00777  *                                     the same listbox in that case it's still
00778  *                                     allowed to set the value.
00779  *
00780  * @end_table
00781  *
00782  *
00783  * Inside the list section there are only the following widgets allowed
00784  * * grid (to nest)
00785  * * selectable widgets which are
00786  * ** toggle_button 
00787  *
00788  */
00789 
00790 //  VALIDATE(cfg.child("list"), _("No list defined."));
00791 
00792     if(cfg.child("list_definition")) {
00793         list_builder = new tbuilder_grid(*(cfg.child("list_definition")));
00794     } else if(cfg.child("list")) {
00795         list = new tbuilder_grid(*(cfg.child("list")));
00796     } else {
00797         VALIDATE(false, _("No 'list_builder' nor a 'list' section defined."));
00798     }
00799 }
00800 
00801 twidget* tbuilder_listbox::build() const
00802 {
00803     tlistbox *listbox = new tlistbox();
00804 
00805     init_control(listbox);
00806 
00807     listbox->set_list_builder(list_builder);
00808 
00809     listbox->set_assume_fixed_row_size(assume_fixed_row_size);
00810 
00811     DBG_G << "Window builder: placed listbox '" << id << "' with defintion '" 
00812         << definition << "'.\n";
00813 
00814     tlistbox_definition::tresolution* conf = static_cast<tlistbox_definition::tresolution*>(listbox->config());
00815     assert(conf);
00816 
00817     tgrid* scrollbar = dynamic_cast<tgrid*>(conf->scrollbar->build());
00818     assert(scrollbar);
00819 
00820     scrollbar->set_id("_scroll");
00821 
00822     twidget* list_area = 0;
00823     if(list_builder) {
00824         list_area = new tspacer();
00825         assert(list_area);
00826         list_area->set_definition("default");
00827     } else {
00828         assert(list);
00829         list_area = dynamic_cast<tgrid*>(list->build());
00830         assert(list_area);
00831     }
00832 
00833     list_area->set_id("_list");
00834 
00835     listbox->grid().set_rows_cols(1, 2);
00836     listbox->grid().add_child(list_area, 0, 0, 
00837         tgrid::VERTICAL_GROW_SEND_TO_CLIENT 
00838         | tgrid::HORIZONTAL_GROW_SEND_TO_CLIENT 
00839         | tgrid::VERTICAL_ALIGN_CENTER
00840         | tgrid::HORIZONTAL_ALIGN_CENTER
00841         , 0);
00842     listbox->grid().set_col_grow_factor(0, 1);
00843     listbox->grid().add_child(scrollbar, 0, 1, 
00844         tgrid::VERTICAL_GROW_SEND_TO_CLIENT
00845         | tgrid::VERTICAL_ALIGN_CENTER
00846         | tgrid::HORIZONTAL_ALIGN_CENTER
00847         , 0);
00848 
00849     listbox->finalize_setup();
00850 
00851     return listbox;
00852 }
00853 
00854 tbuilder_panel::tbuilder_panel(const config& cfg) :
00855     tbuilder_control(cfg),
00856     grid(0)
00857 {
00858 /*WIKI
00859  * @page = GUIToolkitWML
00860  * @order = 3_widget_panel
00861  *
00862  * == Panel ==
00863  *
00864  * A panel is an item which can hold other items. The difference between a grid
00865  * and a panel is that it's possible to define how a panel looks. A grid in an
00866  * invisible container to just hold the items.
00867  *
00868  * @start_table = config
00869  *     grid (section)                  Defines the grid with the widgets to
00870  *                                     place on the panel.
00871  * @end_table                                   
00872  *
00873  */
00874     VALIDATE(cfg.child("grid"), _("No grid defined."));
00875 
00876     grid = new tbuilder_grid(*(cfg.child("grid")));
00877 }
00878 
00879 twidget* tbuilder_panel::build() const
00880 {
00881     tpanel* panel = new tpanel();
00882 
00883     init_control(panel);
00884 
00885     DBG_G << "Window builder: placed panel '" << id << "' with defintion '" 
00886         << definition << "'.\n";
00887 
00888 
00889     log_scope2(gui, "Window builder: building grid for panel.");
00890 
00891     const unsigned rows = grid->rows;
00892     const unsigned cols = grid->cols;
00893 
00894     panel->set_rows_cols(rows, cols);
00895 
00896     for(unsigned x = 0; x < rows; ++x) {
00897         panel->set_row_grow_factor(x, grid->row_grow_factor[x]);
00898         for(unsigned y = 0; y < cols; ++y) {
00899 
00900             if(x == 0) {
00901                 panel->set_col_grow_factor(y, grid->col_grow_factor[y]);
00902             }
00903 
00904             twidget* widget = grid->widgets[x * cols + y]->build();
00905             panel->add_child(widget, x, y, grid->flags[x * cols + y],  grid->border_size[x * cols + y]);
00906         }
00907     }
00908 
00909     return panel;
00910 }
00911 
00912 twidget* tbuilder_spacer::build() const
00913 {
00914     tspacer* spacer = new tspacer();
00915 
00916     init_control(spacer);
00917 
00918     DBG_G << "Window builder: placed spacer '" << id << "' with defintion '" 
00919         << definition << "'.\n";
00920 
00921     return spacer;
00922 }
00923 
00924 twidget* tbuilder_toggle_button::build() const
00925 {
00926     ttoggle_button *toggle_button = new ttoggle_button();
00927 
00928     init_control(toggle_button);
00929 
00930     DBG_G << "Window builder: placed toggle button '" << id << "' with defintion '" 
00931         << definition << "'.\n";
00932 
00933     return toggle_button;
00934 }
00935 
00936 twidget* tbuilder_text_box::build() const
00937 {
00938     ttext_box* text_box = new ttext_box();
00939 
00940     init_control(text_box);
00941 
00942     // A textbox doesn't have a label but a text
00943     text_box->set_text(label);
00944 
00945     if (!history_.empty()) {
00946         text_box->set_history(history_);        
00947     }
00948 
00949     DBG_G << "Window builder: placed text box '" << id << "' with defintion '" 
00950         << definition << "'.\n";
00951 
00952     return text_box;
00953 }
00954 
00955 twidget* tbuilder_vertical_scrollbar::build() const
00956 {
00957     tvertical_scrollbar *vertical_scrollbar = new tvertical_scrollbar();
00958 
00959     init_control(vertical_scrollbar);
00960 
00961     DBG_G << "Window builder: placed text box '" << id << "' with defintion '" 
00962         << definition << "'.\n";
00963 
00964     return vertical_scrollbar;
00965 }
00966 
00967 twidget* tbuilder_grid::build() const
00968 {
00969     tgrid* grid = new tgrid();
00970 
00971     grid->set_rows_cols(rows, cols);
00972 
00973     log_scope2(gui, "Window builder: building grid");
00974 
00975     DBG_G << "Window builder: grid has " << rows << " rows and "
00976         << cols << " columns.\n";
00977 
00978     for(unsigned x = 0; x < rows; ++x) {
00979         grid->set_row_grow_factor(x, row_grow_factor[x]);
00980         for(unsigned y = 0; y < cols; ++y) {
00981 
00982             if(x == 0) {
00983                 grid->set_col_grow_factor(y, col_grow_factor[y]);
00984             }
00985 
00986             DBG_G << "Window builder: adding child at " << x << ',' << y << ".\n";
00987 
00988             twidget* widget = widgets[x * cols + y]->build();
00989             grid->add_child(widget, x, y, flags[x * cols + y],  border_size[x * cols + y]);
00990         }
00991     }
00992 
00993     return grid;
00994 }   
00995 
00996 } // namespace gui2
00997 /*WIKI
00998  * @page = GUIToolkitWML
00999  * @order = ZZZZZZ_footer
01000  *
01001  * [[Category: WML Reference]]
01002  * [[Category: Generated]]
01003  *
01004  */
01005 

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