Files
OpenSceneGraph/src/osgWidget/Table.cpp
2012-03-21 17:36:20 +00:00

225 lines
6.0 KiB
C++

// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008
#include <osgWidget/Table>
namespace osgWidget {
// TODO: There is a serious, outstanding bug with regards to USING a table before ALL Widgets
// are set! FIX THIS!!!
Table::Table(const std::string& name, unsigned int rows, unsigned int cols):
Window (name),
_rows (rows),
_cols (cols),
_lastRowAdd (0),
_lastColAdd (0) {
_objects.resize(_rows * _cols);
}
Table::Table(const Table& table, const osg::CopyOp& co):
Window (table, co),
_rows (table._rows),
_cols (table._cols),
_lastRowAdd (table._lastRowAdd),
_lastColAdd (table._lastColAdd) {
}
unsigned int Table::_calculateIndex(unsigned int row, unsigned int col) const {
return (row * _cols) + col;
}
void Table::_getRows(CellSizes& rows, Getter get) const {
for(unsigned int i = 0; i < _rows; i++) rows.push_back(
_compare<Greater>(get, i * _cols, (i * _cols) + _cols)
);
}
void Table::_getColumns(CellSizes& cols, Getter get) const {
for(unsigned int i = 0; i < _cols; i++) cols.push_back(
_compare<Greater>(get, i, 0, _cols)
);
}
void Table::_resizeImplementation(point_type width, point_type height) {
// We use these vectors so that we don't have to repeatedly call isFillable
// all the time. Usage such as this can really generate a lot of moronic,
// misinformed opposition, but until std::bit_vector is available, this is
// what we get. Deal with it.
std::vector<bool> rowFills;
std::vector<bool> colFills;
point_type numRowFills = 0.0f;
point_type numColFills = 0.0f;
// Enumerate each row and determine whether it can fill. If so, increment
// our numRowFills variable and set the position in rowFills to "true."
for(unsigned int row = 0; row < _rows; row++) {
bool fill = isRowVerticallyFillable(row);
if(fill) numRowFills++;
rowFills.push_back(fill);
}
// Enumerate each column and determine whether it can fill. If so, increment
// our numColFills variable and set the position in colFills to "true."
for(unsigned int col = 0; col < _cols; col++) {
bool fill = isColumnHorizontallyFillable(col);
if(fill) numColFills++;
colFills.push_back(fill);
}
int wrem = 0;
int hrem = 0;
if(numRowFills > 0.0f) {
hrem = static_cast<int>(height) % static_cast<int>(numRowFills);
unsigned int cur = 0;
for(unsigned int row = 0; row < _rows; row++) {
point_type h = height / numRowFills;
if(cur >= _lastRowAdd && hrem) {
_lastRowAdd++;
h++;
hrem--;
}
if(rowFills[row]) addHeightToRow(row, h);
cur++;
}
}
if(numColFills > 0.0f) {
wrem = static_cast<int>(width) % static_cast<int>(numColFills);
unsigned int cur = 0;
for(unsigned int col = 0; col < _cols; col++) {
point_type w = width / numColFills;
if(cur >= _lastColAdd && wrem) {
_lastColAdd++;
w++;
wrem--;
}
if(colFills[col]) addWidthToColumn(col, w);
cur++;
}
}
CellSizes rowHeights;
CellSizes colWidths;
getRowHeights(rowHeights);
getColumnWidths(colWidths);
point_type y = 0.0f;
for(unsigned int row = 0; row < _rows; row++) {
point_type x = 0.0f;
for(unsigned int col = 0; col < _cols; col++) {
Widget* widget = _objects[_calculateIndex(row, col)].get();
if(widget) {
widget->setOrigin(x, y);
_positionWidget(widget, colWidths[col], rowHeights[row]);
}
x += colWidths[col];
}
y += rowHeights[row];
}
}
Window::Sizes Table::_getWidthImplementation() const {
CellSizes cols;
CellSizes minCols;
getColumnWidths(cols);
getColumnMinWidths(minCols);
return Sizes(
std::accumulate(cols.begin(), cols.end(), 0.0f, Plus()),
std::accumulate(minCols.begin(), minCols.end(), 0.0f, Plus())
);
}
Window::Sizes Table::_getHeightImplementation() const {
CellSizes rows;
CellSizes minRows;
getRowHeights(rows);
getRowMinHeights(minRows);
return Sizes(
std::accumulate(rows.begin(), rows.end(), 0.0f, Plus()),
std::accumulate(minRows.begin(), minRows.end(), 0.0f, Plus())
);
}
bool Table::addWidget(Widget* widget) {
return addWidget(widget, 0, 0);
}
bool Table::addWidget(Widget* widget, unsigned int row, unsigned int col) {
return Window::insertWidget(widget, _calculateIndex(row, col));
}
void Table::getRowHeights(CellSizes& rowHeights) const {
_getRows(rowHeights, &Widget::getHeightTotal);
}
void Table::getRowMinHeights(CellSizes& rowMinHeights) const {
_getRows(rowMinHeights, &Widget::getMinHeightTotal);
}
void Table::getColumnWidths(CellSizes& colWidths) const {
_getColumns(colWidths, &Widget::getWidthTotal);
}
void Table::getColumnMinWidths(CellSizes& colMinWidths) const {
_getColumns(colMinWidths, &Widget::getMinWidthTotal);
}
void Table::addHeightToRow(unsigned int row, point_type height) {
for(
Iterator i = begin() + (row * _cols);
i != begin() + ((row * _cols) + _cols);
i++
) if(i->valid()) i->get()->addHeight(height);
}
void Table::addWidthToColumn(unsigned int col, point_type width) {
// See the documentation in include/osgWidget/Window::_forEachApplyOrAssign if you want
// to know why we need this variable.
unsigned int c = col;
for(Iterator i = begin() + col; i < end(); c += _cols) {
if(i->valid()) i->get()->addWidth(width);
if((c + _cols) < size()) i += _cols;
else i = end();
}
}
bool Table::isRowVerticallyFillable(unsigned int row) const {
return static_cast<point_type>(_cols) == _getNumFill(row * _cols, (row * _cols) + _cols);
}
bool Table::isColumnHorizontallyFillable(unsigned int col) const {
return static_cast<point_type>(_rows) == _getNumFill(col, 0, _cols);
}
}