Added new experimental list box implementation.

The code is very experimental and incomplete and therefore ifdeffed with
GUI2_EXPERIMENTAL_LISTBOX.
This commit is contained in:
Mark de Wever 2010-05-02 12:17:38 +00:00
parent 9b19381964
commit 75a0839402
29 changed files with 965 additions and 17 deletions

View file

@ -59,6 +59,8 @@ Version 1.9.0-svn:
* Patch #1645: Fixed a bug sending keyboard events to deactivated controls
* Deprecated the resize flag for gui2 image, use the resize_mode instead
* Patch #1639: Added handlers for keyboard (arrow keys) to move gui2 sliders
* Added new experimental list box implementation, available for testing
with -DGUI2_EXPERIMENTAL_LISTBOX
* WML Engine:
* Deprecated [set_variable]'s random key, use rand instead
* Renamed [unit][status] healable to unhealable so it can default to 'no'

View file

@ -88,6 +88,7 @@
horizontal_grow = "true"
[toggle_panel]
id = "_toggle"
definition = "default"
return_value_id = "ok"

View file

@ -87,6 +87,7 @@ src/gui/widgets/helper.cpp
src/gui/widgets/horizontal_scrollbar.cpp
src/gui/widgets/image.cpp
src/gui/widgets/label.cpp
src/gui/widgets/list.cpp
src/gui/widgets/listbox.cpp
src/gui/widgets/minimap.cpp
src/gui/widgets/multi_page.cpp

View file

