Rewrote the listbox class.

Now uses the scrollbar container as base and the generator for its
items. The scrolling doesn't work properly yet.
This commit is contained in:
Mark de Wever 2008-12-24 16:01:02 +00:00
parent 0fa63be839
commit a963d007a0
11 changed files with 576 additions and 7 deletions

View file

@ -8,7 +8,11 @@
###
[listbox_definition]
#ifdef NEW_DRAW
id = "default-do_not_use"
#else
id = "default"
#endif
description = "a listbox"
[resolution]
@ -150,3 +154,170 @@
[/listbox_definition]
#ifdef NEW_DRAW
#define _GUI_RESOLUTION RESOLUTION FONT_SIZE FONT_STYLE FONT_COLOUR_ENABLED FONT_COLOUR_DISABLED
[resolution]
{RESOLUTION}
min_width = 0
min_height = 0
default_width = 0
default_height = 0
max_width = 0
max_height = 0
text_font_size = {FONT_SIZE}
text_font_style = {FONT_STYLE}
[state_enabled]
full_redraw = "true"
[draw]
[/draw]
[/state_enabled]
[state_disabled]
full_redraw = "true"
[draw]
[/draw]
[/state_disabled]
[grid]
[row]
grow_factor = 1
[column]
grow_factor = 1
horizontal_grow = "true" # needed ?
vertical_grow = "true" # needed ?
[grid]
id = "_content_grid"
[row]
grow_factor = 1
[column]
grow_factor = 1
horizontal_grow = "true"
[grid]
id = "_header_grid"
[/grid]
[/column]
[/row]
[row]
[column]
horizontal_grow = "true"
vertical_grow = "true"
[grid]
id = "_list_grid"
[/grid]
[/column]
[/row]
[row]
[column]
horizontal_grow = "true"
[grid]
id = "_footer_grid"
[/grid]
[/column]
[/row]
[/grid]
[/column]
[column]
grow_factor = 0
{GUI__VERTICAL_SCROLLBAR_GRID}
[/column]
[/row]
[row]
grow_factor = 0
[column]
{GUI__HORIZONTAL_SCROLLBAR_GRID}
[/column]
[column]
[spacer]
[/spacer]
[/column]
[/row]
[/grid]
[/resolution]
#enddef
[listbox_definition]
id = "default"
# id = "test"
description = "Testing version."
{_GUI_RESOLUTION
({GUI_TINY__RESOLUTION})
({GUI_TINY__FONT_SIZE__DEFAULT})
()
({GUI__FONT_COLOUR_ENABLED__DEFAULT})
({GUI__FONT_COLOUR_DISABLED__DEFAULT})
}
{_GUI_RESOLUTION
({GUI_NORMAL__RESOLUTION})
({GUI_NORMAL__FONT_SIZE__DEFAULT})
()
({GUI__FONT_COLOUR_ENABLED__DEFAULT})
({GUI__FONT_COLOUR_DISABLED__DEFAULT})
}
[/listbox_definition]
#undef _GUI_RESOLUTION
#endif

View file

@ -101,7 +101,11 @@
[listbox]
id = "method_list"
#ifdef NEW_DRAW
definition = "test"
#else
definition = "default"
#endif
vertical_scrollbar_mode = "never"
assume_fixed_row_size = "true"

View file

@ -66,8 +66,11 @@
[listbox]
id = "server_list"
#ifdef NEW_DRAW
definition = "test"
#else
definition = "default"
#endif
assume_fixed_row_size = "true"
[header]

View file

@ -67,7 +67,8 @@ void tlanguage_selection::post_show(twindow& window)
tlistbox* list = dynamic_cast<tlistbox*>(window.find_widget("language_list", false));
assert(list);
const unsigned res = list->get_selected_row();
const int res = list->get_selected_row();
assert(res != -1);
const std::vector<language_def>& languages = get_languages();
::set_language(languages[res]);

View file

