From 9c1e36145cf7c3f7b2de96144ab26849517487db Mon Sep 17 00:00:00 2001 From: Mark de Wever Date: Mon, 10 Nov 2008 20:01:25 +0000 Subject: [PATCH] Add a new debug class for the widgets. This debug option can output dot files which can be transformed to images so it's easier to get debug info about the widgets in a window. This function is enabled by the --enable-debug-window-layout configure switch. It has not been implemented in the other build systems yet. (Not sure whether or not it's needed.) --- configure.ac | 10 + src/Makefile.am | 1 + src/game.cpp | 31 +++ src/gui/widgets/container.hpp | 1 + src/gui/widgets/control.hpp | 1 + src/gui/widgets/debug.cpp | 437 ++++++++++++++++++++++++++++++++++ src/gui/widgets/debug.hpp | 176 ++++++++++++++ src/gui/widgets/grid.hpp | 1 + src/gui/widgets/widget.hpp | 1 + src/gui/widgets/window.cpp | 75 ++++-- src/gui/widgets/window.hpp | 10 + 11 files changed, 719 insertions(+), 25 deletions(-) create mode 100644 src/gui/widgets/debug.cpp create mode 100644 src/gui/widgets/debug.hpp diff --git a/configure.ac b/configure.ac index 5e3c1d73edb..f0bc0d5f1cb 100644 --- a/configure.ac +++ b/configure.ac @@ -150,6 +150,16 @@ fi AM_CONDITIONAL([LOWMEM], [test "x$lowmem" = "xyes"]) +AC_ARG_ENABLE([debug-window-layout], + AS_HELP_STRING([--enable-debug-window-layout], [add the debug option to allow the generation of debug layout files in dot format]), + [debug_window_layout=$enableval], + [debug_window_layout=no]) + +if test "x$debug_window_layout" = "xyes" +then + CPPFLAGS="$CPPFLAGS -DDEBUG_WINDOW_LAYOUT_GRAPHS" +fi + DATADIR=$PACKAGE AC_ARG_WITH([datadir-name], AS_HELP_STRING([--with-datadir-name@<:@=DIR@:>@], [change name of data directory @<:@wesnoth@:>@]), diff --git a/src/Makefile.am b/src/Makefile.am index 53209e6ebff..c72a8ba1844 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -77,6 +77,7 @@ wesnoth_source = \ gui/dialogs/mp_method_selection.cpp \ gui/dialogs/title_screen.cpp \ gui/widgets/button.cpp \ + gui/widgets/debug.cpp \ gui/widgets/canvas.cpp \ gui/widgets/control.cpp \ gui/widgets/container.cpp \ diff --git a/src/game.cpp b/src/game.cpp index 53f3557368d..2d868eb43ee 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -37,6 +37,9 @@ #include "gui/dialogs/language_selection.hpp" #include "gui/dialogs/mp_method_selection.hpp" #include "gui/dialogs/title_screen.hpp" +#ifdef DEBUG_WINDOW_LAYOUT_GRAPHS +#include "gui/widgets/debug.hpp" +#endif #include "gui/widgets/window.hpp" #include "help.hpp" #include "hotkeys.hpp" @@ -351,6 +354,12 @@ game_controller::game_controller(int argc, char** argv) : } else if(val == "--debug" || val == "-d") { game_config::debug = true; game_config::mp_debug = true; +#ifdef DEBUG_WINDOW_LAYOUT_GRAPHS + } else if (val.substr(0, 18) == "--debug-dot-level=") { + gui2::tdebug_layout_graph::set_level(val.substr(18)); + } else if (val.substr(0, 19) == "--debug-dot-domain=") { + gui2::tdebug_layout_graph::set_level(val.substr(19)); +#endif } else if(val == "--no-delay") { game_config::no_delay = true; } else if (val.substr(0, 6) == "--log-") { @@ -1688,6 +1697,28 @@ static int process_command_args(int argc, char** argv) { << " --config-path prints the path of the user config directory and\n" << " exits.\n" << " -d, --debug enables additional command mode options in-game.\n" +#ifdef DEBUG_WINDOW_LAYOUT_GRAPHS + << " --debug-dot-level=,,...\n" + << " sets the level of the debug dot files.\n" + << " These files are used for debugging the widgets\n" + << " especially the for the layout engine. When enabled\n" + << " the engine will produce dot files which can be\n" + << " converted to images with the dot tool.\n" + << " Available levels:\n" + << " - child : generate the data about the grid cells.\n" + << " - size : generate the size info of the widget.\n" + << " - state : generate the state info of the widget.\n" + << " --debug-dot-domain=,,...\n" + << " sets the domain of the debug dot files.\n" + << " see --debug-dot-level for more info.\n" + << " Available domains:\n" + << " show : generate the data when the dialog is\n" + << " about to be shown.\n" + << " layout : generate the data during the layout\n" + << " phase (might result in multiple files. \n" + << " The data can also be generated when the F12 is\n" + << " pressed in a dialog.\n" +#endif << " --dummylocales enables dummy locales for switching to non-system\n" << " locales.\n" #ifndef DISABLE_EDITOR2 diff --git a/src/gui/widgets/container.hpp b/src/gui/widgets/container.hpp index 0b4a5e2a4fc..87a817f222f 100644 --- a/src/gui/widgets/container.hpp +++ b/src/gui/widgets/container.hpp @@ -29,6 +29,7 @@ namespace gui2 { */ class tcontainer_ : public tcontrol { + friend class tdebug_layout_graph; public: tcontainer_(const unsigned canvas_count) : tcontrol(canvas_count), diff --git a/src/gui/widgets/control.hpp b/src/gui/widgets/control.hpp index 305e83d4780..53530b48bc8 100644 --- a/src/gui/widgets/control.hpp +++ b/src/gui/widgets/control.hpp @@ -28,6 +28,7 @@ namespace gui2 { /** Base class for all visible items. */ class tcontrol : public virtual twidget { + friend class tdebug_layout_graph; public: tcontrol(const unsigned canvas_count); diff --git a/src/gui/widgets/debug.cpp b/src/gui/widgets/debug.cpp new file mode 100644 index 00000000000..6078be71433 --- /dev/null +++ b/src/gui/widgets/debug.cpp @@ -0,0 +1,437 @@ +/* $Id$ */ +/* + copyright (C) 2008 by mark de wever + part of the battle for wesnoth project http://www.wesnoth.org/ + + this program is free software; you can redistribute it and/or modify + it under the terms of the gnu general public license version 2 + or at your option any later version. + this program is distributed in the hope that it will be useful, + but without any warranty. + + see the copying file for more details. +*/ + +#include "gui/widgets/debug.hpp" + +#include "foreach.hpp" +#include "formatter.hpp" +#include "gui/widgets/window.hpp" +#include "serialization/string_utils.hpp" + +#include + +namespace gui2 { + +namespace { + +/** + * Gets the id of a grid child cell. + * + * @param parent_id The id of the parent grid. + * @param row Row number in the grid. + * @param col Column number in the grid. + * + * @returns The id of the child cell. + */ +std::string get_child_id( + const std::string& parent_id, const unsigned row, const unsigned col) +{ + return (formatter() << parent_id << "_C_" << row << '_' << col).c_str(); +} + +/** + * Gets the id of a widget in a grid child cell. + * + * @param parent_id The id of the parent grid. + * @param row Row number in the grid. + * @param col Column number in the grid. + * + * @returns The id of the widget. + */ +std::string get_child_widget_id( + const std::string& parent_id, const unsigned row, const unsigned col) +{ + return get_child_id(parent_id, row, col) + "_W"; +} + +/** Gets the prefix of the filename. */ +std::string get_base_filename() +{ + char buf[17] = {0}; + time_t t = time(NULL); + tm* lt = localtime(&t); + if(lt) { + strftime(buf, sizeof(buf), "%Y%m%d_%H%M%S", lt); + } + static unsigned counter = 0; + ++counter; + + static const std::string + result((formatter() << buf << '_' << counter << '_').c_str()); + + return result; +} + + /***** ***** ***** ***** FLAGS ***** ***** ***** *****/ + + const unsigned ALL = UINT_MAX; /**< All levels/domains */ + + // level flags + const unsigned CHILD = 1 << 0; /**< + * Shows the child records of a cell. + */ + const unsigned SIZE_INFO = 1 << 1; /**< + * Shows the size info of + * children/widgets. + */ + const unsigned STATE_INFO = 1 << 2; /**< Shows the state info of widgets. */ + + // domain flags + const unsigned SHOW = 1 << 0; /**< + * Shows the info when the dialog is + * shown. + */ + const unsigned LAYOUT = 1 << 1; /**< + * Shows the info in all layout + * phases. + */ + + unsigned level_ = ALL; /** @todo Should default to 0. */ + unsigned domain_ = ALL; /** @todo Should default to 0. */ +} //namespace + +tdebug_layout_graph::tdebug_layout_graph(const twindow* window) + : window_(window) + , sequence_number_(0) + , filename_base_(get_base_filename()) +{ +} + +void tdebug_layout_graph::set_level(const std::string& level) +{ + if(level.empty()) { + level_ = ALL; /** @todo Should default to 0. */ + return; + } + + std::vector params = utils::split(level); + + foreach(const std::string& param, params) { + if(param == "all") { + level_ = ALL; + // No need to look further eventhought invalid items are now + // ignored. + return; + } else if(param == "child") { + level_ |= CHILD; + } else if(param == "size") { + level_ |= SIZE_INFO; + } else if(param == "state") { + level_ |= STATE_INFO; + } else { + // loging might not be up yet. + std::cerr << "Unknown level '" << param << "' is ignored.\n"; + } + } +} + +void tdebug_layout_graph::set_domain(const std::string& domain) +{ + if(domain.empty()) { + // return error and die + domain_ = ALL; /** @todo Should default to 0. */ + return; + } + + std::vector params = utils::split(domain); + + foreach(const std::string& param, params) { + if(param == "all") { + domain_ = ALL; + // No need to look further eventhought invalid items are now + // ignored. + return; + } else if(param == "show") { + domain_ |= SHOW; + } else if(param == "layout") { + domain_ |= LAYOUT; + } else { + // loging might not be up yet. + std::cerr << "Unknown domain '" << param << "' is ignored.\n"; + } + } +} + +void tdebug_layout_graph::generate_dot_file(const std::string& generator) +{ + const std::string filename = filename_base_ + + lexical_cast(++sequence_number_) + "-" + generator + ".dot"; + std::ofstream file(filename.c_str()); + + file << "//Basic layout graph for window id '" << window_->id() + << "' using definition '" << window_->definition() << "'.\n" + << "digraph window {\n" + << "\tnode [shape=record, style=filled, fillcolor=\"bisque\"];\n" + << "\trankdir=LR;\n" + ; + + widget_generate_info(file, window_, "root"); + + file << "}\n"; +} + +void tdebug_layout_graph::widget_generate_info( + std::ostream& out, const twidget* widget, const std::string& id) const +{ + + out << "\t" << id + << " [label=<"; + + widget_generate_basic_info(out, widget); + if(level_ & STATE_INFO) widget_generate_state_info(out, widget); + if(level_ & SIZE_INFO) widget_generate_size_info(out, widget); + + out << "
>];\n"; + + const tgrid* grid = dynamic_cast(widget); + if(!grid) { + const tcontainer_* container = dynamic_cast(widget); + if(container) { + grid = &container->grid(); + } + } + if(grid) { + grid_generate_info(out, grid, id); + } +} + +void tdebug_layout_graph::widget_generate_basic_info( + std::ostream& out, const twidget* widget) const +{ + std::string header_background = level_ & (SIZE_INFO|STATE_INFO) + ? " bgcolor=\"gray\"" : ""; + const tcontrol* control = dynamic_cast(widget); + + out << "" << '\n' + << "type=" << get_type(widget) << '\n' + << "" << '\n' + << "" << '\n' + << "id=" << widget->id() << '\n' + << "" << '\n' + << "" << '\n' + << "definition=" << widget->definition() << '\n' + << "" << '\n'; + if(control) { + out << "" << '\n' + << "label=" << control->label() << '\n' + << "\n"; + } +} + +void tdebug_layout_graph::widget_generate_state_info( + std::ostream& out, const twidget* widget) const +{ + const tcontrol* control = dynamic_cast(widget); + if(!control) { + return; + } + + out << "\n" + << "tooltip=" << control->tooltip() << '\n' + << "\n" + << "\n" + << "help message" << control->help_message() << '\n' + // FIXME add value and other specific items + << "\n" + << "\n" + << "active=" << control->get_active() << '\n' + << "\n" + << "\n" + << "visible=" << control->get_visible() << '\n' + << "\n" + << "\n" + << "use tooltip on label overflow=" + << control->get_use_tooltip_on_label_overflow() << '\n' + << "\n" + << "\n" + << "does block easy close=" << control->does_block_easy_close() << '\n' + << "\n"; +} + +void tdebug_layout_graph::widget_generate_size_info( + std::ostream& out, const twidget* widget) const +{ + out << "\n" + << "minimum size=" << widget->get_minimum_size() << '\n' + << "\n" + << "\n" + << "best size=" << widget->get_best_size() << '\n' + << "\n" + << "\n" + << "maximum size" << widget->get_maximum_size() << '\n' + << "\n" + << "\n" + << "can wrap=" << widget->can_wrap() << '\n' + // FIXME add constrain info + << "\n" + << "\n" + << "has vertical scrollbar=" + << widget->has_vertical_scrollbar() << '\n' + << "\n" + << "\n" + << "has horizontal scrollbar=" + << widget->has_horizontal_scrollbar() << '\n' + << "\n" + << "\n" + << "size=" << widget->get_rect() << '\n' + << "\n"; +} + +void tdebug_layout_graph::grid_generate_info(std::ostream& out, + const tgrid* grid, const std::string& parent_id) const +{ + const bool show_child = level_ & CHILD; + + // maybe change the order to links, child, widgets so the output of the + // dot file might look better. + + out << "\n\n\t// The children of " << parent_id << ".\n"; + + for(unsigned row = 0; row < grid->get_rows(); ++row) { + for(unsigned col = 0; col < grid->get_cols(); ++col) { + + const twidget* widget = grid->child(row, col).widget(); + assert(widget); + + widget_generate_info( + out, widget, get_child_widget_id(parent_id, row, col)); + } + } + + if(show_child) { + out << "\n\t// The grid child data of " << parent_id << ".\n"; + + for(unsigned row = 0; row < grid->get_rows(); ++row) { + for(unsigned col = 0; col < grid->get_cols(); ++col) { + + child_generate_info(out, grid->child(row, col), + get_child_id(parent_id, row, col)); + } + } + + } + + out << "\n\t// The links of " << parent_id << ".\n"; + + for(unsigned row = 0; row < grid->get_rows(); ++row) { + for(unsigned col = 0; col < grid->get_cols(); ++col) { + + if(show_child) { + + // grid -> child + out << "\t" << parent_id << " -> " + << get_child_id(parent_id, row, col) + << " [label=\"(" << row << ',' << col + << ")\"];\n"; + + // child -> widget + out << "\t" << get_child_id(parent_id, row, col) << " -> " + << get_child_widget_id(parent_id, row, col) << ";\n"; + + } else { + + // grid -> widget + out << "\t" << parent_id << " -> " + << get_child_widget_id(parent_id, row, col) + << " [label=\"(" << row << ',' << col + << ")\"];\n"; + } + } + } +} + +void tdebug_layout_graph::child_generate_info(std::ostream& out, + const tgrid::tchild& child, const std::string& id) const +{ + + unsigned flags = child.get_flags(); + + out << "\t" << id + << " [style=\"\", label=<"; + out << "" + << "" + << "" + << ""; + + out << "
" + << "vertical flag="; + + switch(flags & tgrid::VERTICAL_MASK) { + case tgrid::VERTICAL_GROW_SEND_TO_CLIENT : out << "send to client"; break; + case tgrid::VERTICAL_ALIGN_TOP : out << "align to top"; break; + case tgrid::VERTICAL_ALIGN_CENTER : out << "center"; break; + case tgrid::VERTICAL_ALIGN_BOTTOM : out << "align to bottom"; break; + default : + out << "unknown value(" + << ((flags & tgrid::VERTICAL_MASK) >> tgrid::VERTICAL_SHIFT) + << ")"; + } + + out << "
" + << "horizontal flag="; + + switch(flags & tgrid::HORIZONTAL_MASK) { + case tgrid::HORIZONTAL_GROW_SEND_TO_CLIENT : out << "send to client"; break; + case tgrid::HORIZONTAL_ALIGN_LEFT : out << "align to left"; break; + case tgrid::HORIZONTAL_ALIGN_CENTER : out << "center"; break; + case tgrid::HORIZONTAL_ALIGN_RIGHT : out << "align to right"; break; + default : + out << "unknown value(" + << ((flags & tgrid::HORIZONTAL_MASK) >> tgrid::HORIZONTAL_SHIFT) + << ")"; + } + + out << "
" + << "border location="; + + if((flags & tgrid::BORDER_ALL) == 0) { + out << "none"; + } else if((flags & tgrid::BORDER_ALL) == tgrid::BORDER_ALL) { + out << "all"; + } else { + std::string result; + if(flags & tgrid::BORDER_TOP) result += "top, "; + if(flags & tgrid::BORDER_BOTTOM) result += "bottom, "; + if(flags & tgrid::BORDER_LEFT) result += "left, "; + if(flags & tgrid::BORDER_RIGHT) result += "right, "; + + if(!result.empty()) { + result.resize(result.size() - 2); + } + + out << result; + } + + out << "
" + << "border_size="<< child.get_border_size() + << "
>];\n"; +} + +std::string tdebug_layout_graph::get_type(const twidget* widget) const +{ + const tcontrol* control = dynamic_cast(widget); + if(control) { + return control->get_control_type(); + } else { + const tgrid* grid = dynamic_cast(widget); + if(grid) { + return "grid"; + } else { + return "unknown"; + } + } +} + +} // namespace gui2 + diff --git a/src/gui/widgets/debug.hpp b/src/gui/widgets/debug.hpp new file mode 100644 index 00000000000..42f2927f5d5 --- /dev/null +++ b/src/gui/widgets/debug.hpp @@ -0,0 +1,176 @@ +/* $Id$ */ +/* + copyright (C) 2008 by mark de wever + part of the battle for wesnoth project http://www.wesnoth.org/ + + this program is free software; you can redistribute it and/or modify + it under the terms of the gnu general public license version 2 + or at your option any later version. + this program is distributed in the hope that it will be useful, + but without any warranty. + + see the copying file for more details. +*/ + +#ifndef GUI_WIDGETS_DEBUG_HPP_INCLUDED +#define GUI_WIDGETS_DEBUG_HPP_INCLUDED + +#include "gui/widgets/grid.hpp" + +#include +#include + +namespace gui2 { + +class twidget; +class twindow; + +/** + * Helper class to output the layout to dot files. + * + * The class will generate .dot files in the location where wesnoth is running + * (so needs write access there). These files can be converted to images + * containing the graphs. This is used for debugging the widget libary and its + * sizing algorithm. + * + * This class needs to be friends with a lot of classes so it can view the + * private data in the class. This design is choosen so the debug info can be + * put in a separate class instead of adding the info via virtual functions in + * the classes themselves. Also adding 'friend class foo' doesn't need to + * include the header declaring foo, so it avoids header cluttage. + * + */ +class tdebug_layout_graph +{ +public: + + /** + * Constructor. + * + * @param window The window, whose information will be + * generated. + */ + tdebug_layout_graph(const twindow* window); + + /** + * Sets the level of wanted information. + * + * @param level A comma separated list of levels which are + * wanted. Possible values: child, size, state + * and all. + */ + static void set_level(const std::string& level); + + /** + * Sets the domain when to show the information. + * + * @param domain A comma separated list for domains which are + * wanted. Possible values: show, layout and all. + */ + static void set_domain(const std::string& domain); + + /** + * Generates a dot file. + * + * The file will have a fixed prefix filename but for every file a part of + * the name will contain where it was generated. + * + * @param generator The location where the name was generated. + */ + void generate_dot_file(const std::string& generator); + +private: + + /** The window whose info will be shown. */ + const twindow* window_; + + /** The order in which the files are generated. */ + unsigned sequence_number_; + + /** Basic part of the filename. */ + std::string filename_base_; + + /***** ***** Widget ***** *****/ + + /** + * Generates the info about a widget. + * + * @param out The stream to write the info to. + * @param widget The widget to write the info about. + * @param id The dof-file-id of the widget. + */ + void widget_generate_info(std::ostream& out, + const twidget* widget, const std::string& id) const; + + /** + * Generates the basic info about a widget. + * + * @param out The stream to write the info to. + * @param widget The widget to write the info about. + */ + void widget_generate_basic_info( + std::ostream& out, const twidget* widget) const; + + /** + * Generates the info about the state of the widget. + * + * @param out The stream to write the info to. + * @param widget The widget to write the info about. + */ + void widget_generate_state_info( + std::ostream& out, const twidget* widget) const; + + /** + * Generates the info about the size and layout of the widget. + * + * @param out The stream to write the info to. + * @param widget The widget to write the info about. + */ + void widget_generate_size_info( + std::ostream& out, const twidget* widget) const; + + /***** ***** Grid ***** *****/ + + /** + * Generates the info about a grid. + * + * @param out The stream to write the info to. + * @param grid The grid to write the info about. + * @param parent_id The dot-file-id of the parent of the widget. + */ + void grid_generate_info(std::ostream& out, + const tgrid* grid, const std::string& parent_id) const; + + /** + * Generates the info about a grid cell. + * + * @param out The stream to write the info to. + * @param child The grid cell to write the info about. + * @param id The dof-file-id of the child. + */ + void child_generate_info(std::ostream& out, + const tgrid::tchild& child, const std::string& id) const; + + /***** ***** Helper ***** *****/ + + /** + * Returns the control_type of a widget. + * + * This is a small wrapper around tcontrol::get_control_type() since a + * grid is no control and used rather frequently, so we want to give it a + * type. + * + * @param widget The widget to get the type of. + * + * @returns If the widget is a control it returns its + * type. If the widget is a grid it returns + * 'grid', otherwise 'unknown' will be returned. + */ + std::string get_type(const twidget* widget) const; + +}; + +} // namespace gui2 + +#endif + diff --git a/src/gui/widgets/grid.hpp b/src/gui/widgets/grid.hpp index 47caa9bf3e8..1983c15fdf7 100644 --- a/src/gui/widgets/grid.hpp +++ b/src/gui/widgets/grid.hpp @@ -39,6 +39,7 @@ namespace gui2 { */ class tgrid : public virtual twidget { + friend class tdebug_layout_graph; public: tgrid(const unsigned rows = 0, const unsigned cols = 0); diff --git a/src/gui/widgets/widget.hpp b/src/gui/widgets/widget.hpp index 46e226aaee2..a433b47bed7 100644 --- a/src/gui/widgets/widget.hpp +++ b/src/gui/widgets/widget.hpp @@ -259,6 +259,7 @@ private: */ class twidget : public virtual tevent_executor { + friend class tdebug_layout_graph; public: twidget() : id_(""), diff --git a/src/gui/widgets/window.cpp b/src/gui/widgets/window.cpp index 8afa88121ca..13f7bf3e67a 100644 --- a/src/gui/widgets/window.cpp +++ b/src/gui/widgets/window.cpp @@ -21,6 +21,9 @@ #include "cursor.hpp" #include "font.hpp" +#ifdef DEBUG_WINDOW_LAYOUT_GRAPHS +#include "gui/widgets/debug.hpp" +#endif #include "preferences.hpp" #include "titlescreen.hpp" #include "video.hpp" @@ -75,30 +78,33 @@ twindow::twindow(CVideo& video, const bool automatic_placement, const unsigned horizontal_placement, const unsigned vertical_placement, - const std::string& definition) : - tpanel(), - tevent_handler(), - video_(video), - status_(NEW), - retval_(0), - owner_(0), - need_layout_(true), - resized_(true), - suspend_drawing_(true), - top_level_(false), - window_(), - restorer_(), - tooltip_(), - help_popup_(), - automatic_placement_(automatic_placement), - horizontal_placement_(horizontal_placement), - vertical_placement_(vertical_placement), - x_(x), - y_(y), - w_(w), - h_(h), - easy_close_(false), - easy_close_blocker_() + const std::string& definition) + : tpanel() + , tevent_handler() + , video_(video) + , status_(NEW) + , retval_(0) + , owner_(0) + , need_layout_(true) + , resized_(true) + , suspend_drawing_(true) + , top_level_(false) + , window_() + , restorer_() + , tooltip_() + , help_popup_() + , automatic_placement_(automatic_placement) + , horizontal_placement_(horizontal_placement) + , vertical_placement_(vertical_placement) + , x_(x) + , y_(y) + , w_(w) + , h_(h) + , easy_close_(false) + , easy_close_blocker_() +#ifdef DEBUG_WINDOW_LAYOUT_GRAPHS + , debug_layout_(new tdebug_layout_graph(this)) +#endif { // We load the config in here as exception. // Our caller did update the screen size so no need for us to do that again. @@ -185,7 +191,11 @@ twindow::tretval twindow::get_retval_by_id(const std::string& id) int twindow::show(const bool restore, void* /*flip_function*/) { - log_scope2(gui_draw, "Window: show."); + log_scope2(gui_draw, "Window: show."); + +#ifdef DEBUG_WINDOW_LAYOUT_GRAPHS + debug_layout_->generate_dot_file("show"); +#endif assert(status_ == NEW); @@ -339,6 +349,12 @@ void twindow::key_press(tevent_handler& /*event_handler*/, bool& handled, set_retval(CANCEL); handled = true; } +#ifdef DEBUG_WINDOW_LAYOUT_GRAPHS + if(key == SDLK_F12) { + debug_layout_->generate_dot_file("manual"); + handled = true; + } +#endif } SDL_Rect twindow::get_client_rect() const @@ -457,6 +473,9 @@ void twindow::layout() x_(variables), y_(variables), w_(variables), h_(variables))); } +#ifdef DEBUG_WINDOW_LAYOUT_GRAPHS + debug_layout_->generate_dot_file("layout_finished"); +#endif // Make sure the contrains are cleared, they might be partially set. clear_width_constrain(); disable_cache = false; @@ -554,5 +573,11 @@ void twindow::draw(surface& /*surf*/, const bool /*force*/, assert(false); } +#ifdef DEBUG_WINDOW_LAYOUT_GRAPHS +twindow::~twindow() +{ + delete debug_layout_; +} +#endif } // namespace gui2 diff --git a/src/gui/widgets/window.hpp b/src/gui/widgets/window.hpp index 83e8715f167..12bf5c4d364 100644 --- a/src/gui/widgets/window.hpp +++ b/src/gui/widgets/window.hpp @@ -38,6 +38,7 @@ class CVideo; namespace gui2{ class tdialog; +class tdebug_layout_graph; /** * base class of top level items, the only item @@ -45,6 +46,7 @@ class tdialog; */ class twindow : public tpanel, public tevent_handler { + friend class tdebug_layout_graph; public: twindow(CVideo& video, tformulax, @@ -375,6 +377,14 @@ private: */ void draw(surface& surface, const bool force = false, const bool invalidate_background = false); + +#ifdef DEBUG_WINDOW_LAYOUT_GRAPHS + tdebug_layout_graph* debug_layout_; + +public: + // The destructor only needs to delete the debug_layout_ so declared here. + ~twindow(); +#endif }; } // namespace gui2