@ -359,6 +359,7 @@ set(wesnoth-main_SRC
gui/widgets/horizontal_scrollbar.cpp
gui/widgets/image.cpp
gui/widgets/label.cpp
gui/widgets/list.cpp
gui/widgets/listbox.cpp
gui/widgets/minimap.cpp
gui/widgets/multi_page.cpp

View file

@ -186,6 +186,7 @@ wesnoth_source = \
gui/widgets/horizontal_scrollbar.cpp \
gui/widgets/image.cpp \
gui/widgets/label.cpp \
gui/widgets/list.cpp \
gui/widgets/listbox.cpp \
gui/widgets/minimap.cpp \
gui/widgets/multi_page.cpp \

View file

@ -345,6 +345,7 @@ wesnoth_sources = Split("""
gui/widgets/horizontal_scrollbar.cpp
gui/widgets/image.cpp
gui/widgets/label.cpp
gui/widgets/list.cpp
gui/widgets/listbox.cpp
gui/widgets/minimap.cpp
gui/widgets/multi_page.cpp

View file

@ -81,7 +81,6 @@ tbuilder_widget_ptr create_builder_widget(const config& cfg)
if(const config &c = cfg.child("grid")) {
return new tbuilder_grid(c);
}
/*
* This is rather odd, when commented out the classes no longer seem to be in
* the executable, no real idea why, except maybe of an overzealous optimizer

View file

@ -21,7 +21,11 @@
#include "gui/auxiliary/log.hpp"
#include "gui/auxiliary/widget_definition/listbox.hpp"
#include "gui/auxiliary/window_builder/helper.hpp"
#ifdef GUI2_EXPERIMENTAL_LISTBOX
#include "gui/widgets/list.hpp"
#else
#include "gui/widgets/listbox.hpp"
#endif
#include "wml_exception.hpp"
namespace gui2 {
@ -66,6 +70,19 @@ tbuilder_horizontal_listbox::tbuilder_horizontal_listbox(const config& cfg)
twidget* tbuilder_horizontal_listbox::build() const
{
#ifdef GUI2_EXPERIMENTAL_LISTBOX
tlist *widget = new tlist(true
, true
, tgenerator_::horizontal_list
, true
, list_builder);
init_control(widget);
if(!list_data.empty()) {
widget->append_rows(list_data);
}
return widget;
#else
tlistbox *widget = new tlistbox(
true, true, tgenerator_::horizontal_list, true);
@ -90,6 +107,7 @@ twidget* tbuilder_horizontal_listbox::build() const
widget->finalize(NULL, NULL, list_data);
return widget;
#endif
}
} // namespace implementation

View file

@ -21,7 +21,12 @@
#include "gui/auxiliary/log.hpp"
#include "gui/auxiliary/widget_definition/listbox.hpp"
#include "gui/auxiliary/window_builder/helper.hpp"
#ifdef GUI2_EXPERIMENTAL_LISTBOX
#include "gui/widgets/list.hpp"
#else
#include "gui/widgets/listbox.hpp"
#endif
#include "gui/widgets/settings.hpp"
#include "wml_exception.hpp"
namespace gui2 {
@ -79,6 +84,19 @@ tbuilder_listbox::tbuilder_listbox(const config& cfg)
twidget* tbuilder_listbox::build() const
{
#ifdef GUI2_EXPERIMENTAL_LISTBOX
tlist *widget = new tlist(true
, true
, tgenerator_::vertical_list
, true
, list_builder);
init_control(widget);
if(!list_data.empty()) {
widget->append_rows(list_data);
}
return widget;
#else
tlistbox *widget = new tlistbox(
true, true, tgenerator_::vertical_list, true);
@ -103,6 +121,7 @@ twidget* tbuilder_listbox::build() const
widget->finalize(header, footer, list_data);
return widget;
#endif
}
} // namespace implementation

View file

@ -17,7 +17,11 @@
#include "gui/dialogs/addon_list.hpp"
#include "foreach.hpp"
#ifdef GUI2_EXPERIMENTAL_LISTBOX
#include "gui/widgets/list.hpp"
#else
#include "gui/widgets/listbox.hpp"
#endif
#include "gui/widgets/settings.hpp"
#include "gui/widgets/window.hpp"

View file

@ -19,7 +19,11 @@
#include "foreach.hpp"
#include "gui/dialogs/helper.hpp"
#include "gui/widgets/image.hpp"
#ifdef GUI2_EXPERIMENTAL_LISTBOX
#include "gui/widgets/list.hpp"
#else
#include "gui/widgets/listbox.hpp"
#endif
#include "gui/widgets/multi_page.hpp"
#include "gui/widgets/scroll_label.hpp"
#include "gui/widgets/settings.hpp"
@ -81,12 +85,14 @@ void tcampaign_selection::campaign_selected(twindow& window)
&window, "campaign_details", false);
multi_page.select_page(choice);
} else {
tlistbox& list = find_widget<tlistbox>(&window, "campaign_list", false);
const int selected_row =
find_widget<tlistbox>(&window, "campaign_list", false)
.get_selected_row();
tmulti_page& multi_page = find_widget<tmulti_page>(
&window, "campaign_details", false);
multi_page.select_page(list.get_selected_row());
multi_page.select_page(selected_row);
}
}
@ -171,12 +177,20 @@ void tcampaign_selection::pre_show(CVideo& /*video*/, twindow& window)
}
/***** Setup campaign list. *****/
tlistbox& list = find_widget<tlistbox>(&window, "campaign_list", false);
tlistbox& list =
find_widget<tlistbox>(&window, "campaign_list", false);
#ifdef GUI2_EXPERIMENTAL_LISTBOX
connect_signal_notify_modified(list, boost::bind(
&tcampaign_selection::campaign_selected
, *this
, boost::ref(window)));
#else
list.set_callback_value_change(dialog_callback
<tcampaign_selection, &tcampaign_selection::campaign_selected>);
<tcampaign_selection
, &tcampaign_selection::campaign_selected>);
#endif
window.keyboard_capture(&list);
window.keyboard_capture(&list);
/***** Setup campaign details. *****/
tmulti_page& multi_page = find_widget<tmulti_page>(
@ -204,13 +218,6 @@ void tcampaign_selection::pre_show(CVideo& /*video*/, twindow& window)
widget->set_visible(twidget::HIDDEN);
}
if(new_widgets) {
find_widget<tcontrol>(grid, "icon", false)
.set_visible(twidget::INVISIBLE);
find_widget<tcontrol>(grid, "victory", false)
.set_visible(twidget::INVISIBLE);
}
/*** Add detail item ***/
string_map detail_item;
std::map<std::string, string_map> detail_page;

View file

@ -26,7 +26,11 @@
#include "gui/widgets/button.hpp"
#include "gui/widgets/image.hpp"
#include "gui/widgets/label.hpp"
#ifdef GUI2_EXPERIMENTAL_LISTBOX
#include "gui/widgets/list.hpp"
#else
#include "gui/widgets/listbox.hpp"
#endif
#include "gui/widgets/minimap.hpp"
#include "gui/widgets/settings.hpp"
#include "gui/widgets/text_box.hpp"
@ -98,8 +102,16 @@ void tgame_load::pre_show(CVideo& /*video*/, twindow& window)
tlistbox* list = find_widget<tlistbox>(
&window, "savegame_list", false, true);
window.keyboard_capture(list);
#ifdef GUI2_EXPERIMENTAL_LISTBOX
connect_signal_notify_modified(*list, boost::bind(
&tgame_load::list_item_clicked
, *this
, boost::ref(window)));
#else
list->set_callback_value_change(
dialog_callback<tgame_load, &tgame_load::list_item_clicked>);
#endif
{
cursor::setter cur(cursor::WAIT);

View file

@ -18,7 +18,11 @@
#include "gui/dialogs/helper.hpp"
#include "gui/widgets/button.hpp"
#ifdef GUI2_EXPERIMENTAL_LISTBOX
#include "gui/widgets/list.hpp"
#else
#include "gui/widgets/listbox.hpp"
#endif
#include "gui/widgets/settings.hpp"
#include "gui/widgets/window.hpp"
@ -514,11 +518,24 @@ public:
model_.inspect = find_widget<tcontrol>(&window, "inspect", false,true);
model_.inspector_name = &find_widget<tcontrol>(&window, "inspector_name", false);
#ifdef GUI2_EXPERIMENTAL_LISTBOX
connect_signal_notify_modified(*model_.stuff_list, boost::bind(
&tgamestate_inspector::view::handle_stuff_list_item_clicked
, this
, boost::ref(window)));
connect_signal_notify_modified(*model_.stuff_types_list, boost::bind(
&tgamestate_inspector::view::handle_stuff_list_item_clicked
, this
, boost::ref(window)));
#else
model_.stuff_list->set_callback_value_change(
dialog_view_callback<tgamestate_inspector, tgamestate_inspector::view, &tgamestate_inspector::view::handle_stuff_list_item_clicked>);
model_.stuff_types_list->set_callback_value_change(
dialog_view_callback<tgamestate_inspector, tgamestate_inspector::view, &tgamestate_inspector::view::handle_stuff_types_list_item_clicked>);
#endif
}

View file

@ -17,7 +17,11 @@
#include "gui/dialogs/language_selection.hpp"
#include "foreach.hpp"
#ifdef GUI2_EXPERIMENTAL_LISTBOX
#include "gui/widgets/list.hpp"
#else
#include "gui/widgets/listbox.hpp"
#endif
#include "gui/widgets/settings.hpp"
#include "gui/widgets/window.hpp"
#include "language.hpp"

View file

@ -23,7 +23,11 @@
#include "gui/widgets/button.hpp"
#include "gui/widgets/image.hpp"
#include "gui/widgets/label.hpp"
#ifdef GUI2_EXPERIMENTAL_LISTBOX
#include "gui/widgets/list.hpp"
#else
#include "gui/widgets/listbox.hpp"
#endif
#include "gui/widgets/minimap.hpp"
#include "gui/widgets/multi_page.hpp"
#include "gui/widgets/scroll_label.hpp"
@ -654,7 +658,9 @@ void tlobby_main::update_gamelist_header()
symbols["num_shown"] = lexical_cast<std::string>(lobby_info_.games_filtered().size());
symbols["num_total"] = lexical_cast<std::string>(lobby_info_.games().size());
std::string games_string = VGETTEXT("Games: showing $num_shown out of $num_total", symbols);
#ifndef GUI2_EXPERIMENTAL_LISTBOX
find_widget<tlabel>(gamelistbox_, "map", false).set_label(games_string);
#endif
}
std::map<std::string, string_map> tlobby_main::make_game_row_data(const game_info& game)
@ -919,10 +925,27 @@ void tlobby_main::pre_show(CVideo& /*video*/, twindow& window)
{
SCOPE_LB;
roomlistbox_ = find_widget<tlistbox>(&window, "room_list", false, true);
roomlistbox_->set_callback_value_change(dialog_callback<tlobby_main, &tlobby_main::room_switch_callback>);
#ifdef GUI2_EXPERIMENTAL_LISTBOX
connect_signal_notify_modified(*roomlistbox_, boost::bind(
&tlobby_main::room_switch_callback
, *this
, boost::ref(window)));
#else
roomlistbox_->set_callback_value_change(
dialog_callback<tlobby_main, &tlobby_main::room_switch_callback>);
#endif
gamelistbox_ = find_widget<tlistbox>(&window, "game_list", false, true);
gamelistbox_->set_callback_value_change(dialog_callback<tlobby_main, &tlobby_main::gamelist_change_callback>);
#ifdef GUI2_EXPERIMENTAL_LISTBOX
connect_signal_notify_modified(*gamelistbox_, boost::bind(
&tlobby_main::gamelist_change_callback
, *this
, boost::ref(window)));
#else
gamelistbox_->set_callback_value_change(
dialog_callback<tlobby_main
, &tlobby_main::gamelist_change_callback>);
#endif
player_list_.init(window);

View file

@ -26,11 +26,16 @@
class display;
#ifdef GUI2_EXPERIMENTAL_LISTBOX
#include "gui/widgets/list.hpp"
#endif
namespace gui2 {
class tgrid;
class tlabel;
#ifndef GUI2_EXPERIMENTAL_LISTBOX
class tlistbox;
#endif
class ttext_box;
class twindow;
class tmulti_page;

View file

@ -20,7 +20,11 @@
#include "game_preferences.hpp"
#include "gui/dialogs/field.hpp"
#include "gui/widgets/button.hpp"
#ifdef GUI2_EXPERIMENTAL_LISTBOX
#include "gui/widgets/list.hpp"
#else
#include "gui/widgets/listbox.hpp"
#endif
#include "gui/widgets/label.hpp"
#include "gui/widgets/password_box.hpp"
#include "gui/widgets/settings.hpp"

View file

@ -22,11 +22,18 @@
#include "gui/dialogs/field.hpp"
#include "gui/dialogs/helper.hpp"
#include "gui/widgets/integer_selector.hpp"
#ifdef GUI2_EXPERIMENTAL_LISTBOX
#include "gui/widgets/list.hpp"
#else
#include "gui/widgets/listbox.hpp"
#endif
#include "gui/widgets/minimap.hpp"
#include "gui/widgets/settings.hpp"
#include "../../settings.hpp"
#ifdef GUI2_EXPERIMENTAL_LISTBOX
#include <boost/bind.hpp>
#endif
namespace gui2 {
REGISTER_WINDOW(mp_create_game)
@ -65,8 +72,15 @@ void tmp_create_game::pre_show(CVideo& /*video*/, twindow& window)
find_widget<tminimap>(&window, "minimap", false).set_config(&cfg_);
tlistbox& list = find_widget<tlistbox>(&window, "map_list", false);
#ifdef GUI2_EXPERIMENTAL_LISTBOX
connect_signal_notify_modified(list, boost::bind(
&tmp_create_game::update_map
, *this
, boost::ref(window)));
#else
list.set_callback_value_change(
dialog_callback<tmp_create_game, &tmp_create_game::update_map>);
#endif
// Load option (might turn it into a button later).
string_map item;

View file

@ -16,7 +16,11 @@
#include "gui/dialogs/mp_method_selection.hpp"
#ifdef GUI2_EXPERIMENTAL_LISTBOX
#include "gui/widgets/list.hpp"
#else
#include "gui/widgets/listbox.hpp"
#endif
#include "gui/widgets/window.hpp"
#include "gui/widgets/settings.hpp"
#include "gui/widgets/text_box.hpp"

View file

@ -17,7 +17,11 @@
#include "gui/dialogs/unit_attack.hpp"
#include "gui/widgets/image.hpp"
#ifdef GUI2_EXPERIMENTAL_LISTBOX
#include "gui/widgets/list.hpp"
#else
#include "gui/widgets/listbox.hpp"
#endif
#include "gui/widgets/settings.hpp"
#include "gui/widgets/window.hpp"
#include "unit.hpp"

View file

@ -18,7 +18,11 @@
#include "gui/auxiliary/log.hpp"
#include "gui/dialogs/helper.hpp"
#ifdef GUI2_EXPERIMENTAL_LISTBOX
#include "gui/widgets/list.hpp"
#else
#include "gui/widgets/listbox.hpp"
#endif
#include "gui/widgets/settings.hpp"
#include "gui/widgets/toggle_button.hpp"
#include "gui/widgets/window.hpp"

View file

@ -19,7 +19,11 @@
#include "foreach.hpp"
#include "gui/widgets/button.hpp"
#include "gui/widgets/label.hpp"
#ifdef GUI2_EXPERIMENTAL_LISTBOX
#include "gui/widgets/list.hpp"
#else
#include "gui/widgets/listbox.hpp"
#endif
#include "gui/widgets/settings.hpp"
#include "gui/widgets/text_box.hpp"
#include "gui/widgets/window.hpp"

View file

@ -22,7 +22,11 @@
#include "foreach.hpp"
#include "formatter.hpp"
#include "gui/widgets/generator.hpp"
#ifdef GUI2_EXPERIMENTAL_LISTBOX
#include "gui/widgets/list.hpp"
#else
#include "gui/widgets/listbox.hpp"
#endif
#include "gui/widgets/scrollbar_container.hpp"
#include "gui/widgets/window.hpp"
#include "serialization/string_utils.hpp"

481
src/gui/widgets/list.cpp Normal file
View file

@ -0,0 +1,481 @@
/* $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.
*/
#ifdef GUI2_EXPERIMENTAL_LISTBOX
#define GETTEXT_DOMAIN "wesnoth-lib"
#include "gui/widgets/list.hpp"
#include "foreach.hpp"
#include "gui/auxiliary/log.hpp"
#include "gui/auxiliary/widget_definition/listbox.hpp"
#include "gui/auxiliary/window_builder/listbox.hpp"
#include "gui/widgets/selectable.hpp"
#include "gui/widgets/settings.hpp"
#include "gui/widgets/window.hpp"
#include <boost/bind.hpp>
#define LOG_SCOPE_HEADER get_control_type() + " [" + id() + "] " + __func__
#define LOG_HEADER LOG_SCOPE_HEADER + ':'
namespace gui2 {
#ifdef GUI2_EXPERIMENTAL_LISTBOX
REGISTER_WIDGET(listbox)
#endif
tlist::tlist(const bool has_minimum
, const bool has_maximum
, const tgenerator_::tplacement placement
, const bool select
, const tbuilder_grid_const_ptr list_builder)
: tcontainer_(2) // FIXME magic number
, state_(ENABLED)
, generator_(NULL)
, list_builder_(list_builder)
, need_layout_(false)
{
assert(list_builder);
generator_ = tgenerator_::build(
has_minimum, has_maximum, placement, select);
assert(generator_);
connect_signal<event::LEFT_BUTTON_DOWN>(
boost::bind(
&tlist::signal_handler_left_button_down
, this
, _2)
, event::tdispatcher::back_pre_child);
connect_signal<event::SDL_KEY_DOWN>(
boost::bind(
&tlist::signal_handler_sdl_key_down
, this
, _2
, _3
, _5
, _6));
connect_signal<event::SDL_KEY_DOWN>(
boost::bind(
&tlist::signal_handler_sdl_key_down
, this
, _2
, _3
, _5
, _6)
, event::tdispatcher::back_pre_child);
}
void tlist::add_row(const string_map& item, const int index)
{
std::map<std::string, string_map> data;
data.insert(std::make_pair("", item));
add_row(data, index);
}
void tlist::add_row(
const std::map<std::string /* widget id */, string_map>& data
, const int index)
{
assert(generator_);
tgrid& grid =
generator_->create_item(index, list_builder_, data, NULL);
tselectable_* selectable =
find_widget<tselectable_>(&grid, "_toggle", false, false);
if(selectable) {
dynamic_cast<twidget&>(*selectable).
connect_signal<event::LEFT_BUTTON_CLICK>(
boost::bind(
&tlist::signal_handler_pre_child_left_button_click
, this
, &grid
, _2
, _3
, _4)
, event::tdispatcher::back_pre_child);
// Post widget for panel.
dynamic_cast<twidget&>(*selectable).
connect_signal<event::LEFT_BUTTON_CLICK>(
boost::bind(
&tlist::signal_handler_left_button_click
, this
, &grid
, _2)
, event::tdispatcher::back_post_child);
// Post widget for button and widgets on the panel.
dynamic_cast<twidget&>(*selectable).
connect_signal<event::LEFT_BUTTON_CLICK>(
boost::bind(
&tlist::signal_handler_left_button_click
, this
, &grid
, _2)
, event::tdispatcher::back_child);
}
}
void tlist::append_rows(const std::vector<string_map>& items)
{
foreach(const string_map& item, items) {
add_row(item);
}
}
void tlist::remove_row(const unsigned row, unsigned count)
{
assert(generator_);
if(row >= get_item_count()) {
return;
}
if(!count || count > get_item_count()) {
count = get_item_count();
}
unsigned height_reduced = 0;
for(; count; --count) {
if(generator_->item(row).get_visible() != INVISIBLE) {
height_reduced += generator_->item(row).get_height();
}
generator_->delete_item(row);
}
if(height_reduced != 0) {
// resize_content(0, -height_reduced);
}
}
void tlist::clear()
{
// Due to the removing from the linked group, don't use
// generator_->clear() directly.
remove_row(0, 0);
}
unsigned tlist::get_item_count() const
{
assert(generator_);
return generator_->get_item_count();
}
void tlist::set_row_active(const unsigned row, const bool active)
{
assert(generator_);
generator_->item(row).set_active(active);
}
void tlist::set_row_shown(const unsigned row, const bool shown)
{
assert(generator_);
twindow *window = get_window();
assert(window);
const int selected_row = get_selected_row();
bool resize_needed;
{
twindow::tinvalidate_layout_blocker invalidate_layout_blocker(*window);
generator_->set_item_shown(row, shown);
generator_->place(generator_->get_origin()
, generator_->calculate_best_size());
// resize_needed = !content_resize_request();
}
if(resize_needed) {
window->invalidate_layout();
} else {
// grid().set_visible_area(content_visible_area());
set_dirty();
}
if(selected_row != get_selected_row()) {
fire(event::NOTIFY_MODIFIED, *this, NULL);
}
}
void tlist::set_row_shown(const std::vector<bool>& shown)
{
assert(generator_);
assert(shown.size() == get_item_count());
twindow *window = get_window();
assert(window);
const int selected_row = get_selected_row();
bool resize_needed;
{
twindow::tinvalidate_layout_blocker invalidate_layout_blocker(*window);
for(size_t i = 0; i < shown.size(); ++i) {
generator_->set_item_shown(i, shown[i]);
}
generator_->place(generator_->get_origin()
, generator_->calculate_best_size());
// resize_needed = !content_resize_request();
}
if(resize_needed) {
window->invalidate_layout();
} else {
// content_grid_->set_visible_area(content_visible_area());
set_dirty();
}
if(selected_row != get_selected_row()) {
fire(event::NOTIFY_MODIFIED, *this, NULL);
}
}
const tgrid* tlist::get_row_grid(const unsigned row) const
{
assert(generator_);
// rename this function and can we return a reference??
return &generator_->item(row);
}
tgrid* tlist::get_row_grid(const unsigned row)
{
assert(generator_);
return &generator_->item(row);
}
bool tlist::select_row(const unsigned row, const bool select)
{
assert(generator_);
generator_->select_item(row, select);
return true; // FIXME test what result should have been!!!
}
int tlist::get_selected_row() const
{
assert(generator_);
return generator_->get_selected_item();
}
void tlist::place(const tpoint& origin, const tpoint& size)
{
// Inherited.
tcontainer_::place(origin, size);
/**
* @todo Work-around to set the selected item visible again.
*
* At the moment the listes and dialogs in general are resized a lot as
* work-around for sizing. So this function makes the selected item in view
* again. It doesn't work great in all cases but the proper fix is to avoid
* resizing dialogs a lot. Need more work later on.
*/
const int selected_item = generator_->get_selected_item();
if(selected_item != -1) {
/*
const SDL_Rect& visible = content_visible_area();
SDL_Rect rect = generator_->item(selected_item).get_rect();
rect.x = visible.x;
rect.w = visible.w;
show_content_rect(rect);
*/
}
}
#if 0
void tlist::resize_content(
const int width_modification
, const int height_modification)
{
DBG_GUI_L << LOG_HEADER << " current size " << content_grid()->get_size()
<< " width_modification " << width_modification
<< " height_modification " << height_modification
<< ".\n";
if(content_resize_request(width_modification, height_modification)) {
// Calculate new size.
tpoint size = content_grid()->get_size();
size.x += width_modification;
size.y += height_modification;
// Set new size.
content_grid()->set_size(size);
// Set status.
need_layout_ = true;
// If the content grows assume it "overwrites" the old content.
if(width_modification < 0 || height_modification < 0) {
set_dirty();
}
DBG_GUI_L << LOG_HEADER << " succeeded.\n";
} else {
DBG_GUI_L << LOG_HEADER << " failed.\n";
}
}
#endif
void tlist::init()
{
init_grid(cast<tlistbox_definition::tresolution>(config()).grid);
set_single_child(
find_widget<tgrid>(&grid(), "_list_grid", false)
, generator_);
/*
* These items should be managed by the new listbox class.
* So make them invisible for now.
*/
tgrid* g = find_widget<tgrid>(&grid(), "_header_grid", false, false);
if(g) g->set_visible(twidget::INVISIBLE);
g = find_widget<tgrid>(&grid(), "_footer_grid", false, false);
if(g) g->set_visible(twidget::INVISIBLE);
g = find_widget<tgrid>(&grid(), "_vertical_scrollbar_grid", false, false);
if(g) g->set_visible(twidget::INVISIBLE);
g = find_widget<tgrid>(&grid(), "_horizontal_scrollbar_grid", false, false);
if(g) g->set_visible(twidget::INVISIBLE);
}
void tlist::layout_children(const bool force)
{
if(need_layout_ || force) {
grid().place(grid().get_origin(), grid().get_size());
/*
grid().set_visible_area(content_visible_area_);
*/
need_layout_ = false;
set_dirty();
}
}
const std::string& tlist::get_control_type() const
{
static const std::string type = "list";
return type;
}
void tlist::signal_handler_left_button_down(const event::tevent event)
{
DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
assert(get_window());
get_window()->keyboard_capture(this);
}
void tlist::signal_handler_pre_child_left_button_click(
tgrid* grid
, const event::tevent event
, bool& handled
, bool& halt)
{
DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
assert(grid);
assert(generator_);
for(size_t i = 0; i < generator_->get_item_count(); ++i) {
if(&generator_->item(i) == grid) {
/**
* @todo Here we should check whether the panel can be toggled.
*
* NO set halt + handled
* YES do nothing
*
* Then a post to the widget, which if done sets the proper state
* in the list.
*
* For now we simply assume an item can only be selected and not
* deselected (which is true at the moment).
*/
if(generator_->is_selected(i)) {
halt = true;
handled = true;
}
return;
}
}
assert(false);
}
void tlist::signal_handler_left_button_click(
tgrid* grid
, const event::tevent event)
{
DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
assert(grid);
assert(generator_);
/** @todo Test the proper state to set. */
for(size_t i = 0; i < generator_->get_item_count(); ++i) {
if(&generator_->item(i) == grid) {
generator_->select_item(i);
fire(event::NOTIFY_MODIFIED, *this, NULL);
}
}
}
void tlist::signal_handler_sdl_key_down(const event::tevent event
, bool& handled
, const SDLKey key
, SDLMod modifier)
{
DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
if(handled) {
return;
}
switch(key) {
case SDLK_UP :
generator_->handle_key_up_arrow(modifier, handled);
break;
case SDLK_DOWN :
generator_->handle_key_down_arrow(modifier, handled);
break;
case SDLK_LEFT :
generator_->handle_key_left_arrow(modifier, handled);
break;
case SDLK_RIGHT :
generator_->handle_key_right_arrow(modifier, handled);
break;
default : ;
/* Do nothing. */
}
if(handled) {
fire(event::NOTIFY_MODIFIED, *this, NULL);
}
}
} // namespace gui2
#endif

299
src/gui/widgets/list.hpp Normal file
View file

@ -0,0 +1,299 @@
/* $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_WIDGETS_LIST_HPP_INCLUDED
#define GUI_WIDGETS_LIST_HPP_INCLUDED
#ifdef GUI2_EXPERIMENTAL_LISTBOX
#include "gui/widgets/generator.hpp"
#include "gui/widgets/scrollbar_container.hpp"
namespace gui2 {
/**
* The list class.
*
* For now it's a generic for all kind of lists, horizontal, vertical etc.
* Might be that there will be different types per class, not sure yet.
*/
class tlist
: public tcontainer_
{
friend class tdebug_layout_graph;
public:
/**
* 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.
*/
tlist(const bool has_minimum
, const bool has_maximum
, const tgenerator_::tplacement placement
, const bool select
, const tbuilder_grid_const_ptr list_builder);
/***** ***** ***** ***** Row handling. ***** ***** ****** *****/
/**
* When an item in the list is selected by the user we need to
* update the state. We installed a callback handler which
* calls us.
*
* @param item The data send to the set_members of the
* widgets.
* @param index The item before which to add the new item,
* 0 == begin, -1 == end.
*/
void add_row(const string_map& item, const int index = -1);
/**
* Adds single row to the grid.
*
* This function expect a row to have multiple widgets (either multiple
* columns or one column with multiple widgets).
*
*
* @param data The data to send to the set_members of the
* widgets. If the member id is not an empty
* string it is only send to the widget that has
* the wanted id (if any). If the member id is an
* empty string, it is send to all members.
* Having both empty and non-empty id's gives
* undefined behaviour.
* @param index The item before which to add the new item,
* 0 == begin, -1 == end.
*/
void add_row(
const std::map<std::string /* widget id */, string_map>& data
, const int index = -1);
/**
* Appends several rows to the grid.
*
* @param items The data to send to the set_members of the
* widgets.
*/
void append_rows(const std::vector<string_map>& items);
/**
* Removes a row in the listbox.
*
* @param row The row to remove, when not in
* range the function is ignored.
* @param count The number of rows to remove, 0 means all
* rows (starting from row).
*/
void remove_row(const unsigned row, unsigned count = 1);
/** Removes all the rows in the listbox, clearing it. */
void clear();
/** Returns the number of items in the listbox. */
unsigned get_item_count() const;
/**
* Makes a row active or inactive.
*
* NOTE this doesn't change the select status of the row.
*
* @param row The row to (de)activate.
* @param active true activate, false deactivate.
*/
void set_row_active(const unsigned row, const bool active);
/**
* Makes a row visible or invisible.
*
* @param row The row to show or hide.
* @param shown true visible, false invisible.
*/
void set_row_shown(const unsigned row, const bool shown);
/**
* Makes a row visible or invisible.
*
* Use this version if you want to show hide multiple items since it's
* optimized for that purpose, for one it calls the selection changed
* callback only once instead of serveral times.
*
* @param shown A vector with the show hide status for every
* row. The number of items in the vector must
* be equal to the number of items in the
* listbox.
*/
void set_row_shown(const std::vector<bool>& shown);
/**
* Returns the grid of the wanted row.
*
* There's only a const version since allowing callers to modify the grid
* behind our backs might give problems. We return a pointer instead of a
* reference since dynamic casting of pointers is easier (no try catch
* needed).
*
* @param row The row to get the grid from, the caller has
* to make sure the row is a valid row.
* @returns The grid of the wanted row.
*/
const tgrid* get_row_grid(const unsigned row) const;
/**
* The possibly-giving-problems nonconst version of get_row_grid
*
* @param row The row to get the grid from, the caller has
* to make sure the row is a valid row.
* @returns The grid of the wanted row.
*/
tgrid* get_row_grid(const unsigned row);
/**
* Selectes a row.
*
* @param row The row to select.
* @param select Select or deselect the row.
*/
bool select_row(const unsigned row, const bool select = true);
/**
* Returns the first selected row
*
* @returns The first selected row.
* @retval -1 No row selected.
*/
int get_selected_row() const;
#if 0
/**
* Request to update the size of the content after changing the content.
*
* When a resize is required the container first can try to handle it
* itself. If it can't honour the request the function will call @ref
* twindow::invalidate_layout().
*
* @note Calling this function on a widget with size == (0, 0) results
* false but doesn't call invalidate_layout, the engine expects to be in
* build up phase with the layout already invalidated.
*
* @returns True if the resizing succeeded, false
* otherwise.
*/
bool update_content_size();
#endif
/***** ***** ***** ***** inherited ***** ***** ****** *****/
/** Inherited from tcontrol_. */
void init();
/** Inherited from tcontainer_. */
bool get_active() const { return state_ != DISABLED; }
/** Inherited from tcontainer_. */
unsigned get_state() const { return state_; }
/** Inherited from tscrollbar_container. */
void place(const tpoint& origin, const tpoint& size);
private:
/**
* Possible states of the widget.
*
* Note the order of the states must be the same as defined in settings.hpp.
*/
enum tstate { ENABLED, DISABLED, COUNT };
/**
* Current state of the widget.
*
* The state of the widget determines what to render and how the widget
* reacts to certain 'events'.
*/
tstate state_;
/**
* Contains a pointer to the generator.
*
* The pointer is not owned by this class, it's stored in the content_grid_
* of the tscrollbar_container super class and freed when it's grid is
* freed.
*/
tgenerator_* generator_;
/** Contains the builder for the new items. */
tbuilder_grid_const_ptr list_builder_;
bool need_layout_;
#if 0
/**
* Resizes the content.
*
* The resize either happens due to resizing the content or invalidate the
* layout of the window.
*
* @param width_modification The wanted modification to the width:
* * negative values reduce width.
* * zero leave width as is.
* * positive values increase width.
* @param height_modification The wanted modification to the height:
* * negative values reduce height.
* * zero leave height as is.
* * positive values increase height.
*/
void resize_content(
const int width_modification
, const int height_modification);
#endif
/** Layouts the children if needed. */
void layout_children(const bool force);
#if 0
/** Inherited from tscrollbar_container. */
virtual void set_content_size(const tpoint& origin, const tpoint& size);
#endif
/** Inherited from tcontainer_. */
void set_self_active(const bool) {}
/** Inherited from tcontrol. */
const std::string& get_control_type() const;
/***** ***** ***** signal handlers ***** ****** *****/
void signal_handler_left_button_down(const event::tevent event);
void signal_handler_pre_child_left_button_click(
tgrid* grid
, const event::tevent event
, bool& handled
, bool& halt);
void signal_handler_left_button_click(
tgrid* grid
, const event::tevent event);
void signal_handler_sdl_key_down(const event::tevent event
, bool& handled
, const SDLKey key
, SDLMod modifier);
};
typedef tlist tlistbox;
} // namespace gui2
#endif
#endif

View file

@ -12,6 +12,8 @@
See the COPYING file for more details.
*/
#ifndef GUI2_EXPERIMENTAL_LISTBOX
#define GETTEXT_DOMAIN "wesnoth-lib"
#include "gui/widgets/listbox.hpp"
@ -521,3 +523,4 @@ const std::string& tlistbox::get_control_type() const
}
} // namespace gui2
#endif

View file

@ -15,6 +15,8 @@
#ifndef GUI_WIDGETS_LISTBOX_HPP_INCLUDED
#define GUI_WIDGETS_LISTBOX_HPP_INCLUDED
#ifndef GUI2_EXPERIMENTAL_LISTBOX
#include "gui/widgets/generator.hpp"
#include "gui/widgets/scrollbar_container.hpp"
@ -311,4 +313,5 @@ private:
} // namespace gui2
#endif
#endif

View file

@ -43,7 +43,9 @@ class tscrollbar_container
friend struct implementation::tbuilder_scroll_label;
friend struct implementation::tbuilder_scrollbar_panel;
#ifndef GUI2_EXPERIMENTAL_LISTBOX
friend class tlistbox;
#endif
friend class ttree_view;
friend struct tscrollbar_container_implementation;

View file

@ -495,7 +495,14 @@ tresolution_definition_ptr get_control(
const std::string& control_type, const std::string& definition)
{
const tgui_definition::tcontrol_definition_map::const_iterator
control_definition = current_gui->second.control_definition.find(control_type);
#ifdef GUI2_EXPERIMENTAL_LISTBOX
control_definition = (control_type == "list")
? current_gui->second.control_definition.find("listbox")
: current_gui->second.control_definition.find(control_type);
#else
control_definition =
current_gui->second.control_definition.find(control_type);
#endif
ASSERT_LOG(control_definition != current_gui->second.control_definition.end(),
"Type '" << control_type << "' is unknown.");