Add an initial version of the tree view widget.

I might want to work on the widget at the FOSDEM, so it's easier to commit
the code now.
This commit is contained in:
Mark de Wever 2010-02-04 20:35:01 +00:00
parent caeb337341
commit 9ec2566ee8
15 changed files with 1196 additions and 1 deletions

View file

@ -0,0 +1,103 @@
#textdomain wesnoth-lib
###
### Definition of a toggle button to be used in a tree view as node fold/unfold indicator
###
[toggle_button_definition]
id = "tree_view_node"
description = "Fold/unfold status indicator of a tree view node."
[resolution]
{GUI_NORMAL__RESOLUTION}
min_width = 25
min_height = 19
default_width = 25
default_height = 19
max_width = 25
max_height = 19
[state_enabled]
[draw]
[image]
name = "buttons/fold-arrow.png"
[/image]
[/draw]
[/state_enabled]
[state_disabled]
[draw]
[image]
name = "buttons/fold-arrow-active.png"
[/image]
[/draw]
[/state_disabled]
[state_focussed]
[draw]
[image]
name = "buttons/fold-arrow-pressed.png"
[/image]
[/draw]
[/state_focussed]
###
### Selected
###
[state_enabled_selected]
[draw]
[image]
name = "buttons/unfold-arrow.png"
[/image]
[/draw]
[/state_enabled_selected]
[state_disabled_selected]
[draw]
[image]
name = "buttons/unfold-arrow-active.png"
[/image]
[/draw]
[/state_disabled_selected]
[state_focussed_selected]
[draw]
[image]
name = "buttons/unfold-arrow-pressed.png"
[/image]
[/draw]
[/state_focussed_selected]
[/resolution]
[/toggle_button_definition]

View file

@ -0,0 +1,109 @@
#textdomain wesnoth-lib
###
### Definition of a tree view
###
#define _GUI_RESOLUTION RESOLUTION FONT_SIZE FONT_STYLE FONT_COLOUR_ENABLED FONT_COLOUR_DISABLED
[resolution]
{RESOLUTION}
min_width = 0
min_height = 0
default_width = 0
default_height = 0
max_width = 0
max_height = 0
text_font_size = {FONT_SIZE}
text_font_style = {FONT_STYLE}
[state_enabled]
[draw]
[/draw]
[/state_enabled]
[state_disabled]
[draw]
[/draw]
[/state_disabled]
[grid]
[row]
grow_factor = 1
[column]
grow_factor = 1
horizontal_grow = "true" # needed ?
vertical_grow = "true" # needed ?
[grid]
id = "_content_grid"
[/grid]
[/column]
[column]
grow_factor = 0
{GUI__VERTICAL_SCROLLBAR_GRID}
[/column]
[/row]
[row]
grow_factor = 0
[column]
{GUI__HORIZONTAL_SCROLLBAR_GRID}
[/column]
[column]
[spacer]
[/spacer]
[/column]
[/row]
[/grid]
[/resolution]
#enddef
[tree_view_definition]
id = "default"
description = "Default tree view."
{_GUI_RESOLUTION
({GUI_TINY__RESOLUTION})
({GUI_TINY__FONT_SIZE__DEFAULT})
()
({GUI__FONT_COLOUR_ENABLED__DEFAULT})
({GUI__FONT_COLOUR_DISABLED__DEFAULT})
}
{_GUI_RESOLUTION
({GUI_NORMAL__RESOLUTION})
({GUI_NORMAL__FONT_SIZE__DEFAULT})
()
({GUI__FONT_COLOUR_ENABLED__DEFAULT})
({GUI__FONT_COLOUR_DISABLED__DEFAULT})
}
[/tree_view_definition]
#undef _GUI_RESOLUTION

View file

