Esempio n. 1
0
bool tableAddChildWithSpanAlign(table *self, widget *child,
                                int row, int rowspan, vAlign v,
                                int column, int colspan, hAlign h)
{
	int i, j;
	const int rowCount = tableGetRowCount(self);
	const int columnCount = tableGetColumnCount(self);
	childPositionInfo *pos;
	
	// First, check the row and column is valid
	assert(row > 0 && row <= tableGetRowCount(self) + 1);
	assert(column > 0 && column <= tableGetColumnCount(self) + 1);
	
	// Second, check all of the cells spanned are empty
	for (i = row; i < row + rowspan && i <= rowCount; i++)
	{
		for (j = column; j < column + colspan && j <= columnCount; j++)
		{
			assert(tableGetCell(self, i, j) == NULL);
		}
	}
	
	// Update the row and column counts
	self->numRows = MAX(rowCount, row + rowspan - 1);
	self->numColumns = MAX(columnCount, column + colspan - 1);
	
	// Add positional information regarding the child to our list
	pos = malloc(sizeof(childPositionInfo));
	
	pos->row = row;
	pos->rowspan = rowspan;
	
	pos->column = column;
	pos->colspan = colspan;
	
	pos->vAlignment = v;
	pos->hAlignment = h;
	
	vectorAdd(self->childPositions, pos);
	
	// Call widgetAddChildImpl, which will add the child and re-do the layout
	if (widgetAddChildImpl(WIDGET(self), child))
	{
		return true;
	}
	// Problem adding the child; positional information needs to be restored
	else
	{
		vectorRemoveAt(self->childPositions, vectorSize(self->childPositions) - 1);
		
		// Release the memory we malloc'ed earlier
		free(pos);
		
		// Restore the row and column counts
		self->numRows = rowCount;
		self->numColumns = columnCount;
		
		return false;
	}
}
Esempio n. 2
0
widget *tableGetCell(const table *self, int row, int column)
{
	int i;
	const int numChildren = vectorSize(WIDGET(self)->children);

	// Ensure that row and column are valid
	assert(row > 0 && row <= tableGetRowCount(self));
	assert(column > 0 && column <= tableGetColumnCount(self));
	
	// Search through the list of children until we find one matching
	for (i = 0; i < numChildren; i++)
	{
		// Legal as widget->children and table->childPositions are siblings
		const childPositionInfo *pos = vectorAt(self->childPositions, i);
		
		// See if it is a match
		if (row >= pos->row && row < pos->row + pos->rowspan
		 && column >= pos->column && column < pos->column + pos->colspan)
		{
			// We've found the widget
			return vectorAt(WIDGET(self)->children, i);
		}
	}
	
	// If the cell is empty, return NULL
	return NULL;
}
Esempio n. 3
0
bool hBoxAddChildImpl(widget *self, widget *child)
{
	// We want to add the child to the next free column
	const int column = tableGetColumnCount(TABLE(self)) + 1;

	// Delegate to tableAddChild with row = 1
	return tableAddChild(TABLE(self), child, 1, column);
}
Esempio n. 4
0
size tableGetMaxSizeImpl(widget *self)
{
	size maxSize;
	
	const int numRows = tableGetRowCount(TABLE(self));
	const int numColumns = tableGetColumnCount(TABLE(self));
	
	int *maxRowHeight = alloca(sizeof(int) * numRows);
	int *maxColumnWidth = alloca(sizeof(int) * numColumns);
	
	tableGetMaximumCellSizes(TABLE(self), maxRowHeight, maxColumnWidth);
	
	// Sum up the widths and the heights to get the table size
	maxSize.x = tablePartialSum(maxColumnWidth, 0, numColumns);
	maxSize.y = tablePartialSum(maxRowHeight, 0, numRows);
	
	return maxSize;
}
Esempio n. 5
0
/**
 * Removes any rows from the table which no cells occupy.
 *
 * @param self  The table to remove empty rows from.
 */
