16 #define GETTEXT_DOMAIN "wesnoth-lib"
19 #ifdef DEBUG_WINDOW_LAYOUT_GRAPHS
49 std::string get_child_id(
const std::string& parent_id,
58 std::string result = parent_id +
"_C_" + std::to_string(row)
59 +
'_' + std::to_string(col);
73 std::string get_child_widget_id(
const std::string& parent_id,
77 return get_child_id(parent_id, row, col) +
"_W";
81 std::string get_base_filename()
83 std::ostringstream ss;
85 std::time_t
t = std::time(
nullptr);
86 ss << std::put_time(std::localtime(&
t),
"%Y%m%d_%H%M%S");
88 static unsigned counter = 0;
91 ss <<
'_' << counter <<
'_';
97 const unsigned ALL = std::numeric_limits<unsigned>::max();
99 const unsigned SIZE_INFO = 1 << 0;
103 const unsigned STATE_INFO = 1 << 1;
107 unsigned domain_ = 0;
110 debug_layout_graph::debug_layout_graph(
const window* window)
111 : window_(window), sequence_number_(0), filename_base_(get_base_filename())
115 void debug_layout_graph::set_level(
const std::string&
level)
124 for(
const auto & param : params)
131 }
else if(param ==
"size") {
133 }
else if(param ==
"state") {
134 level_ |= STATE_INFO;
136 PLAIN_LOG <<
"Unknown level '" << param <<
"' is ignored.";
141 void debug_layout_graph::set_domain(
const std::string& domain)
151 for(
const auto & param : params)
158 }
else if(param ==
"show") {
160 }
else if(param ==
"layout") {
163 PLAIN_LOG <<
"Unknown domain '" << param <<
"' is ignored.";
168 void debug_layout_graph::generate_dot_file(
const std::string&
generator,
169 const unsigned domain)
172 if((domain_ & domain) != domain) {
176 std::string
id = window_->id();
180 const std::string
filename = filename_base_ +
id
181 + std::to_string(++sequence_number_)
184 std::ofstream file(
filename.c_str());
186 file <<
"//Basic layout graph for window id '" << window_->id()
187 <<
"' using definition '" << window_->definition_ <<
"'.\n"
188 <<
"digraph window {\n"
189 <<
"\tnode [shape=record, style=filled, fillcolor=\"bisque\"];\n"
190 <<
"\trankdir=LR;\n";
192 widget_generate_info(file, window_,
"root");
197 void debug_layout_graph::widget_generate_info(std::ostream& out,
198 const widget* widget,
199 const std::string&
id,
200 const bool embedded)
const
205 <<
" [label=<<table border=\"0\" cellborder=\"1\" cellspacing=\"0\">";
207 widget_generate_basic_info(out, widget);
208 if(level_ & STATE_INFO)
209 widget_generate_state_info(out, widget);
210 if(level_ & SIZE_INFO)
211 widget_generate_size_info(out, widget);
215 out <<
", fillcolor=\"palegoldenrod\"";
219 const grid* grid =
dynamic_cast<const class grid*
>(widget);
221 const container_base* container =
dynamic_cast<const container_base*
>(widget);
225 widget_generate_info(out, &container->get_grid(),
id +
"_G",
true);
226 out <<
"\t" <<
id <<
" -> " <<
id <<
"_G"
227 <<
" [label=\"(grid)\"];\n";
230 const scrollbar_container* scrollbar_container
231 =
dynamic_cast<const class scrollbar_container*
>(widget);
233 if(scrollbar_container) {
234 widget_generate_info(out,
235 scrollbar_container->content_grid_.get(),
id +
"_C",
true);
236 out <<
"\t" <<
id <<
" -> " <<
id <<
"_C"
237 <<
" [label=\"(content)\"];\n";
240 const listbox* listbox =
dynamic_cast<const class listbox*
>(widget);
242 assert(listbox->generator_);
245 const generator_base*
generator =
dynamic_cast<const generator_base*
>(widget);
248 for(std::size_t
i = 0;
i <
generator->get_item_count(); ++
i) {
250 const std::string child_id =
id +
"_I_"
253 widget_generate_info(out, &
generator->item(
i), child_id,
true);
255 out <<
"\t" <<
id <<
" -> " << child_id
256 <<
" [label=\"(item)\"];\n";
261 grid_generate_info(out, grid,
id);
265 static std::string format_label(std::string
label)
267 if(
label.size() > 50) {
272 std::replace(
label.begin(),
label.end(),
'>',
'_');
277 void debug_layout_graph::widget_generate_basic_info(std::ostream& out,
278 const widget* widget)
281 std::string header_background
282 = level_ & (SIZE_INFO | STATE_INFO) ?
" bgcolor=\"gray\"" :
"";
283 const styled_widget* control =
dynamic_cast<const class styled_widget*
>(widget);
285 out <<
"<tr><td" << header_background <<
">" <<
'\n'
286 <<
"type=" << get_type(widget) <<
'\n' <<
"</td></tr>" <<
'\n'
287 <<
"<tr><td" << header_background <<
">" <<
'\n'
288 <<
"id=" << widget->id() <<
'\n' <<
"</td></tr>" <<
'\n' <<
"<tr><td"
289 << header_background <<
">" <<
'\n' <<
"address=" << widget <<
'\n'
290 <<
"</td></tr>" <<
'\n' <<
"<tr><td" << header_background <<
">" <<
'\n'
291 <<
"parent=" << widget->parent_ <<
'\n' <<
"</td></tr>" <<
'\n';
293 out <<
"<tr><td" << header_background <<
">" <<
'\n'
294 <<
"label=" << format_label(control->get_label()) <<
'\n' <<
"<tr><td"
295 << header_background <<
">" <<
'\n'
296 <<
"definition=" << control->definition_ <<
'\n' <<
"</td></tr>"
297 <<
'\n' <<
"</td></tr>\n";
301 void debug_layout_graph::widget_generate_state_info(std::ostream& out,
302 const widget* widget)
305 const styled_widget* control =
dynamic_cast<const styled_widget*
>(widget);
311 <<
"tooltip=" << control->tooltip() <<
'\n' <<
"</td></tr>\n"
313 <<
"help message" << control->help_message() <<
'\n'
317 <<
"active=" << control->get_active() <<
'\n' <<
"</td></tr>\n"
319 <<
"visible=" <<
static_cast<int>(control->get_visible()) <<
'\n' <<
"</td></tr>\n"
321 <<
"drawing action=" <<
static_cast<int>(control->get_drawing_action()) <<
'\n'
324 <<
"clip rect=" << control->clipping_rectangle_ <<
'\n'
327 <<
"use tooltip on label overflow="
328 << control->get_use_tooltip_on_label_overflow() <<
'\n'
331 <<
"does block click dismiss=" << control->disable_click_dismiss()
332 <<
'\n' <<
"</td></tr>\n";
334 const scrollbar_container* scrollbar_container
335 =
dynamic_cast<const class scrollbar_container*
>(widget);
337 if(scrollbar_container) {
339 <<
"vertical_scrollbar_mode_="
340 << scrollbar_container->vertical_scrollbar_mode_ <<
'\n'
343 <<
"horizontal_scrollbar_mode_="
344 << scrollbar_container->horizontal_scrollbar_mode_ <<
'\n'
349 void debug_layout_graph::widget_generate_size_info(std::ostream& out,
350 const widget* widget)
const
353 <<
"can wrap=" << widget->can_wrap() <<
'\n' <<
"</td></tr>\n"
355 <<
"size=" << widget->get_size() <<
'\n' <<
"</td></tr>\n"
357 <<
"position=" << widget->get_origin() <<
'\n' <<
"</td></tr>\n"
359 <<
"last_best_size_=" << widget->last_best_size_ <<
'\n'
362 <<
"layout_size_=" << widget->layout_size_ <<
'\n' <<
"</td></tr>\n";
365 const styled_widget* control =
dynamic_cast<const styled_widget*
>(widget);
369 <<
"minimum config size=" << control->get_config_minimum_size()
370 <<
'\n' <<
"</td></tr>\n"
372 <<
"default config size=" << control->get_config_default_size()
373 <<
'\n' <<
"</td></tr>\n"
375 <<
"maximum config size=" << control->get_config_maximum_size()
376 <<
'\n' <<
"</td></tr>\n"
378 <<
"shrunken_=" << control->shrunken_ <<
'\n' <<
"</td></tr>\n";
381 const container_base* container =
dynamic_cast<const container_base*
>(widget);
385 <<
"border_space=" << container->border_space() <<
'\n'
390 void debug_layout_graph::grid_generate_info(std::ostream& out,
392 const std::string& parent_id)
const
394 assert(!parent_id.empty());
399 out <<
"\n\n\t// The children of " << parent_id <<
".\n";
401 for(
unsigned row = 0; row < grid->get_rows(); ++row) {
402 for(
unsigned col = 0; col < grid->get_cols(); ++col) {
404 const widget* widget = grid->get_widget(row, col);
407 widget_generate_info(
408 out, widget, get_child_widget_id(parent_id, row, col));
412 out <<
"\n\t// The grid child data of " << parent_id <<
".\n";
414 for(
unsigned row = 0; row < grid->get_rows(); ++row) {
415 for(
unsigned col = 0; col < grid->get_cols(); ++col) {
417 child_generate_info(out,
418 grid->get_child(row, col),
419 get_child_id(parent_id, row, col));
424 out <<
"\n\t// The links of " << parent_id <<
".\n";
426 for(
unsigned row = 0; row < grid->get_rows(); ++row) {
427 for(
unsigned col = 0; col < grid->get_cols(); ++col) {
430 out <<
"\t" << parent_id <<
" -> "
431 << get_child_id(parent_id, row, col) <<
" [label=\"(" << row
432 <<
',' << col <<
")\"];\n";
435 out <<
"\t" << get_child_id(parent_id, row, col) <<
" -> "
436 << get_child_widget_id(parent_id, row, col) <<
";\n";
441 void debug_layout_graph::child_generate_info(std::ostream& out,
443 const std::string&
id)
const
447 unsigned flags = child.get_flags();
449 out <<
"\t" <<
id <<
" [style=\"\", label=<<table border=\"0\" "
450 "cellborder=\"1\" cellspacing=\"0\">\n";
456 out <<
"send to client";
459 out <<
"align to top";
465 out <<
"align to bottom";
468 out <<
"unknown value("
473 out <<
"\n</td></tr>\n"
475 <<
"horizontal flag=";
479 out <<
"send to client";
482 out <<
"align to left";
488 out <<
"align to right";
491 out <<
"unknown value("
496 out <<
"\n</td></tr>\n"
498 <<
"border location=";
509 result +=
"bottom, ";
515 if(!result.empty()) {
516 result.resize(result.size() - 2);
522 out <<
"\n</td></tr>\n"
524 <<
"border_size=" << child.get_border_size() <<
"\n</td></tr>\n";
526 out <<
"</table>>];\n";
529 std::string debug_layout_graph::get_type(
const widget* widget)
const
531 const styled_widget* control =
dynamic_cast<const styled_widget*
>(widget);
533 return control->get_control_type();
535 const grid* grid =
dynamic_cast<const class grid*
>(widget);
536 const generator_base*
generator =
dynamic_cast<const generator_base*
>(widget);
static const unsigned HORIZONTAL_GROW_SEND_TO_CLIENT
static const unsigned HORIZONTAL_ALIGN_RIGHT
static const unsigned HORIZONTAL_SHIFT
static const unsigned HORIZONTAL_MASK
static const unsigned VERTICAL_ALIGN_BOTTOM
static const unsigned BORDER_TOP
static const unsigned VERTICAL_ALIGN_CENTER
static const unsigned VERTICAL_GROW_SEND_TO_CLIENT
static const unsigned BORDER_BOTTOM
static const unsigned BORDER_RIGHT
static const unsigned HORIZONTAL_ALIGN_CENTER
static const unsigned VERTICAL_MASK
static const unsigned VERTICAL_ALIGN_TOP
static const unsigned BORDER_LEFT
static const unsigned BORDER_ALL
static const unsigned HORIZONTAL_ALIGN_LEFT
static const unsigned VERTICAL_SHIFT
std::string label
What to show in the filter's drop-down list.
rng * generator
This generator is automatically synced during synced context.
std::vector< std::string > split(const config_attribute_value &val)
std::string filename
Filename.