@ -29,6 +29,7 @@ src/gui/auxiliary/widget_definition/text_box.cpp
src/gui/auxiliary/widget_definition/toggle_button.cpp
src/gui/auxiliary/widget_definition/toggle_panel.cpp
src/gui/auxiliary/widget_definition/tooltip.cpp
src/gui/auxiliary/widget_definition/tree_view.cpp
src/gui/auxiliary/widget_definition/vertical_scrollbar.cpp
src/gui/auxiliary/widget_definition/window.cpp
src/gui/auxiliary/window_builder/button.cpp
@ -54,6 +55,7 @@ src/gui/auxiliary/window_builder/stacked_widget.cpp
src/gui/auxiliary/window_builder/text_box.cpp
src/gui/auxiliary/window_builder/toggle_button.cpp
src/gui/auxiliary/window_builder/toggle_panel.cpp
src/gui/auxiliary/window_builder/tree_view.cpp
src/gui/auxiliary/window_builder/vertical_scrollbar.cpp
src/gui/dialogs/addon_connect.cpp
src/gui/dialogs/addon_list.cpp
@ -105,6 +107,7 @@ src/gui/widgets/text.cpp
src/gui/widgets/toggle_button.cpp
src/gui/widgets/toggle_panel.cpp
src/gui/widgets/tooltip.cpp
src/gui/widgets/tree_view.cpp
src/gui/widgets/vertical_scrollbar.cpp
src/gui/widgets/widget.cpp
src/gui/widgets/window.cpp

View file

