Add a new generator widget.

This widget is meant to be used for containers which have a variable number of
items. This widget also will allow to add items when the widget is displayed
(not yet implemented).
This commit is contained in:
Mark de Wever 2008-12-21 11:20:13 +00:00
parent 6f3bdee34a
commit a93b3267b5
8 changed files with 1344 additions and 0 deletions

View file

@ -19,6 +19,7 @@ src/gui/widgets/control.cpp
src/gui/widgets/container.cpp
src/gui/widgets/debug.cpp
src/gui/widgets/event_handler.cpp
src/gui/widgets/generator.cpp
src/gui/widgets/grid.cpp
src/gui/widgets/helper.cpp
src/gui/widgets/horizontal_scrollbar.cpp

View file

@ -237,6 +237,7 @@ SET(wesnoth-main_SRC
gui/widgets/control.cpp
gui/widgets/container.cpp
gui/widgets/event_handler.cpp
gui/widgets/generator.cpp
gui/widgets/grid.cpp
gui/widgets/helper.cpp
gui/widgets/horizontal_scrollbar.cpp

View file

@ -83,6 +83,7 @@ wesnoth_source = \
gui/widgets/control.cpp \
gui/widgets/container.cpp \
gui/widgets/event_handler.cpp \
gui/widgets/generator.cpp \
gui/widgets/grid.cpp \
gui/widgets/helper.cpp \
gui/widgets/horizontal_scrollbar.cpp \

View file

@ -225,6 +225,7 @@ wesnoth_sources = Split("""
gui/widgets/control.cpp
gui/widgets/container.cpp
gui/widgets/event_handler.cpp
gui/widgets/generator.cpp
gui/widgets/grid.cpp
gui/widgets/helper.cpp
gui/widgets/horizontal_scrollbar.cpp

View file

@ -20,6 +20,7 @@
#include "formatter.hpp"
#include "gui/widgets/vertical_scrollbar_container.hpp"
#ifdef NEW_DRAW
#include "gui/widgets/generator.hpp"
#include "gui/widgets/scrollbar_container.hpp"
#endif
#include "gui/widgets/window.hpp"
@ -223,6 +224,26 @@ void tdebug_layout_graph::widget_generate_info(std::ostream& out,
<< id << "_C"
<< " [label=\"(content)\"];\n";
}
const tgenerator_* generator =
dynamic_cast<const tgenerator_*>(widget);
if(generator) {
for(size_t i = 0;
i < generator->get_item_count(); ++i) {
const std::string child_id =
id + "_I_" + lexical_cast<std::string>(i);
widget_generate_info(out,
&generator->get_item(i),
child_id, true);
out << "\t" << id << " -> "
<< child_id
<< " [label=\"(item)\"];\n";
}
}
#endif
}
if(grid) {
@ -528,8 +549,16 @@ std::string tdebug_layout_graph::get_type(const twidget* widget) const
return control->get_control_type();
} else {
const tgrid* grid = dynamic_cast<const tgrid*>(widget);
#ifdef NEW_DRAW
const tgenerator_* generator =
dynamic_cast<const tgenerator_*>(widget);
#endif
if(grid) {
return "grid";
#ifdef NEW_DRAW
} else if(generator) {
return "generator";
#endif
} else {
return "unknown";
}

View file

@ -0,0 +1,375 @@
/* $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.
*/
#ifdef NEW_DRAW
#include "gui/widgets/generator_private.hpp"
#include "gui/widgets/window.hpp"
namespace gui2 {
namespace policy {
/***** ***** ***** ***** Minimum selection ***** ***** ***** *****/
namespace minimum_selection {
void tone::create_item(const unsigned index)
{
if(get_selected_item_count() == 0) {
do_select_item(index);
}
}
bool tone::deselect_item(const unsigned index)
{
if(get_selected_item_count() > 1) {
do_deselect_item(index);
return true;
}
return false;
}
void tone::delete_item(const unsigned index)
{
if(is_selected(index)) {
do_deselect_item(index);
if(get_selected_item_count() == 0) {
// Are there items left?
const unsigned item_count = get_item_count();
if(item_count > 1) {
// Is the last item deselected?
if(index == item_count - 1) {
// Select the second last.
do_select_item(index - 2);
} else {
// Select the next item.
do_select_item(index + 1);
}
}
}
}
}
} // namespace minimum_selection
/***** ***** ***** ***** Placement ***** ***** ***** *****/
namespace placement {
tvertical_list::tvertical_list()
: placed_(false)
{
}
void tvertical_list::create_item(const unsigned /*index*/)
{
if(!placed_) {
return;
}
/** @todo implement. */
assert(false);
}
tpoint tvertical_list::calculate_best_size() const
{
// The best size is the sum of the heights and the greatest width.
tpoint result(0, 0);
for(size_t i = 0; i < get_item_count(); ++i) {
const tgrid& grid = get_item(i);
const tpoint best_size = grid.get_best_size();
if(best_size.x > result.x) {
result.x = best_size.x;
}
result.y += best_size.y;
}
return result;
}
void tvertical_list::set_size(const tpoint& origin, const tpoint& size)
{
/*
* - Set every item to it's best size.
* - The origin gets increased with the height of the last item.
* - No item should be wider as the size.
* - In the end the origin should be the sum or the origin and the wanted
* height.
*/
tpoint current_origin = origin;
for(size_t i = 0; i < get_item_count(); ++i) {
tgrid& grid = get_item(i);
tpoint best_size = grid.get_best_size();
assert(best_size.x <= size.x);
// FIXME should we look at grow factors???
best_size.x = size.x;
/*
* For set_size to work properly, we need to disable the parent
* temporary. Without a parent the screen coordinates won't be
* remapped, which is wanted in this case. For event handling the
* parent is needed.
*/
twidget* parent = grid.parent();
grid.set_parent(NULL);
grid.set_size(current_origin, best_size);
grid.set_parent(parent);
current_origin.y += best_size.y;
}
assert(current_origin.y == origin.y + size.y);
}
twidget* tvertical_list::find_widget(
const tpoint& coordinate, const bool must_be_active)
{
twindow* window = get_window();
assert(window);
const tpoint screen_coordinate =
window->screen_position(coordinate);
for(size_t i = 0; i < get_item_count(); ++i) {
tgrid& grid = get_item(i);
twidget* widget =
grid.find_widget2(screen_coordinate, must_be_active);
if(widget) {
return widget;
}
}
return NULL;
}
const twidget* tvertical_list::find_widget(const tpoint& coordinate,
const bool must_be_active) const
{
const twindow* window = get_window();
assert(window);
const tpoint screen_coordinate =
window->screen_position(coordinate);
for(size_t i = 0; i < get_item_count(); ++i) {
const tgrid& grid = get_item(i);
const twidget* widget =
grid.find_widget2(screen_coordinate, must_be_active);
if(widget) {
return widget;
}
}
return NULL;
}
} // namespace placement
/***** ***** ***** ***** Select action ***** ***** ***** *****/
namespace select_action {
void tselect::select(tgrid& grid, const bool select)
{
tselectable_* selectable =
dynamic_cast<tselectable_*>(grid.widget(0, 0));
assert(selectable);
selectable->set_value(select);
}
} // namespace select_action
} // namespace policy
/***** ***** ***** ***** Helper macros ***** ***** ***** *****/
#ifdef GENERATE_PLACEMENT
char compile_assert[0];
#else
#define GENERATE_PLACEMENT \
switch(placement) { \
case tgenerator_::horizontal_list : \
result = new tgenerator \
< minimum \
, maximum \
, policy::placement::thorizontal_list \
, select \
>; \
break; \
case tgenerator_::vertical_list : \
result = new tgenerator \
< minimum \
, maximum \
, policy::placement::tvertical_list \
, select \
>; \
break; \
case tgenerator_::grid : \
result = new tgenerator \
< minimum \
, maximum \
, policy::placement::tmatrix \
, select \
>; \
break; \
case tgenerator_::independant : \
result = new tgenerator \
< minimum \
, maximum \
, policy::placement::tindependant \
, select \
>; \
break; \
default: \
assert(false); \
}
#endif
#ifdef GENERATE_SELECT
char compile_assert[0];
#else
#define GENERATE_SELECT \
if(select) { \
typedef policy::select_action::tselect select; \
GENERATE_PLACEMENT \
} else { \
typedef policy::select_action::tshow select; \
GENERATE_PLACEMENT \
}
#endif
#ifdef GENERATE_MAXIMUM
char compile_assert[0];
#else
#define GENERATE_MAXIMUM \
if(has_maximum) { \
typedef policy::maximum_selection::tone maximum; \
GENERATE_SELECT \
} else { \
typedef policy::maximum_selection::tinfinite maximum; \
GENERATE_SELECT \
}
#endif
#ifdef GENERATE_BODY
char compile_assert[0];
#else
#define GENERATE_BODY \
if(has_minimum) { \
typedef policy::minimum_selection::tone minimum; \
GENERATE_MAXIMUM \
} else { \
typedef policy::minimum_selection::tnone minimum; \
GENERATE_MAXIMUM \
}
#endif
tgenerator_* tgenerator_::build(
const bool has_minimum, const bool has_maximum,
const tplacement placement, const bool select)
{
tgenerator_* result = NULL;
GENERATE_BODY;
return result;
}
/***** ***** ***** ***** Test code ***** ***** ***** *****/
#if 0
namespace {
void pointer_test()
{
tgenerator_ *a = tgenerator_::build(
true, true, tgenerator_::horizontal_list, true);
tgenerator_ *b = tgenerator_::build(
true, false, tgenerator_::horizontal_list, true);
tgenerator_ *c = tgenerator_::build(
false, true, tgenerator_::horizontal_list, true);
tgenerator_ *d = tgenerator_::build(
false, false, tgenerator_::horizontal_list, true);
a->clear();
b->clear();
c->clear();
d->clear();
delete a;
delete b;
delete c;
delete d;
}
void direct_test()
{
tgenerator
< policy::minimum_selection::tone
, policy::maximum_selection::tone
, policy::placement::tvertical_list
, policy::select_action::tselect
> a;
tgenerator
< policy::minimum_selection::tone
, policy::maximum_selection::tinfinite
, policy::placement::tvertical_list
, policy::select_action::tselect
> b;
tgenerator
< policy::minimum_selection::tnone
, policy::maximum_selection::tone
, policy::placement::tvertical_list
, policy::select_action::tselect
> c;
tgenerator
< policy::minimum_selection::tnone
, policy::maximum_selection::tinfinite
, policy::placement::tvertical_list
, policy::select_action::tselect
> d;
a.clear();
b.clear();
c.clear();
d.clear();
}
} // namespace
#endif
} // namespace gui2
#endif

View file

@ -0,0 +1,254 @@
/* $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.
*/
#ifdef NEW_DRAW
#ifndef GUI_WIDGETS_GENERATOR_HPP_INCLUDED
#define GUI_WIDGETS_GENERATOR_HPP_INCLUDED
#include <boost/noncopyable.hpp>
#include "widget.hpp"
#include "config.hpp"
#include "gui/widgets/window_builder.hpp"
namespace gui2 {
class tgrid;
/**
* Abstract base class for the generator.
*
* A generator is a class which holds multiple grids and controls their
* placement on the screen. The final class is policy based, more info about
* the possible policies is documented in the build() function. This function
* is the factory to generate the classes as well.
*/
class tgenerator_
: private boost::noncopyable
, public twidget
{
friend class tdebug_layout_graph;
public:
virtual ~tgenerator_() {}
/** Determines how the items are placed. */
enum tplacement
{ horizontal_list
, vertical_list
, grid
, independant
};
/**
* Create a new generator.
*
* @param has_minimum Does one item need to be selected.
* @param has_maximum Is one the maximum number of items that can
* be selected?
* @param placement The placement of the grids, see tplacement
* for more info.
* @param select If a grid is selected, what should happen?
* If true the grid is selected, if false the
* grid is shown.
*
* @returns A pointer to a new object. The caller gets
* ownership of the new object.
*/
static tgenerator_* build(const bool has_minimum, const bool has_maximum,
const tplacement placement, const bool select);
/**
* Deletes an item.
*/
virtual void delete_item(const unsigned index) = 0;
/** Deletes all items. */
virtual void clear() = 0;
/**
* (De)selects an item.
*
* @param index The item to (de)select.
* @param select If true selects, if false deselects.
*/
virtual void select_item(const unsigned index,
const bool select = true) = 0;
/**
* Toggles the selection state of an item.
*
* @param index The item to toggle.
*/
void toggle_item(const unsigned index)
{
select_item(index, !is_selected(index));
}
/** Returns whether the item is selected. */
virtual bool is_selected(const unsigned index) const = 0;
/** Returns the number of items. */
virtual unsigned get_item_count() const = 0;
/** Returns the number of selected items. */
virtual unsigned get_selected_item_count() const = 0;
/** Returns the first selected item, -1 if none selected. */
virtual int get_selected_item() const = 0;
/** Gets the grid of an item. */
virtual tgrid& get_item(const unsigned index) = 0;
/***** ***** ***** ***** Create items ***** ***** ***** *****/
/**
* Creates a new item.
*
* The item_data is used for the first widget found, this normally should
* be used when there's one widget in an item.
*
* @param index The item before which to add the new item,
* 0 == begin, -1 == end.
* @param list_builder A grid builder that's will build the
* contents of the new item.
* @param item_data The data to initialize the parameters of
* the new item.
* @param callback The callback function to call when an item
* in the grid is (de)selected.
*/
virtual void create_item(const int index,
tbuilder_grid_const_ptr list_builder,
const string_map& item_data,
void (*callback)(twidget*)) = 0;
/**
* Creates a new item.
*
* The item_data is used by id, and is meant to set multiple widgets in
* an item.
*
* @param index The item before which to add the new item,
* 0 == begin, -1 == end.
* @param list_builder A grid builder that's will build the
* contents of the new item.
* @param item_data The data to initialize the parameters of
* the new item.
* @param callback The callback function to call when an item
* in the grid is (de)selected.
*/
virtual void create_item(const int index,
tbuilder_grid_const_ptr list_builder,
const std::map<std::string /* widget id */,
string_map>& data,
void (*callback)(twidget*)) = 0;
/**
* Creates one or more new item(s).
*
* For every item in item_data a new item is generated. This version
* expects one widget per item.
*
* @param index The item before which to add the new item,
* 0 == begin, -1 == end.
* @param list_builder A grid builder that's will build the
* contents of the new item.
* @param item_data The data to initialize the parameters of
* the new item.
* @param callback The callback function to call when an item
* in the grid is (de)selected.
*/
virtual void create_items(const int index,
tbuilder_grid_const_ptr list_builder,
const std::vector<string_map>& data,
void (*callback)(twidget*)) = 0;
/**
* Creates one or more new item(s).
*
* For every item in item_data a new item is generated. This version
* expects multiple widgets per item.
*
* @param index The item before which to add the new item,
* 0 == begin, -1 == end.
* @param list_builder A grid builder that's will build the
* contents of the new item.
* @param item_data The data to initialize the parameters of
* the new item.
* @param callback The callback function to call when an item
* in the grid is (de)selected.
*/
virtual void create_items(const int index,
tbuilder_grid_const_ptr list_builder,
const std::vector<std::map<std::string /*widget id*/,
string_map> >& data,
void (*callback)(twidget*)) = 0;
/***** ***** ***** ***** Inherited ***** ***** ***** *****/
/*
* These functions must be defined in our child classes so make sure they
* become pure virtuals.
*/
/** Inherited from twidget. */
virtual void layout_init() = 0;
/** Inherited from twidget. */
virtual tpoint calculate_best_size() const = 0;
/** Inherited from twidget. */
virtual void set_size(const tpoint& origin, const tpoint& size) = 0;
/** Inherited from twidget. */
virtual void draw_children(surface& frame_buffer) = 0;
/** Inherited from twidget. */
virtual void child_populate_dirty_list(twindow& caller,
const std::vector<twidget*>& call_stack) = 0;
/** Inherited from twidget. */
virtual twidget* find_widget(
const tpoint& coordinate, const bool must_be_active) = 0;
/** Inherited from twidget. */
virtual const twidget* find_widget(
const tpoint& coordinate, const bool must_be_active) const = 0;
protected:
/** Gets the grid of an item. */
virtual const tgrid& get_item(const unsigned index) const = 0;
/**
* Selects a not selected item.
*
* @param index The index of a not selected item.
*/
virtual void do_select_item(const unsigned index) = 0;
/**
* Deselects a selected item.
*
* @param index The index of a selected item.
*/
virtual void do_deselect_item(const unsigned index) = 0;
};
} // namespace gui2
#endif
#endif

View file

@ -0,0 +1,682 @@
/* $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.
*/
#ifdef NEW_DRAW
#ifndef GUI_WIDGETS_GENERATOR_PRIVATE_HPP_INCLUDED
#define GUI_WIDGETS_GENERATOR_PRIVATE_HPP_INCLUDED
#include "gui/widgets/generator.hpp"
#include "asserts.hpp"
#include "foreach.hpp"
#include "gui/widgets/grid.hpp"
#include "gui/widgets/selectable.hpp"
#include "gui/widgets/toggle_button.hpp"
#include "gui/widgets/toggle_panel.hpp"
namespace gui2 {
/**
* Contains the policies for the tgenerator class.
*/
namespace policy {
/***** ***** ***** ***** Minimum selection ***** ***** ***** *****/
/** Contains the policy for the minimum number of selected items. */
namespace minimum_selection {
/** Must select at least one item. */
struct tone
: public virtual tgenerator_
{
/**
* Called when an item is created.
*
* @param index The index of the new item.
*/
void create_item(const unsigned index);
/**
* Called when the users wants to deselect an item.
*
* If the item can be deselected this function should call
* do_deselect_item() to make the deslection happen. If not allowed no
* action needs to be taken.
*
* @param index The index of the item to deselect.
*
* @returns Whether the item was deselected, some
* actions might happen automatically upon
* deselecting, so if this function returns
* false the caller should make sure the
* select state is restored.
*/
bool deselect_item(const unsigned index);
/**
* Called just before an item is deleted.
*
* This function can if needed select another items to try to obey the
* policy.
*
* @param index The index of the item to be deleted.
*/
void delete_item(const unsigned index);
};
/** No minimum selection. */
struct tnone
: public virtual tgenerator_
{
/** See minimum_selection::tone::create_item() */
void create_item(const unsigned /*index*/) {}
/** See minimum_selection::tone::deselect_item() */
bool deselect_item(const unsigned index)
{
do_deselect_item(index);
return true;
}
/** See ::minimum_selection::tone::delete_item() */
void delete_item(const unsigned index)
{
if(is_selected(index)) {
do_deselect_item(index);
}
}
};
} // namespace minimum_selection
/***** ***** ***** ***** Maximum selection ***** ***** ***** *****/
/** Contains the policy for the maximum number of selected items. */
namespace maximum_selection {
/** May select only one item. */
struct tone
: public virtual tgenerator_
{
/**
* Called when an item is selected.
*
* This function can deselect other items to obey the policy. This
* function should always call do_select_item() so the new item does get
* selected.
*
* @param index The item to select.
*/
void select_item(const unsigned index)
{
if(get_selected_item_count() == 1) {
// deselect current.
do_deselect_item(get_selected_item());
// select new.
do_select_item(index);
}
}
};
/** No maximum amount of items to select. */
struct tinfinite
: public virtual tgenerator_
{
void select_item(const unsigned index)
{
do_select_item(index);
}
};
} // namespace maximum_selection
/***** ***** ***** ***** Placement ***** ***** ***** *****/
/** Controls how new items are placed. */
namespace placement {
/**
* Places the items in a horizontal row.
*
* @todo Implement.
*/
struct thorizontal_list
: public virtual tgenerator_
{
/**
* Called when an item is created.
*
* This function should place the new item.
*
* @param index The index of the new item.
*/
void create_item(const unsigned /*index*/) { assert(false); }
/**
* Calculates the best size for the generator.
*
* @return The best size,
*/
tpoint calculate_best_size() const
{ assert(false); return tpoint(0,0); }
/**
* Sets the size of the generator.
*
* @param origin The origin of the generator.
* @param size The size of the generator.
*/
void set_size(const tpoint& /*origin*/, const tpoint& /*size*/)
{ assert(false); }
/** Inherited from tgenerator_. */
twidget* find_widget(const tpoint&, const bool) { assert(false); }
/** Inherited from tgenerator_. */
const twidget* find_widget(const tpoint&, const bool) const
{ assert(false); }
};
/** Places the items in a vertical column. */
struct tvertical_list
: public virtual tgenerator_
{
tvertical_list();
/** See thorizontal_list::create_item(). */
void create_item(const unsigned index);
/** See thorizontal_list::calculate_best_size(). */
tpoint calculate_best_size() const;
/** See thorizontal_list::set_size(). */
void set_size(const tpoint& origin, const tpoint& size);
/** See thorizontal_list::find_widget(). */
twidget* find_widget(const tpoint& coordinate, const bool must_be_active);
/** See thorizontal_list::find_widget(). */
const twidget* find_widget(const tpoint& coordinate,
const bool must_be_active) const;
// FIXME we need a delete handler as well,
// when deleting the last item we need to remove the placed flag.
// FIXME we also need a clear function, called when
// clear is called.
private:
/**
* Has the grid already been placed?
*
* If the grid is placed it's no problem set the location of the new
* item,it hasn't been placed, there's no information about its location
* so do nothing.
*/
bool placed_;
};
/**
* Places the items in a grid.
*
* The items will be placed in rows and columns. It has to be determined
* whether the number of columns will be fixed or variable.
*
* @todo Implement.
*/
struct tmatrix
: public virtual tgenerator_
{
/** See thorizontal_list::create_item(). */
void create_item(const unsigned /*index*/) { assert(false); }
/** See thorizontal_list::calculate_best_size(). */
tpoint calculate_best_size() const
{ assert(false); return tpoint(0,0); }
/** See thorizontal_list::set_size(). */
void set_size(const tpoint& /*origin*/, const tpoint& /*size*/)
{ assert(false); }
/** See thorizontal_list::find_widget(). */
twidget* find_widget(const tpoint&, const bool) { assert(false); }
/** See thorizontal_list::find_widget(). */
const twidget* find_widget(const tpoint&, const bool) const
{ assert(false); }
};
/**
* Places the items independent of eachother.
*
* This is mainly meant for when only one item is shown at the same time.
*
* @todo Implement.
*/
struct tindependant
: public virtual tgenerator_
{
/** See thorizontal_list::create_item(). */
void create_item(const unsigned /*index*/) { assert(false); }
/** See thorizontal_list::calculate_best_size(). */
tpoint calculate_best_size() const
{ assert(false); return tpoint(0,0); }
/** See thorizontal_list::set_size(). */
void set_size(const tpoint& /*origin*/, const tpoint& /*size*/)
{ assert(false); }
/** See thorizontal_list::find_widget(). */
twidget* find_widget(const tpoint&, const bool) { assert(false); }
/** See thorizontal_list::find_widget(). */
const twidget* find_widget(const tpoint&, const bool) const
{ assert(false); }
};
} // namespace placement
/***** ***** ***** ***** Select action ***** ***** ***** *****/
/**
* Contains the policy for which action to take when an item is selected or
* deselected.
*/
namespace select_action {
/** Select the item, this requires the grid to contain a tselectable_. */
struct tselect
: public virtual tgenerator_
{
void select(tgrid& grid, const bool select);
};
/** Show the item. */
struct tshow
: public virtual tgenerator_
{
/** @todo implement when set_visible works. */
void select(tgrid& /*grid*/, const bool /*show*/)
{
//grid->set_visible(show);
}
};
} // namespace select_action
} // namespace policy
/***** ***** ***** ***** tgenerator ***** ***** ***** *****/
/**
* Basic template class to generate new items.
*
* The class is policy based so the behaviour can be selected.
*/
template
< class minimum_selection
, class maximum_selection
, class placement
, class select_action
>
class tgenerator
: public minimum_selection
, public maximum_selection
, public placement
, public select_action
{
public:
tgenerator()
: minimum_selection()
, maximum_selection()
, placement()
, select_action()
, selected_item_count_(0)
, items_()
{
}
~tgenerator()
{
clear();
}
/***** ***** ***** inherited ***** ****** *****/
/** Inherited from tgenerator_. */
void delete_item(const unsigned index)
{
assert(index < items_.size());
minimum_selection::delete_item(index);
delete items_[index];
items_.erase(items_.begin() + index);
}
/** Inherited from tgenerator_. */
void clear()
{
foreach(titem* item, items_) {
delete item;
}
selected_item_count_ = 0;
}
/** Inherited from tgenerator_. */
void select_item(const unsigned index,
const bool select = true)
{
assert(index < items_.size());
if(select && !is_selected(index)) {
maximum_selection::select_item(index);
} else if(is_selected(index)) {
if(!minimum_selection::deselect_item(index)) {
// Some items might have deseleted themselves so
// make sure they do get selected again.
select_action::select(get_item(index), true);
}
}
}
/** Inherited from tgenerator_. */
bool is_selected(const unsigned index) const
{
assert(index < items_.size());
return (*items_[index]).selected;
}
/** Inherited from tgenerator_. */
unsigned get_item_count() const
{
return items_.size();
}
/** Inherited from tgenerator_. */
unsigned get_selected_item_count() const
{
return selected_item_count_;
}
/** Inherited from tgenerator_. */
int get_selected_item() const
{
if(selected_item_count_ == 0) {
return -1;
} else {
for(size_t i = 0; i < items_.size(); ++i) {
if((*items_[i]).selected) {
return i;
}
}
ERROR_LOG("No item selected.");
}
}
/** Inherited from tgenerator_. */
tgrid& get_item(const unsigned index)
{
assert(index < items_.size());
return items_[index]->grid;
}
/** Inherited from tgenerator_. */
void create_item(const int index,
tbuilder_grid_const_ptr list_builder,
const string_map& item_data,
void (*callback)(twidget*))
{
std::map<std::string, string_map> data;
data.insert(std::make_pair("", item_data));
create_item(index, list_builder, data, callback);
}
/** Inherited from tgenerator_. */
void create_item(const int index,
tbuilder_grid_const_ptr list_builder,
const std::map<std::string /* widget id */,
string_map>& item_data,
void (*callback)(twidget*))
{
assert(list_builder);
assert(index == -1 || static_cast<unsigned>(index) < items_.size());
titem* item = new titem;
list_builder->build(&item->grid);
init(&item->grid, item_data, callback);
const unsigned item_index = index == -1
? items_.size()
: index;
items_.insert(items_.begin() + item_index, item);
minimum_selection::create_item(item_index);
placement::create_item(item_index);
}
/** Inherited from tgenerator_. */
virtual void create_items(const int index,
tbuilder_grid_const_ptr list_builder,
const std::vector<std::map<std::string /*widget id*/,
string_map> >& data,
void (*callback)(twidget*))
{
impl_create_items(index, list_builder, data, callback);
}
/** Inherited from tgenerator_. */
virtual void create_items(const int index,
tbuilder_grid_const_ptr list_builder,
const std::vector<string_map>& data,
void (*callback)(twidget*))
{
impl_create_items(index, list_builder, data, callback);
}
/** Inherited from tgenerator_. */
void layout_init()
{
foreach(titem* item, items_) {
item->grid.layout_init();
}
}
/** Inherited from tgenerator_. */
tpoint calculate_best_size() const
{
return placement::calculate_best_size();
}
/** Inherited from tgenerator_. */
void set_size(const tpoint& origin, const tpoint& size)
{
// Inherited, so we get useful debug info.
twidget::set_size(origin, size);
placement::set_size(origin, size);
}
/** Inherited from tgenerator_. */
void draw_children(surface& frame_buffer)
{
foreach(titem* item, items_) {
item->grid.draw_children(frame_buffer);
}
}
/** Inherited from tgenerator_. */
void child_populate_dirty_list(twindow& caller,
const std::vector<twidget*>& call_stack)
{
foreach(titem* item, items_) {
item->grid.child_populate_dirty_list(caller, call_stack);
}
}
protected:
/** Inherited from tgenerator_. */
const tgrid& get_item(const unsigned index) const
{
assert(index < items_.size());
return items_[index]->grid;
}
/** Inherited from tgenerator_. */
void do_select_item(const unsigned index) //fixme rename to impl
{
assert(index < items_.size());
++selected_item_count_;
set_item_selected(index, true);
}
/** Inherited from tgenerator_. */
void do_deselect_item(const unsigned index)
{
assert(index < items_.size());
--selected_item_count_;
set_item_selected(index, false);
}
private:
/** Definition of an item. */
struct titem {
titem()
: grid()
, selected(false)
{
}
/** The grid containing the widgets. */
tgrid grid;
/** Is the item selected or not. */
bool selected;
};
/** The number of selected items. */
unsigned selected_item_count_;
/** The items in the generator. */
std::vector<titem*> items_;
/**
* Sets the selected state of an item.
*
* @param index The item to modify.
* @param selected Select or deselect.
*/
void set_item_selected(const unsigned index, const bool selected)
{
assert(index < items_.size());
(*items_[index]).selected = selected;
select_action::select((*items_[index]).grid, selected);
}
/**
* Helper function for create_items().
*
* @tparam T Type of the data, this should be one of the
* valid parameters for create_item().
*
* @param index The item before which to add the new item,
* 0 == begin, -1 == end.
* @param list_builder A grid builder that's will build the
* contents of the new item.
* @param data The data to initialize the parameters of
* the new item.
* @param callback The callback function to call when an item
* in the grid is (de)selected.
*/
template<class T>
void impl_create_items(const int index,
tbuilder_grid_const_ptr list_builder,
const std::vector<T>& data,
void (*callback)(twidget*))
{
int i = index;
foreach(const T& item_data, data) {
create_item(i, list_builder, item_data, callback);
if(i != -1) {
++i;
}
}
}
/**
* Helper function to initialize a grid.
*
* @param grid The grid to initialize.
* @param data The data to initialize the parameters of
* the new item.
* @param callback The callback function to call when an item
* in the grid is (de)selected.
*/
void init(tgrid* grid,
const std::map<std::string /* widget id */, string_map>& data,
void (*callback)(twidget*))
{
assert(grid);
grid->set_parent(this);
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);
if(btn) {
btn->set_callback_state_change(callback);
std::map<std::string, string_map>::const_iterator itor =
data.find(btn->id());
if(itor == data.end()) {
itor = data.find("");
}
if(itor != data.end()) {
btn->set_members(itor->second);
}
} else if(panel) {
panel->set_callback_state_change(callback);
panel->set_child_members(data);
} else if(child_grid) {
init(child_grid, data, callback);
} else {
ERROR_LOG("Widget type '"
<< typeid(*widget).name() << "'.");
}
}
}
}
};
} // namespace gui2
#endif
#endif