Moved the tsizer class to grid.?pp and renamed it to tgrid.

This commit is contained in:
Mark de Wever 2008-03-16 14:04:18 +00:00
parent 9f342c90e1
commit b6d222a683
6 changed files with 482 additions and 410 deletions

271
src/gui/widgets/grid.cpp Normal file
View file

@ -0,0 +1,271 @@
/* $Id$ */
/*
copyright (c) 2008 by mark de wever <koraq@xs4all.nl>
part of the battle for wesnoth project http://www.wesnoth.org/
this program is free software; you can redistribute it and/or modify
it under the terms of the gnu general public license version 2
or at your option any later version.
this program is distributed in the hope that it will be useful,
but without any warranty.
see the copying file for more details.
*/
#include "gui/widgets/grid.hpp"
#include "log.hpp"
#include <cassert>
#include <numeric>
#define DBG_G LOG_STREAM(debug, gui)
#define LOG_G LOG_STREAM(info, gui)
#define WRN_G LOG_STREAM(warn, gui)
#define ERR_G LOG_STREAM(err, gui)
#define DBG_G_D LOG_STREAM(debug, gui_draw)
#define LOG_G_D LOG_STREAM(info, gui_draw)
#define WRN_G_D LOG_STREAM(warn, gui_draw)
#define ERR_G_D LOG_STREAM(err, gui_draw)
#define DBG_G_E LOG_STREAM(debug, gui_event)
#define LOG_G_E LOG_STREAM(info, gui_event)
#define WRN_G_E LOG_STREAM(warn, gui_event)
#define ERR_G_E LOG_STREAM(err, gui_event)
#define DBG_G_P LOG_STREAM(debug, gui_parse)
#define LOG_G_P LOG_STREAM(info, gui_parse)
#define WRN_G_P LOG_STREAM(warn, gui_parse)
#define ERR_G_P LOG_STREAM(err, gui_parse)
namespace gui2 {
tgrid::tgrid(const unsigned rows, const unsigned cols,
const unsigned default_flags, const unsigned default_border_size) :
rows_(rows),
cols_(cols),
default_flags_(default_flags),
default_border_size_(default_border_size),
children_(rows * cols)
{
}
tgrid::~tgrid()
{
for(std::vector<tchild>::iterator itor = children_.begin();
itor != children_.end(); ++itor) {
if(itor->widget()) {
delete itor->widget();
}
}
}
void tgrid::add_child(twidget* widget, const unsigned row,
const unsigned col, const unsigned flags, const unsigned border_size)
{
assert(row < rows_ && col < cols_);
tchild& cell = child(row, col);
// clear old child if any
if(cell.widget()) {
// free a child when overwriting it
WRN_G << "Grid: child '" << cell.id()
<< "' at cell '" << row << ',' << col << "' will be replaced.\n";
delete cell.widget();
}
// copy data
cell.set_flags(flags);
cell.set_border_size(border_size);
cell.set_widget(widget);
if(cell.widget()) {
// make sure the new child is valid before deferring
cell.set_id(cell.widget()->id());
cell.widget()->set_parent(this);
} else {
cell.set_id("");
}
}
void tgrid::set_rows(const unsigned rows)
{
if(rows == rows_) {
return;
}
if(!children_.empty()) {
WRN_G << "Grid: resizing a non-empty grid may give unexpected problems.\n";
}
rows_ = rows;
children_.resize(rows_ * cols_);
}
void tgrid::set_cols(const unsigned cols)
{
if(cols == cols_) {
return;
}
if(!children_.empty()) {
WRN_G << "Grid: resizing a non-empty grid may give unexpected problems.\n";
}
cols_ = cols;
children_.resize(cols_ * cols_);
}
void tgrid::remove_child(const unsigned row, const unsigned col)
{
assert(row < rows_ && col < cols_);
tchild& cell = child(row, col);
cell.set_id("");
cell.set_widget(0);
}
void tgrid::removed_child(const std::string& id, const bool find_all)
{
for(std::vector<tchild>::iterator itor = children_.begin();
itor != children_.end(); ++itor) {
if(itor->id() == id) {
itor->set_id("");
itor->set_widget(0);
if(!find_all) {
break;
}
}
}
}
tpoint tgrid::get_best_size()
{
std::vector<unsigned> best_col_width(cols_, 0);
std::vector<unsigned> best_row_height(rows_, 0);
// First get the best sizes for all items.
for(unsigned row = 0; row < rows_; ++row) {
for(unsigned col = 0; col < cols_; ++col) {
const tpoint size = child(row, col).get_best_size();
if(size.x > best_col_width[col]) {
best_col_width[col] = size.x;
}
if(size.y > best_row_height[row]) {
best_row_height[row] = size.y;
}
}
}
for(unsigned row = 0; row < rows_; ++row) {
DBG_G << "Grid: the best height for row " << row
<< " will be " << best_row_height[row] << ".\n";
}
for(unsigned col = 0; col < cols_; ++col) {
DBG_G << "Grid: the best width for col " << col
<< " will be " << best_col_width[col] << ".\n";
}
return tpoint(
std::accumulate(best_col_width.begin(), best_col_width.end(), 0),
std::accumulate(best_row_height.begin(), best_row_height.end(), 0));
}
void tgrid::set_best_size(const tpoint& origin)
{
std::vector<unsigned> best_col_width(cols_, 0);
std::vector<unsigned> best_row_height(rows_, 0);
// First get the best sizes for all items. (FIXME copy and paste of get best size)
for(unsigned row = 0; row < rows_; ++row) {
for(unsigned col = 0; col < cols_; ++col) {
const tpoint size = child(row, col).get_best_size();
if(size.x > best_col_width[col]) {
best_col_width[col] = size.x;
}
if(size.y > best_row_height[row]) {
best_row_height[row] = size.y;
}
}
}
// Set the sizes
tpoint orig = origin;
for(unsigned row = 0; row < rows_; ++row) {
for(unsigned col = 0; col < cols_; ++col) {
DBG_G << "Grid: set widget at " << row
<< ',' << col << " at origin " << orig << ".\n";
if(child(row, col).widget()) {
child(row, col).widget()->set_best_size(orig);
}
orig.x += best_col_width[col];
}
orig.y += best_row_height[row];
orig.x = origin.x;
}
}
twidget* tgrid::get_widget(const tpoint& coordinate)
{
//! FIXME we need to store the sizes, since this is quite
//! pathatic.
for(unsigned row = 0; row < rows_; ++row) {
for(unsigned col = 0; col < cols_; ++col) {
twidget* widget = child(row, col).widget();
if(!widget) {
continue;
}
widget = widget->get_widget(coordinate);
if(widget) {
return widget;
}
}
}
return 0;
}
tpoint tgrid::tchild::get_best_size()
{
if(!dirty_ && (!widget_ || !widget_->dirty())) {
return best_size_;
}
best_size_ = widget_ ? widget_->get_best_size() : tpoint(0, 0);
//FIXME take care of the border configuration.
best_size_.x += 2 * border_size_;
best_size_.y += 2 * border_size_;
dirty_ = false;
return best_size_;
}
} // namespace gui2

