00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #define GETTEXT_DOMAIN "wesnoth-lib"
00017
00018
00019 #ifdef DEBUG_WINDOW_LAYOUT_GRAPHS
00020
00021 #include "gui/widgets/debug.hpp"
00022
00023 #include "foreach.hpp"
00024 #include "formatter.hpp"
00025 #include "gui/widgets/generator.hpp"
00026 #ifdef GUI2_EXPERIMENTAL_LISTBOX
00027 #include "gui/widgets/list.hpp"
00028 #else
00029 #include "gui/widgets/listbox.hpp"
00030 #endif
00031 #include "gui/widgets/scrollbar_container.hpp"
00032 #include "gui/widgets/window.hpp"
00033 #include "serialization/string_utils.hpp"
00034
00035 #include <fstream>
00036 #include <iostream>
00037
00038 namespace gui2 {
00039
00040 namespace {
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051 std::string get_child_id(
00052 const std::string& parent_id, const unsigned row, const unsigned col)
00053 {
00054
00055
00056
00057
00058 std::string result = parent_id + "_C_"
00059 + lexical_cast<std::string>(row) + '_'
00060 + lexical_cast<std::string>(col);
00061
00062 return result;
00063 }
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074 std::string get_child_widget_id(
00075 const std::string& parent_id, const unsigned row, const unsigned col)
00076 {
00077 return get_child_id(parent_id, row, col) + "_W";
00078 }
00079
00080
00081 std::string get_base_filename()
00082 {
00083 char buf[17] = {0};
00084 time_t t = time(NULL);
00085 tm* lt = localtime(&t);
00086 if(lt) {
00087 strftime(buf, sizeof(buf), "%Y%m%d_%H%M%S", lt);
00088 }
00089 static unsigned counter = 0;
00090 ++counter;
00091
00092 return (formatter() << buf << '_' << counter << '_').str();
00093 }
00094
00095
00096 const unsigned ALL = UINT_MAX;
00097
00098 const unsigned SIZE_INFO = 1 << 0;
00099
00100
00101
00102 const unsigned STATE_INFO = 1 << 1;
00103
00104
00105 unsigned level_ = 0;
00106 unsigned domain_ = 0;
00107 }
00108
00109 tdebug_layout_graph::tdebug_layout_graph(const twindow* window)
00110 : window_(window)
00111 , sequence_number_(0)
00112 , filename_base_(get_base_filename())
00113 {
00114 }
00115
00116 void tdebug_layout_graph::set_level(const std::string& level)
00117 {
00118 if(level.empty()) {
00119 level_ = ALL;
00120 return;
00121 }
00122
00123 std::vector<std::string> params = utils::split(level);
00124
00125 foreach(const std::string& param, params) {
00126 if(param == "all") {
00127 level_ = ALL;
00128
00129
00130 return;
00131 } else if(param == "size") {
00132 level_ |= SIZE_INFO;
00133 } else if(param == "state") {
00134 level_ |= STATE_INFO;
00135 } else {
00136
00137 std::cerr << "Unknown level '" << param << "' is ignored.\n";
00138 }
00139 }
00140 }
00141
00142 void tdebug_layout_graph::set_domain(const std::string& domain)
00143 {
00144 if(domain.empty()) {
00145
00146 domain_ = ALL;
00147 return;
00148 }
00149
00150 std::vector<std::string> params = utils::split(domain);
00151
00152 foreach(const std::string& param, params) {
00153 if(param == "all") {
00154 domain_ = ALL;
00155
00156
00157 return;
00158 } else if(param == "show") {
00159 domain_ |= SHOW;
00160 } else if(param == "layout") {
00161 domain_ |= LAYOUT;
00162 } else {
00163
00164 std::cerr << "Unknown domain '" << param << "' is ignored.\n";
00165 }
00166 }
00167 }
00168
00169 void tdebug_layout_graph::generate_dot_file(
00170 const std::string& generator, const unsigned domain)
00171 {
00172
00173 if((domain_ & domain) != domain) {
00174 return;
00175 }
00176
00177 std::string id = window_->id();
00178 if(!id.empty()) {
00179 id += '_';
00180 }
00181 const std::string filename = filename_base_ + id
00182 + lexical_cast<std::string>(++sequence_number_)
00183 + "-" + generator + ".dot";
00184
00185 std::ofstream file(filename.c_str());
00186
00187 file << "//Basic layout graph for window id '" << window_->id()
00188 << "' using definition '" << window_->definition_ << "'.\n"
00189 << "digraph window {\n"
00190 << "\tnode [shape=record, style=filled, fillcolor=\"bisque\"];\n"
00191 << "\trankdir=LR;\n"
00192 ;
00193
00194 widget_generate_info(file, window_, "root");
00195
00196 file << "}\n";
00197 }
00198
00199 void tdebug_layout_graph::widget_generate_info(std::ostream& out,
00200 const twidget* widget, const std::string& id, const bool embedded) const
00201 {
00202 assert(!id.empty());
00203
00204 out << "\t" << id
00205 << " [label=<<table border=\"0\" cellborder=\"1\" cellspacing=\"0\">";
00206
00207 widget_generate_basic_info(out, widget);
00208 if(level_ & STATE_INFO) widget_generate_state_info(out, widget);
00209 if(level_ & SIZE_INFO) widget_generate_size_info(out, widget);
00210
00211 out << "</table>>";
00212 if(embedded) {
00213 out << ", fillcolor=\"palegoldenrod\"";
00214 }
00215 out << "];\n";
00216
00217 const tgrid* grid = dynamic_cast<const tgrid*>(widget);
00218 if(!grid) {
00219 const tcontainer_* container = dynamic_cast<const tcontainer_*>(widget);
00220
00221 if(container) {
00222
00223 widget_generate_info(out, &container->grid(), id + "_G", true);
00224 out << "\t" << id << " -> "
00225 << id << "_G"
00226 << " [label=\"(grid)\"];\n";
00227 }
00228
00229 const tscrollbar_container* scrollbar_container =
00230 dynamic_cast<const tscrollbar_container*>(widget);
00231
00232 if(scrollbar_container) {
00233 widget_generate_info(out, scrollbar_container->content_grid_, id + "_C", true);
00234 out << "\t" << id << " -> "
00235 << id << "_C"
00236 << " [label=\"(content)\"];\n";
00237 }
00238
00239 const tlistbox* listbox = dynamic_cast<const tlistbox*>(widget);
00240 if(listbox) {
00241 assert(listbox->generator_);
00242 }
00243
00244 const tgenerator_* generator =
00245 dynamic_cast<const tgenerator_*>(widget);
00246
00247 if(generator) {
00248 for(size_t i = 0;
00249 i < generator->get_item_count(); ++i) {
00250
00251 const std::string child_id =
00252 id + "_I_" + lexical_cast<std::string>(i);
00253
00254 widget_generate_info(out,
00255 &generator->item(i),
00256 child_id, true);
00257
00258 out << "\t" << id << " -> "
00259 << child_id
00260 << " [label=\"(item)\"];\n";
00261 }
00262 }
00263 }
00264 if(grid) {
00265 grid_generate_info(out, grid, id);
00266 }
00267 }
00268
00269 static std::string format_label(std::string label)
00270 {
00271 if(label.size() > 50) {
00272 label = label.substr(0, 50) + "...";
00273 }
00274
00275
00276 std::replace(label.begin(), label.end(), '>', '_');
00277
00278 return label;
00279 }
00280
00281 void tdebug_layout_graph::widget_generate_basic_info(
00282 std::ostream& out, const twidget* widget) const
00283 {
00284 std::string header_background = level_ & (SIZE_INFO|STATE_INFO)
00285 ? " bgcolor=\"gray\"" : "";
00286 const tcontrol* control = dynamic_cast<const tcontrol*>(widget);
00287
00288 out << "<tr><td" << header_background << ">" << '\n'
00289 << "type=" << get_type(widget) << '\n'
00290 << "</td></tr>" << '\n'
00291 << "<tr><td" << header_background << ">" << '\n'
00292 << "id=" << widget->id() << '\n'
00293 << "</td></tr>" << '\n'
00294 << "<tr><td" << header_background << ">" << '\n'
00295 << "address=" << widget << '\n'
00296 << "</td></tr>" << '\n'
00297 << "<tr><td" << header_background << ">" << '\n'
00298 << "parent=" << widget->parent_ << '\n'
00299 << "</td></tr>" << '\n';
00300 if(control) {
00301 out << "<tr><td" << header_background << ">" << '\n'
00302 << "label=" << format_label(control->label()) << '\n'
00303 << "<tr><td" << header_background << ">" << '\n'
00304 << "definition=" << control->definition_ << '\n'
00305 << "</td></tr>" << '\n'
00306 << "</td></tr>\n";
00307 }
00308 }
00309
00310 void tdebug_layout_graph::widget_generate_state_info(
00311 std::ostream& out, const twidget* widget) const
00312 {
00313 const tcontrol* control = dynamic_cast<const tcontrol*>(widget);
00314 if(!control) {
00315 return;
00316 }
00317
00318 out << "<tr><td>\n"
00319 << "tooltip=" << control->tooltip() << '\n'
00320 << "</td></tr>\n"
00321 << "<tr><td>\n"
00322 << "help message" << control->help_message() << '\n'
00323
00324 << "</td></tr>\n"
00325 << "<tr><td>\n"
00326 << "active=" << control->get_active() << '\n'
00327 << "</td></tr>\n"
00328 << "<tr><td>\n"
00329 << "visible=" << control->get_visible() << '\n'
00330 << "</td></tr>\n"
00331 << "<tr><td>\n"
00332 << "drawing action=" << control->get_drawing_action() << '\n'
00333 << "</td></tr>\n"
00334 << "<tr><td>\n"
00335 << "clip rect=" << control->clip_rect_ << '\n'
00336 << "</td></tr>\n"
00337 << "<tr><td>\n"
00338 << "use tooltip on label overflow="
00339 << control->get_use_tooltip_on_label_overflow() << '\n'
00340 << "</td></tr>\n"
00341 << "<tr><td>\n"
00342 << "does block click dismiss="
00343 << control->disable_click_dismiss() << '\n'
00344 << "</td></tr>\n";
00345
00346 const tscrollbar_container* scrollbar_container =
00347 dynamic_cast<const tscrollbar_container*>(widget);
00348
00349 if(scrollbar_container) {
00350 out << "<tr><td>\n"
00351 << "vertical_scrollbar_mode_="
00352 << scrollbar_container->vertical_scrollbar_mode_ << '\n'
00353 << "</td></tr>\n"
00354 << "<tr><td>\n"
00355 << "horizontal_scrollbar_mode_="
00356 << scrollbar_container->horizontal_scrollbar_mode_ << '\n'
00357 << "</td></tr>\n";
00358 }
00359 }
00360
00361 void tdebug_layout_graph::widget_generate_size_info(
00362 std::ostream& out, const twidget* widget) const
00363 {
00364 out << "<tr><td>\n"
00365 << "can wrap=" << widget->can_wrap() << '\n'
00366 << "</td></tr>\n"
00367 << "<tr><td>\n"
00368 << "size=" << widget->get_size() << '\n'
00369 << "</td></tr>\n"
00370 << "<tr><td>\n"
00371 << "position=" << widget->get_origin() << '\n'
00372 << "</td></tr>\n"
00373 << "<tr><td>\n"
00374 << "last_best_size_=" << widget->last_best_size_ << '\n'
00375 << "</td></tr>\n"
00376 << "<tr><td>\n"
00377 << "layout_size_=" << widget->layout_size_ << '\n'
00378 << "</td></tr>\n";
00379
00380
00381 const tcontrol* control = dynamic_cast<const tcontrol*>(widget);
00382
00383 if(control) {
00384 out << "<tr><td>\n"
00385 << "minimum config size=" << control->get_config_minimum_size() << '\n'
00386 << "</td></tr>\n"
00387 << "<tr><td>\n"
00388 << "default config size=" << control->get_config_default_size() << '\n'
00389 << "</td></tr>\n"
00390 << "<tr><td>\n"
00391 << "maximum config size=" << control->get_config_maximum_size() << '\n'
00392 << "</td></tr>\n"
00393 << "<tr><td>\n"
00394 << "shrunken_=" << control->shrunken_ << '\n'
00395 << "</td></tr>\n";
00396 }
00397
00398 const tcontainer_* container = dynamic_cast<const tcontainer_*>(widget);
00399
00400 if(container) {
00401 out << "<tr><td>\n"
00402 << "border_space=" << container->border_space() << '\n'
00403 << "</td></tr>\n";
00404 }
00405 }
00406
00407 void tdebug_layout_graph::grid_generate_info(std::ostream& out,
00408 const tgrid* grid, const std::string& parent_id) const
00409 {
00410 assert(!parent_id.empty());
00411
00412
00413
00414
00415 out << "\n\n\t// The children of " << parent_id << ".\n";
00416
00417 for(unsigned row = 0; row < grid->get_rows(); ++row) {
00418 for(unsigned col = 0; col < grid->get_cols(); ++col) {
00419
00420 const twidget* widget = grid->child(row, col).widget();
00421 assert(widget);
00422
00423 widget_generate_info(
00424 out, widget, get_child_widget_id(parent_id, row, col));
00425 }
00426 }
00427
00428 out << "\n\t// The grid child data of " << parent_id << ".\n";
00429
00430 for(unsigned row = 0; row < grid->get_rows(); ++row) {
00431 for(unsigned col = 0; col < grid->get_cols(); ++col) {
00432
00433 child_generate_info(out, grid->child(row, col),
00434 get_child_id(parent_id, row, col));
00435 }
00436 }
00437
00438
00439 out << "\n\t// The links of " << parent_id << ".\n";
00440
00441 for(unsigned row = 0; row < grid->get_rows(); ++row) {
00442 for(unsigned col = 0; col < grid->get_cols(); ++col) {
00443
00444
00445 out << "\t" << parent_id << " -> "
00446 << get_child_id(parent_id, row, col)
00447 << " [label=\"(" << row << ',' << col
00448 << ")\"];\n";
00449
00450
00451 out << "\t" << get_child_id(parent_id, row, col) << " -> "
00452 << get_child_widget_id(parent_id, row, col) << ";\n";
00453 }
00454 }
00455 }
00456
00457 void tdebug_layout_graph::child_generate_info(std::ostream& out,
00458 const tgrid::tchild& child, const std::string& id) const
00459 {
00460 assert(!id.empty());
00461
00462 unsigned flags = child.get_flags();
00463
00464 out << "\t" << id
00465 << " [style=\"\", label=<<table border=\"0\" "
00466 "cellborder=\"1\" cellspacing=\"0\">\n";
00467 out << "<tr><td>\n"
00468 << "vertical flag=";
00469
00470 switch(flags & tgrid::VERTICAL_MASK) {
00471 case tgrid::VERTICAL_GROW_SEND_TO_CLIENT : out << "send to client"; break;
00472 case tgrid::VERTICAL_ALIGN_TOP : out << "align to top"; break;
00473 case tgrid::VERTICAL_ALIGN_CENTER : out << "center"; break;
00474 case tgrid::VERTICAL_ALIGN_BOTTOM : out << "align to bottom"; break;
00475 default :
00476 out << "unknown value("
00477 << ((flags & tgrid::VERTICAL_MASK) >> tgrid::VERTICAL_SHIFT)
00478 << ")";
00479 }
00480
00481 out << "\n</td></tr>\n"
00482 << "<tr><td>\n"
00483 << "horizontal flag=";
00484
00485 switch(flags & tgrid::HORIZONTAL_MASK) {
00486 case tgrid::HORIZONTAL_GROW_SEND_TO_CLIENT : out << "send to client"; break;
00487 case tgrid::HORIZONTAL_ALIGN_LEFT : out << "align to left"; break;
00488 case tgrid::HORIZONTAL_ALIGN_CENTER : out << "center"; break;
00489 case tgrid::HORIZONTAL_ALIGN_RIGHT : out << "align to right"; break;
00490 default :
00491 out << "unknown value("
00492 << ((flags & tgrid::HORIZONTAL_MASK) >> tgrid::HORIZONTAL_SHIFT)
00493 << ")";
00494 }
00495
00496 out << "\n</td></tr>\n"
00497 << "<tr><td>\n"
00498 << "border location=";
00499
00500 if((flags & tgrid::BORDER_ALL) == 0) {
00501 out << "none";
00502 } else if((flags & tgrid::BORDER_ALL) == tgrid::BORDER_ALL) {
00503 out << "all";
00504 } else {
00505 std::string result;
00506 if(flags & tgrid::BORDER_TOP) result += "top, ";
00507 if(flags & tgrid::BORDER_BOTTOM) result += "bottom, ";
00508 if(flags & tgrid::BORDER_LEFT) result += "left, ";
00509 if(flags & tgrid::BORDER_RIGHT) result += "right, ";
00510
00511 if(!result.empty()) {
00512 result.resize(result.size() - 2);
00513 }
00514
00515 out << result;
00516 }
00517
00518 out << "\n</td></tr>\n"
00519 << "<tr><td>\n"
00520 << "border_size="<< child.get_border_size()
00521 << "\n</td></tr>\n";
00522
00523 out << "</table>>];\n";
00524 }
00525
00526 std::string tdebug_layout_graph::get_type(const twidget* widget) const
00527 {
00528 const tcontrol* control = dynamic_cast<const tcontrol*>(widget);
00529 if(control) {
00530 return control->get_control_type();
00531 } else {
00532 const tgrid* grid = dynamic_cast<const tgrid*>(widget);
00533 const tgenerator_* generator =
00534 dynamic_cast<const tgenerator_*>(widget);
00535
00536 if(grid) {
00537 return "grid";
00538 } else if(generator) {
00539 return "generator";
00540 } else {
00541 return "unknown";
00542 }
00543 }
00544 }
00545
00546 }
00547 #endif
00548