@ -21,6 +21,7 @@
#include "gui/widgets/vertical_scrollbar_container.hpp"
#ifdef NEW_DRAW
#include "gui/widgets/generator.hpp"
#include "gui/widgets/listbox.hpp"
#include "gui/widgets/scrollbar_container.hpp"
#endif
#include "gui/widgets/window.hpp"
@ -225,6 +226,11 @@ void tdebug_layout_graph::widget_generate_info(std::ostream& out,
<< " [label=\"(content)\"];\n";
}
const tlistbox* listbox = dynamic_cast<const tlistbox*>(widget);
if(listbox) {
assert(listbox->generator_);
}
const tgenerator_* generator =
dynamic_cast<const tgenerator_*>(widget);

View file

@ -14,14 +14,19 @@
#include "gui/widgets/listbox.hpp"
#ifndef NEW_DRAW
#include "foreach.hpp"
#include "gui/widgets/scrollbar.hpp"
#include "gui/widgets/toggle_button.hpp"
#include "gui/widgets/toggle_panel.hpp"
#endif
#include "gui/widgets/window.hpp"
namespace gui2 {
#ifndef NEW_DRAW
static void callback_select_list_item(twidget* caller)
{
get_parent<tlistbox>(caller)->list_item_selected(caller);
@ -627,4 +632,184 @@ const twidget* tlistbox::content_find_widget(
tpoint(coordinate.x, offset), must_be_active);
}
#else
namespace {
void callback_list_item_clicked(twidget* caller)
{
get_parent<tlistbox>(caller)->list_item_clicked(caller);
}
} // namespace
tlistbox::tlistbox(const bool has_minimum, const bool has_maximum,
const tgenerator_::tplacement placement, const bool select)
: tscrollbar_container(2) // FIXME magic number
, generator_(NULL)
, list_builder_(NULL)
{
generator_ = tgenerator_::build(
has_minimum, has_maximum, placement, select);
}
void tlistbox::add_row(const string_map& item)
{
assert(generator_);
generator_->create_item(
-1, list_builder_, item, callback_list_item_clicked);
}
void tlistbox::add_row(
const std::map<std::string /* widget id */, string_map>& data)
{
assert(generator_);
generator_->create_item(
-1, list_builder_, data, callback_list_item_clicked);
}
unsigned tlistbox::get_item_count() const
{
assert(generator_);
return generator_->get_item_count();
}
void tlistbox::set_row_active(const unsigned row, const bool active)
{
assert(generator_);
generator_->get_item(row).set_active(active);
}
const tgrid* tlistbox::get_row_grid(const unsigned row) const
{
assert(generator_);
// rename this function and can we return a reference??
return &generator_->get_item(row);
}
bool tlistbox::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 tlistbox::get_selected_row() const
{
assert(generator_);
return generator_->get_selected_item();
}
twidget* tlistbox::find_widget(
const tpoint& coordinate, const bool must_be_active)
{
twidget* result =
generator_->find_widget(coordinate, must_be_active);
return result
? result
// Inherited.
: tscrollbar_container::find_widget(coordinate, must_be_active);
}
const twidget* tlistbox::find_widget(
const tpoint& coordinate, const bool must_be_active) const
{
const twidget* result =
generator_->find_widget(coordinate, must_be_active);
return result
? result
// Inherited.
: tscrollbar_container::find_widget(coordinate, must_be_active);
}
void tlistbox::list_item_clicked(twidget* caller)
{
assert(caller);
assert(generator_);
/** @todo Hack to capture the keyboard focus. */
get_window()->keyboard_capture(this);
for(size_t i = 0; i < generator_->get_item_count(); ++i) {
if(generator_->get_item(i).has_widget(caller)) {
generator_->toggle_item(i);
return;
}
}
assert(false);
}
void tlistbox::child_populate_dirty_list(twindow& caller,
const std::vector<twidget*>& call_stack)
{
// Inherited.
tscrollbar_container::child_populate_dirty_list(caller, call_stack);
assert(generator_);
std::vector<twidget*> child_call_stack = call_stack;
generator_->populate_dirty_list(caller, child_call_stack);
}
namespace {
/**
* Swaps an item in a grid for another one.*/
void swap_grid(tgrid* grid,
tgrid* content_grid, twidget* widget, const std::string& id)
{
assert(content_grid);
assert(widget);
// Get the container containing the wanted widget.
tgrid* parent_grid = NULL;
if(grid) {
parent_grid = grid->find_widget<tgrid>(id, false, false);
}
if(!parent_grid) {
parent_grid = content_grid->find_widget<tgrid>(id, true, false);
}
parent_grid = dynamic_cast<tgrid*>(parent_grid->parent());
assert(parent_grid);
// Replace the child.
widget = parent_grid->swap_child(id, widget, false);
assert(widget);
delete widget;
}
} // namespace
void tlistbox::finalize(
tbuilder_grid_const_ptr header,
tbuilder_grid_const_ptr footer,
const std::vector<string_map>& list_data)
{
// "Inherited."
tscrollbar_container::finalize_setup();
assert(generator_);
if(header) {
swap_grid(&grid(), content_grid(), header->build(), "_header_grid");
}
if(footer) {
swap_grid(&grid(), content_grid(), footer->build(), "_footer_grid");
}
generator_->create_items(
-1, list_builder_, list_data, callback_list_item_clicked);
swap_grid(NULL, content_grid(), generator_, "_list_grid");
}
#endif
} // namespace gui2

