#include "table_layout.h"
#include "render_table.h"
#include <kglobal.h>
using namespace khtml;
FixedTableLayout::FixedTableLayout( RenderTable *table )
: TableLayout ( table )
{
}
FixedTableLayout::~FixedTableLayout()
{
}
int FixedTableLayout::calcWidthArray(int tableWidth)
{
int usedWidth = 0;
RenderObject *child = table->firstChild();
int cCol = 0;
int nEffCols = table->numEffCols();
width.resize( nEffCols );
width.fill( Length( Variable ) );
#ifdef DEBUG_LAYOUT
qDebug("FixedTableLayout::calcWidthArray( %d )", tableWidth );
qDebug(" col elements:");
#endif
Length grpWidth;
while ( child ) {
if ( child->isTableCol() ) {
RenderTableCol *col = static_cast<RenderTableCol *>(child);
int span = col->span();
if ( col->firstChild() ) {
grpWidth = col->style()->width();
} else {
Length w = col->style()->width();
if ( w.isVariable() )
w = grpWidth;
int effWidth = 0;
if ( w.type == Fixed && w.value > 0 )
effWidth = w.value;
#ifdef DEBUG_LAYOUT
qDebug(" col element: effCol=%d, span=%d: %d w=%d type=%d",
cCol, span, effWidth, w.value, w.type);
#endif
int usedSpan = 0;
int i = 0;
while ( usedSpan < span ) {
if( cCol + i >= nEffCols ) {
table->appendColumn( span - usedSpan );
nEffCols++;
width.resize( nEffCols );
width[nEffCols-1] = Length();
}
int eSpan = table->spanOfEffCol( cCol+i );
if ( (w.type == Fixed || w.type == Percent) && w.value > 0 ) {
width[cCol+i] = Length( w.value * eSpan, w.type );
usedWidth += effWidth * eSpan;
#ifdef DEBUG_LAYOUT
qDebug(" setting effCol %d (span=%d) to width %d(type=%d)",
cCol+i, eSpan, width[cCol+i].value, width[cCol+i].type );
#endif
}
usedSpan += eSpan;
i++;
}
cCol += i;
}
} else {
break;
}
RenderObject *next = child->firstChild();
if ( !next )
next = child->nextSibling();
if ( !next && child->parent()->isTableCol() ) {
next = child->parent()->nextSibling();
grpWidth = Length();
}
child = next;
}
#ifdef DEBUG_LAYOUT
qDebug(" first row:");
#endif
RenderTableSection *section = table->head;
if ( !section )
section = table->firstBody;
if ( !section )
section = table->foot;
if ( section ) {
cCol = 0;
RenderObject* firstRow = section->firstChild();
child = firstRow ? firstRow->firstChild() : 0;
while ( child ) {
if ( child->isTableCell() ) {
RenderTableCell *cell = static_cast<RenderTableCell *>(child);
Length w = cell->style()->width();
int span = cell->colSpan();
int effWidth = 0;
if ( (w.type == Fixed || w.type == Percent) && w.value > 0 )
effWidth = w.value;
#ifdef DEBUG_LAYOUT
qDebug(" table cell: effCol=%d, span=%d: %d", cCol, span, effWidth);
#endif
int usedSpan = 0;
int i = 0;
while ( usedSpan < span ) {
Q_ASSERT( cCol + i < nEffCols );
int eSpan = table->spanOfEffCol( cCol+i );
if ( width[cCol+i].type == Variable && w.type != Variable ) {
width[cCol+i] = Length( w.value*eSpan, w.type );
usedWidth += effWidth*eSpan;
#ifdef DEBUG_LAYOUT
qDebug(" setting effCol %d (span=%d) to width %d(type=%d)",
cCol+i, eSpan, width[cCol+i].value, width[cCol+i].type );
#endif
}
#ifdef DEBUG_LAYOUT
else {
qDebug(" width of col %d already defined (span=%d)", cCol, table->spanOfEffCol( cCol ) );
}
#endif
usedSpan += eSpan;
i++;
}
cCol += i;
} else {
Q_ASSERT( false );
}
child = child->nextSibling();
}
}
return usedWidth;
}
void FixedTableLayout::calcMinMaxWidth()
{
int bs = table->bordersPaddingAndSpacing();
int tableWidth = table->style()->width().type == Fixed ? table->style()->width().value - bs : 0;
int mw = calcWidthArray( tableWidth ) + bs;
table->m_minWidth = kMax( mw, tableWidth );
table->m_maxWidth = table->m_minWidth;
}
void FixedTableLayout::layout()
{
int tableWidth = table->width() - table->bordersPaddingAndSpacing();
int available = tableWidth;
int nEffCols = table->numEffCols();
int totalPercent = 0;
#ifdef DEBUG_LAYOUT
qDebug("FixedTableLayout::layout: tableWidth=%d, numEffCols=%d", tableWidth, nEffCols);
#endif
QMemArray<int> calcWidth;
calcWidth.resize( nEffCols );
calcWidth.fill( -1 );
if ( available > 0 ) {
for ( int i = 0; i < nEffCols; i++ )
if ( width[i].type == Percent )
totalPercent += width[i].value;
int base = tableWidth * totalPercent / 100;
if ( base > available )
base = available;
else
totalPercent = 100;
#ifdef DEBUG_LAYOUT
qDebug("FixedTableLayout::layout: assigning percent width, base=%d, totalPercent=%d", base, totalPercent);
#endif
for ( int i = 0; available > 0 && i < nEffCols; i++ ) {
if ( width[i].type == Percent ) {
int w = base * width[i].value / totalPercent;
available -= w;
calcWidth[i] = w;
}
}
}
for ( int i = 0; i < nEffCols; i++ ) {
if ( width[i].type == Fixed ) {
calcWidth[i] = width[i].value;
available -= width[i].value;
}
}
if ( available > 0 ) {
int totalVariable = 0;
for ( int i = 0; i < nEffCols; i++ )
if ( width[i].type == Variable )
totalVariable++;
for ( int i = 0; available > 0 && i < nEffCols; i++ ) {
if ( width[i].type == Variable ) {
int w = available / totalVariable;
available -= w;
calcWidth[i] = w;
totalVariable--;
}
}
}
for ( int i = 0; i < nEffCols; i++ )
if ( calcWidth[i] <= 0 )
calcWidth[i] = 0;
if ( available > 0 ) {
int total = nEffCols;
int i = nEffCols;
while ( i-- ) {
int w = available / total;
available -= w;
total--;
calcWidth[i] += w;
}
}
int pos = 0;
int hspacing = table->hBorderSpacing();
for ( int i = 0; i < nEffCols; i++ ) {
#ifdef DEBUG_LAYOUT
qDebug("col %d: %d (width %d)", i, pos, calcWidth[i] );
#endif
table->columnPos[i] = pos;
pos += calcWidth[i] + hspacing;
}
table->columnPos[table->columnPos.size()-1] = pos;
}
AutoTableLayout::AutoTableLayout( RenderTable* table )
: TableLayout( table )
{
percentagesDirty = true;
effWidthDirty = true;
total_percent = 0;
hasPercent = false;
}
AutoTableLayout::~AutoTableLayout()
{
}
void AutoTableLayout::recalcColumn( int effCol )
{
Layout &l = layoutStruct[effCol];
RenderObject *child = table->firstChild();
RenderTableCell *fixedContributor = 0;
RenderTableCell *maxContributor = 0;
while ( child ) {
if ( child->isTableSection() ) {
RenderTableSection *section = static_cast<RenderTableSection *>(child);
int numRows = section->numRows();
RenderTableCell *last = 0;
for ( int i = 0; i < numRows; i++ ) {
RenderTableCell *cell = section->cellAt( i, effCol );
if ( cell == (RenderTableCell *)-1 )
continue;
if ( cell && cell->colSpan() == 1 ) {
l.minWidth = QMAX(l.minWidth, 1);
l.maxWidth = QMAX(l.maxWidth, 1);
if ( !cell->minMaxKnown() )
cell->calcMinMaxWidth();
if ( cell->minWidth() > l.minWidth )
l.minWidth = cell->minWidth();
if ( cell->maxWidth() > l.maxWidth ) {
l.maxWidth = cell->maxWidth();
maxContributor = cell;
}
Length w = cell->style()->width();
if ( w.value > 32760 )
w.value = 32760;
if ( w.value < 0 )
w.value = 0;
switch( w.type ) {
case Fixed:
if ( w.value > 0 && (int)l.width.type != Percent ) {
int wval = w.value + (cell->paddingLeft()+cell->paddingRight());
if ( l.width.type == Fixed ) {
if ((wval > l.width.value) ||
((l.width.value == wval) && (maxContributor == cell))) {
l.width.value = wval;
fixedContributor = cell;
}
} else {
l.width.type = Fixed;
l.width.value = wval;
fixedContributor = cell;
}
}
break;
case Percent:
hasPercent = true;
if ( w.value > 0 && (l.width.type != Percent || w.value > l.width.value ) )
l.width = w;
break;
case Relative:
if ( w.type == Variable || (w.type == Relative && w.value > l.width.value ) )
l.width = w;
default:
break;
}
} else {
if ( cell && (!effCol || section->cellAt( i, effCol-1 ) != cell) ) {
l.minWidth = QMAX(l.minWidth, 1);
l.maxWidth = QMAX(l.maxWidth, 1);
insertSpanCell( cell );
}
last = cell;
}
}
}
child = child->nextSibling();
}
if ( l.width.type == Fixed ) {
if ( table->style()->htmlHacks()
&& (l.maxWidth > l.width.value) && (fixedContributor != maxContributor)) {
l.width = Length();
fixedContributor = 0;
}
}
l.maxWidth = kMax(l.maxWidth, l.minWidth);
#ifdef DEBUG_LAYOUT
qDebug("col %d, final min=%d, max=%d, width=%d(%d)", effCol, l.minWidth, l.maxWidth, l.width.value, l.width.type );
#endif
}
void AutoTableLayout::fullRecalc()
{
percentagesDirty = true;
hasPercent = false;
effWidthDirty = true;
int nEffCols = table->numEffCols();
layoutStruct.resize( nEffCols );
layoutStruct.fill( Layout() );
spanCells.fill( 0 );
RenderObject *child = table->firstChild();
Length grpWidth;
int cCol = 0;
while ( child ) {
if ( child->isTableCol() ) {
RenderTableCol *col = static_cast<RenderTableCol *>(child);
int span = col->span();
if ( col->firstChild() ) {
grpWidth = col->style()->width();
} else {
Length w = col->style()->width();
if ( w.isVariable() )
w = grpWidth;
if ( (w.type == Fixed && w.value == 0) ||
(w.type == Percent && w.value == 0) )
w = Length();
int cEffCol = table->colToEffCol( cCol );
#ifdef DEBUG_LAYOUT
qDebug(" col element %d (eff=%d): Length=%d(%d), span=%d, effColSpan=%d", cCol, cEffCol, w.value, w.type, span, table->spanOfEffCol(cEffCol ) );
#endif
if ( (int)w.type != Variable && span == 1 && cEffCol < nEffCols ) {
if ( table->spanOfEffCol( cEffCol ) == 1 ) {
layoutStruct[cEffCol].width = w;
if (w.isFixed() && layoutStruct[cEffCol].maxWidth < w.value)
layoutStruct[cEffCol].maxWidth = w.value;
}
}
cCol += span;
}
} else {
break;
}
RenderObject *next = child->firstChild();
if ( !next )
next = child->nextSibling();
if ( !next && child->parent()->isTableCol() ) {
next = child->parent()->nextSibling();
grpWidth = Length();
}
child = next;
}
for ( int i = 0; i < nEffCols; i++ )
recalcColumn( i );
}
static bool shouldScaleColumns(RenderTable* table)
{
bool scale = true;
while (table) {
Length tw = table->style()->width();
if ((tw.isVariable() || tw.isPercent()) && !table->isPositioned()) {
RenderBlock* cb = table->containingBlock();
while (cb && !cb->isCanvas() && !cb->isTableCell() &&
cb->style()->width().isVariable() && !cb->isPositioned())
cb = cb->containingBlock();
table = 0;
if (cb && cb->isTableCell() &&
(cb->style()->width().isVariable() || cb->style()->width().isPercent())) {
if (tw.isPercent())
scale = false;
else {
RenderTableCell* cell = static_cast<RenderTableCell*>(cb);
if (cell->colSpan() > 1 || cell->table()->style()->width().isVariable())
scale = false;
else
table = cell->table();
}
}
}
else
table = 0;
}
return scale;
}
void AutoTableLayout::calcMinMaxWidth()
{
#ifdef DEBUG_LAYOUT
qDebug("AutoTableLayout::calcMinMaxWidth");
#endif
fullRecalc();
int spanMaxWidth = calcEffectiveWidth();
int minWidth = 0;
int maxWidth = 0;
int maxPercent = 0;
int maxNonPercent = 0;
int remainingPercent = 100;
for ( unsigned int i = 0; i < layoutStruct.size(); i++ ) {
minWidth += layoutStruct[i].effMinWidth;
maxWidth += layoutStruct[i].effMaxWidth;
if ( layoutStruct[i].effWidth.type == Percent ) {
int percent = kMin(layoutStruct[i].effWidth.value, remainingPercent);
int pw = ( layoutStruct[i].effMaxWidth * 100) / kMax(percent, 1);
remainingPercent -= percent;
maxPercent = kMax( pw, maxPercent );
} else {
maxNonPercent += layoutStruct[i].effMaxWidth;
}
}
if (shouldScaleColumns(table)) {
maxNonPercent = (maxNonPercent * 100 + 50) / kMax(remainingPercent, 1);
maxWidth = kMax( maxNonPercent, maxWidth );
maxWidth = kMax( maxWidth, maxPercent );
}
maxWidth = kMax( maxWidth, spanMaxWidth );
int bs = table->bordersPaddingAndSpacing();
minWidth += bs;
maxWidth += bs;
Length tw = table->style()->width();
if ( tw.isFixed() && tw.value > 0 ) {
minWidth = kMax( minWidth, int( tw.value ) );
maxWidth = minWidth;
}
table->m_maxWidth = maxWidth;
table->m_minWidth = minWidth;
#ifdef DEBUG_LAYOUT
qDebug(" minWidth=%d, maxWidth=%d", table->m_minWidth, table->m_maxWidth );
#endif
}
int AutoTableLayout::calcEffectiveWidth()
{
int tMaxWidth = 0;
unsigned int nEffCols = layoutStruct.size();
int hspacing = table->hBorderSpacing();
#ifdef DEBUG_LAYOUT
qDebug("AutoTableLayout::calcEffectiveWidth for %d cols", nEffCols );
#endif
for ( unsigned int i = 0; i < nEffCols; i++ ) {
layoutStruct[i].effWidth = layoutStruct[i].width;
layoutStruct[i].effMinWidth = layoutStruct[i].minWidth;
layoutStruct[i].effMaxWidth = layoutStruct[i].maxWidth;
}
for ( unsigned int i = 0; i < spanCells.size(); i++ ) {
RenderTableCell *cell = spanCells[i];
if ( !cell || cell == (RenderTableCell *)-1 )
break;
int span = cell->colSpan();
Length w = cell->style()->width();
if ( !(w.type == Relative) && w.value == 0 )
w = Length();
int col = table->colToEffCol( cell->col() );
unsigned int lastCol = col;
int cMinWidth = cell->minWidth() + hspacing;
int cMaxWidth = cell->maxWidth() + hspacing;
int totalPercent = 0;
int minWidth = 0;
int maxWidth = 0;
bool allColsArePercent = true;
bool allColsAreFixed = true;
bool haveVariable = false;
int fixedWidth = 0;
#ifdef DEBUG_LAYOUT
int cSpan = span;
#endif
while ( lastCol < nEffCols && span > 0 ) {
switch( layoutStruct[lastCol].width.type ) {
case Percent:
totalPercent += layoutStruct[lastCol].width.value;
allColsAreFixed = false;
break;
case Fixed:
if (layoutStruct[lastCol].width.value > 0) {
fixedWidth += layoutStruct[lastCol].width.value;
allColsArePercent = false;
break;
}
case Variable:
haveVariable = true;
default:
if (layoutStruct[lastCol].effWidth.type != Percent) {
layoutStruct[lastCol].effWidth = Length();
allColsArePercent = false;
}
else
totalPercent += layoutStruct[lastCol].effWidth.value;
allColsAreFixed = false;
}
span -= table->spanOfEffCol( lastCol );
minWidth += layoutStruct[lastCol].effMinWidth;
maxWidth += layoutStruct[lastCol].effMaxWidth;
lastCol++;
cMinWidth -= hspacing;
cMaxWidth -= hspacing;
}
#ifdef DEBUG_LAYOUT
qDebug(" colspan cell %p at effCol %d, span %d, type %d, value %d cmin=%d min=%d fixedwidth=%d", cell, col, cSpan, w.type, w.value, cMinWidth, minWidth, fixedWidth );
#endif
if ( w.type == Percent ) {
if ( totalPercent > w.value || allColsArePercent ) {
w = Length();
} else {
int spanMax = QMAX( maxWidth, cMaxWidth );
#ifdef DEBUG_LAYOUT
qDebug(" adjusting tMaxWidth (%d): spanMax=%d, value=%d, totalPercent=%d", tMaxWidth, spanMax, w.value, totalPercent );
#endif
tMaxWidth = QMAX( tMaxWidth, spanMax * 100 / w.value );
int percentMissing = w.value - totalPercent;
int totalWidth = 0;
for ( unsigned int pos = col; pos < lastCol; pos++ ) {
if ( !(layoutStruct[pos].width.type == Percent ) )
totalWidth += layoutStruct[pos].effMaxWidth;
}
for ( unsigned int pos = col; pos < lastCol && totalWidth > 0; pos++ ) {
if ( !(layoutStruct[pos].width.type == Percent ) ) {
int percent = percentMissing * layoutStruct[pos].effMaxWidth / totalWidth;
#ifdef DEBUG_LAYOUT
qDebug(" col %d: setting percent value %d effMaxWidth=%d totalWidth=%d", pos, percent, layoutStruct[pos].effMaxWidth, totalWidth );
#endif
totalWidth -= layoutStruct[pos].effMaxWidth;
percentMissing -= percent;
if ( percent > 0 )
layoutStruct[pos].effWidth = Length( percent, Percent );
else
layoutStruct[pos].effWidth = Length();
}
}
}
}
if ( cMinWidth > minWidth ) {
if ( allColsAreFixed ) {
#ifdef DEBUG_LAYOUT
qDebug("extending minWidth of cols %d-%d to %dpx currentMin=%d accroding to fixed sum %d", col, lastCol-1, cMinWidth, minWidth, fixedWidth );
#endif
for ( unsigned int pos = col; fixedWidth > 0 && pos < lastCol; pos++ ) {
int w = QMAX( layoutStruct[pos].effMinWidth, cMinWidth * layoutStruct[pos].width.value / fixedWidth );
#ifdef DEBUG_LAYOUT
qDebug(" col %d: min=%d, effMin=%d, new=%d", pos, layoutStruct[pos].effMinWidth, layoutStruct[pos].effMinWidth, w );
#endif
fixedWidth -= layoutStruct[pos].width.value;
cMinWidth -= w;
layoutStruct[pos].effMinWidth = w;
}
} else {
#ifdef DEBUG_LAYOUT
qDebug("extending minWidth of cols %d-%d to %dpx currentMin=%d", col, lastCol-1, cMinWidth, minWidth );
#endif
int maxw = maxWidth;
int minw = minWidth;
for ( unsigned int pos = col; maxw > 0 && pos < lastCol; pos++ ) {
if ( layoutStruct[pos].width.type == Fixed && haveVariable && fixedWidth <= cMinWidth ) {
int w = QMAX( layoutStruct[pos].effMinWidth, layoutStruct[pos].width.value );
fixedWidth -= layoutStruct[pos].width.value;
minw -= layoutStruct[pos].effMinWidth;
#ifdef DEBUG_LAYOUT
qDebug(" col %d: min=%d, effMin=%d, new=%d", pos, layoutStruct[pos].effMinWidth, layoutStruct[pos].effMinWidth, w );
#endif
maxw -= layoutStruct[pos].effMaxWidth;
cMinWidth -= w;
layoutStruct[pos].effMinWidth = w;
}
}
for ( unsigned int pos = col; maxw > 0 && pos < lastCol && minw < cMinWidth; pos++ ) {
if ( !(layoutStruct[pos].width.type == Fixed && haveVariable && fixedWidth <= cMinWidth) ) {
int w = QMAX( layoutStruct[pos].effMinWidth, cMinWidth * layoutStruct[pos].effMaxWidth / maxw );
w = QMIN(layoutStruct[pos].effMinWidth+(cMinWidth-minw), w);
#ifdef DEBUG_LAYOUT
qDebug(" col %d: min=%d, effMin=%d, new=%d", pos, layoutStruct[pos].effMinWidth, layoutStruct[pos].effMinWidth, w );
#endif
maxw -= layoutStruct[pos].effMaxWidth;
minw -= layoutStruct[pos].effMinWidth;
cMinWidth -= w;
layoutStruct[pos].effMinWidth = w;
}
}
}
}
if ( !(w.type == Percent ) ) {
if ( cMaxWidth > maxWidth ) {
#ifdef DEBUG_LAYOUT
qDebug("extending maxWidth of cols %d-%d to %dpx", col, lastCol-1, cMaxWidth );
#endif
for ( unsigned int pos = col; maxWidth > 0 && pos < lastCol; pos++ ) {
int w = QMAX( layoutStruct[pos].effMaxWidth, cMaxWidth * layoutStruct[pos].effMaxWidth / maxWidth );
#ifdef DEBUG_LAYOUT
qDebug(" col %d: max=%d, effMax=%d, new=%d", pos, layoutStruct[pos].effMaxWidth, layoutStruct[pos].effMaxWidth, w );
#endif
maxWidth -= layoutStruct[pos].effMaxWidth;
cMaxWidth -= w;
layoutStruct[pos].effMaxWidth = w;
}
}
} else {
for ( unsigned int pos = col; pos < lastCol; pos++ )
layoutStruct[pos].maxWidth = QMAX(layoutStruct[pos].maxWidth, layoutStruct[pos].minWidth );
}
}
effWidthDirty = false;
return tMaxWidth;
}
void AutoTableLayout::insertSpanCell( RenderTableCell *cell )
{
if ( !cell || cell == (RenderTableCell *)-1 || cell->colSpan() == 1 )
return;
int size = spanCells.size();
if ( !size || spanCells[size-1] != 0 ) {
spanCells.resize( size + 10 );
for ( int i = 0; i < 10; i++ )
spanCells[size+i] = 0;
size += 10;
}
unsigned int pos = 0;
int span = cell->colSpan();
while ( pos < spanCells.size() && spanCells[pos] && span > spanCells[pos]->colSpan() )
pos++;
memmove( spanCells.data()+pos+1, spanCells.data()+pos, (size-pos-1)*sizeof( RenderTableCell * ) );
spanCells[pos] = cell;
}
void AutoTableLayout::layout()
{
int tableWidth = table->width() - table->bordersPaddingAndSpacing();
int available = tableWidth;
int nEffCols = table->numEffCols();
if ( nEffCols != (int)layoutStruct.size() ) {
qWarning("WARNING: nEffCols is not equal to layoutstruct!" );
fullRecalc();
nEffCols = table->numEffCols();
}
#ifdef DEBUG_LAYOUT
qDebug("AutoTableLayout::layout()");
#endif
if ( effWidthDirty )
calcEffectiveWidth();
#ifdef DEBUG_LAYOUT
qDebug(" tableWidth=%d, nEffCols=%d", tableWidth, nEffCols );
for ( int i = 0; i < nEffCols; i++ ) {
qDebug(" effcol %d is of type %d value %d, minWidth=%d, maxWidth=%d",
i, layoutStruct[i].width.type, layoutStruct[i].width.value,
layoutStruct[i].minWidth, layoutStruct[i].maxWidth );
qDebug(" effective: type %d value %d, minWidth=%d, maxWidth=%d",
layoutStruct[i].effWidth.type, layoutStruct[i].effWidth.value,
layoutStruct[i].effMinWidth, layoutStruct[i].effMaxWidth );
}
#endif
bool havePercent = false;
bool haveRelative = false;
int totalRelative = 0;
int numVariable = 0;
int numFixed = 0;
int totalVariable = 0;
int totalFixed = 0;
int totalPercent = 0;
int allocVariable = 0;
for ( int i = 0; i < nEffCols; i++ ) {
int w = layoutStruct[i].effMinWidth;
layoutStruct[i].calcWidth = w;
available -= w;
Length& width = layoutStruct[i].effWidth;
switch( width.type) {
case Percent:
havePercent = true;
totalPercent += width.value;
break;
case Relative:
haveRelative = true;
totalRelative += width.value;
break;
case Fixed:
numFixed++;
totalFixed += layoutStruct[i].effMaxWidth;
break;
case Variable:
case Static:
numVariable++;
totalVariable += layoutStruct[i].effMaxWidth;
allocVariable += w;
default:
break;
}
}
if ( available > 0 && havePercent ) {
for ( int i = 0; i < nEffCols; i++ ) {
Length &width = layoutStruct[i].effWidth;
if ( width.type == Percent ) {
int w = kMax ( int( layoutStruct[i].effMinWidth ), width.minWidth( tableWidth ) );
available += layoutStruct[i].calcWidth - w;
layoutStruct[i].calcWidth = w;
}
}
if ( totalPercent > 100 ) {
int excess = tableWidth*(totalPercent-100)/100;
for ( int i = nEffCols-1; i >= 0; i-- ) {
if ( layoutStruct[i].effWidth.type == Percent ) {
int w = layoutStruct[i].calcWidth;
int reduction = kMin( w, excess );
excess -= reduction;
int newWidth = kMax( int (layoutStruct[i].effMinWidth), w - reduction );
available += w - newWidth;
layoutStruct[i].calcWidth = newWidth;
}
}
}
}
#ifdef DEBUG_LAYOUT
qDebug("percent satisfied: available is %d", available);
#endif
if ( available > 0 ) {
for ( int i = 0; i < nEffCols; ++i ) {
Length &width = layoutStruct[i].effWidth;
if ( width.type == Fixed && width.value > layoutStruct[i].calcWidth ) {
available += layoutStruct[i].calcWidth - width.value;
layoutStruct[i].calcWidth = width.value;
}
}
}
#ifdef DEBUG_LAYOUT
qDebug("fixed satisfied: available is %d", available);
#endif
if ( available > 0 ) {
for ( int i = 0; i < nEffCols; i++ ) {
Length &width = layoutStruct[i].effWidth;
if ( width.type == Relative && width.value != 0 ) {
int w = width.value*tableWidth/totalRelative;
available += layoutStruct[i].calcWidth - w;
layoutStruct[i].calcWidth = w;
}
}
}
if ( available > 0 && numVariable ) {
available += allocVariable; for ( int i = 0; i < nEffCols; i++ ) {
Length &width = layoutStruct[i].effWidth;
if ( width.type == Variable && totalVariable != 0 ) {
int w = kMax( int ( layoutStruct[i].calcWidth ),
available * layoutStruct[i].effMaxWidth / totalVariable );
available -= w;
totalVariable -= layoutStruct[i].effMaxWidth;
layoutStruct[i].calcWidth = w;
}
}
}
#ifdef DEBUG_LAYOUT
qDebug("variable satisfied: available is %d", available );
#endif
if (available > 0 && numFixed) {
for ( int i = 0; i < nEffCols; i++ ) {
Length &width = layoutStruct[i].effWidth;
if ( width.isFixed() ) {
int w = available * layoutStruct[i].effMaxWidth / totalFixed;
available -= w;
totalFixed -= layoutStruct[i].effMaxWidth;
layoutStruct[i].calcWidth += w;
}
}
}
#ifdef DEBUG_LAYOUT
qDebug("after fixed distribution: available=%d", available );
#endif
if (available > 0 && hasPercent && totalPercent < 100) {
for ( int i = 0; i < nEffCols; i++ ) {
Length &width = layoutStruct[i].effWidth;
if ( width.isPercent() ) {
int w = available * width.value / totalPercent;
available -= w;
totalPercent -= width.value;
layoutStruct[i].calcWidth += w;
if (!available || !totalPercent) break;
}
}
}
#ifdef DEBUG_LAYOUT
qDebug("after percent distribution: available=%d", available );
#endif
if ( available > 0 ) {
int total = nEffCols;
int i = nEffCols;
while ( i-- ) {
int w = available / total;
available -= w;
total--;
layoutStruct[i].calcWidth += w;
}
}
#ifdef DEBUG_LAYOUT
qDebug("after equal distribution: available=%d", available );
#endif
if ( available < 0 ) {
if (available < 0) {
int mw = 0;
for ( int i = nEffCols-1; i >= 0; i-- ) {
Length &width = layoutStruct[i].effWidth;
if (width.isVariable())
mw += layoutStruct[i].calcWidth - layoutStruct[i].effMinWidth;
}
for ( int i = nEffCols-1; i >= 0 && mw > 0; i-- ) {
Length &width = layoutStruct[i].effWidth;
if (width.isVariable()) {
int minMaxDiff = layoutStruct[i].calcWidth-layoutStruct[i].effMinWidth;
int reduce = available * minMaxDiff / mw;
layoutStruct[i].calcWidth += reduce;
available -= reduce;
mw -= minMaxDiff;
if ( available >= 0 )
break;
}
}
}
if (available < 0) {
int mw = 0;
for ( int i = nEffCols-1; i >= 0; i-- ) {
Length &width = layoutStruct[i].effWidth;
if (width.isRelative())
mw += layoutStruct[i].calcWidth - layoutStruct[i].effMinWidth;
}
for ( int i = nEffCols-1; i >= 0 && mw > 0; i-- ) {
Length &width = layoutStruct[i].effWidth;
if (width.isRelative()) {
int minMaxDiff = layoutStruct[i].calcWidth-layoutStruct[i].effMinWidth;
int reduce = available * minMaxDiff / mw;
layoutStruct[i].calcWidth += reduce;
available -= reduce;
mw -= minMaxDiff;
if ( available >= 0 )
break;
}
}
}
if (available < 0) {
int mw = 0;
for ( int i = nEffCols-1; i >= 0; i-- ) {
Length &width = layoutStruct[i].effWidth;
if (width.isFixed())
mw += layoutStruct[i].calcWidth - layoutStruct[i].effMinWidth;
}
for ( int i = nEffCols-1; i >= 0 && mw > 0; i-- ) {
Length &width = layoutStruct[i].effWidth;
if (width.isFixed()) {
int minMaxDiff = layoutStruct[i].calcWidth-layoutStruct[i].effMinWidth;
int reduce = available * minMaxDiff / mw;
layoutStruct[i].calcWidth += reduce;
available -= reduce;
mw -= minMaxDiff;
if ( available >= 0 )
break;
}
}
}
if (available < 0) {
int mw = 0;
for ( int i = nEffCols-1; i >= 0; i-- ) {
Length &width = layoutStruct[i].effWidth;
if (width.isPercent())
mw += layoutStruct[i].calcWidth - layoutStruct[i].effMinWidth;
}
for ( int i = nEffCols-1; i >= 0 && mw > 0; i-- ) {
Length &width = layoutStruct[i].effWidth;
if (width.isPercent()) {
int minMaxDiff = layoutStruct[i].calcWidth-layoutStruct[i].effMinWidth;
int reduce = available * minMaxDiff / mw;
layoutStruct[i].calcWidth += reduce;
available -= reduce;
mw -= minMaxDiff;
if ( available >= 0 )
break;
}
}
}
}
int pos = 0;
for ( int i = 0; i < nEffCols; i++ ) {
#ifdef DEBUG_LAYOUT
qDebug("col %d: %d (width %d)", i, pos, layoutStruct[i].calcWidth );
#endif
table->columnPos[i] = pos;
pos += layoutStruct[i].calcWidth + table->hBorderSpacing();
}
table->columnPos[table->columnPos.size()-1] = pos;
}
void AutoTableLayout::calcPercentages() const
{
total_percent = 0;
for ( unsigned int i = 0; i < layoutStruct.size(); i++ ) {
if ( layoutStruct[i].width.type == Percent )
total_percent += layoutStruct[i].width.value;
}
percentagesDirty = false;
}
#undef DEBUG_LAYOUT