@ -247,6 +247,7 @@ set(wesnoth-main_SRC
gui/auxiliary/widget_definition/toggle_button.cpp
gui/auxiliary/widget_definition/toggle_panel.cpp
gui/auxiliary/widget_definition/tooltip.cpp
gui/auxiliary/widget_definition/tree_view.cpp
gui/auxiliary/widget_definition/vertical_scrollbar.cpp
gui/auxiliary/widget_definition/window.cpp
gui/auxiliary/window_builder/button.cpp
@ -272,6 +273,7 @@ set(wesnoth-main_SRC
gui/auxiliary/window_builder/panel.cpp
gui/auxiliary/window_builder/password_box.cpp
gui/auxiliary/window_builder/toggle_panel.cpp
gui/auxiliary/window_builder/tree_view.cpp
gui/auxiliary/window_builder.cpp
gui/dialogs/addon_connect.cpp
gui/dialogs/addon_list.cpp
@ -324,6 +326,7 @@ set(wesnoth-main_SRC
gui/widgets/toggle_button.cpp
gui/widgets/toggle_panel.cpp
gui/widgets/tooltip.cpp
gui/widgets/tree_view.cpp
gui/widgets/vertical_scrollbar.cpp
gui/widgets/widget.cpp
gui/widgets/window.cpp

View file

@ -127,6 +127,7 @@ wesnoth_source = \
gui/auxiliary/widget_definition/toggle_button.cpp \
gui/auxiliary/widget_definition/toggle_panel.cpp \
gui/auxiliary/widget_definition/tooltip.cpp \
gui/auxiliary/widget_definition/tree_view.cpp \
gui/auxiliary/widget_definition/vertical_scrollbar.cpp \
gui/auxiliary/widget_definition/window.cpp \
gui/auxiliary/window_builder/button.cpp \
@ -152,6 +153,7 @@ wesnoth_source = \
gui/auxiliary/window_builder/panel.cpp \
gui/auxiliary/window_builder/password_box.cpp \
gui/auxiliary/window_builder/toggle_panel.cpp \
gui/auxiliary/window_builder/tree_view.cpp \
gui/auxiliary/window_builder.cpp \
gui/dialogs/addon_connect.cpp \
gui/dialogs/addon_list.cpp \
@ -204,6 +206,7 @@ wesnoth_source = \
gui/widgets/toggle_button.cpp \
gui/widgets/toggle_panel.cpp \
gui/widgets/tooltip.cpp \
gui/widgets/tree_view.cpp \
gui/widgets/vertical_scrollbar.cpp \
gui/widgets/widget.cpp \
gui/widgets/window.cpp \

View file

@ -289,6 +289,7 @@ wesnoth_sources = Split("""
gui/auxiliary/widget_definition/toggle_button.cpp
gui/auxiliary/widget_definition/toggle_panel.cpp
gui/auxiliary/widget_definition/tooltip.cpp
gui/auxiliary/widget_definition/tree_view.cpp
gui/auxiliary/widget_definition/window.cpp
gui/auxiliary/window_builder/button.cpp
gui/auxiliary/window_builder/control.cpp
@ -313,6 +314,7 @@ wesnoth_sources = Split("""
gui/auxiliary/window_builder/panel.cpp
gui/auxiliary/window_builder/password_box.cpp
gui/auxiliary/window_builder/toggle_panel.cpp
gui/auxiliary/window_builder/tree_view.cpp
gui/auxiliary/window_builder.cpp
gui/dialogs/addon_connect.cpp
gui/dialogs/addon_list.cpp
@ -365,6 +367,7 @@ wesnoth_sources = Split("""
gui/widgets/toggle_button.cpp
gui/widgets/toggle_panel.cpp
gui/widgets/tooltip.cpp
gui/widgets/tree_view.cpp
gui/widgets/vertical_scrollbar.cpp
gui/widgets/widget.cpp
gui/widgets/window.cpp

View file

@ -0,0 +1,48 @@
/* $Id$ */
/*
Copyright (C) 2010 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.
*/
#define GETTEXT_DOMAIN "wesnoth-lib"
#include "gui/auxiliary/widget_definition/tree_view.hpp"
#include "gettext.hpp"
#include "gui/auxiliary/log.hpp"
#include "wml_exception.hpp"
namespace gui2 {
ttree_view_definition::ttree_view_definition(const config& cfg) :
tcontrol_definition(cfg)
{
DBG_GUI_P << "Parsing tree view " << id << '\n';
load_resolutions<tresolution>(cfg);
}
ttree_view_definition::tresolution::tresolution(const config& cfg) :
tresolution_definition_(cfg),
grid(NULL)
{
// Note the order should be the same as the enum tstate is listbox.hpp.
state.push_back(tstate_definition(cfg.child("state_enabled")));
state.push_back(tstate_definition(cfg.child("state_disabled")));
const config &child = cfg.child("grid");
VALIDATE(child, _("No grid defined."));
grid = new tbuilder_grid(child);
}
} // namespace gui2

View file

@ -0,0 +1,41 @@
/* $Id$ */
/*
Copyright (C) 2010 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_AUXILIARY_WIDGET_DEFINITION_TREE_VIEW_HPP_INCLUDED
#define GUI_AUXILIARY_WIDGET_DEFINITION_TREE_VIEW_HPP_INCLUDED
#include "gui/auxiliary/widget_definition.hpp"
#include "gui/auxiliary/window_builder.hpp"
namespace gui2 {
struct ttree_view_definition
: public tcontrol_definition
{
explicit ttree_view_definition(const config& cfg);
struct tresolution
: public tresolution_definition_
{
explicit tresolution(const config& cfg);
tbuilder_grid_ptr grid;
};
};
} // namespace gui2
#endif

View file

@ -38,6 +38,7 @@
#include "gui/auxiliary/window_builder/stacked_widget.hpp"
#include "gui/auxiliary/window_builder/text_box.hpp"
#include "gui/auxiliary/window_builder/toggle_button.hpp"
#include "gui/auxiliary/window_builder/tree_view.hpp"
#include "gui/auxiliary/window_builder/panel.hpp"
#include "gui/auxiliary/window_builder/password_box.hpp"
#include "gui/auxiliary/window_builder/toggle_panel.hpp"
@ -89,6 +90,7 @@ tbuilder_widget_ptr create_builder_widget(const config& cfg)
TRY(password_box);
TRY(toggle_button);
TRY(toggle_panel);
TRY(tree_view);
TRY(vertical_scrollbar);
TRY(grid);

View file

@ -0,0 +1,112 @@
/* $Id$ */
/*
Copyright (C) 2008 - 2010 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.
*/
#define GETTEXT_DOMAIN "wesnoth-lib"
#include "gui/auxiliary/window_builder/tree_view.hpp"
#include "foreach.hpp"
#include "gettext.hpp"
#include "gui/auxiliary/log.hpp"
#include "gui/auxiliary/widget_definition/tree_view.hpp"
#include "gui/auxiliary/window_builder/helper.hpp"
#include "gui/widgets/tree_view.hpp"
#include "wml_exception.hpp"
namespace gui2 {
namespace implementation {
tbuilder_tree_view::tbuilder_tree_view(const config& cfg)
: tbuilder_control(cfg)
, vertical_scrollbar_mode(
get_scrollbar_mode(cfg["vertical_scrollbar_mode"]))
, horizontal_scrollbar_mode(
get_scrollbar_mode(cfg["horizontal_scrollbar_mode"]))
, indention_step_size(
lexical_cast_default<unsigned>(cfg["indention_step_size"]))
, nodes()
{
foreach(const config &node, cfg.child_range("node")) {
nodes.push_back(tnode(node));
}
/** @todo activate after the string freeze. */
#if 0
// VALIDATE(!nodes.empty(), _("No nodes defined for a tree view."));
#else
assert(!nodes.empty());
#endif
}
twidget* tbuilder_tree_view::build() const
{
/*
* TODO see how much we can move in the constructor instead of
* builing in several steps.
*/
ttree_view *widget = new ttree_view(nodes);
init_control(widget);
widget->set_vertical_scrollbar_mode(vertical_scrollbar_mode);
widget->set_horizontal_scrollbar_mode(horizontal_scrollbar_mode);
widget->set_indention_step_size(indention_step_size);
DBG_GUI_G << "Window builder: placed tree_view '"
<< id << "' with defintion '"
<< definition << "'.\n";
boost::intrusive_ptr<const ttree_view_definition::tresolution> conf =
boost::dynamic_pointer_cast
<const ttree_view_definition::tresolution>(widget->config());
assert(conf);
widget->init_grid(conf->grid);
widget->finalize_setup();
return widget;
}
tbuilder_tree_view::tnode::tnode(const config& cfg)
: id(cfg["id"])
, builder(NULL)
{
VALIDATE(!id.empty(), missing_mandatory_wml_key("node", "id"));
/** @todo activate after the string freeze. */
#if 0
// VALIDATE(id != "root",
_("[node]id 'root' is reserved for the implentation."));
#else
assert(id != "root");
#endif
const config& node_definition = cfg.child("node_definition");
/** @todo activate after the string freeze. */
#if 0
// VALIDATE(node_definition, _("No node defined."));
#else
assert(node_definition);
#endif
builder = new tbuilder_grid(node_definition);
}
} // namespace implementation
} // namespace gui2

View file

@ -0,0 +1,68 @@
/* $Id$ */
/*
Copyright (C) 2008 - 2010 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_AUXILIARY_WINDOW_BUILDER_TREE_VIEW_HPP_INCLUDED
#define GUI_AUXILIARY_WINDOW_BUILDER_TREE_VIEW_HPP_INCLUDED
#include "gui/auxiliary/window_builder/control.hpp"
#include "gui/widgets/scrollbar_container.hpp"
namespace gui2 {
namespace implementation {
struct tbuilder_tree_view
: public tbuilder_control
{
explicit tbuilder_tree_view(const config& cfg);
twidget* build () const;
tscrollbar_container::tscrollbar_mode
vertical_scrollbar_mode,
horizontal_scrollbar_mode;
unsigned indention_step_size;
struct tnode
{
explicit tnode(const config& cfg);
std::string id;
tbuilder_grid_ptr builder;
};
/**
* The types of nodes in the tree view.
*
* Since we expect the amount of nodes to remain low it's stored in a
* vector and not in a map.
*/
std::vector<tnode> nodes;
/*
* NOTE this class doesn't have a data section, so it can only be filled
* with data by the engine. I think this poses no limit on the usage since
* I don't foresee that somebody wants to pre-fill a tree view. If the need
* arises the data part can be added.
*/
};
} // namespace implementation
} // namespace gui2
#endif

View file

@ -43,6 +43,7 @@ class tscrollbar_container
friend struct implementation::tbuilder_scroll_label;
friend struct implementation::tbuilder_scrollbar_panel;
friend class tlistbox;
friend class ttree_view;
friend struct tscrollbar_container_implementation;
public:
@ -388,7 +389,7 @@ private:
SDL_Rect content_visible_area_;
/** The builder needs to call us so we do our setup. */
void finalize_setup();
void finalize_setup(); // FIXME make protected
/**
* Function for the subclasses to do their setup.

View file

@ -46,6 +46,7 @@
#include "gui/auxiliary/widget_definition/toggle_button.hpp"
#include "gui/auxiliary/widget_definition/toggle_panel.hpp"
#include "gui/auxiliary/widget_definition/tooltip.hpp"
#include "gui/auxiliary/widget_definition/tree_view.hpp"
#include "gui/auxiliary/widget_definition/vertical_scrollbar.hpp"
#include "gui/widgets/window.hpp"
#include "serialization/parser.hpp"
@ -211,6 +212,7 @@ const std::string& tgui_definition::read(const config& cfg)
* Toggle_panel Like a toggle button but then as panel so
* can hold multiple items in a grid.
* Tooltip A small tooltip with help.
* Tree_view A tree view widget.
* Vertical_scrollbar A vertical scrollbar.
* Window A window.
* @end_table
@ -280,6 +282,7 @@ const std::string& tgui_definition::read(const config& cfg)
load_definitions<ttoggle_button_definition>("toggle_button", cfg);
load_definitions<ttoggle_panel_definition>("toggle_panel", cfg);
load_definitions<ttooltip_definition>("tooltip", cfg);
load_definitions<ttree_view_definition>("tree_view", cfg);
load_definitions<tvertical_scrollbar_definition>("vertical_scrollbar", cfg);
load_definitions<twindow_definition>("window", cfg);

View file

@ -0,0 +1,471 @@
/* $Id$ */
/*
Copyright (C) 2008 - 2010 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.
*/
#define GETTEXT_DOMAIN "wesnoth-lib"
#include "gui/widgets/tree_view.hpp"
#include "gui/auxiliary/log.hpp"
#include "gui/widgets/control.hpp"
#include "gui/widgets/toggle_button.hpp"
#include "gui/widgets/toggle_panel.hpp"
#include <boost/bind.hpp>
#define LOG_NODE_SCOPE_HEADER \
get_control_type() + " [" + parent_widget_->id() + "] " + __func__
#define LOG_NODE_HEADER LOG_NODE_SCOPE_HEADER + ':'
#define LOG_SCOPE_HEADER get_control_type() + " [" + id() + "] " + __func__
#define LOG_HEADER LOG_SCOPE_HEADER + ':'
#undef DBG_GUI_L
#define DBG_GUI_L std::cerr
namespace gui2 {
ttree_view::tnode::tnode(const std::string& id
, const std::vector<tnode_definition>& node_definitions
, tnode* parent
, ttree_view* parent_widget
, const std::map<std::string /* widget id */, string_map>& data
)
: parent_(parent)
, parent_widget_(parent_widget) // need to store? also used in set_parent
, grid_()
, children_()
, node_definitions_(node_definitions)
, icon_(NULL)
{
set_parent(parent_widget);
grid_.set_parent(this);
if(id != "root") {
foreach(const tnode_definition& node_definition, node_definitions_) {
if(node_definition.id == id) {
node_definition.builder->build(&grid_);
init_grid(&grid_, data);
icon_ = find_widget<ttoggle_button>(
&grid_
, "tree_view_node_icon"
, false
, false);
if(icon_) {
icon_->set_visible(twidget::HIDDEN);
icon_->connect_signal<event::LEFT_BUTTON_CLICK>(
boost::bind(&ttree_view::tnode::
signal_handler_left_button_click
, this, _2));
}
if(parent_ && parent_->icon_) {
parent_->icon_->set_visible(twidget::VISIBLE);
}
/*
twidget* w = find_widget<twidget>(
&grid_
, "tree_view_node_label"
, false
, false); {
assert(w);
w->connect_signal<event::LEFT_BUTTON_CLICK>(
boost::bind(&ttree_view::tnode::
signal_handler_left_button_click
, this, _2));
}
*/
// init_grid(&grid_, data);
return;
}
}
/** @todo enable after 1.9. */
#if 0
// FIXME add node id
// VALIDATE(false, _("Unknown builder id for tree view node."));
#else
assert(false);
#endif
}
}
ttree_view::tnode& ttree_view::tnode::add_child(
const std::string& id
, const std::map<std::string /* widget id */, string_map>& data
, const int)
{
children_.push_back(new tnode::tnode(
id
, node_definitions_
, this
, parent_widget_
, data));
return children_.back();
}
ttree_view::tnode& ttree_view::tnode::parent()
{
assert(!is_root_node());
return *parent_;
}
bool ttree_view::tnode::is_folded() const
{
return icon_ && icon_->get_value();
}
void ttree_view::tnode::fold(const bool /*recursive*/)
{
// FIXME set state
parent_widget_->set_size(
parent_widget_->get_origin()
, parent_widget_->get_size());
}
void ttree_view::tnode::unfold(const texpand_mode /*mode*/)
{
// FIXME set state
parent_widget_->set_size(
parent_widget_->get_origin()
, parent_widget_->get_size());
}
struct ttree_view_node_implementation
{
template<class W>
static W* find_at(
typename tconst_duplicator<W, ttree_view::tnode>::type&
tree_view_node
, const tpoint& coordinate, const bool must_be_active)
{
std::cerr
<< " Checking at " << coordinate
<< " must be active " << must_be_active
<< ".\n";
if(W* widget =
tree_view_node.grid_.find_at(coordinate, must_be_active)) {
std::cerr
<< " found the widget in our grid, id '" << widget->id()
<< "'.\n";
return widget;
}
if(tree_view_node.is_folded()) {
std::cerr << " folded found nothing.\n";
return NULL;
}
typedef typename tconst_duplicator<W, ttree_view::tnode>::type thack;
foreach(thack& node, tree_view_node.children_) {
if(W* widget = node./*grid_.*/find_at(coordinate, must_be_active)) {
std::cerr
<< " found the widget in a child grid, id '"
<< widget->id() << "'.\n";
return widget;
}
}
std::cerr << " found nothing.\n";
return NULL;
}
};
twidget* ttree_view::tnode::find_at(
const tpoint& coordinate
, const bool must_be_active)
{
return ttree_view_node_implementation::find_at<twidget>(
*this, coordinate, must_be_active);
}
const twidget* ttree_view::tnode::find_at(
const tpoint& coordinate
, const bool must_be_active) const
{
return ttree_view_node_implementation::find_at<const twidget>(
*this, coordinate, must_be_active);
}
void ttree_view::tnode::child_populate_dirty_list(twindow& caller
, const std::vector<twidget*>& call_stack)
{
std::cerr << "Dirty list, grid " << grid_.get_dirty() << ".\n";
std::vector<twidget*> child_call_stack = call_stack;
grid_.populate_dirty_list(caller, child_call_stack);
if(is_folded()) {
return;
}
foreach(tnode& node, children_) {
std::vector<twidget*> child_call_stack = call_stack;
node.populate_dirty_list(caller, child_call_stack);
}
}
tpoint ttree_view::tnode::calculate_best_size(const int indention_level
, const unsigned indention_step_size) const
{
log_scope2(log_gui_layout, LOG_NODE_SCOPE_HEADER);
tpoint best_size = grid_.get_best_size();
if(indention_level > 0) {
best_size.x += indention_level * indention_step_size;
}
if(is_folded()) {
DBG_GUI_L << LOG_NODE_HEADER
<< " Folded grid return own best size " << best_size << ".\n";
return best_size;
}
DBG_GUI_L << LOG_NODE_HEADER << " own grid best size " << best_size << ".\n";
foreach(const tnode& node, children_) {
if(node.grid_.get_visible() == twidget::INVISIBLE) {
continue;
}
const tpoint node_size = node.calculate_best_size(indention_level + 1,
indention_step_size);
best_size.y += node_size.y;
best_size.x = std::max(best_size.x, node_size.x);
}
DBG_GUI_L << LOG_NODE_HEADER << " result " << best_size << ".\n";
return best_size;
}
void ttree_view::tnode::set_size(const tpoint& origin, const tpoint& size)
{
// Inherited.
twidget::set_size(origin, size);
set_size(40, origin);
}
unsigned ttree_view::tnode::set_size(
const unsigned indention_step_size
, tpoint origin)
{
log_scope2(log_gui_layout, LOG_NODE_SCOPE_HEADER);
DBG_GUI_L << LOG_NODE_HEADER << " origin " << origin << ".\n";
const unsigned offset = origin.y;
const tpoint best_size = grid_.get_best_size();
grid_.set_size(origin, best_size);
if(!is_root_node()) {
origin.x += indention_step_size;
}
origin.y += best_size.y;
if(is_folded()) {
DBG_GUI_L << LOG_NODE_HEADER << " folded node done.\n";
return origin.y - offset;
}
DBG_GUI_L << LOG_NODE_HEADER << " set children.\n";
foreach(tnode& node, children_) {
origin.y += node.set_size(indention_step_size, origin);
}
DBG_GUI_L << LOG_NODE_HEADER << " result " << ( origin.y - offset) << ".\n";
return origin.y - offset;
}
void ttree_view::tnode::set_visible_area(const SDL_Rect& area)
{
log_scope2(log_gui_layout, LOG_NODE_SCOPE_HEADER);
DBG_GUI_L << LOG_NODE_HEADER << " area " << area << ".\n";
grid_.set_visible_area(area);
if(is_folded()) {
DBG_GUI_L << LOG_NODE_HEADER << " folded node done.\n";
return;
}
foreach(tnode& node, children_) {
node.set_visible_area(area);
}
}
void ttree_view::tnode::impl_draw_children(surface& frame_buffer)
{
grid_.draw_children(frame_buffer);
if(is_folded()) {
return;
}
foreach(tnode& node, children_) {
node.impl_draw_children(frame_buffer);
}
}
void ttree_view::tnode::signal_handler_left_button_click(
const event::tevent event)
{
DBG_GUI_E << LOG_NODE_HEADER << ' ' << event << ".\n";
assert(icon_);
/*
if(!icon_->get_value()) {
fold(false);
} else {
unfold(recursive_restore);
}
*/
parent_widget_->set_size(
parent_widget_->get_origin()
, parent_widget_->get_size());
}
void ttree_view::tnode::init_grid(tgrid* grid
, const std::map<std::string /* widget id */, string_map>& data)
{
assert(grid);
for(unsigned row = 0; row < grid->get_rows(); ++row) {
for(unsigned col = 0; col < grid->get_cols(); ++col) {
twidget* widget = grid->widget(row, col);
assert(widget);
tgrid* child_grid = dynamic_cast<tgrid*>(widget);
// ttoggle_button* btn = dynamic_cast<ttoggle_button*>(widget);
ttoggle_panel* panel = dynamic_cast<ttoggle_panel*>(widget);
tcontrol* ctrl = dynamic_cast<tcontrol*>(widget);
if(panel) {
panel->set_child_members(data);
} else if(child_grid) {
init_grid(child_grid, data);
} else if(ctrl) {
std::map<std::string, string_map>::const_iterator itor =
data.find(ctrl->id());
if(itor == data.end()) {
itor = data.find("");
}
if(itor != data.end()) {
ctrl->set_members(itor->second);
}
// ctrl->set_members(data);
} else {
// ERROR_LOG("Widget type '"
// << typeid(*widget).name() << "'.");
}
}
}
}
ttree_view::ttree_view(const std::vector<tnode_definition>& node_definitions)
: tscrollbar_container(2)
, node_definitions_(node_definitions)
, indention_step_size_(0)
, root_node_(new tnode(
"root"
, node_definitions_
, NULL
, this
, std::map<std::string, string_map>()))
{
}
const std::string& ttree_view::tnode::get_control_type() const
{
static const std::string type = "tree_view_node";
return type;
}
namespace {
/**
* Swaps an item in a grid for another one.*/
void swap_grid(tgrid* grid,
tgrid* content_grid, twidget* widget, const std::string& id)
{
assert(content_grid);
assert(widget);
// Make sure the new child has same id.
widget->set_id(id);
// Get the container containing the wanted widget.
tgrid* parent_grid = NULL;
if(grid) {
parent_grid = find_widget<tgrid>(grid, id, false, false);
}
if(!parent_grid) {
parent_grid = find_widget<tgrid>(content_grid, id, true, false);
}
assert(parent_grid);
parent_grid = dynamic_cast<tgrid*>(parent_grid->parent());
assert(parent_grid);
// Replace the child.
widget = parent_grid->swap_child(id, widget, false);
assert(widget);
delete widget;
}
} // namespace
void ttree_view::finalize_setup()
{
tgrid* g = new tgrid();
g->set_rows_cols(1, 1);
g->set_child(
root_node_
, 0
, 0
, tgrid::VERTICAL_GROW_SEND_TO_CLIENT
| tgrid::HORIZONTAL_GROW_SEND_TO_CLIENT
, 0);
swap_grid(NULL, &grid(), g/*root_node_*/, "_content_grid");
// Inherited.
tscrollbar_container::finalize_setup();
}
const std::string& ttree_view::get_control_type() const
{
static const std::string type = "tree_view";
return type;
}
} // namespace gui2

View file

@ -0,0 +1,225 @@
/* $Id$ */
/*
Copyright (C) 2008 - 2010 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_TREE_VIEW_HPP_INCLUDED
#define GUI_WIDGETS_TREE_VIEW_HPP_INCLUDED
#include "config.hpp"
#include "gui/widgets/scrollbar_container.hpp"
#include "gui/auxiliary/window_builder/tree_view.hpp"
#include <boost/ptr_container/ptr_vector.hpp>
namespace gui2 {
class ttoggle_button;
class ttree_view
: public tscrollbar_container
{
friend struct implementation::tbuilder_tree_view;
public:
typedef implementation::tbuilder_tree_view::tnode tnode_definition;
/**
* Constructor.
*
* @param has_minimum Does the listbox need to have one item
* selected.
* @param has_maximum Can the listbox only have one item
* selected.
* @param placement How are the items placed.
* @param select Select an item when selected, if false it
* changes the visible state instead.
*/
ttree_view(const std::vector<tnode_definition>& node_definitions);
using tscrollbar_container::finalize_setup;
/***** ***** ***** ***** Node handling. ***** ***** ****** *****/
class tnode
: public twidget
{
friend struct ttree_view_node_implementation;
friend class ttree_view;
tnode(const std::string& id
, const std::vector<tnode_definition>& node_definitions
, tnode* parent
, ttree_view* parent_widget
, const std::map<
std::string /* widget id */, string_map>& data);
public:
/**
* Adds a child item to the list.
*/
tnode& add_child(const std::string& id
, const std::map<std::string /* widget id */, string_map>& data
, const int index = -1);
/**
* Adds a sibbling to the end of the list.
*/
tnode& add_sibling(const std::string& id
, const std::map<std::string /* widget id */, string_map>& data)
{
assert(!is_root_node());
return parent().add_child(id, data);
}
bool is_root_node() const { return parent_ == NULL; }
/**
* Returns the parent node, can't be used on the root node.
*/
tnode& parent();
bool empty() const { return children_.empty(); }
enum texpand_mode
{
recursive_restore // recursively restores collapse mode
, recursive_expand // recursively expands the children
, not_recursive
};
bool is_folded() const;
// If recursive all children will be closed recursively causing
// restore expaning not to expand anything
void fold(const bool recursive); // FIXME implement
void unfold(const texpand_mode mode); // FIXME implement
twidget* find_at(const tpoint& coordinate, const bool must_be_active);
const twidget* find_at(
const tpoint& coordinate
, const bool must_be_active) const;
private:
void request_reduce_width(unsigned int) {}
tnode* parent_;
ttree_view* parent_widget_;
tgrid grid_;
// We want the returned child nodes to remain stable.
boost::ptr_vector<tnode> children_;
const std::vector<tnode_definition>& node_definitions_;
ttoggle_button* icon_;
void child_populate_dirty_list(twindow& caller,
const std::vector<twidget*>& call_stack);
tpoint calculate_best_size() const
{
return calculate_best_size(-1, 40); // FIXME step only negative
}
bool disable_click_dismiss() const { return true; }
tpoint calculate_best_size(const int indention_level
, const unsigned indention_step_size) const;
void set_size(const tpoint& origin, const tpoint& size);
unsigned set_size(
const unsigned indention_step_size
, tpoint origin);
void set_visible_area(const SDL_Rect& area);
void impl_draw_children(surface& frame_buffer);
void signal_handler_left_button_click(const event::tevent event);
void init_grid(tgrid* grid
, const std::map<
std::string /* widget id */, string_map>& data);
const std::string& get_control_type() const;
};
tnode& get_root_node() { return *root_node_; }
tnode& add_node(const std::string& id
, const std::map<std::string /* widget id */, string_map>& data)
{
return get_root_node().add_child(id, data);
}
/** Inherited from tcontainer_. */
void set_self_active(const bool /*active*/) {}
// { state_ = active ? ENABLED : DISABLED; }
/***** ***** ***** setters / getters for members ***** ****** *****/
void set_indention_step_size(const unsigned indention_step_size)
{
indention_step_size_ = indention_step_size;
}
protected:
/***** ***** ***** ***** keyboard functions ***** ***** ***** *****/
#if 0
/** Inherited from tscrollbar_container. */
void handle_key_up_arrow(SDLMod modifier, bool& handled);
/** Inherited from tscrollbar_container. */
void handle_key_down_arrow(SDLMod modifier, bool& handled);
/** Inherited from tscrollbar_container. */
void handle_key_left_arrow(SDLMod modifier, bool& handled);
/** Inherited from tscrollbar_container. */
void handle_key_right_arrow(SDLMod modifier, bool& handled);
#endif
private:
/**
* @todo evaluate which way the dependancy should go.
*
* We no depend on the implementation, maybe the implementation should
* depend on us instead.
*/
const std::vector<tnode_definition> node_definitions_;
unsigned indention_step_size_;
tnode* root_node_;
/** Inherited from tcontainer_. */
virtual void finalize_setup();
/** Inherited from tcontrol. */
const std::string& get_control_type() const;
};
} // namespace gui2
#endif