View file

@ -15,11 +15,18 @@
#ifndef GUI_WIDGETS_LISTBOX_HPP_INCLUDED
#define GUI_WIDGETS_LISTBOX_HPP_INCLUDED
#ifndef NEW_DRAW
#include "tstring.hpp"
#include "gui/widgets/vertical_scrollbar_container.hpp"
#else
#include "gui/widgets/generator.hpp"
#include "gui/widgets/scrollbar_container.hpp"
#endif
namespace gui2 {
#ifndef NEW_DRAW
class tspacer;
/**
@ -371,6 +378,161 @@ private:
const bool must_be_active) const;
};
#else
/** The listbox class. */
class tlistbox
: public tscrollbar_container
{
friend class tbuilder_listbox;
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.
*/
tlistbox(const bool has_minimum, const bool has_maximum,
const tgenerator_::tplacement placement, const bool select);
/***** ***** ***** ***** 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.
*/
void add_row(const string_map& item);
/**
* 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.
*/
void add_row(const std::map<std::string /* widget id */,
string_map>& data);
/** 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 select true activate, false deactivate.
*/
void set_row_active(const unsigned row, const bool active);
/**
* 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;
/**
* 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;
/** Function to call after the user clicked on a row. */
void list_item_clicked(twidget* caller);
/** Inherited from tcontainer_. */
void set_self_active(const bool /*active*/) {}
// { state_ = active ? ENABLED : DISABLED; }
//
/***** ***** ***** ***** inherited ***** ***** ****** *****/
/** Inherited from tscrollbar_container. */
twidget* find_widget(
const tpoint& coordinate, const bool must_be_active);
/** Inherited from tscrollbar_container. */
const twidget* find_widget(
const tpoint& coordinate, const bool must_be_active) const;
/** Import overloaded versions. */
using tscrollbar_container::find_widget;
/** Inherited from tscrollbar_container. */
void child_populate_dirty_list(twindow& caller,
const std::vector<twidget*>& call_stack);
/***** ***** ***** setters / getters for members ***** ****** *****/
// FIXME implement
void set_callback_value_change(void (*) (twidget* caller)) {}
void set_list_builder(tbuilder_grid_ptr list_builder)
{ list_builder_ = list_builder; }
private:
/**
* Finishes the building initialization of the widget.
*
* @param header Builder for the header.
* @param footer Builder for the footer.
* @param list_data The initial data to fill the listbox with.
*/
void finalize(
tbuilder_grid_const_ptr header,
tbuilder_grid_const_ptr footer,
const std::vector<string_map>& list_data);
/**
* Contains a pointer to the generator.
*
* The pointer is not owned by this variable.
*/
tgenerator_* generator_;
/** Contains the builder for the new items. */
tbuilder_grid_const_ptr list_builder_;
/** Inherited from tcontrol. */
const std::string& get_control_type() const
{ static const std::string type = "listbox"; return type; }
};
#endif
} // namespace gui2
#endif

