mirror of
https://github.com/wesnoth/wesnoth
synced 2025-04-29 04:23:18 +00:00
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.)
This commit is contained in:
parent
af0b4a21dd
commit
9c1e36145c
10
configure.ac
10
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@:>@]),
|
||||
|
@ -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 \
|
||||
|
31
src/game.cpp
31
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=<level1>,<level2>,...\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=<domain1>,<domain2>,...\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
|
||||
|
@ -29,6 +29,7 @@ namespace gui2 {
|
||||
*/
|
||||
class tcontainer_ : public tcontrol
|
||||
{
|
||||
friend class tdebug_layout_graph;
|
||||
public:
|
||||
tcontainer_(const unsigned canvas_count) :
|
||||
tcontrol(canvas_count),
|
||||
|
@ -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);
|
||||
|
437
src/gui/widgets/debug.cpp
Normal file
437
src/gui/widgets/debug.cpp
Normal file
@ -0,0 +1,437 @@
|
||||
/* $Id$ */
|
||||
/*
|
||||
copyright (C) 2008 by mark de wever <koraq@xs4all.nl>
|
||||
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 <fstream>
|
||||
|
||||
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<std::string> 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<std::string> 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<std::string>(++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=<<table border=\"0\" cellborder=\"1\" cellspacing=\"0\">";
|
||||
|
||||
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 << "</table>>];\n";
|
||||
|
||||
const tgrid* grid = dynamic_cast<const tgrid*>(widget);
|
||||
if(!grid) {
|
||||
const tcontainer_* container = dynamic_cast<const tcontainer_*>(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<const tcontrol*>(widget);
|
||||
|
||||
out << "<tr><td" << header_background << ">" << '\n'
|
||||
<< "type=" << get_type(widget) << '\n'
|
||||
<< "</td></tr>" << '\n'
|
||||
<< "<tr><td" << header_background << ">" << '\n'
|
||||
<< "id=" << widget->id() << '\n'
|
||||
<< "</td></tr>" << '\n'
|
||||
<< "<tr><td" << header_background << ">" << '\n'
|
||||
<< "definition=" << widget->definition() << '\n'
|
||||
<< "</td></tr>" << '\n';
|
||||
if(control) {
|
||||
out << "<tr><td" << header_background << ">" << '\n'
|
||||
<< "label=" << control->label() << '\n'
|
||||
<< "</td></tr>\n";
|
||||
}
|
||||
}
|
||||
|
||||
void tdebug_layout_graph::widget_generate_state_info(
|
||||
std::ostream& out, const twidget* widget) const
|
||||
{
|
||||
const tcontrol* control = dynamic_cast<const tcontrol*>(widget);
|
||||
if(!control) {
|
||||
return;
|
||||
}
|
||||
|
||||
out << "<tr><td>\n"
|
||||
<< "tooltip=" << control->tooltip() << '\n'
|
||||
<< "</td></tr>\n"
|
||||
<< "<tr><td>\n"
|
||||
<< "help message" << control->help_message() << '\n'
|
||||
// FIXME add value and other specific items
|
||||
<< "</td></tr>\n"
|
||||
<< "<tr><td>\n"
|
||||
<< "active=" << control->get_active() << '\n'
|
||||
<< "</td></tr>\n"
|
||||
<< "<tr><td>\n"
|
||||
<< "visible=" << control->get_visible() << '\n'
|
||||
<< "</td></tr>\n"
|
||||
<< "<tr><td>\n"
|
||||
<< "use tooltip on label overflow="
|
||||
<< control->get_use_tooltip_on_label_overflow() << '\n'
|
||||
<< "</td></tr>\n"
|
||||
<< "<tr><td>\n"
|
||||
<< "does block easy close=" << control->does_block_easy_close() << '\n'
|
||||
<< "</td></tr>\n";
|
||||
}
|
||||
|
||||
void tdebug_layout_graph::widget_generate_size_info(
|
||||
std::ostream& out, const twidget* widget) const
|
||||
{
|
||||
out << "<tr><td>\n"
|
||||
<< "minimum size=" << widget->get_minimum_size() << '\n'
|
||||
<< "</td></tr>\n"
|
||||
<< "<tr><td>\n"
|
||||
<< "best size=" << widget->get_best_size() << '\n'
|
||||
<< "</td></tr>\n"
|
||||
<< "<tr><td>\n"
|
||||
<< "maximum size" << widget->get_maximum_size() << '\n'
|
||||
<< "</td></tr>\n"
|
||||
<< "<tr><td>\n"
|
||||
<< "can wrap=" << widget->can_wrap() << '\n'
|
||||
// FIXME add constrain info
|
||||
<< "</td></tr>\n"
|
||||
<< "<tr><td>\n"
|
||||
<< "has vertical scrollbar="
|
||||
<< widget->has_vertical_scrollbar() << '\n'
|
||||
<< "</td></tr>\n"
|
||||
<< "<tr><td>\n"
|
||||
<< "has horizontal scrollbar="
|
||||
<< widget->has_horizontal_scrollbar() << '\n'
|
||||
<< "</td></tr>\n"
|
||||
<< "<tr><td>\n"
|
||||
<< "size=" << widget->get_rect() << '\n'
|
||||
<< "</td></tr>\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=<<table border=\"0\" cellborder=\"1\" cellspacing=\"0\">";
|
||||
out << "<tr><td>"
|
||||
<< "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 << "</td></tr>"
|
||||
<< "<tr><td>"
|
||||
<< "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 << "</td></tr>"
|
||||
<< "<tr><td>"
|
||||
<< "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 << "</td></tr>"
|
||||
<< "<tr><td>"
|
||||
<< "border_size="<< child.get_border_size()
|
||||
<< "</td></tr>";
|
||||
|
||||
out << "</table>>];\n";
|
||||
}
|
||||
|
||||
std::string tdebug_layout_graph::get_type(const twidget* widget) const
|
||||
{
|
||||
const tcontrol* control = dynamic_cast<const tcontrol*>(widget);
|
||||
if(control) {
|
||||
return control->get_control_type();
|
||||
} else {
|
||||
const tgrid* grid = dynamic_cast<const tgrid*>(widget);
|
||||
if(grid) {
|
||||
return "grid";
|
||||
} else {
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace gui2
|
||||
|
176
src/gui/widgets/debug.hpp
Normal file
176
src/gui/widgets/debug.hpp
Normal file
@ -0,0 +1,176 @@
|
||||
/* $Id$ */
|
||||
/*
|
||||
copyright (C) 2008 by mark de wever <koraq@xs4all.nl>
|
||||
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 <iosfwd>
|
||||
#include <string>
|
||||
|
||||
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
|
||||
|
@ -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);
|
||||
|
@ -259,6 +259,7 @@ private:
|
||||
*/
|
||||
class twidget : public virtual tevent_executor
|
||||
{
|
||||
friend class tdebug_layout_graph;
|
||||
public:
|
||||
twidget() :
|
||||
id_(""),
|
||||
|
@ -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
|
||||
|
||||
|
@ -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,
|
||||
tformula<unsigned>x,
|
||||
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user