static void tableRemoveEmptyRows(table *self)
{
	int i, j, k;
	const int columnCount = tableGetColumnCount(self);
	const int numChildren = vectorSize(WIDGET(self)->children);
	
	// Iterate over each row of the table
	for (i = 1; i <= tableGetRowCount(self); i++)
	{
		// See if any of the columns in the row are occupied
		for (j = 1; j <= columnCount; j++)
		{
			if (tableGetCell(self, i, j))
			{
				break;
			}
		}
		
		// If the cells are all empty, we can remove the row
		if (j > columnCount)
		{
			// Find all cells in rows after the one to be removed
			for (k = 0; k < numChildren; k++)
			{
				childPositionInfo *pos = vectorAt(self->childPositions, k);
				
				// Decrease the row number of all rows > i by 1
				if (pos->row > i)
				{
					pos->row--;
				}
			}
			
			// The table now has one fewer rows in it
			self->numRows--;
			i--;
		}
	}
}
Esempio n. 6
0
bool tableDoLayoutImpl(widget *self)
{
	table *selfTable = TABLE(self);
	
	const int numChildren = vectorSize(self->children);
	
	const int numRows = tableGetRowCount(selfTable);
	const int numColumns = tableGetColumnCount(selfTable);
	
	int i;
	int dx, dy;
	
	int *minColumnWidth = alloca(sizeof(int) * numColumns);
	int *maxColumnWidth = alloca(sizeof(int) * numColumns);
	
	int *minRowHeight = alloca(sizeof(int) * numRows);
	int *maxRowHeight = alloca(sizeof(int) * numRows);
	
	// Syntatic sugar
	int *columnWidth = minColumnWidth;
	int *rowHeight = minRowHeight;
	
	// Get the minimum and maximum cell sizes
	tableGetMinimumCellSizes(selfTable, minRowHeight, minColumnWidth);
	tableGetMaximumCellSizes(selfTable, maxRowHeight, maxColumnWidth);
	
	// Calculate how much space we have left to fill
	dx = self->size.x - tablePartialSum(minColumnWidth, 0, numColumns);
	dy = self->size.y - tablePartialSum(minRowHeight, 0, numRows);
	
	// Increase the column size until we run out of space
	for (i = 0; dx; i = (i + 1) % numColumns)
	{
		// If the column is not maxed out, increases its size by one
		if (columnWidth[i] < maxColumnWidth[i])
		{
			columnWidth[i]++;
			dx--;
		}
	}
	
	// Increase the row size until we run out of space
	for (i = 0; dy; i = (i + 1) % numRows)
	{
		// If the row is not maxed out, increase its size by one
		if (rowHeight[i] < minRowHeight[i])
		{
			rowHeight[i]++;
			dy--;
		}
	}
	
	// Now we need to position the children, taking padding into account
	for (i = 0; i < numChildren; i++)
	{
		// Get the child and its position info
		widget *child = vectorAt(self->children, i);
		const childPositionInfo *pos = vectorAt(selfTable->childPositions, i);
		size maxChildSize = widgetGetMaxSize(child);
		
		// left is the sum of all of the preceding columns
		int left = tablePartialSum(columnWidth, 0, pos->column);
		
		// top is the sum of all of the preceding rows
		int top = tablePartialSum(rowHeight, 0, pos->row);
		
		// cellWidth is the sum of the columns we span
		int cellWidth = tablePartialSum(columnWidth, pos->column - 1, pos->colspan);
		
		// cellHeight is the sum of the rows we span
		int cellHeight = tablePartialSum(rowHeight, pos->row - 1, pos->rowspan);
		
		// Final width and height of the child
		int w, h;
		
		// Final x,y offsets of the child
		int x, y;
		
		// If we are not the last row/column, subtract the row/column padding
		if (pos->column + pos->colspan - 1 != numColumns)
		{
			cellWidth -= selfTable->columnPadding;
		}
		if (pos->row + pos->rowspan - 1 != numRows)
		{
			cellHeight -= selfTable->rowPadding;
		}
		
		// Compute the final width and height of the child
		w = MIN(cellWidth, maxChildSize.x);
		h = MIN(cellHeight, maxChildSize.y);
		
		// Pad out any remaining space
		switch (pos->hAlignment)
		{
			case LEFT:
				x = left;
				break;
			case CENTRE:
				x = left + (cellWidth - w) / 2;
				break;
			case RIGHT:
				x = left + cellWidth - w;
				break;
		}
		
		switch (pos->vAlignment)
		{
			case TOP:
				y = top;
				break;
			case MIDDLE:
				y = top + (cellHeight - h) / 2;
				break;
			case BOTTOM:
				y = top + cellHeight - h;
				break;
		}
		
		// Resize and reposition the widget
		widgetResize(child, w, h);
		widgetReposition(child, x, y);
	}
	
	return true;
}
Esempio n. 7
0
/**
 * Computes the maximum row/column size for each row/column in the table. It is
 * important to note that the widths/heights are inclusive of padding. Therefore
 * all but the rightmost column and bottom row will have either self->rowPadding
 * or self->columnPadding added onto their sizes.
 *
 * @param self  The table to get the minimum cell sizes of.
 * @param maxRowHeight  The array to place the maximum row heights for the table
 *                      into; assumed to be tableGetRowCount(self) in size.
 * @param maxColumnWidth    The array to place the maximum column widths for the
 *                          table into; assumed to be tableGetColumnCount(self)
 *                          in size.
 */