206
src/gui/widgets/grid.hpp Normal file
View file

@ -0,0 +1,206 @@
/* $Id$ */
/*
copyright (c) 2008 by mark de wever <koraq@xs4all.nl>
part of the battle for wesnoth project http://www.wesnoth.org/
this program is free software; you can redistribute it and/or modify
it under the terms of the gnu general public license version 2
or at your option any later version.
this program is distributed in the hope that it will be useful,
but without any warranty.
see the copying file for more details.
*/
#ifndef __GUI_WIDGETS_GRID_HPP_INCLUDED__
#define __GUI_WIDGETS_GRID_HPP_INCLUDED__
#include "gui/widgets/widget.hpp"
namespace gui2 {
//! Base container class which needs to size children
class tgrid : public virtual twidget
{
public:
// ***** ***** FLAGS ***** *****
static const unsigned VERTICAL_RESIZE_GROW = 1 << 1;
static const unsigned VERTICAL_GROW_SEND_TO_CLIENT = 1 << 2;
static const unsigned VERTICAL_ALIGN_TOP = 1 << 4;
static const unsigned VERTICAL_ALIGN_CENTER = 1 << 5;
static const unsigned VERTICAL_ALIGN_BOTTOM = 1 << 6;
static const unsigned VERTICAL_ALIGN_LANGUAGE = 1 << 7;
static const unsigned HORIZONTAL_RESIZE_GROW = 1 << 16;
static const unsigned HORIZONTAL_GROW_SEND_TO_CLIENT = 1 << 17;
static const unsigned HORIZONTAL_ALIGN_TOP = 1 << 18;
static const unsigned HORIZONTAL_ALIGN_CENTER = 1 << 19;
static const unsigned HORIZONTAL_ALIGN_BOTTOM = 1 << 20;
static const unsigned HORIZONTAL_ALIGN_LANGUAGE = 1 << 21;
static const unsigned BORDER_TOP = 1 << 24;
static const unsigned BORDER_BOTTOM = 1 << 25;
static const unsigned BORDER_LEFT = 1 << 26;
static const unsigned BORDER_RIGHT = 1 << 27;
tgrid(const unsigned rows, const unsigned cols,
const unsigned default_flags, const unsigned default_border_size);
virtual ~tgrid();
void add_child(twidget* widget, const unsigned row,
const unsigned col, const unsigned flags, const unsigned border_size);
void add_child(twidget* widget, const unsigned row, const unsigned col)
{ add_child(widget, row, col, default_flags_, default_border_size_); }
void add_child(twidget* widget, const unsigned row, const unsigned col, const unsigned flags)
{ add_child(widget, row, col, flags, default_border_size_); }
void set_rows(const unsigned rows);
unsigned int get_rows() const { return rows_; }
void set_cols(const unsigned cols);
unsigned int get_cols() const { return cols_; }
void remove_child(const unsigned row, const unsigned col);
void removed_child(const std::string& id, const bool find_all = false);
//! Inherited
tpoint get_best_size();
//! Inherited
void set_best_size(const tpoint& origin);
//! Gets the widget at the wanted coordinates.
//! Override base class.
twidget* get_widget(const tpoint& coordinate);
private:
class tchild
{
public:
tchild() :
id_(),
flags_(0),
border_size_(0),
widget_(0),
best_size_(0, 0),
dirty_(true),
clip_()
// Fixme make a class wo we can store some properties in the cache
// regarding size etc.
{}
const std::string& id() const { return id_; }
void set_id(const std::string& id) { id_ = id; }
unsigned get_flags() const { return flags_; }
void set_flags(const unsigned flags) { flags_ = flags; dirty_ = true; }
unsigned get_border_size() const { return border_size_; }
void set_border_size(const unsigned border_size)
{ border_size_ = border_size; dirty_ = true; }
twidget* widget() { return widget_; }
void set_widget(twidget* widget) { widget_ = widget; dirty_ = true; }
//! Gets the best size for the cell, not const since we modify the internal
//! state, might use mutable later (if really needed).
tpoint get_best_size();
private:
//! The id of the widget if it has a widget.
std::string id_;
//! The flags for the border and cell setup.
unsigned flags_;
//! The size of the border, the actual configuration of the border
//! is determined by the flags.
unsigned border_size_;
//! Pointer to the widget. FIXME who owns the widget....
twidget* widget_;
//! The best size for this cell, determined by the best size
//! of the widget and the border_size_ and flags_.
tpoint best_size_;
//! Tracks the dirty state of the cell regarding best_size_.
bool dirty_;
//! The clipping area for the widget. This is also the size of
//! the container.
SDL_Rect clip_;
}; // class tchild
public:
class iterator
{
public:
iterator(std::vector<tchild>::iterator itor) :
itor_(itor)
{}
iterator operator++() { return iterator(++itor_); }
iterator operator--() { return iterator(--itor_); }
twidget* operator->() { return itor_->widget(); }
twidget* operator*() { return itor_->widget(); }
bool operator!=(const iterator& i) const
{ return i.itor_ != this->itor_; }
private:
std::vector<tchild>::iterator itor_;
};
iterator begin() { return iterator(children_.begin()); }
iterator end() { return iterator(children_.end()); }
private:
unsigned rows_;
unsigned cols_;
const unsigned default_flags_;
const unsigned default_border_size_;
std::vector<tchild> children_;
tchild& child(const unsigned row, const unsigned col)
{ return children_[rows_ * col + row]; }
};
//! Visible container to hold children.
class tpanel : public tgrid, public tcontrol
{
public:
tpanel() :
tgrid(0, 0, 0, 0),
tcontrol()
{}
private:
};
} // namespace gui2
#endif

