void widgetResizeImpl(widget *self, int w, int h) { const size minSize = widgetGetMinSize(self); const size maxSize = widgetGetMaxSize(self); // Create an event eventResize evtResize; evtResize.event = widgetCreateEvent(EVT_RESIZE); // Save the current size in the event evtResize.oldSize = self->size; assert(minSize.x <= w); assert(minSize.y <= h); assert(w <= maxSize.x); assert(h <= maxSize.y); self->size.x = w; self->size.y = h; // Re-create the cairo context at this new size widgetCairoCreate(&self->cr, CAIRO_FORMAT_ARGB32, w, h); // If a mask is enabled; re-create it also if (self->maskEnabled) { widgetCairoCreate(&self->maskCr, CAIRO_FORMAT_A1, w, h); // Re-draw the mask (only done on resize) widgetDrawMask(self); } // If OpenGL is enabled disable and re-enable it if (self->openGLEnabled) { widgetDisableGL(self); widgetEnableGL(self); } // Set the needs redraw flag self->needsRedraw = true; // If we have any children, we need to redo their layout if (vectorSize(self->children)) { widgetDoLayout(self); } // Fire any EVT_RESIZE callbacks widgetFireCallbacks(self, (event *) &evtResize); }
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; }
/** * 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]++; } } }