Refactoring the listbox.
Added the option to show or hide the scrollbar. Moved the sizing code to the tvertical_scrollbar_container_ class which will query the listbox to as it for the best size for the list.
This commit is contained in:
parent
2bf9f805c4
commit
b721f865f2
8 changed files with 645 additions and 329 deletions
|
@ -103,6 +103,7 @@
|
|||
id = "method_list"
|
||||
definition = "default"
|
||||
|
||||
vertical_scrollbar_mode = "never"
|
||||
assume_fixed_row_size = "true"
|
||||
|
||||
[list_definition]
|
||||
|
|
|
@ -261,6 +261,17 @@ tline::tline(const config& cfg) :
|
|||
* @* all alias for "left, right, top,
|
||||
* bottom"
|
||||
*
|
||||
* scrollbar_mode How to show the scrollbar of a widget.
|
||||
* Possible values:
|
||||
* @* always The scrollbar is always shown,
|
||||
* regardless whether it's required or not.
|
||||
* @* never The scrollbar is never shown,
|
||||
* even not when needed. (Note when setting
|
||||
* this mode dialogs might not properly fit
|
||||
* anymore).
|
||||
* @* auto Shows the scrollbar when
|
||||
* needed. The widget will reserve space for
|
||||
* the scrollbar, but only show when needed.
|
||||
* @end_table
|
||||
*/
|
||||
|
||||
|
|
|
@ -61,9 +61,7 @@ tlistbox::tlistbox() :
|
|||
row_select_(true),
|
||||
must_select_(true),
|
||||
multi_select_(false),
|
||||
list_rect_(),
|
||||
list_background_(),
|
||||
best_spacer_size_(0, 0),
|
||||
rows_()
|
||||
{
|
||||
}
|
||||
|
@ -127,7 +125,6 @@ void tlistbox::add_row(const std::map<std::string /* widget id */, std::map<
|
|||
foreach(trow& row, rows_) {
|
||||
height += row.get_height();
|
||||
}
|
||||
std::cerr << "Items " << height << ".\n";
|
||||
find_scrollbar()->set_item_count(height);
|
||||
}
|
||||
|
||||
|
@ -169,219 +166,6 @@ void tlistbox::mouse_left_button_down(tevent_handler& event)
|
|||
event.keyboard_capture(this);
|
||||
}
|
||||
|
||||
tpoint tlistbox::get_best_size(const tpoint& maximum_size) const
|
||||
{
|
||||
log_scope2(gui, "Listbox: Get best size");
|
||||
|
||||
tpoint best_size = get_best_size();
|
||||
|
||||
// We can only reduce our height so we ignore the x value.
|
||||
// NOTE we might later be able to reduce our width as well, but that's
|
||||
// something for later, also we don't ask our children for a better value.
|
||||
if(best_size.y <= maximum_size.y) {
|
||||
return best_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @todo At this point we should check whether maximum_size is larger as
|
||||
* the minimum size for the widget (the scrollbar) and adjust accordingly.
|
||||
*/
|
||||
tpoint max = maximum_size;
|
||||
|
||||
if(assume_fixed_row_size_) {
|
||||
// Only adjust the sizes if we have some rows
|
||||
if(rows_.size() > 0) {
|
||||
// The row might not have a size, since it might never been set
|
||||
// so ask the best size.
|
||||
const unsigned row_height = (*rows_[0].grid()).get_best_size().y;
|
||||
best_size.y = (max.y / row_height) * row_height;
|
||||
}
|
||||
|
||||
} else {
|
||||
best_size.y = max.y;
|
||||
}
|
||||
|
||||
DBG_G << "Grid : maximum size "
|
||||
<< maximum_size << " returning " << best_size << ".\n";
|
||||
|
||||
return best_size;
|
||||
}
|
||||
|
||||
tpoint tlistbox::get_best_size() const
|
||||
{
|
||||
// Set the size of the spacer to the wanted size for the list.
|
||||
unsigned width = 0;
|
||||
unsigned height = 0;
|
||||
|
||||
if(best_spacer_size_ != tpoint(0, 0)) {
|
||||
// We got a best size set use that instead of calculating it.
|
||||
height = best_spacer_size_.y;
|
||||
width = best_spacer_size_.x;
|
||||
} else {
|
||||
// NOTE we should look at the number of visible items etc
|
||||
foreach(const trow& row, rows_) {
|
||||
assert(row.grid());
|
||||
const tpoint best_size = row.grid()->get_best_size();
|
||||
width = (static_cast<int>(width) >= best_size.x) ?
|
||||
width : static_cast<int>(best_size.x);
|
||||
|
||||
height += static_cast<int>(best_size.y);
|
||||
}
|
||||
}
|
||||
|
||||
// Kind of a hack, we edit the spacer in a const function.
|
||||
// Of course we could cache the list and make it mutable instead.
|
||||
// But since the spacer is a kind of cache the const_cast doesn't
|
||||
// look too ugly.
|
||||
const_cast<tspacer*>(list())->set_best_size(tpoint(width, height));
|
||||
|
||||
// Now the container will return the wanted result.
|
||||
return tcontainer_::get_best_size();
|
||||
}
|
||||
|
||||
void tlistbox::draw(surface& surface, const bool force,
|
||||
const bool invalidate_background)
|
||||
{
|
||||
// Inherited.
|
||||
tcontainer_::draw(surface, force, invalidate_background);
|
||||
|
||||
if(invalidate_background) {
|
||||
list_background_.assign(NULL);
|
||||
}
|
||||
|
||||
// Handle our full redraw for the spacer area.
|
||||
if(!list_background_) {
|
||||
list_background_.assign(gui2::save_background(surface, list_rect_));
|
||||
} else {
|
||||
gui2::restore_background(list_background_, surface, list_rect_);
|
||||
}
|
||||
|
||||
// Now paint the list over the spacer.
|
||||
if(assume_fixed_row_size_) {
|
||||
draw_list_area_fixed_row_height(surface, force, invalidate_background);
|
||||
} else {
|
||||
draw_list_area_variable_row_height(
|
||||
surface, force, invalidate_background);
|
||||
}
|
||||
}
|
||||
|
||||
twidget* tlistbox::find_widget(const tpoint& coordinate, const bool must_be_active)
|
||||
{
|
||||
// Inherited
|
||||
twidget* result = tcontainer_::find_widget(coordinate, must_be_active);
|
||||
|
||||
// if on the panel we need to do special things.
|
||||
if(result && result->id() == "_list") {
|
||||
int offset = 0;
|
||||
const size_t row = row_at_offset(coordinate.y - list_rect_.y, offset);
|
||||
|
||||
if(row == static_cast<size_t>(-1)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
assert(row < rows_.size());
|
||||
assert(rows_[row].grid());
|
||||
return rows_[row].grid()->find_widget(
|
||||
tpoint(coordinate.x - list_rect_.x, offset), must_be_active);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const twidget* tlistbox::find_widget(
|
||||
const tpoint& coordinate, const bool must_be_active) const
|
||||
{
|
||||
// Inherited
|
||||
const twidget* result = tcontainer_::find_widget(coordinate, must_be_active);
|
||||
|
||||
// if on the panel we need to do special things.
|
||||
if(result && result->id() == "_list") {
|
||||
int offset = 0;
|
||||
const size_t row = row_at_offset(coordinate.y - list_rect_.y, offset);
|
||||
|
||||
if(row == static_cast<size_t>(-1)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
assert(row < rows_.size());
|
||||
assert(rows_[row].grid());
|
||||
return rows_[row].grid()->find_widget(
|
||||
tpoint(coordinate.x - list_rect_.x, offset), must_be_active);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void tlistbox::set_size(const SDL_Rect& rect)
|
||||
{
|
||||
// Since we allow to be resized we need to determine the real size we get.
|
||||
assert(best_spacer_size_ == tpoint(0, 0));
|
||||
SDL_Rect best_rect = rect;
|
||||
if(rows_.size()) {
|
||||
|
||||
const tpoint best_size = get_best_size();
|
||||
|
||||
if(best_size.y > rect.h) {
|
||||
best_spacer_size_ = list()->get_best_size();
|
||||
best_spacer_size_.y -= (best_size.y - rect.h);
|
||||
if(assume_fixed_row_size_) {
|
||||
const unsigned row_height = rows_[0].grid()->get_best_size().y;
|
||||
const unsigned orig_height = best_spacer_size_.y;
|
||||
best_spacer_size_.y =
|
||||
(best_spacer_size_.y / row_height) * row_height;
|
||||
|
||||
best_rect.h -= (orig_height - best_spacer_size_.y);
|
||||
}
|
||||
// This call is required to update the best size.
|
||||
get_best_size();
|
||||
}
|
||||
}
|
||||
|
||||
// Inherit.
|
||||
tcontainer_::set_size(best_rect);
|
||||
|
||||
// Now set the items in the spacer.
|
||||
tspacer* spacer = list();
|
||||
list_rect_ = spacer->get_rect();
|
||||
|
||||
unsigned total_height = 0;
|
||||
foreach(trow& row, rows_) {
|
||||
assert(row.grid());
|
||||
|
||||
const unsigned height = row.grid()->get_best_size().y;
|
||||
row.set_height(height);
|
||||
|
||||
row.grid()->set_size(::create_rect(0, 0, list_rect_.w, height));
|
||||
row.canvas().assign(create_neutral_surface(list_rect_.w, height));
|
||||
|
||||
total_height += height;
|
||||
}
|
||||
if(!assume_fixed_row_size_) {
|
||||
find_scrollbar()->set_item_count(total_height);
|
||||
}
|
||||
|
||||
if(rows_.size() > 0) {
|
||||
if(assume_fixed_row_size_) {
|
||||
const unsigned row_height = rows_[0].get_height();
|
||||
if(row_height) {
|
||||
const unsigned rows = list()->get_best_size().y / row_height;
|
||||
find_scrollbar()->set_visible_items(rows);
|
||||
} else {
|
||||
WRN_G << "Listbox row 0 has no height, making all rows visible.\n";
|
||||
find_scrollbar()->set_visible_items(rows_.size());
|
||||
}
|
||||
} else {
|
||||
find_scrollbar()->set_visible_items(best_spacer_size_.y);
|
||||
}
|
||||
} else {
|
||||
find_scrollbar()->set_visible_items(1);
|
||||
}
|
||||
set_scrollbar_button_status();
|
||||
|
||||
// Clear for next run.
|
||||
best_spacer_size_ = tpoint(0, 0);
|
||||
}
|
||||
|
||||
bool tlistbox::select_row(const unsigned row, const bool select)
|
||||
{
|
||||
if(!select && must_select_ && selection_count_ < 2) {
|
||||
|
@ -412,22 +196,6 @@ bool tlistbox::select_row(const unsigned row, const bool select)
|
|||
return true;
|
||||
}
|
||||
|
||||
tspacer* tlistbox::list()
|
||||
{
|
||||
tspacer* list =
|
||||
dynamic_cast<tspacer*>(tcontainer_::find_widget("_list", false));
|
||||
assert(list);
|
||||
return list;
|
||||
}
|
||||
|
||||
const tspacer* tlistbox::list() const
|
||||
{
|
||||
const tspacer* list =
|
||||
dynamic_cast<const tspacer*>(tcontainer_::find_widget("_list", false));
|
||||
assert(list);
|
||||
return list;
|
||||
}
|
||||
|
||||
bool tlistbox::list_row_selected(const size_t row, twidget* caller)
|
||||
{
|
||||
assert(rows_[row].grid());
|
||||
|
@ -448,10 +216,22 @@ bool tlistbox::list_row_selected(const size_t row, twidget* caller)
|
|||
return false;
|
||||
}
|
||||
|
||||
tgrid* tlistbox::find_list(const bool must_exist)
|
||||
{
|
||||
tgrid* result = find_widget<tgrid>("_list", false, false);
|
||||
return result ? result : find_content_grid(must_exist);
|
||||
}
|
||||
|
||||
const tgrid* tlistbox::find_list(const bool must_exist) const
|
||||
{
|
||||
const tgrid* result = find_widget<const tgrid>("_list", false, false);
|
||||
return result ? result : find_content_grid(must_exist);
|
||||
}
|
||||
|
||||
void tlistbox::draw_list_area_fixed_row_height(surface& surface,
|
||||
const bool force, const bool invalidate_background)
|
||||
{
|
||||
unsigned offset = list_rect_.y;
|
||||
unsigned offset = find_list()->get_rect().y;
|
||||
for(unsigned i = 0; i < find_scrollbar()->get_visible_items(); ++i) {
|
||||
|
||||
// make sure we stay inside the valid range.
|
||||
|
@ -466,7 +246,8 @@ void tlistbox::draw_list_area_fixed_row_height(surface& surface,
|
|||
|
||||
// draw background
|
||||
const SDL_Rect rect =
|
||||
{list_rect_.x, offset, list_rect_.w, row.get_height() };
|
||||
{find_list()->get_rect().x, offset,
|
||||
find_list()->get_rect().w, row.get_height() };
|
||||
|
||||
// draw widget
|
||||
blit_surface(row.canvas(), 0, surface, &rect);
|
||||
|
@ -483,7 +264,7 @@ void tlistbox::draw_list_area_variable_row_height(surface& surface,
|
|||
const unsigned start = find_scrollbar()->get_item_position();
|
||||
const unsigned end = start + find_scrollbar()->get_visible_items();
|
||||
|
||||
unsigned offset = 0;
|
||||
unsigned offset = find_list()->get_rect().y;
|
||||
foreach(trow& row, rows_) {
|
||||
const unsigned height = row.get_height();
|
||||
|
||||
|
@ -510,8 +291,8 @@ void tlistbox::draw_list_area_variable_row_height(surface& surface,
|
|||
|
||||
// Draw on the surface.
|
||||
SDL_Rect rect = {
|
||||
list_rect_.x,
|
||||
offset + top_cut - start + list_rect_.y,
|
||||
find_list()->get_rect().x,
|
||||
offset + top_cut - start + find_list()->get_rect().y,
|
||||
0,
|
||||
0};
|
||||
|
||||
|
@ -645,5 +426,165 @@ void tlistbox::trow::select_in_grid(tgrid* grid, const bool selected)
|
|||
}
|
||||
}
|
||||
|
||||
} // namespace gui2
|
||||
tpoint tlistbox::get_content_best_size(const tpoint& maximum_size) const
|
||||
{
|
||||
log_scope2(gui, "Listbox: Get best content size with max");
|
||||
|
||||
tpoint best_size = get_content_best_size();
|
||||
|
||||
// We can only reduce our height so we ignore the x value.
|
||||
// NOTE we might later be able to reduce our width as well, but that's
|
||||
// something for later, also we don't ask our children for a better value.
|
||||
if(best_size.y <= maximum_size.y) {
|
||||
return best_size;
|
||||
}
|
||||
|
||||
tpoint max = maximum_size;
|
||||
|
||||
// Adjust for the size of the header and footer.
|
||||
const tpoint base = find_content_grid()->get_best_size();
|
||||
max.y -= base.y;
|
||||
if(base.x > max.x) {
|
||||
max.x = base.x;
|
||||
}
|
||||
|
||||
if(assume_fixed_row_size_) {
|
||||
// Only adjust the sizes if we have some rows
|
||||
if(rows_.size() > 0) {
|
||||
// The row might not have a size, since it might never been set
|
||||
// so ask the best size.
|
||||
const unsigned row_height = (*rows_[0].grid()).get_best_size().y;
|
||||
best_size.y = (max.y / row_height) * row_height;
|
||||
}
|
||||
|
||||
} else {
|
||||
best_size.y = max.y;
|
||||
}
|
||||
|
||||
DBG_G << "Grid : maximum size "
|
||||
<< maximum_size << " returning " << best_size << ".\n";
|
||||
|
||||
return best_size;
|
||||
}
|
||||
|
||||
tpoint tlistbox::get_content_best_size() const
|
||||
{
|
||||
log_scope2(gui, "Listbox: Get best content size");
|
||||
|
||||
// First determine the size wanted for the grid, which is used when header
|
||||
// or footer are used.
|
||||
const tpoint base = find_content_grid()->get_best_size();
|
||||
unsigned width = base.x;
|
||||
unsigned height = base.y;
|
||||
|
||||
// NOTE we should look at the number of visible items etc
|
||||
foreach(const trow& row, rows_) {
|
||||
assert(row.grid());
|
||||
const tpoint best_size = row.grid()->get_best_size();
|
||||
width = (static_cast<int>(width) >= best_size.x) ?
|
||||
width : static_cast<int>(best_size.x);
|
||||
|
||||
height += static_cast<int>(best_size.y);
|
||||
}
|
||||
|
||||
return tpoint(width, height);
|
||||
}
|
||||
|
||||
void tlistbox::set_content_size(const SDL_Rect& rect)
|
||||
{
|
||||
unsigned total_height = 0;
|
||||
foreach(trow& row, rows_) {
|
||||
assert(row.grid());
|
||||
|
||||
const unsigned height = row.grid()->get_best_size().y;
|
||||
row.set_height(height);
|
||||
|
||||
row.grid()->set_size(::create_rect(0, 0, rect.w, height));
|
||||
row.canvas().assign(create_neutral_surface(rect.w, height));
|
||||
|
||||
total_height += height;
|
||||
}
|
||||
if(!assume_fixed_row_size_) {
|
||||
find_scrollbar()->set_item_count(total_height);
|
||||
}
|
||||
|
||||
if(rows_.size() > 0) {
|
||||
if(assume_fixed_row_size_) {
|
||||
const unsigned row_height = rows_[0].get_height();
|
||||
if(row_height) {
|
||||
const unsigned rows = rect.h / row_height;
|
||||
find_scrollbar()->set_visible_items(rows);
|
||||
} else {
|
||||
WRN_G << "Listbox row 0 has no height, making all rows visible.\n";
|
||||
find_scrollbar()->set_visible_items(rows_.size());
|
||||
}
|
||||
} else {
|
||||
find_scrollbar()->set_visible_items(rect.h);
|
||||
}
|
||||
} else {
|
||||
find_scrollbar()->set_visible_items(1);
|
||||
}
|
||||
}
|
||||
|
||||
void tlistbox::draw_content(surface& surface, const bool force,
|
||||
const bool invalidate_background)
|
||||
{
|
||||
// Handle our full redraw for the spacer area.
|
||||
if(!list_background_) {
|
||||
list_background_.assign(
|
||||
gui2::save_background(surface, find_content_grid()->get_rect()));
|
||||
} else {
|
||||
gui2::restore_background(
|
||||
list_background_, surface, find_content_grid()->get_rect());
|
||||
}
|
||||
|
||||
// draw header and footer.
|
||||
find_content_grid()->draw(surface, force, invalidate_background);
|
||||
|
||||
// Now paint the list
|
||||
if(assume_fixed_row_size_) {
|
||||
draw_list_area_fixed_row_height(surface, force, invalidate_background);
|
||||
} else {
|
||||
draw_list_area_variable_row_height(
|
||||
surface, force, invalidate_background);
|
||||
}
|
||||
}
|
||||
|
||||
twidget* tlistbox::find_content_widget(
|
||||
const tpoint& coordinate, const bool must_be_active)
|
||||
{
|
||||
|
||||
int offset = 0;
|
||||
tpoint coord = coordinate;
|
||||
coord.y -= find_list()->get_rect().y - find_content_grid()->get_rect().y;
|
||||
const size_t row = row_at_offset(coord.y, offset);
|
||||
|
||||
if(row == static_cast<size_t>(-1)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
assert(row < rows_.size());
|
||||
assert(rows_[row].grid());
|
||||
return rows_[row].grid()->find_widget(
|
||||
tpoint(coordinate.x, offset), must_be_active);
|
||||
}
|
||||
|
||||
const twidget* tlistbox::find_content_widget(
|
||||
const tpoint& coordinate, const bool must_be_active) const
|
||||
{
|
||||
int offset = 0;
|
||||
tpoint coord = coordinate;
|
||||
coord.y -= find_list()->get_rect().y - find_content_grid()->get_rect().y;
|
||||
const size_t row = row_at_offset(coord.y, offset);
|
||||
|
||||
if(row == static_cast<size_t>(-1)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
assert(row < rows_.size());
|
||||
assert(rows_[row].grid());
|
||||
return rows_[row].grid()->find_widget(
|
||||
tpoint(coordinate.x, offset), must_be_active);
|
||||
}
|
||||
|
||||
} // namespace gui2
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#ifndef GUI_WIDGETS_LISTBOX_HPP_INCLUDED
|
||||
#define GUI_WIDGETS_LISTBOX_HPP_INCLUDED
|
||||
|
||||
#include "tstring.hpp" //NEEDED?
|
||||
#include "tstring.hpp"
|
||||
#include "gui/widgets/vertical_scrollbar_container.hpp"
|
||||
|
||||
namespace gui2 {
|
||||
|
@ -27,6 +27,9 @@ class tspacer;
|
|||
* - Header row + footer row same width as client data.
|
||||
* - Cell or row select.
|
||||
* - Sort at some way.
|
||||
* - Test whether footers work properly.
|
||||
* - More testing with listboxes with their own background.
|
||||
* - client rect is also untested.
|
||||
*
|
||||
* Maybe create two types 1 fixed size and one with a builder to add new rows.
|
||||
*/
|
||||
|
@ -122,29 +125,6 @@ public:
|
|||
/** Inherited from tevent_executor. */
|
||||
void mouse_left_button_down(tevent_handler& event);
|
||||
|
||||
/** Inherited from twidget. */
|
||||
tpoint get_best_size(const tpoint& maximum_size) const;
|
||||
|
||||
/** Inherited from tcontainer_. */
|
||||
tpoint get_best_size() const;
|
||||
|
||||
/** Inherited from tcontainer_. */
|
||||
void draw(surface& surface, const bool force = false,
|
||||
const bool invalidate_background = false);
|
||||
|
||||
/** Inherited from tcontainer_. */
|
||||
twidget* find_widget(const tpoint& coordinate, const bool must_be_active);
|
||||
|
||||
/** Inherited from tcontainer_. */
|
||||
const twidget* find_widget(const tpoint& coordinate,
|
||||
const bool must_be_active) const;
|
||||
|
||||
/** Import overloaded versions. */
|
||||
using tvertical_scrollbar_container_::find_widget;
|
||||
|
||||
/** Inherited from tcontainer_. */
|
||||
void set_size(const SDL_Rect& rect);
|
||||
|
||||
/** Inherited from tcontainer_. */
|
||||
void set_self_active(const bool active)
|
||||
{ state_ = active ? ENABLED : DISABLED; }
|
||||
|
@ -192,12 +172,6 @@ private:
|
|||
*/
|
||||
tbuilder_grid_ptr list_builder_;
|
||||
|
||||
/** Returns the spacer widget which is used to reserve space of the real list. */
|
||||
tspacer* list();
|
||||
|
||||
/** Returns the spacer widget which is used to reserve space of the real list. */
|
||||
const tspacer* list() const;
|
||||
|
||||
/**
|
||||
* Does every row in the listbox have the same height?
|
||||
*
|
||||
|
@ -237,16 +211,38 @@ private:
|
|||
|
||||
/** Multiple items can be selected. */
|
||||
bool multi_select_;
|
||||
|
||||
/** The sizes of the spacer. */
|
||||
SDL_Rect list_rect_;
|
||||
|
||||
/** The background of the list, needed for redrawing. */
|
||||
surface list_background_;
|
||||
|
||||
/** The best size for the spacer, if not set it's calculated. */
|
||||
tpoint best_spacer_size_;
|
||||
/**
|
||||
* The content grid of a list might contain another grid name _list. This
|
||||
* grid must exist if there is a header or footer. This grid marks the
|
||||
* space for the real scrollable area.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @todo evaluate whether the value of the grid needs to be cached as well
|
||||
* as it's size. It would be save since we get notified about a resize.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns the list area.
|
||||
*
|
||||
* If the listbox has no _list grid the _content_grid grid will be returned
|
||||
* instead.
|
||||
*
|
||||
* @param must_exist If true the grid must exist and the
|
||||
* function will fail if that's not the case. If
|
||||
* true the pointer returned is always valid.
|
||||
*
|
||||
* @returns A pointer to the grid or NULL.
|
||||
*/
|
||||
tgrid* find_list(const bool must_exist = true);
|
||||
|
||||
/** The const version. */
|
||||
const tgrid* find_list(const bool must_exist = true) const;
|
||||
|
||||
/**
|
||||
* Draws the list area if assume_fixed_row_size_ is true.
|
||||
*
|
||||
|
@ -345,9 +341,32 @@ private:
|
|||
/** The rows in the listbox. */
|
||||
std::vector<trow> rows_;
|
||||
|
||||
/***** ***** ***** inherited ****** *****/
|
||||
|
||||
/** Inherited from tcontrol. */
|
||||
const std::string& get_control_type() const
|
||||
{ static const std::string type = "listbox"; return type; }
|
||||
|
||||
/** Inherited from tvertical_scrollbar_container_. */
|
||||
tpoint get_content_best_size(const tpoint& maximum_size) const;
|
||||
|
||||
/** Inherited from tvertical_scrollbar_container_. */
|
||||
tpoint get_content_best_size() const;
|
||||
|
||||
/** Inherited from tvertical_scrollbar_container_. */
|
||||
void set_content_size(const SDL_Rect& rect);
|
||||
|
||||
/** Inherited from tvertical_scrollbar_container_. */
|
||||
void draw_content(surface& surface, const bool force = false,
|
||||
const bool invalidate_background = false);
|
||||
|
||||
/** Inherited from tvertical_scrollbar_container_. */
|
||||
twidget* find_content_widget(
|
||||
const tpoint& coordinate, const bool must_be_active);
|
||||
|
||||
/** Inherited from tvertical_scrollbar_container_. */
|
||||
const twidget* find_content_widget(const tpoint& coordinate,
|
||||
const bool must_be_active) const;
|
||||
};
|
||||
|
||||
} // namespace gui2
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "foreach.hpp"
|
||||
#include "gui/widgets/button.hpp"
|
||||
#include "gui/widgets/scrollbar.hpp"
|
||||
#include "gui/widgets/widget.hpp"
|
||||
#include "gui/widgets/window.hpp"
|
||||
#include "log.hpp"
|
||||
|
||||
|
@ -85,6 +86,29 @@ const std::map<std::string, tscrollbar_::tscroll>& scroll_lookup()
|
|||
|
||||
} // namespace
|
||||
|
||||
tvertical_scrollbar_container_::
|
||||
tvertical_scrollbar_container_(const unsigned canvas_count)
|
||||
: tcontainer_(canvas_count)
|
||||
, scrollbar_mode_(SHOW_WHEN_NEEDED)
|
||||
, scrollbar_grid_(NULL)
|
||||
, callback_value_change_(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
tvertical_scrollbar_container_::~tvertical_scrollbar_container_()
|
||||
{
|
||||
delete scrollbar_grid_;
|
||||
}
|
||||
|
||||
void tvertical_scrollbar_container_::
|
||||
set_scrollbar_mode(const tscrollbar_mode scrollbar_mode)
|
||||
{
|
||||
if(scrollbar_mode_ != scrollbar_mode) {
|
||||
scrollbar_mode_ = scrollbar_mode;
|
||||
show_scrollbar(scrollbar_mode_ != HIDE);
|
||||
}
|
||||
}
|
||||
|
||||
void tvertical_scrollbar_container_::key_press(tevent_handler& /*event*/,
|
||||
bool& handled, SDLKey key, SDLMod /*modifier*/, Uint16 /*unicode*/)
|
||||
{
|
||||
|
@ -129,13 +153,16 @@ void tvertical_scrollbar_container_::key_press(tevent_handler& /*event*/,
|
|||
case SDLK_DOWN :
|
||||
|
||||
++row;
|
||||
while(static_cast<size_t>(row) < sb->get_item_count() && !get_item_active(row)) {
|
||||
while(static_cast<size_t>(row) < sb->get_item_count()
|
||||
&& !get_item_active(row)) {
|
||||
|
||||
++row;
|
||||
}
|
||||
if(static_cast<size_t>(row) < sb->get_item_count()) {
|
||||
select_row(row);
|
||||
handled = true;
|
||||
if(static_cast<size_t>(row) >= sb->get_item_position() + sb->get_visible_items()) {
|
||||
if(static_cast<size_t>(row) >= sb->get_item_position()
|
||||
+ sb->get_visible_items()) {
|
||||
|
||||
sb->set_item_position(row + 1 - sb->get_visible_items());
|
||||
set_scrollbar_button_status();
|
||||
|
@ -150,6 +177,129 @@ void tvertical_scrollbar_container_::key_press(tevent_handler& /*event*/,
|
|||
}
|
||||
}
|
||||
|
||||
tpoint tvertical_scrollbar_container_::get_best_size() const
|
||||
{
|
||||
const tpoint content = get_content_best_size();
|
||||
if(scrollbar_mode_ == HIDE) {
|
||||
return content;
|
||||
}
|
||||
|
||||
const tpoint scrollbar = find_scrollbar_grid()->get_best_size();
|
||||
if(scrollbar_mode_ == SHOW) {
|
||||
// We need to show the scrollbar so the biggest height of scrollbar and
|
||||
// content is needed. The width is the sum of them.
|
||||
return tpoint(
|
||||
content.x + scrollbar.x,
|
||||
std::max(content.y, scrollbar.y));
|
||||
}
|
||||
|
||||
// When auto show the height of the content is leading. (Width again the sum.)
|
||||
return tpoint(content.x + scrollbar.x, content.y);
|
||||
}
|
||||
|
||||
tpoint tvertical_scrollbar_container_::get_best_size(const tpoint& maximum_size) const
|
||||
{
|
||||
if(scrollbar_mode_ == HIDE) {
|
||||
// No scrollbar hope the normal size is small enough. Don't send the
|
||||
// maximum_size parameter since then the content 'thinks' there will be
|
||||
// a scrollbar.
|
||||
return get_content_best_size();
|
||||
} else {
|
||||
// The scrollbar also can't be resized so ask the best size.
|
||||
const tpoint scrollbar = find_scrollbar_grid()->get_best_size();
|
||||
const tpoint content = get_content_best_size(tpoint(maximum_size.x - scrollbar.x, maximum_size.y));
|
||||
|
||||
// Width and height same rules as above.
|
||||
if(scrollbar_mode_ == SHOW) {
|
||||
return tpoint(
|
||||
content.x + scrollbar.x,
|
||||
std::max(content.y, scrollbar.y));
|
||||
}
|
||||
return tpoint(content.x + scrollbar.x, content.y);
|
||||
}
|
||||
}
|
||||
|
||||
void tvertical_scrollbar_container_::set_size(const SDL_Rect& rect)
|
||||
{
|
||||
// Inherited. -- note we don't use client size, might change
|
||||
tcontrol::set_size(rect);
|
||||
|
||||
// Test whether we need a scrollbar.
|
||||
bool scrollbar_needed = (scrollbar_mode_ == SHOW);
|
||||
if(scrollbar_mode_ == SHOW_WHEN_NEEDED) {
|
||||
tpoint size = get_content_best_size();
|
||||
scrollbar_needed = size.x > rect.w || size.y > rect.h;
|
||||
}
|
||||
|
||||
if(scrollbar_needed) {
|
||||
|
||||
show_scrollbar(true);
|
||||
|
||||
const tpoint scrollbar = find_scrollbar_grid()->get_best_size();
|
||||
SDL_Rect tmp = rect;
|
||||
tmp.x += tmp.w - scrollbar.x;
|
||||
tmp.w = scrollbar.x;
|
||||
find_scrollbar_grid()->set_size(tmp);
|
||||
|
||||
tmp = rect;
|
||||
tmp.w -= scrollbar.x;
|
||||
find_content_grid()->set_size(tmp);
|
||||
set_content_size(tmp);
|
||||
} else {
|
||||
|
||||
show_scrollbar(false);
|
||||
|
||||
find_content_grid()->set_size(rect);
|
||||
set_content_size(rect);
|
||||
}
|
||||
|
||||
set_scrollbar_button_status();
|
||||
}
|
||||
|
||||
void tvertical_scrollbar_container_::draw(
|
||||
surface& surface, const bool force, const bool invalidate_background)
|
||||
{
|
||||
// Inherited.
|
||||
tcontainer_::draw(surface, force, invalidate_background);
|
||||
|
||||
if(scrollbar_mode_ != HIDE) {
|
||||
draw_content(surface, force, invalidate_background);
|
||||
}
|
||||
draw_content(surface, force, invalidate_background);
|
||||
}
|
||||
|
||||
twidget* tvertical_scrollbar_container_::find_widget(
|
||||
const tpoint& coordinate, const bool must_be_active)
|
||||
{
|
||||
SDL_Rect content = find_content_grid()->get_rect();
|
||||
|
||||
if(point_in_rect(coordinate.x, coordinate.y, content)) {
|
||||
|
||||
return find_content_widget(tpoint(
|
||||
coordinate.x - get_x(), coordinate.y - get_y())
|
||||
, must_be_active);
|
||||
}
|
||||
|
||||
// Inherited
|
||||
return tcontainer_::find_widget(coordinate, must_be_active);
|
||||
}
|
||||
|
||||
const twidget* tvertical_scrollbar_container_::find_widget(
|
||||
const tpoint& coordinate, const bool must_be_active) const
|
||||
{
|
||||
SDL_Rect content = find_content_grid()->get_rect();
|
||||
|
||||
if(point_in_rect(coordinate.x, coordinate.y, content)) {
|
||||
|
||||
return find_content_widget(tpoint(
|
||||
coordinate.x - get_x(), coordinate.y - get_y())
|
||||
, must_be_active);
|
||||
}
|
||||
|
||||
// Inherited
|
||||
return tcontainer_::find_widget(coordinate, must_be_active);
|
||||
}
|
||||
|
||||
void tvertical_scrollbar_container_::value_changed()
|
||||
{
|
||||
if(callback_value_change_) {
|
||||
|
@ -157,15 +307,41 @@ void tvertical_scrollbar_container_::value_changed()
|
|||
}
|
||||
}
|
||||
|
||||
tgrid* tvertical_scrollbar_container_::find_scrollbar_grid(const bool must_exist)
|
||||
{
|
||||
return scrollbar_grid_ ? scrollbar_grid_
|
||||
: find_widget<tgrid>("_scrollbar_grid", false, must_exist);
|
||||
}
|
||||
|
||||
const tgrid* tvertical_scrollbar_container_::
|
||||
find_scrollbar_grid(const bool must_exist) const
|
||||
{
|
||||
return scrollbar_grid_ ? scrollbar_grid_
|
||||
: find_widget<tgrid>("_scrollbar_grid", false, must_exist);
|
||||
}
|
||||
|
||||
tscrollbar_* tvertical_scrollbar_container_::find_scrollbar(const bool must_exist)
|
||||
{
|
||||
return find_widget<tscrollbar_>("_scrollbar", false, must_exist);
|
||||
return static_cast<twidget*>(find_scrollbar_grid())
|
||||
->find_widget<tscrollbar_>("_scrollbar", false, must_exist);
|
||||
}
|
||||
|
||||
const tscrollbar_* tvertical_scrollbar_container_::find_scrollbar(
|
||||
const bool must_exist) const
|
||||
{
|
||||
return find_widget<const tscrollbar_>("_scrollbar", false, must_exist);
|
||||
return static_cast<const twidget*>(find_scrollbar_grid())
|
||||
->find_widget<const tscrollbar_>("_scrollbar", false, must_exist);
|
||||
}
|
||||
|
||||
tgrid* tvertical_scrollbar_container_::find_content_grid(const bool must_exist)
|
||||
{
|
||||
return find_widget<tgrid>("_content_grid", false, must_exist);
|
||||
}
|
||||
|
||||
const tgrid* tvertical_scrollbar_container_::
|
||||
find_content_grid(const bool must_exist) const
|
||||
{
|
||||
return find_widget<tgrid>("_content_grid", false, must_exist);
|
||||
}
|
||||
|
||||
void tvertical_scrollbar_container_::set_scrollbar_button_status()
|
||||
|
@ -195,6 +371,24 @@ void tvertical_scrollbar_container_::set_scrollbar_button_status()
|
|||
!(find_scrollbar()->at_begin() && find_scrollbar()->at_end()));
|
||||
}
|
||||
|
||||
void tvertical_scrollbar_container_::show_scrollbar(const bool show)
|
||||
{
|
||||
if(show && scrollbar_grid_) {
|
||||
|
||||
tgrid* tmp = dynamic_cast<tgrid*>
|
||||
(grid().swap_child("_scrollbar_grid", scrollbar_grid_, true));
|
||||
|
||||
delete tmp;
|
||||
scrollbar_grid_ = NULL;
|
||||
|
||||
} else if(!show && !scrollbar_grid_) {
|
||||
|
||||
tgrid* tmp = new tgrid();
|
||||
scrollbar_grid_ = dynamic_cast<tgrid*>
|
||||
(grid().swap_child("_scrollbar_grid", tmp, true));
|
||||
}
|
||||
}
|
||||
|
||||
void tvertical_scrollbar_container_::finalize_setup()
|
||||
{
|
||||
find_scrollbar()->set_callback_positioner_move(callback_scrollbar);
|
||||
|
@ -210,6 +404,10 @@ void tvertical_scrollbar_container_::finalize_setup()
|
|||
button->set_callback_mouse_left_click(callback_scrollbar_button);
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure all mandatory widgets are tested
|
||||
find_scrollbar_grid();
|
||||
find_content_grid();
|
||||
}
|
||||
|
||||
void tvertical_scrollbar_container_::scrollbar_click(twidget* caller)
|
||||
|
@ -230,5 +428,6 @@ unsigned tvertical_scrollbar_container_::get_selected_row() const
|
|||
{
|
||||
return find_scrollbar()->get_item_position();
|
||||
}
|
||||
|
||||
} // namespace gui2
|
||||
|
||||
|
|
|
@ -21,8 +21,6 @@ namespace gui2 {
|
|||
|
||||
class tscrollbar_;
|
||||
|
||||
|
||||
|
||||
/** Base class for creating containers with a vertical scrollbar. */
|
||||
class tvertical_scrollbar_container_ : public tcontainer_
|
||||
{
|
||||
|
@ -30,26 +28,35 @@ class tvertical_scrollbar_container_ : public tcontainer_
|
|||
friend class tbuilder_listbox;
|
||||
|
||||
|
||||
// Callbacks can call update rountines. Note these are not further declared
|
||||
// here only need extrnal linkage to be friends.
|
||||
// Callbacks can call update routines. Note these are not further declared
|
||||
// here only need external linkage to be friends.
|
||||
friend void callback_scrollbar_button(twidget*);
|
||||
friend void callback_scrollbar(twidget*);
|
||||
public:
|
||||
|
||||
tvertical_scrollbar_container_(const unsigned canvas_count)
|
||||
: tcontainer_(canvas_count),
|
||||
callback_value_change_(NULL)
|
||||
{
|
||||
}
|
||||
tvertical_scrollbar_container_(const unsigned canvas_count);
|
||||
|
||||
/***** ***** ***** inherited ****** *****/
|
||||
~tvertical_scrollbar_container_();
|
||||
|
||||
/** Inherited from tevent_executor. */
|
||||
void key_press(tevent_handler& event, bool& handled,
|
||||
SDLKey key, SDLMod modifier, Uint16 unicode);
|
||||
|
||||
/** Inherited from twidget. */
|
||||
bool has_vertical_scrollbar() const { return true; }
|
||||
/** The way to handle the showing or hiding of the scrollbar. */
|
||||
enum tscrollbar_mode {
|
||||
SHOW, /**<
|
||||
* The scrollbar is always shown, whether
|
||||
* needed or not.
|
||||
*/
|
||||
HIDE, /**<
|
||||
* The scrollbar is never shown even not when
|
||||
* needed. There's also no space reserved for
|
||||
* the scrollbar.
|
||||
*/
|
||||
SHOW_WHEN_NEEDED /**<
|
||||
* The scrollbar is shown when the number of
|
||||
* items is larger as the visible items. The
|
||||
* space for the scrollbar is always
|
||||
* reserved, just in case it's needed after
|
||||
* the initial sizing (due to adding items).
|
||||
*/
|
||||
};
|
||||
|
||||
/**
|
||||
* Selects an entire row.
|
||||
|
@ -62,10 +69,46 @@ public:
|
|||
*/
|
||||
virtual bool select_row(const unsigned row, const bool select = true) = 0;
|
||||
|
||||
/***** ***** ***** inherited ****** *****/
|
||||
|
||||
/** Inherited from tevent_executor. */
|
||||
void key_press(tevent_handler& event, bool& handled,
|
||||
SDLKey key, SDLMod modifier, Uint16 unicode);
|
||||
|
||||
/** Inherited from twidget. */
|
||||
bool has_vertical_scrollbar() const { return true; }
|
||||
|
||||
/** Inherited from tcontainer. */
|
||||
tpoint get_best_size() const;
|
||||
|
||||
/** Inherited from tcontainer. */
|
||||
tpoint get_best_size(const tpoint& maximum_size) const;
|
||||
|
||||
/** Inherited from tcontainer. */
|
||||
void draw(surface& surface, const bool force = false,
|
||||
const bool invalidate_background = false);
|
||||
|
||||
/** Inherited from tcontainer. */
|
||||
void set_size(const SDL_Rect& rect);
|
||||
|
||||
/** Inherited from tcontainer_. */
|
||||
twidget* find_widget(const tpoint& coordinate, const bool must_be_active);
|
||||
|
||||
/** Inherited from tcontainer_. */
|
||||
const twidget* find_widget(const tpoint& coordinate,
|
||||
const bool must_be_active) const;
|
||||
|
||||
/** Import overloaded versions. */
|
||||
using tcontainer_::find_widget;
|
||||
|
||||
/***** ***** ***** setters / getters for members ***** ****** *****/
|
||||
|
||||
void set_callback_value_change(void (*callback) (twidget* caller))
|
||||
{ callback_value_change_ = callback; }
|
||||
|
||||
void set_scrollbar_mode(const tscrollbar_mode scrollbar_mode);
|
||||
tscrollbar_mode get_scrollbar_mode() const { return scrollbar_mode_; }
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
|
@ -74,22 +117,42 @@ protected:
|
|||
*/
|
||||
void value_changed();
|
||||
|
||||
/**
|
||||
* The widget contains named widgets:
|
||||
* - _scrollbar_grid a grid containing all items regarding the scrollbar and
|
||||
* associated buttons etc.
|
||||
* - _scrollbar a scrollbar itself.
|
||||
* - _content_grid a grid containing the widgets in the container.
|
||||
* Subclasses may define extra named widgets in this container for their
|
||||
* own purposes.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns the scroll widget.
|
||||
* Returns the scrollbar grid.
|
||||
*
|
||||
* This always returns the wdiget, regardless of the mode.
|
||||
* This always returns the grid, regardless of the mode (active or not).
|
||||
*
|
||||
* @param must_exist If true the widget must exist and the
|
||||
* @param must_exist If true the grid must exist and the
|
||||
* function will fail if that's not the case. If
|
||||
* true the pointer returned is always valid.
|
||||
*
|
||||
* @returns A pointer to the widget or NULL.
|
||||
* @returns A pointer to the grid or NULL.
|
||||
*/
|
||||
tscrollbar_* find_scrollbar(const bool must_exist = true);
|
||||
tgrid* find_scrollbar_grid(const bool must_exist = true);
|
||||
|
||||
/** The const version. */
|
||||
const tscrollbar_* find_scrollbar(const bool must_exist = true) const;
|
||||
const tgrid* find_scrollbar_grid(const bool must_exist = true) const;
|
||||
|
||||
|
||||
/** See find_scrollbar_grid, but returns the scrollbar instead. */
|
||||
tscrollbar_* find_scrollbar(const bool must_exist = true);
|
||||
|
||||
/** The const version. */
|
||||
const tscrollbar_* find_scrollbar(const bool must_exist = true) const;
|
||||
|
||||
/** See find_scrollbar_grid, but returns the content grid instead. */
|
||||
tgrid* find_content_grid(const bool must_exist = true);
|
||||
const tgrid* find_content_grid(const bool must_exist = true) const;
|
||||
|
||||
/**
|
||||
* Sets the status of the scrollbar buttons.
|
||||
|
@ -101,9 +164,21 @@ protected:
|
|||
|
||||
private:
|
||||
|
||||
/**
|
||||
* The mode of how to show the scrollbar.
|
||||
*
|
||||
* This value should only be modified before showing, doing it while
|
||||
* showing results in UB.
|
||||
*/
|
||||
tscrollbar_mode scrollbar_mode_;
|
||||
|
||||
tgrid* scrollbar_grid_;
|
||||
|
||||
void show_scrollbar(const bool show);
|
||||
|
||||
/**
|
||||
* This callback is used when the selection is changed due to a user event.
|
||||
* The name is not fully appropriate for the event but it's choosen to be
|
||||
* The name is not fully appropriate for the event but it's chosen to be
|
||||
* generic.
|
||||
*/
|
||||
void (*callback_value_change_) (twidget* caller);
|
||||
|
@ -132,10 +207,54 @@ private:
|
|||
*/
|
||||
virtual bool get_item_active(const unsigned /*item*/) const { return true; }
|
||||
|
||||
|
||||
/** Returns the selected row. */
|
||||
virtual unsigned get_selected_row() const;
|
||||
|
||||
/***** ***** pure virtuals for the subclasses ****** *****/
|
||||
|
||||
/**
|
||||
* Returns the best size for the content part.
|
||||
*
|
||||
* See get_best_size() for more info.
|
||||
*/
|
||||
virtual tpoint get_content_best_size() const = 0;
|
||||
|
||||
/**
|
||||
* Returns the best size for the content part.
|
||||
*
|
||||
* See get_best_size(cont tpoint&) for more info.
|
||||
*/
|
||||
virtual tpoint get_content_best_size(const tpoint& maximum_size) const = 0;
|
||||
|
||||
/**
|
||||
* Sets the size for the content.
|
||||
*
|
||||
* This is a notification after the size of the content grid has been set
|
||||
* so the function only needs to update its state if applicable.
|
||||
*
|
||||
* @param rect The new size of the content grid.
|
||||
*/
|
||||
virtual void set_content_size(const SDL_Rect& rect) = 0;
|
||||
|
||||
/**
|
||||
* Draws the content part of the widget.
|
||||
*
|
||||
* See draw_content for more info.
|
||||
*/
|
||||
virtual void draw_content(surface& surface, const bool force,
|
||||
const bool invalidate_background) = 0;
|
||||
|
||||
/**
|
||||
* Finds a widget in the content area.
|
||||
*
|
||||
* See find_content_widget for more info.
|
||||
*/
|
||||
virtual twidget* find_content_widget(
|
||||
const tpoint& coordinate, const bool must_be_active) = 0;
|
||||
|
||||
/** The const version. */
|
||||
virtual const twidget* find_content_widget(
|
||||
const tpoint& coordinate, const bool must_be_active) const = 0;
|
||||
};
|
||||
|
||||
} // namespace gui2
|
||||
|
|
|
@ -60,6 +60,8 @@ static unsigned get_v_align(const std::string& v_align);
|
|||
static unsigned get_h_align(const std::string& h_align);
|
||||
static unsigned get_border(const std::vector<std::string>& border);
|
||||
static unsigned read_flags(const config& cfg);
|
||||
static tvertical_scrollbar_container_::tscrollbar_mode
|
||||
get_scrollbar_mode(const std::string& scrollbar_mode);
|
||||
|
||||
twindow build(CVideo& video, const std::string& type)
|
||||
{
|
||||
|
@ -221,7 +223,6 @@ twindow_builder::tresolution::tresolution(const config& cfg) :
|
|||
|
||||
static unsigned get_v_align(const std::string& v_align)
|
||||
{
|
||||
|
||||
if(v_align == "top") {
|
||||
return tgrid::VERTICAL_ALIGN_TOP;
|
||||
} else if(v_align == "bottom") {
|
||||
|
@ -616,8 +617,25 @@ twidget* tbuilder_label::build() const
|
|||
return tmp_label;
|
||||
}
|
||||
|
||||
static tvertical_scrollbar_container_::tscrollbar_mode
|
||||
get_scrollbar_mode(const std::string& scrollbar_mode)
|
||||
{
|
||||
if(scrollbar_mode == "always") {
|
||||
return tvertical_scrollbar_container_::SHOW;
|
||||
} else if(scrollbar_mode == "never") {
|
||||
return tvertical_scrollbar_container_::HIDE;
|
||||
} else {
|
||||
if(!scrollbar_mode.empty() && scrollbar_mode != "auto") {
|
||||
ERR_G_E << "Invalid scrollbar mode '"
|
||||
<< scrollbar_mode << "' falling back to 'auto'.\n";
|
||||
}
|
||||
return tvertical_scrollbar_container_::SHOW_WHEN_NEEDED;
|
||||
}
|
||||
}
|
||||
|
||||
tbuilder_listbox::tbuilder_listbox(const config& cfg) :
|
||||
tbuilder_control(cfg),
|
||||
scrollbar_mode(get_scrollbar_mode(cfg["vertical_scrollbar_mode"])),
|
||||
header(cfg.child("header") ? new tbuilder_grid(*(cfg.child("header"))) : 0),
|
||||
footer(cfg.child("footer") ? new tbuilder_grid(*(cfg.child("footer"))) : 0),
|
||||
list_builder(0),
|
||||
|
@ -634,16 +652,10 @@ tbuilder_listbox::tbuilder_listbox(const config& cfg) :
|
|||
*
|
||||
* List with the listbox specific variables:
|
||||
* @start_table = config
|
||||
* scrollbar_mode (foo) The mode for the scrollbar
|
||||
* @* always_show the srollbar is always
|
||||
* shown even if all items can be shown. The
|
||||
* scrollbar will be disabled in this case.
|
||||
* @* auto_show the scrollbar is shown if
|
||||
* more items are in the listbox as can be
|
||||
* shown.
|
||||
* @* never_show the scrollbar is
|
||||
* never shown even not if more items are
|
||||
* available as visible.
|
||||
* vertical_scrollbar_mode (scrollbar_mode = auto)
|
||||
* Determines whether or not to show the
|
||||
* scrollbar.
|
||||
*
|
||||
* header (section = []) Defines the grid for the optional header.
|
||||
* footer (section = []) Defines the grid for the optional footer.
|
||||
*
|
||||
|
@ -713,6 +725,7 @@ twidget* tbuilder_listbox::build() const
|
|||
|
||||
listbox->set_list_builder(list_builder);
|
||||
listbox->set_assume_fixed_row_size(assume_fixed_row_size);
|
||||
listbox->set_scrollbar_mode(scrollbar_mode);
|
||||
|
||||
DBG_G << "Window builder: placed listbox '" << id << "' with defintion '"
|
||||
<< definition << "'.\n";
|
||||
|
@ -721,21 +734,29 @@ twidget* tbuilder_listbox::build() const
|
|||
boost::dynamic_pointer_cast<const tlistbox_definition::tresolution>(listbox->config());
|
||||
assert(conf);
|
||||
|
||||
/*
|
||||
* We generate the following items to put in the listbox grid
|
||||
* - _scrollbar_grid the grid containing the scrollbar.
|
||||
* - _content_grid the grid containing the content of the listbox.
|
||||
* - _list if the content has a header of footer they're an extra
|
||||
* grid needed to find the scrolling content, the item
|
||||
* with the id _list holds this, so the listbox needs to
|
||||
* test for this item as well.
|
||||
*/
|
||||
|
||||
tgrid* scrollbar = dynamic_cast<tgrid*>(conf->scrollbar->build());
|
||||
assert(scrollbar);
|
||||
|
||||
scrollbar->set_id("_scroll");
|
||||
scrollbar->set_id("_scrollbar_grid");
|
||||
|
||||
twidget* list_area = new tspacer();
|
||||
assert(list_area);
|
||||
list_area->set_definition("default");
|
||||
list_area->set_id("_list");
|
||||
tgrid* content_grid = new tgrid();
|
||||
content_grid->set_definition("default");
|
||||
content_grid->set_id("_content_grid");
|
||||
assert(content_grid);
|
||||
|
||||
if(header || footer) {
|
||||
|
||||
// Create a grid to hold header (if needed), list and footer (if needed).
|
||||
tgrid* grid = new tgrid();
|
||||
grid->set_rows_cols(header && footer ? 3 : 2, 1);
|
||||
content_grid->set_rows_cols(header && footer ? 3 : 2, 1);
|
||||
|
||||
// Create and add the header.
|
||||
if(header) {
|
||||
|
@ -748,7 +769,7 @@ twidget* tbuilder_listbox::build() const
|
|||
* We need sort indicators, which are tristat_buttons;
|
||||
* none, acending, decending. Once we have them we can write them in.
|
||||
*/
|
||||
grid->set_child(widget, 0, 0, tgrid::HORIZONTAL_GROW_SEND_TO_CLIENT
|
||||
content_grid->set_child(widget, 0, 0, tgrid::HORIZONTAL_GROW_SEND_TO_CLIENT
|
||||
| tgrid::VERTICAL_ALIGN_TOP, 0);
|
||||
}
|
||||
|
||||
|
@ -757,24 +778,26 @@ twidget* tbuilder_listbox::build() const
|
|||
twidget* widget = footer->build();
|
||||
assert(widget);
|
||||
|
||||
grid->set_child(widget, header && footer ? 2 : 1, 0,
|
||||
content_grid->set_child(widget, header && footer ? 2 : 1, 0,
|
||||
tgrid::HORIZONTAL_GROW_SEND_TO_CLIENT
|
||||
| tgrid::VERTICAL_ALIGN_BOTTOM, 0);
|
||||
}
|
||||
|
||||
// Add the list itself.
|
||||
grid->set_child(list_area, header ? 1 : 0, 0,
|
||||
// Add the list itself which needs a new grid as described above.
|
||||
tgrid* list = new tgrid();
|
||||
assert(list);
|
||||
|
||||
list->set_definition("default");
|
||||
list->set_id("_list");
|
||||
content_grid->set_child(list, header ? 1 : 0, 0,
|
||||
tgrid::HORIZONTAL_GROW_SEND_TO_CLIENT
|
||||
| tgrid::VERTICAL_GROW_SEND_TO_CLIENT
|
||||
, 0);
|
||||
|
||||
// Now make the list_area the grid so the code with and without a header
|
||||
// or footer is the same.
|
||||
list_area = grid;
|
||||
content_grid->set_row_grow_factor( header ? 1 : 0, 1);
|
||||
}
|
||||
|
||||
listbox->grid().set_rows_cols(1, 2);
|
||||
listbox->grid().set_child(list_area, 0, 0,
|
||||
listbox->grid().set_child(content_grid, 0, 0,
|
||||
tgrid::VERTICAL_GROW_SEND_TO_CLIENT
|
||||
| tgrid::HORIZONTAL_GROW_SEND_TO_CLIENT
|
||||
, 0);
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
#include "config.hpp"
|
||||
#include "gui/widgets/menubar.hpp"
|
||||
#include "gui/widgets/vertical_scrollbar_container.hpp"
|
||||
|
||||
namespace gui2 {
|
||||
|
||||
|
@ -116,6 +117,8 @@ public:
|
|||
|
||||
twidget* build () const;
|
||||
|
||||
tvertical_scrollbar_container_::tscrollbar_mode scrollbar_mode;
|
||||
|
||||
tbuilder_grid_ptr header;
|
||||
tbuilder_grid_ptr footer;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue