(getParent ());
if (table->Border) {
CRGBA lighter = blend(table->BorderColor, CRGBA::White, 0.5f);
CRGBA borderColorTL;
borderColorTL.modulateFromColor (lighter, CWidgetManager::getInstance()->getGlobalColor());
borderColorTL.A = (uint8) (((uint16) table->CurrentAlpha * (uint16) borderColorTL.A) >> 8);
CRGBA borderColorBR;
borderColorBR.modulateFromColor (table->BorderColor, CWidgetManager::getInstance()->getGlobalColor());
borderColorBR.A = (uint8) (((uint16) table->CurrentAlpha * (uint16) borderColorBR.A) >> 8);
CViewRenderer &rVR = *CViewRenderer::getInstance();
rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal, _WReal, 1, 0, false, rVR.getBlankTextureId(), borderColorTL );
rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal, 1, _HReal, 0, false, rVR.getBlankTextureId(), borderColorBR );
rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal+_HReal-1, _WReal, 1, 0, false, rVR.getBlankTextureId(), borderColorBR );
rVR.drawRotFlipBitmap (_RenderLayer, _XReal+_WReal-1, _YReal, 1, _HReal, 0, false, rVR.getBlankTextureId(), borderColorTL );
}
}
CInterfaceGroup::draw ();
}
// ----------------------------------------------------------------------------
sint32 CGroupCell::getMaxUsedW() const
{
return Group->getMaxUsedW();
}
// ------------------------------------------------------------------------------------------------
sint32 CGroupCell::getMinUsedW() const
{
return Group->getMinUsedW();
}
// ----------------------------------------------------------------------------
void CGroupCell::setTexture(const std::string & TxName)
{
if (TxName.empty() || TxName == "none")
{
_UserTexture = false;
nlinfo("Set no texture");
}
else
{
nlinfo("Set texture to cell : %s", TxName.c_str());
_UserTexture = true;
_TextureId.setTexture (TxName.c_str (), 0, 0, -1, -1, false);
}
}
// ----------------------------------------------------------------------------
void CGroupCell::setTextureTile(bool tiled)
{
if (tiled)
nlinfo("Set texture is Tiled");
_TextureTiled = tiled;
}
// ----------------------------------------------------------------------------
void CGroupCell::setTextureScale(bool scaled)
{
if (scaled)
nlinfo("Set texture is Scaled : %s");
_TextureScaled = scaled;
}
// ----------------------------------------------------------------------------
NLMISC_REGISTER_OBJECT(CViewBase, CGroupTable, std::string, "table");
CGroupTable::CGroupTable(const TCtorParam ¶m)
: CInterfaceGroup(param),
BgColor(0,0,0,255)
{
_ContentValidated = false;
TableRatio = 0.f;
ForceWidthMin = 0;
Border=0;
BorderColor = CRGBA(32, 32, 32, 255);
CellPadding=1;
CellSpacing=2;
ContinuousUpdate = false;
}
// ----------------------------------------------------------------------------
void CGroupTable::addChild (CGroupCell* child)
{
// Cell empty ?
if (_Cells.empty())
// New line
child->NewLine = true;
// Cells are moved and resized by the table
child->setParent(this);
child->setParentPos(this);
child->setPosRef(Hotspot_TL);
child->setParentPosRef(Hotspot_TL);
child->setResizeFromChildW(false);
// Child resize H for cells
child->setResizeFromChildH(false);
/* // New line ?
if (child->NewLine)
{
// First element
if (_Cells.empty())
{
child->setParentPos(NULL);
child->setPosRef(Hotspot_TL);
child->setParentPosRef(Hotspot_TL);
}
// New line
else
{
// Look for previous new line
uint i;
for (i=_Cells.size()-1; i>0; i--)
if (_Cells[i]->NewLine)
break;
child->setParentPos(_Cells[i]);
child->setPosRef(Hotspot_TL);
child->setParentPosRef(Hotspot_BL);
}
}
else
{
nlassert(!_Cells.empty());
child->setParentPos(_Cells.back());
child->setPosRef(Hotspot_TL);
child->setParentPosRef(Hotspot_TR);
}*/
// Add the child
addGroup(child);
_Cells.push_back(child);
invalidateContent();
}
// ----------------------------------------------------------------------------
CGroupTable::~CGroupTable()
{
/* uint i;
for (i=0; i<_Cells.size(); i++)
delete _Cells[i];
_Cells.clear ();*/
}
// ----------------------------------------------------------------------------
void CGroupTable::updateCoords()
{
if (_Parent)
{
if (ContinuousUpdate)
{
sint parentWidth = std::min(_Parent->getMaxWReal(), _Parent->getWReal());
if (_LastParentW != (sint) parentWidth)
{
_LastParentW = parentWidth;
_ContentValidated = false;
}
}
if (!_ContentValidated)
{
// Update W and XReal
CInterfaceElement::updateCoords();
// *** For each children, update coords, gets min and max values
// *** Get the column sizes, we need to know min for the table
uint i;
uint column = 0;
_Columns.clear ();
for (i=0; i<_Cells.size(); i++)
{
// Update coords to get XReal
CGroupCell *cell = _Cells[i];
cell->checkCoords();
cell->updateCoords();
sint32 additionnalWidth = 0;
if (cell->AddChildW)
{
sint width, height;
cell->Group->evalChildrenBBox(true, false, width, height);
additionnalWidth = (sint32) width;
}
// Get width min and max
if( !cell->IgnoreMaxWidth)
{
cell->WidthMax = cell->getMaxUsedW() + cell->LeftMargin;
}
else
{
cell->WidthMax = cell->WidthWanted + additionnalWidth + cell->LeftMargin;
}
sint32 cellWidth;
if(!cell->IgnoreMinWidth)
{
cellWidth = cell->NoWrap ? cell->WidthMax : cell->getMinUsedW() + cell->LeftMargin;
}
else
{
cellWidth = cell->NoWrap ? cell->WidthMax : cell->LeftMargin;
}
// New cell ?
if (cell->NewLine)
{
while (column < _Columns.size())
{
if (_Columns[column].RowSpan > 1)
_Columns[column].RowSpan--;
column++;
}
column = 0;
}
// Resize the array
if (column>=_Columns.size())
_Columns.resize(column+1);
// Handle rowspan from previous row
while (_Columns[column].RowSpan > 1)
{
_Columns[column].RowSpan--;
column++;
// if previous row had less elements, then we missing columns
if (column>=_Columns.size())
_Columns.resize(column+1);
}
// remember column index for later use
cell->TableColumnIndex = column;
// new column, set rowspan from current |
_Columns[column].RowSpan = cell->RowSpan;
float colspan = 1.f / cell->ColSpan;
float rowspan = 1.f / cell->RowSpan;
// Update sizes
if (cellWidth*colspan > _Columns[column].Width)
_Columns[column].Width = cellWidth*colspan;
if (cell->WidthMax*colspan > _Columns[column].WidthMax)
_Columns[column].WidthMax = cell->WidthMax*colspan;
if (cell->TableRatio*colspan > _Columns[column].TableRatio)
_Columns[column].TableRatio = cell->TableRatio*colspan;
if (cell->WidthWanted*colspan + additionnalWidth > _Columns[column].WidthWanted)
_Columns[column].WidthWanted = (sint32)(cell->WidthWanted*colspan) + additionnalWidth;
if (_Columns[column].WidthWanted + additionnalWidth)
_Columns[column].WidthMax = _Columns[column].WidthWanted + additionnalWidth;
if (_Columns[column].WidthWanted > _Columns[column].Width)
_Columns[column].Width = _Columns[column].WidthWanted;
if (cell->ColSpan > 1) {
// copy this info to all spanned columns, create new columns as needed
uint newsize = column + cell->ColSpan - 1;
if (newsize >= _Columns.size())
_Columns.resize(newsize+1);
for(uint span = 0; span < cell->ColSpan -1; span++){
column++;
_Columns[column].Width = _Columns[column-1].Width;
_Columns[column].WidthMax = _Columns[column-1].WidthMax;
_Columns[column].TableRatio = _Columns[column-1].TableRatio;
_Columns[column].WidthWanted = _Columns[column-1].WidthWanted;
_Columns[column].RowSpan = _Columns[column-1].RowSpan;
}
}
// Next column
column++;
}
// Width of cells and table borders
sint32 padding = CellPadding + (Border ? 1 : 0);
sint32 borderWidth = 2*Border + ((sint32)_Columns.size()+1) * CellSpacing + ((sint32)_Columns.size()*2) * padding;
// Get the width
sint32 tableWidthMax = ForceWidthMin?ForceWidthMin:_LastParentW; // getWReal();
sint32 tableWidthMin = std::max(ForceWidthMin, (sint32)((float)tableWidthMax*TableRatio));
tableWidthMax = std::max ((sint32)0, tableWidthMax-borderWidth);
tableWidthMin = std::max ((sint32)0, tableWidthMin-borderWidth);
// Get the width of the table and normalize percent of the cell (sum of TableRatio must == 1)
sint32 tableWidth = 0;
sint32 tableMaxContentWidth = 0;
float ratio = 1;
for (i=0; i<_Columns.size(); i++)
{
tableWidth += _Columns[i].Width;
tableMaxContentWidth += _Columns[i].WidthMax;
_Columns[i].TableRatio = std::min(_Columns[i].TableRatio, ratio);
ratio -= _Columns[i].TableRatio;
}
// Eval table size with all percent cells resized
sint32 tableWidthSizeAfterPercent = tableWidth;
for (i=0; i<_Columns.size(); i++)
{
if (_Columns[i].TableRatio > 0)
{
// Size of the cell with its percent
sint32 me = (sint32)((float)_Columns[i].Width / _Columns[i].TableRatio);
tableWidthSizeAfterPercent = std::min(tableWidthMax, std::max(tableWidthSizeAfterPercent, me));
}
}
for (i=0; i<_Columns.size(); i++)
{
if (_Columns[i].TableRatio > 0)
{
// Size of the other cells
sint32 cellSize;
if (_Columns[i].TableRatio < 1.f)
cellSize = (sint32)((float)tableWidthSizeAfterPercent*_Columns[i].TableRatio) + 1;
else
cellSize = 10000;
sint32 diff = std::min(tableWidthMax, (std::max(_Columns[i].Width, cellSize) - _Columns[i].Width)+tableWidth) - tableWidth;
tableWidth += diff;
_Columns[i].Width += diff;
// tableMaxContentWidth = std::max(tableMaxContentWidth, (sint32)((float)_Columns[i].WidthMax / _Columns[i].TableRatio));
}
}
sint32 space = tableWidthMax - tableWidth;
// Normalize percent window
for (i=0; i<_Columns.size(); i++)
{
// Width for the cell
sint32 diff = (sint32)((float)tableWidth*_Columns[i].TableRatio) - _Columns[i].Width;
diff = std::min(diff, space);
if (diff > 0)
{
_Columns[i].Width += diff;
tableWidth += diff;
space -= diff;
}
}
// Ok, now percent window are nomralized
// Evaluate space to put in windows
sint32 finalWidth = std::max(tableWidthMin, std::min(std::max(tableWidth, tableMaxContentWidth), tableWidthMax));
space = finalWidth - tableWidth;
if (space > 0)
{
// First give to percent cells
for (i=0; i<_Columns.size(); i++)
{
// Width for the cell
sint32 dif = (sint32)((float)space*_Columns[i].TableRatio);
_Columns[i].Width += dif;
tableWidth += dif;
}
// Some space ?
space = finalWidth - tableWidth;
if (space > 0)
{
// Then add in wanted Width cells
for (i=0; i<_Columns.size(); i++)
{
// Width for the cell
if (_Columns[i].Width < _Columns[i].WidthWanted)
{
sint32 dif = std::min(space, _Columns[i].WidthWanted-_Columns[i].Width);
_Columns[i].Width += dif;
space -= dif;
}
}
if (space > 0)
{
// All cells with sizewanted are full
// Distribute remaining space in resizable cells that have a WidthMax
sint32 sumDeltaWidth = 0;
for (i=0; i<_Columns.size(); i++)
{
if ((_Columns[i].TableRatio == 0) && (_Columns[i].WidthWanted == 0))
sumDeltaWidth += std::max ((sint32)0, _Columns[i].WidthMax - _Columns[i].Width);
}
if (sumDeltaWidth)
{
sint32 toDistribute = space;
for (i=0; i<_Columns.size(); i++)
{
if ((_Columns[i].TableRatio == 0) && (_Columns[i].WidthWanted == 0))
{
sint32 marge = std::max ((sint32)0, _Columns[i].WidthMax - _Columns[i].Width);
sint32 cellPart = std::min(marge, std::min(space, 1 + marge * toDistribute / sumDeltaWidth));
if (cellPart)
{
_Columns[i].Width += cellPart;
space -= cellPart;
}
}
}
}
if (space > 0)
{
// All cells with sizemax are full
// Distribute remaining space in others resizable cells
sumDeltaWidth = 0;
for (i=0; i<_Columns.size(); i++)
{
if ((_Columns[i].TableRatio == 0) && (_Columns[i].WidthWanted == 0))
sumDeltaWidth++;
}
if (sumDeltaWidth)
{
sint32 toDistribute = space;
for (i=0; i<_Columns.size(); i++)
{
if ((_Columns[i].TableRatio == 0) && (_Columns[i].WidthWanted == 0))
{
sint32 cellPart = std::min(space, 1 + toDistribute / sumDeltaWidth);
_Columns[i].Width += cellPart;
space -= cellPart;
}
}
}
if (space > 0)
{
// No cells with sizemax not sizewanted, resize size wanted
// Distribute remaining space in others resizable cells
sumDeltaWidth = 0;
for (i=0; i<_Columns.size(); i++)
{
if ((_Columns[i].TableRatio == 0) && (_Columns[i].WidthWanted != 0))
sumDeltaWidth++;
}
if (sumDeltaWidth)
{
sint32 toDistribute = space;
for (i=0; i<_Columns.size(); i++)
{
if ((_Columns[i].TableRatio == 0) && (_Columns[i].WidthWanted != 0))
{
sint32 cellPart = std::min(space, 1 + toDistribute / sumDeltaWidth);
_Columns[i].Width += cellPart;
space -= cellPart;
}
}
}
// If there is still space left, then sum up column widths
// and add all the remaining space to final column.
if (space > 0)
{
sint32 innerWidth = 0;
for(i=0;i<_Columns.size();i++)
innerWidth += _Columns[i].Width;
if (innerWidth > 0 && finalWidth > innerWidth)
_Columns[_Columns.size()-1].Width += finalWidth - innerWidth;
}
}
}
}
}
}
// *** Now we know each column width, resize cells and get the height for each row
column = 0;
sint32 row = 0;
sint32 currentX = Border + CellSpacing + padding;
_Rows.clear ();
for (i=0; i<_Cells.size(); i++)
{
CGroupCell *cell = _Cells[i];
// New cell ?
if (cell->NewLine)
{
column = 0;
currentX = Border + CellSpacing + padding;
_Rows.push_back(CRow());
}
if (cell->TableColumnIndex > 0)
{
// we have active rowspan, must add up 'skipped' columns
for( ; columnTableColumnIndex; column++)
currentX += _Columns[column].Width + padding*2 + CellSpacing;
}
// Set the x and width
// Check align
sint32 alignmentX = 0;
sint32 widthReduceX = 0;
sint32 columnWidth = _Columns[column].Width;
if (cell->ColSpan > 1)
{
// scan ahead and add up column widths as they might be different
for(int j = 1; jColSpan; j++)
columnWidth += CellSpacing + padding*2 + _Columns[column+j].Width;
}
if (cell->WidthMax < columnWidth)
{
switch (cell->Align)
{
case CGroupCell::Center:
alignmentX = (columnWidth - cell->WidthMax) / 2;
widthReduceX = alignmentX * 2;
break;
case CGroupCell::Right:
alignmentX = columnWidth - cell->WidthMax;
widthReduceX = alignmentX;
break;
default:
break;
}
}
cell->setX(currentX - padding);
cell->setW(columnWidth + padding*2);
cell->Group->setX(alignmentX + cell->LeftMargin + padding);
cell->Group->setW(columnWidth - widthReduceX);
cell->Group->CInterfaceElement::updateCoords();
// Update coords to get H
cell->Group->checkCoords();
cell->Group->updateCoords();
// Resize the row array
float rowspan = 1 / cell->RowSpan;
_Rows.back().Height = std::max((sint32)(cell->Height*rowspan), std::max(_Rows.back().Height, (sint32)(cell->Group->getH()*rowspan)));
// Next column
currentX += columnWidth + 2*padding + CellSpacing;
column += cell->ColSpan;
}
// Set cell Y
row = 0;
sint32 currentY = -(Border + CellSpacing + padding);
for (i=0; i<_Cells.size(); i++)
{
// New cell ?
CGroupCell *cell = _Cells[i];
if ((i != 0) && (cell->NewLine))
{
if (_Rows[row].Height != 0)
{
currentY -= _Rows[row].Height + 2*padding + CellSpacing;
}
row++;
}
// Check align
sint32 alignmentY = 0;
sint32 rowHeight = _Rows[row].Height;
if (cell->RowSpan > 1)
{
// we need to scan down and add up row heights
int k = std::min((sint32)_Rows.size(), row + cell->RowSpan);
for(int j=row+1; jGroup->getH() < rowHeight)
{
switch (cell->VAlign)
{
case CGroupCell::Middle:
alignmentY = (rowHeight - (sint32)cell->Group->getH()) / 2;
break;
case CGroupCell::Bottom:
alignmentY = rowHeight - (sint32)cell->Group->getH();
break;
default:
break;
}
}
cell->setY(currentY + padding);
cell->setH (rowHeight + 2*padding);
cell->Group->setY(-(alignmentY + padding));
}
// Resize the table
setW(finalWidth+borderWidth-_LastParentW);
if (!_Rows.empty())
currentY -= _Rows[row].Height + padding + CellSpacing + Border;
setH(-currentY);
// All done
}
}
CInterfaceGroup::updateCoords();
// Validated
_ContentValidated = true;
}
// ----------------------------------------------------------------------------
void CGroupTable::checkCoords ()
{
if (_Parent != NULL)
{
sint parentWidth = std::min(_Parent->getMaxWReal(), _Parent->getWReal());
if (_LastParentW != (sint) parentWidth)
{
if (ContinuousUpdate)
{
_LastParentW = parentWidth;
invalidateContent();
}
else
{
CCtrlBase *pCB = CWidgetManager::getInstance()->getCapturePointerLeft();
if (pCB != NULL)
{
CCtrlResizer *pCR = dynamic_cast(pCB);
if (pCR != NULL)
{
// We are resizing !!!!
}
else
{
_LastParentW = parentWidth;
invalidateContent();
}
}
else
{
_LastParentW = parentWidth;
invalidateContent();
}
}
}
}
CInterfaceGroup::checkCoords();
}
// ----------------------------------------------------------------------------
void CGroupTable::onInvalidateContent()
{
_ContentValidated = false;
invalidateCoords();
}
// ----------------------------------------------------------------------------
sint32 CGroupTable::getMaxUsedW() const
{
uint i;
uint column = 0;
vector columns;
columns.clear ();
for (i=0; i<_Cells.size(); i++)
{
// Update coords to get XReal
CGroupCell *cell = _Cells[i];
cell->checkCoords();
cell->updateCoords();
// Get width min and max
sint32 cellWidthMax = cell->getMaxUsedW();
// New cell ?
if (cell->NewLine)
column = 0;
// Resize the array
if (column>=columns.size())
columns.resize(column+1, 0);
// Update sizes
if (cellWidthMax > columns[column])
columns[column] = cellWidthMax;
if (cell->WidthWanted)
columns[column] = cell->WidthWanted;
// Hack to force a table with ratio to be large
sint32 cellRatio = (sint32)ceil(cell->TableRatio * 1024.f);
if (cellRatio > columns[column])
columns[column] = cellRatio;
// Next column
column++;
}
// Sum
sint32 maxWidth = 0;
for (i=0; i columns;
columns.clear ();
for (i=0; i<_Cells.size(); i++)
{
// Update coords to get XReal
CGroupCell *cell = _Cells[i];
cell->checkCoords();
cell->updateCoords();
// Get width min and max
sint32 cellWidthMin = cell->getMinUsedW();
// New cell ?
if (cell->NewLine)
column = 0;
// Resize the array
if (column>=columns.size())
columns.resize(column+1, 0);
// Update sizes
if (cellWidthMin > columns[column])
columns[column] = cellWidthMin;
if (cell->WidthWanted)
columns[column] = cell->WidthWanted;
// Next column
column++;
}
// Sum
sint32 maxWidth = 0;
for (i=0; iisGroupContainer())
{
CGroupContainer *gc = static_cast(gr);
CurrentAlpha = gc->getCurrentContainerAlpha();
break;
}
gr = gr->getParent();
}
// Not found ?
if (gr == NULL)
CurrentAlpha = 255;
if (!_Columns.empty() && !_Rows.empty())
{
sint32 border = Border + CellSpacing;
if (border && BgColor.A)
{
CRGBA finalColor;
finalColor.modulateFromColor (BgColor, CWidgetManager::getInstance()->getGlobalColor());
finalColor.A = CurrentAlpha;
// Draw the top line
CViewRenderer &rVR = *CViewRenderer::getInstance();
rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal-border+_HReal, _WReal, border, 0, false, rVR.getBlankTextureId(), finalColor);
// Draw the left line
sint32 insideHeight = std::max((sint32)0, (sint32)_HReal - (sint32)border);
rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal, border, insideHeight, 0, false, rVR.getBlankTextureId(), finalColor);
// Draw the inside borders
if (CellSpacing)
{
uint i;
sint32 x, y;
for (i=0; i<_Cells.size(); i++)
{
CGroupCell *cell = _Cells[i];
x = cell->getXReal();
y = cell->getYReal() - CellSpacing;
// right
rVR.drawRotFlipBitmap (_RenderLayer, x + cell->getW(), y, CellSpacing, cell->getH() + CellSpacing, 0, false, rVR.getBlankTextureId(), finalColor);
// bottom
rVR.drawRotFlipBitmap (_RenderLayer, x, y, cell->getW(), CellSpacing, 0, false, rVR.getBlankTextureId(), finalColor);
}
}
}
if (Border)
{
CViewRenderer &rVR = *CViewRenderer::getInstance();
CRGBA borderColorTL;
CRGBA lighter = blend(BorderColor, CRGBA::White, 0.5f);
borderColorTL.modulateFromColor (lighter, CWidgetManager::getInstance()->getGlobalColor());
borderColorTL.A = CurrentAlpha;
CRGBA borderColorBR;
borderColorBR.modulateFromColor (BorderColor, CWidgetManager::getInstance()->getGlobalColor());
borderColorBR.A = CurrentAlpha;
// beveled table border
for (sint32 i=0; ichildren;
while (currRow != NULL)
{
// look for 'TR' markup
if (strcmp((char*)currRow->name,"TR") == 0)
{
// found a row, parse cells inside
xmlNodePtr currCol = currRow->children;
bool newLine = true;
uint column = 0;
while (currCol != NULL)
{
// look for 'TR' markup
if (strcmp((char*)currCol->name,"TD") == 0)
{
CGroupCell *cell = new CGroupCell(CViewBase::TCtorParam());
if (cell->parse(currCol, this, column, row))
{
cell->NewLine = newLine;
newLine = false;
addChild(cell);
}
else
{
delete cell;
}
++ column;
}
currCol = currCol->next;
}
++ row;
}
currRow = currRow->next;
}
return true;
}
}
|