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:
parent
6f3bdee34a
commit
a93b3267b5
8 changed files with 1344 additions and 0 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
|
|
375
src/gui/widgets/generator.cpp
Normal file
375
src/gui/widgets/generator.cpp
Normal 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
|
254
src/gui/widgets/generator.hpp
Normal file
254
src/gui/widgets/generator.hpp
Normal 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
|
||||
|
682
src/gui/widgets/generator_private.hpp
Normal file
682
src/gui/widgets/generator_private.hpp
Normal 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
|
||||
|
Loading…
Add table
Reference in a new issue