static void tableGetMaximumCellSizes(const table *self, int *maxRowHeight,
                                     int *maxColumnWidth)
{
	int i;
	int spanningIndex;
	
	const int numChildren = vectorSize(WIDGET(self)->children);
	const int numRows = tableGetRowCount(self);
	const int numColumns = tableGetColumnCount(self);
	
	size *maxChildSize = alloca(sizeof(size) * numChildren);
	
	// Zero the min row/column sizes
	memset(maxRowHeight, '\0', sizeof(int) * numRows);
	memset(maxColumnWidth, '\0', sizeof(int) * numColumns);
	
	// Get the maximum row/column sizes for single-spanning cells
	for (i = 0; i < numChildren; i++)
	{
		const childPositionInfo *pos = vectorAt(self->childPositions, i);
		const int row = pos->row - 1;
		const int col  = pos->column - 1;
		
		// Get the maximum size of the cell
		maxChildSize[i] = widgetGetMaxSize(vectorAt(WIDGET(self)->children, i));
		
		// If the row has a rowspan of 1; see if it is the highest thus far
		if (pos->rowspan == 1)
		{
			maxRowHeight[row] = MAX(maxRowHeight[row], maxChildSize[i].y);
		}
		
		// If the column has a colspan of 1; see if it is the widest thus far
		if (pos->colspan == 1)
		{
			maxColumnWidth[col] = MAX(maxColumnWidth[col], maxChildSize[i].x);
		}
	}
	
	// Handle spanning rows
	while ((spanningIndex = tableGetMostOversizedRow(self,
	                                                 maxRowHeight,
	                                                 maxChildSize)) != -1)
	{
		int i;
		const childPositionInfo *pos = vectorAt(self->childPositions, spanningIndex);
		
		// Calculate how much larger we need to make the spanned rows
		int delta = maxChildSize[spanningIndex].y - tablePartialSum(maxRowHeight,
																	pos->row - 1,
																	pos->rowspan);
		
		// Loop over the rows spanned increasing their height by 1
		for (i = pos->row; delta; i = pos->row + (i + 1) % pos->rowspan, delta--)
		{
			maxRowHeight[i]++;
		}
	}
	
	// Handle spanning columns
	while ((spanningIndex = tableGetMostOversizedColumn(self,
	                                                    maxColumnWidth,
	                                                    maxChildSize)) != -1)
	{
		int i;
		const childPositionInfo *pos = vectorAt(self->childPositions, spanningIndex);
		
		// Calculate how much larger we need to make the spanned columns
		int delta = maxChildSize[spanningIndex].x - tablePartialSum(maxColumnWidth, 
		                                                            pos->column - 1,
		                                                            pos->colspan);
		
		for (i = pos->column; delta; i = pos->column + (i + 1) % pos->colspan, delta--)
		{
			maxColumnWidth[i]++;
		}
	}
}