View file

@ -42,6 +42,7 @@ class tscrollbar_container
friend class tdebug_layout_graph;
friend struct tbuilder_scroll_label;
friend class tlistbox;
public:

View file

@ -644,7 +644,11 @@ tlistbox_definition::tlistbox_definition(const config& cfg) :
tlistbox_definition::tresolution::tresolution(const config& cfg) :
tresolution_definition_(cfg),
#ifndef NEW_DRAW
scrollbar(0)
#else
grid(NULL)
#endif
{
/*WIKI
@ -700,10 +704,21 @@ tlistbox_definition::tresolution::tresolution(const config& cfg) :
state.push_back(tstate_definition(cfg.child("state_enabled")));
state.push_back(tstate_definition(cfg.child("state_disabled")));
#ifndef NEW_DRAW
const config* grid = cfg.child("scrollbar");
VALIDATE(grid, _("No scrollbar defined."));
scrollbar = new tbuilder_grid(*grid);
#else
const config* child = cfg.child("grid");
if(child) { // HACK needed to support old grids
VALIDATE(child, _("No grid defined."));
grid = new tbuilder_grid(*child);
}
#endif
}
tmenubar_definition::tmenubar_definition(const config& cfg) :

View file

@ -205,8 +205,11 @@ struct tlistbox_definition : public tcontrol_definition
tresolution(const config& cfg);
// NOTE maybe we need the borders...
#ifndef NEW_DRAW
tbuilder_grid_ptr scrollbar;
#else
tbuilder_grid_ptr grid;
#endif
};
};

View file

@ -21,6 +21,9 @@
#include "gui/widgets/image.hpp"
#include "gui/widgets/label.hpp"
#include "gui/widgets/listbox.hpp"
#ifdef NEW_DRAW
#include "gui/widgets/generator.hpp"
#endif
#include "gui/widgets/minimap.hpp"
#include "gui/widgets/scroll_label.hpp"
#include "gui/widgets/slider.hpp"
@ -763,21 +766,35 @@ tbuilder_listbox::tbuilder_listbox(const config& cfg) :
twidget* tbuilder_listbox::build() const
{
#ifndef NEW_DRAW
tlistbox *listbox = new tlistbox();
#else
tlistbox *listbox = new tlistbox(
true, true, tgenerator_::vertical_list, true);
#endif
init_control(listbox);
listbox->set_list_builder(list_builder);
listbox->set_list_builder(list_builder); // FIXME in finalize???
#ifndef NEW_DRAW
listbox->set_assume_fixed_row_size(assume_fixed_row_size);
listbox->set_scrollbar_mode(scrollbar_mode);
#else
// scrollbar mode
#endif
DBG_GUI << "Window builder: placed listbox '" << id << "' with defintion '"
<< definition << "'.\n";
boost::intrusive_ptr<const tlistbox_definition::tresolution> conf =
boost::dynamic_pointer_cast<const tlistbox_definition::tresolution>(listbox->config());
boost::dynamic_pointer_cast
<const tlistbox_definition::tresolution>(listbox->config());
assert(conf);
#ifdef NEW_DRAW
conf->grid->build(&listbox->grid());
listbox->finalize(header, footer, list_data);
#else
/*
* We generate the following items to put in the listbox grid
* - _scrollbar_grid the grid containing the scrollbar.
@ -856,6 +873,7 @@ twidget* tbuilder_listbox::build() const
}
listbox->finalize_setup();
#endif
return listbox;
}