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/auxiliary/window_builder.hpp"
00019
00020 #include "asserts.hpp"
00021 #include "foreach.hpp"
00022 #include "gettext.hpp"
00023 #include "gui/auxiliary/log.hpp"
00024 #include "gui/auxiliary/window_builder/helper.hpp"
00025 #if 1 // See the #if in create_builder_widget.
00026 #include "gui/auxiliary/window_builder/scrollbar_panel.hpp"
00027 #include "gui/auxiliary/window_builder/horizontal_scrollbar.hpp"
00028 #include "gui/auxiliary/window_builder/repeating_button.hpp"
00029 #include "gui/auxiliary/window_builder/stacked_widget.hpp"
00030 #include "gui/auxiliary/window_builder/vertical_scrollbar.hpp"
00031 #include "gui/auxiliary/window_builder/label.hpp"
00032 #include "gui/auxiliary/window_builder/image.hpp"
00033 #include "gui/auxiliary/window_builder/toggle_button.hpp"
00034 #include "gui/auxiliary/window_builder/slider.hpp"
00035 #include "gui/auxiliary/window_builder/scroll_label.hpp"
00036 #include "gui/auxiliary/window_builder/minimap.hpp"
00037 #include "gui/auxiliary/window_builder/button.hpp"
00038 #include "gui/auxiliary/window_builder/drawing.hpp"
00039 #include "gui/auxiliary/window_builder/password_box.hpp"
00040 #endif
00041 #include "gui/widgets/settings.hpp"
00042 #include "gui/widgets/window.hpp"
00043 #include "formula_string_utils.hpp"
00044
00045 #include <boost/bind.hpp>
00046
00047 namespace gui2 {
00048
00049 namespace {
00050
00051 static std::map<std::string, boost::function<tbuilder_widget_ptr(config)> >&
00052 builder_widget_lookup()
00053 {
00054 static std::map<std::string, boost::function<tbuilder_widget_ptr(config)> >
00055 result;
00056 return result;
00057 }
00058
00059 tbuilder_widget_ptr create_builder_widget(const config& cfg)
00060 {
00061 config::all_children_itors children = cfg.all_children_range();
00062 size_t nb_children = std::distance(children.first, children.second);
00063 VALIDATE(nb_children == 1, "Grid cell does not have exactly 1 child.");
00064
00065 typedef
00066 std::pair<
00067 std::string
00068 , boost::function<tbuilder_widget_ptr(config)> >
00069 thack;
00070 foreach(const thack& item, builder_widget_lookup()) {
00071 if(item.first == "window" || item.first == "tooltip") {
00072 continue;
00073 }
00074 if(const config &c = cfg.child(item.first)) {
00075 return item.second(c);
00076 }
00077 }
00078
00079 if(const config &c = cfg.child("grid")) {
00080 return new tbuilder_grid(c);
00081 }
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092 #if 1
00093 #define TRY(name) \
00094 do { \
00095 if(const config &c = cfg.child(#name)) { \
00096 tbuilder_widget_ptr p = new implementation::tbuilder_##name(c);\
00097 assert(false); \
00098 } \
00099 } while (0)
00100
00101 TRY(stacked_widget);
00102 TRY(scrollbar_panel);
00103 TRY(horizontal_scrollbar);
00104 TRY(repeating_button);
00105 TRY(vertical_scrollbar);
00106 TRY(label);
00107 TRY(image);
00108 TRY(toggle_button);
00109 TRY(slider);
00110 TRY(scroll_label);
00111 TRY(minimap);
00112 TRY(button);
00113 TRY(drawing);
00114 TRY(password_box);
00115 #undef TRY
00116 #endif
00117
00118 std::cerr << cfg;
00119 ERROR_LOG(false);
00120 }
00121
00122 }
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137 twindow *build(CVideo &video, const twindow_builder::tresolution *definition)
00138 {
00139
00140
00141 twindow* window = new twindow(video
00142 , definition->x
00143 , definition->y
00144 , definition->width
00145 , definition->height
00146 , definition->automatic_placement
00147 , definition->horizontal_placement
00148 , definition->vertical_placement
00149 , definition->maximum_width
00150 , definition->maximum_height
00151 , definition->definition
00152 , definition->tooltip
00153 , definition->helptip);
00154 assert(window);
00155
00156 foreach(const twindow_builder::tresolution::tlinked_group& lg,
00157 definition->linked_groups) {
00158
00159 if(window->has_linked_size_group(lg.id)) {
00160 utils::string_map symbols;
00161 symbols["id"] = lg.id;
00162 t_string msg = vgettext(
00163 "Linked '$id' group has multiple definitions."
00164 , symbols);
00165
00166 VALIDATE(false, msg);
00167 }
00168
00169 window->init_linked_size_group(
00170 lg.id, lg.fixed_width, lg.fixed_height);
00171 }
00172
00173 window->set_click_dismiss(definition->click_dismiss);
00174
00175 boost::intrusive_ptr<const twindow_definition::tresolution> conf =
00176 boost::dynamic_pointer_cast<
00177 const twindow_definition::tresolution>(window->config());
00178 assert(conf);
00179
00180 if(conf->grid) {
00181 window->init_grid(conf->grid);
00182 window->finalize(definition->grid);
00183 } else {
00184 window->init_grid(definition->grid);
00185 }
00186
00187 window->add_to_keyboard_chain(window);
00188
00189 return window;
00190 }
00191
00192 twindow *build(CVideo &video, const std::string &type)
00193 {
00194 std::vector<twindow_builder::tresolution>::const_iterator
00195 definition = get_window_builder(type);
00196 twindow *window = build(video, &*definition);
00197 window->set_id(type);
00198 return window;
00199 }
00200
00201 tbuilder_widget::tbuilder_widget(const config& cfg)
00202 : id(cfg["id"])
00203 , linked_group(cfg["linked_group"])
00204 #ifndef LOW_MEM
00205 , debug_border_mode(cfg["debug_border_mode"])
00206 , debug_border_color(decode_color(cfg["debug_border_color"]))
00207 #endif
00208 {
00209 }
00210
00211 void register_builder_widget(const std::string& id
00212 , boost::function<tbuilder_widget_ptr(config)> functor)
00213 {
00214 builder_widget_lookup().insert(std::make_pair(id, functor));
00215 }
00216
00217 const std::string& twindow_builder::read(const config& cfg)
00218 {
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241 id_ = cfg["id"].str();
00242 description_ = cfg["description"].str();
00243
00244 VALIDATE(!id_.empty(), missing_mandatory_wml_key("window", "id"));
00245 VALIDATE(!description_.empty(), missing_mandatory_wml_key("window", "description"));
00246
00247 DBG_GUI_P << "Window builder: reading data for window " << id_ << ".\n";
00248
00249 config::const_child_itors cfgs = cfg.child_range("resolution");
00250 VALIDATE(cfgs.first != cfgs.second, _("No resolution defined."));
00251 foreach (const config &i, cfgs) {
00252 resolutions.push_back(tresolution(i));
00253 }
00254
00255 return id_;
00256 }
00257
00258 twindow_builder::tresolution::tresolution(const config& cfg) :
00259 window_width(cfg["window_width"]),
00260 window_height(cfg["window_height"]),
00261 automatic_placement(cfg["automatic_placement"].to_bool(true)),
00262 x(cfg["x"]),
00263 y(cfg["y"]),
00264 width(cfg["width"]),
00265 height(cfg["height"]),
00266 vertical_placement(
00267 implementation::get_v_align(cfg["vertical_placement"])),
00268 horizontal_placement(
00269 implementation::get_h_align(cfg["horizontal_placement"])),
00270 maximum_width(cfg["maximum_width"]),
00271 maximum_height(cfg["maximum_height"]),
00272 click_dismiss(cfg["click_dismiss"].to_bool()),
00273 definition(cfg["definition"]),
00274 linked_groups(),
00275 tooltip(cfg.child_or_empty("tooltip")),
00276 helptip(cfg.child_or_empty("helptip")),
00277 grid(0)
00278 {
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379 const config &c = cfg.child("grid");
00380
00381 VALIDATE(c, _("No grid defined."));
00382
00383 grid = new tbuilder_grid(c);
00384
00385 if(!automatic_placement) {
00386 VALIDATE(width.has_formula() || width(),
00387 missing_mandatory_wml_key("resolution", "width"));
00388 VALIDATE(height.has_formula() || height(),
00389 missing_mandatory_wml_key("resolution", "height"));
00390 }
00391
00392 DBG_GUI_P << "Window builder: parsing resolution "
00393 << window_width << ',' << window_height << '\n';
00394
00395 if(definition.empty()) {
00396 definition = "default";
00397 }
00398
00399 foreach (const config &lg, cfg.child_range("linked_group")) {
00400 tlinked_group linked_group;
00401 linked_group.id = lg["id"].str();
00402 linked_group.fixed_width = lg["fixed_width"].to_bool();
00403 linked_group.fixed_height = lg["fixed_height"].to_bool();
00404
00405 VALIDATE(!linked_group.id.empty()
00406 , missing_mandatory_wml_key("linked_group", "id"));
00407
00408 if(!(linked_group.fixed_width || linked_group.fixed_height)) {
00409 utils::string_map symbols;
00410 symbols["id"] = linked_group.id;
00411 t_string msg = vgettext(
00412 "Linked '$id' group needs a 'fixed_width' or "
00413 "'fixed_height' key."
00414 , symbols);
00415
00416 VALIDATE(false, msg);
00417 }
00418
00419 linked_groups.push_back(linked_group);
00420 }
00421 }
00422
00423 twindow_builder::tresolution::ttip::ttip(const config& cfg)
00424 : id(cfg["id"])
00425 {
00426 VALIDATE(!id.empty()
00427 , missing_mandatory_wml_key("[window][resolution][tip]", "id"));
00428 }
00429
00430 tbuilder_grid::tbuilder_grid(const config& cfg) :
00431 tbuilder_widget(cfg),
00432 rows(0),
00433 cols(0),
00434 row_grow_factor(),
00435 col_grow_factor(),
00436 flags(),
00437 border_size(),
00438 widgets()
00439 {
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502 log_scope2(log_gui_parse, "Window builder: parsing a grid");
00503
00504 foreach (const config &row, cfg.child_range("row"))
00505 {
00506 unsigned col = 0;
00507
00508 row_grow_factor.push_back(row["grow_factor"]);
00509
00510 foreach (const config &c, row.child_range("column"))
00511 {
00512 flags.push_back(implementation::read_flags(c));
00513 border_size.push_back(c["border_size"]);
00514 if(rows == 0) {
00515 col_grow_factor.push_back(c["grow_factor"]);
00516 }
00517
00518 widgets.push_back(create_builder_widget(c));
00519
00520 ++col;
00521 }
00522
00523 ++rows;
00524 if (rows == 1) {
00525 cols = col;
00526 } else {
00527 VALIDATE(col, _("A row must have a column."));
00528 VALIDATE(col == cols, _("Number of columns differ."));
00529 }
00530
00531 }
00532
00533 DBG_GUI_P << "Window builder: grid has "
00534 << rows << " rows and " << cols << " columns.\n";
00535 }
00536
00537 tgrid* tbuilder_grid::build() const
00538 {
00539 return build(new tgrid());
00540 }
00541
00542 tgrid* tbuilder_grid::build (tgrid* grid) const
00543 {
00544 grid->set_id(id);
00545 grid->set_linked_group(linked_group);
00546 grid->set_rows_cols(rows, cols);
00547
00548 log_scope2(log_gui_general, "Window builder: building grid");
00549
00550 DBG_GUI_G << "Window builder: grid '" << id
00551 << "' has " << rows << " rows and "
00552 << cols << " columns.\n";
00553
00554 for(unsigned x = 0; x < rows; ++x) {
00555 grid->set_row_grow_factor(x, row_grow_factor[x]);
00556 for(unsigned y = 0; y < cols; ++y) {
00557
00558 if(x == 0) {
00559 grid->set_column_grow_factor(y, col_grow_factor[y]);
00560 }
00561
00562 DBG_GUI_G << "Window builder: adding child at " << x << ',' << y << ".\n";
00563
00564 twidget* widget = widgets[x * cols + y]->build();
00565 grid->set_child(widget, x, y, flags[x * cols + y], border_size[x * cols + y]);
00566 }
00567 }
00568
00569 return grid;
00570 }
00571
00572 }
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589