View file

@ -21,7 +21,6 @@
#include "serialization/preprocessor.hpp"
#include <cassert>
#include <numeric>
#define DBG_G LOG_STREAM(debug, gui)
#define LOG_G LOG_STREAM(info, gui)
@ -114,229 +113,6 @@ bool tcontainer::remove_child(const std::string& id)
}
#endif
tsizer::tsizer(const unsigned rows, const unsigned cols,
const unsigned default_flags, const unsigned default_border_size) :
rows_(rows),
cols_(cols),
default_flags_(default_flags),
default_border_size_(default_border_size),
children_(rows * cols)
{
}
tsizer::~tsizer()
{
for(std::vector<tchild>::iterator itor = children_.begin();
itor != children_.end(); ++itor) {
if(itor->widget()) {
delete itor->widget();
}
}
}
void tsizer::add_child(twidget* widget, const unsigned row,
const unsigned col, const unsigned flags, const unsigned border_size)
{
assert(row < rows_ && col < cols_);
tchild& cell = child(row, col);
// clear old child if any
if(cell.widget()) {
// free a child when overwriting it
WRN_G << "Grid: child '" << cell.id()
<< "' at cell '" << row << ',' << col << "' will be replaced.\n";
delete cell.widget();
}
// copy data
cell.set_flags(flags);
cell.set_border_size(border_size);
cell.set_widget(widget);
if(cell.widget()) {
// make sure the new child is valid before deferring
cell.set_id(cell.widget()->id());
cell.widget()->set_parent(this);
} else {
cell.set_id("");
}
}
void tsizer::set_rows(const unsigned rows)
{
if(rows == rows_) {
return;
}
if(!children_.empty()) {
WRN_G << "Grid: resizing a non-empty grid may give unexpected problems.\n";
}
rows_ = rows;
children_.resize(rows_ * cols_);
}
void tsizer::set_cols(const unsigned cols)
{
if(cols == cols_) {
return;
}
if(!children_.empty()) {
WRN_G << "Grid: resizing a non-empty grid may give unexpected problems.\n";
}
cols_ = cols;
children_.resize(cols_ * cols_);
}
void tsizer::remove_child(const unsigned row, const unsigned col)
{
assert(row < rows_ && col < cols_);
tchild& cell = child(row, col);
cell.set_id("");
cell.set_widget(0);
}
void tsizer::removed_child(const std::string& id, const bool find_all)
{
for(std::vector<tchild>::iterator itor = children_.begin();
itor != children_.end(); ++itor) {
if(itor->id() == id) {
itor->set_id("");
itor->set_widget(0);
if(!find_all) {
break;
}
}
}
}
tpoint tsizer::get_best_size()
{
std::vector<unsigned> best_col_width(cols_, 0);
std::vector<unsigned> best_row_height(rows_, 0);
// First get the best sizes for all items.
for(unsigned row = 0; row < rows_; ++row) {
for(unsigned col = 0; col < cols_; ++col) {
const tpoint size = child(row, col).get_best_size();
if(size.x > best_col_width[col]) {
best_col_width[col] = size.x;
}
if(size.y > best_row_height[row]) {
best_row_height[row] = size.y;
}
}
}
for(unsigned row = 0; row < rows_; ++row) {
DBG_G << "Grid: the best height for row " << row
<< " will be " << best_row_height[row] << ".\n";
}
for(unsigned col = 0; col < cols_; ++col) {
DBG_G << "Grid: the best width for col " << col
<< " will be " << best_col_width[col] << ".\n";
}
return tpoint(
std::accumulate(best_col_width.begin(), best_col_width.end(), 0),
std::accumulate(best_row_height.begin(), best_row_height.end(), 0));
}
void tsizer::set_best_size(const tpoint& origin)
{
std::vector<unsigned> best_col_width(cols_, 0);
std::vector<unsigned> best_row_height(rows_, 0);
// First get the best sizes for all items. (FIXME copy and paste of get best size)
for(unsigned row = 0; row < rows_; ++row) {
for(unsigned col = 0; col < cols_; ++col) {
const tpoint size = child(row, col).get_best_size();
if(size.x > best_col_width[col]) {
best_col_width[col] = size.x;
}
if(size.y > best_row_height[row]) {
best_row_height[row] = size.y;
}
}
}
// Set the sizes
tpoint orig = origin;
for(unsigned row = 0; row < rows_; ++row) {
for(unsigned col = 0; col < cols_; ++col) {
DBG_G << "Grid: set widget at " << row
<< ',' << col << " at origin " << orig << ".\n";
if(child(row, col).widget()) {
child(row, col).widget()->set_best_size(orig);
}
orig.x += best_col_width[col];
}
orig.y += best_row_height[row];
orig.x = origin.x;
}
}
twidget* tsizer::get_widget(const tpoint& coordinate)
{
//! FIXME we need to store the sizes, since this is quite
//! pathatic.
for(unsigned row = 0; row < rows_; ++row) {
for(unsigned col = 0; col < cols_; ++col) {
twidget* widget = child(row, col).widget();
if(!widget) {
continue;
}
widget = widget->get_widget(coordinate);
if(widget) {
return widget;
}
}
}
return 0;
}
tpoint tsizer::tchild::get_best_size()
{
if(!dirty_ && (!widget_ || !widget_->dirty())) {
return best_size_;
}
best_size_ = widget_ ? widget_->get_best_size() : tpoint(0, 0);
//FIXME take care of the border configuration.
best_size_.x += 2 * border_size_;
best_size_.y += 2 * border_size_;
dirty_ = false;
return best_size_;
}
tcontrol::tcontrol(/*const int x, const int y, const int w, const int h*/) :
/* x_(x),
y_(y),

View file

@ -276,174 +276,6 @@ private:
};
#endif
//! Base container class which needs to size children
class tsizer : /*public tcontainer,*/ public virtual twidget
{
public:
// ***** ***** FLAGS ***** *****
static const unsigned VERTICAL_RESIZE_GROW = 1 << 1;
static const unsigned VERTICAL_GROW_SEND_TO_CLIENT = 1 << 2;
static const unsigned VERTICAL_ALIGN_TOP = 1 << 4;
static const unsigned VERTICAL_ALIGN_CENTER = 1 << 5;
static const unsigned VERTICAL_ALIGN_BOTTOM = 1 << 6;
static const unsigned VERTICAL_ALIGN_LANGUAGE = 1 << 7;
static const unsigned HORIZONTAL_RESIZE_GROW = 1 << 16;
static const unsigned HORIZONTAL_GROW_SEND_TO_CLIENT = 1 << 17;
static const unsigned HORIZONTAL_ALIGN_TOP = 1 << 18;
static const unsigned HORIZONTAL_ALIGN_CENTER = 1 << 19;
static const unsigned HORIZONTAL_ALIGN_BOTTOM = 1 << 20;
static const unsigned HORIZONTAL_ALIGN_LANGUAGE = 1 << 21;
static const unsigned BORDER_TOP = 1 << 24;
static const unsigned BORDER_BOTTOM = 1 << 25;
static const unsigned BORDER_LEFT = 1 << 26;
static const unsigned BORDER_RIGHT = 1 << 27;
tsizer(const unsigned rows, const unsigned cols,
const unsigned default_flags, const unsigned default_border_size);
virtual ~tsizer();
void add_child(twidget* widget, const unsigned row,
const unsigned col, const unsigned flags, const unsigned border_size);
void add_child(twidget* widget, const unsigned row, const unsigned col)
{ add_child(widget, row, col, default_flags_, default_border_size_); }
void add_child(twidget* widget, const unsigned row, const unsigned col, const unsigned flags)
{ add_child(widget, row, col, flags, default_border_size_); }
void set_rows(const unsigned rows);
unsigned int get_rows() const { return rows_; }
void set_cols(const unsigned cols);
unsigned int get_cols() const { return cols_; }
void remove_child(const unsigned row, const unsigned col);
void removed_child(const std::string& id, const bool find_all = false);
//! Inherited
tpoint get_best_size();
//! Inherited
void set_best_size(const tpoint& origin);
//! Gets the widget at the wanted coordinates.
//! Override base class.
twidget* get_widget(const tpoint& coordinate);
private:
class tchild
{
public:
tchild() :
id_(),
flags_(0),
border_size_(0),
widget_(0),
best_size_(0, 0),
dirty_(true),
clip_()
// Fixme make a class wo we can store some properties in the cache
// regarding size etc.
{}
const std::string& id() const { return id_; }
void set_id(const std::string& id) { id_ = id; }
unsigned get_flags() const { return flags_; }
void set_flags(const unsigned flags) { flags_ = flags; dirty_ = true; }
unsigned get_border_size() const { return border_size_; }
void set_border_size(const unsigned border_size)
{ border_size_ = border_size; dirty_ = true; }
twidget* widget() { return widget_; }
void set_widget(twidget* widget) { widget_ = widget; dirty_ = true; }
//! Gets the best size for the cell, not const since we modify the internal
//! state, might use mutable later (if really needed).
tpoint get_best_size();
private:
//! The id of the widget if it has a widget.
std::string id_;
//! The flags for the border and cell setup.
unsigned flags_;
//! The size of the border, the actual configuration of the border
//! is determined by the flags.
unsigned border_size_;
//! Pointer to the widget. FIXME who owns the widget....
twidget* widget_;
//! The best size for this cell, determined by the best size
//! of the widget and the border_size_ and flags_.
tpoint best_size_;
//! Tracks the dirty state of the cell regarding best_size_.
bool dirty_;
//! The clipping area for the widget. This is also the size of
//! the container.
SDL_Rect clip_;
}; // class tchild
public:
class iterator
{
public:
iterator(std::vector<tchild>::iterator itor) :
itor_(itor)
{}
iterator operator++() { return iterator(++itor_); }
iterator operator--() { return iterator(--itor_); }
twidget* operator->() { return itor_->widget(); }
twidget* operator*() { return itor_->widget(); }
bool operator!=(const iterator& i) const
{ return i.itor_ != this->itor_; }
private:
std::vector<tchild>::iterator itor_;
};
iterator begin() { return iterator(children_.begin()); }
iterator end() { return iterator(children_.end()); }
private:
unsigned rows_;
unsigned cols_;
const unsigned default_flags_;
const unsigned default_border_size_;
std::vector<tchild> children_;
tchild& child(const unsigned row, const unsigned col)
{ return children_[rows_ * col + row]; }
};
//! Base class for all visible items.
class tcontrol : public virtual twidget
@ -503,20 +335,7 @@ private:
surface canvas_;
};
//! Visible container to hold children.
class tpanel : public tsizer, public tcontrol
{
public:
tpanel() :
tsizer(0, 0, 0, 0),
tcontrol()
{}
private:
};
#if 0
/**
* tscroll_panel is a panel which handels scrolling for
* clients which have more data then can be shown
@ -525,7 +344,7 @@ private:
class tscrollpanel : public tpanel /*etc*/
{
};
#endif
/**
* The slider has a few extra option
* min, max minimum maximum of the slider

View file

@ -120,7 +120,7 @@ void twindow::show(const bool restore, void* /*flip_function*/)
fill_rect_alpha(temp_rect, 0, 1, screen);
#endif
for(tsizer::iterator itor = begin(); itor != end(); ++itor) {
for(tgrid::iterator itor = begin(); itor != end(); ++itor) {
if(! *itor || !itor->dirty()) {
continue;

View file

@ -19,10 +19,10 @@
#ifndef __GUI_WIDGETS_WINDOW_HPP_INCLUDED__
#define __GUI_WIDGETS_WINDOW_HPP_INCLUDED__
#include "gui/widgets/widget.hpp"
#include "gui/widgets/canvas.hpp"
#include "gui/widgets/settings.hpp"
#include "gui/widgets/event_info.hpp"
#include "gui/widgets/grid.hpp"
#include "gui/widgets/settings.hpp"
#include "sdl_utils.hpp"
#include "video.hpp"