static void createGUI(lua_State *L) { window *w = malloc(sizeof(window)); windowInit(w, "main", 300, 400); widgetReposition(WIDGET(w), 50, 50); widgetShow(WIDGET(w)); // GL stuff widgetEnableGL(WIDGET(w)); WIDGET(w)->vtbl->doDraw = paintWithGL; widgetAddTimerEventHandler(WIDGET(w), EVT_TIMER_SINGLE_SHOT, 3000, timer, NULL, NULL); }
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; }
static bool widgetAnimationTimerCallback(widget *self, const event *evt, int handlerId, void *userData) { int i; vector *frames = userData; animationFrame *currFrame; // Regular timer event if (evt->type == EVT_TIMER_PERSISTENT) { bool didInterpolate = false; // Currently active keyframes to be interpolated between struct { animationFrame *pre; animationFrame *post; } interpolateFrames[ANI_TYPE_COUNT] = { { NULL, NULL } }; // Work out what frames we need to interpolate between for (i = 0; i < vectorSize(frames); i++) { currFrame = vectorAt(frames, i); /* * We are only interested in the key frames which either directly * precede now or come directly after. (As it is these frames which * will be interpolated between.) */ if (currFrame->time <= evt->time) { interpolateFrames[currFrame->type].pre = currFrame; } else if (currFrame->time > evt->time && !interpolateFrames[currFrame->type].post) { interpolateFrames[currFrame->type].post = currFrame; } } // Do the interpolation for (i = 0; i < ANI_TYPE_COUNT; i++) { // If there are frames to interpolate between then do so if (interpolateFrames[i].pre && interpolateFrames[i].post) { // Get the points to interpolate between animationFrame k1 = *interpolateFrames[i].pre; animationFrame k2 = *interpolateFrames[i].post; int time = evt->time; switch (i) { case ANI_TYPE_TRANSLATE: { // Get the new position point pos = widgetAnimationInterpolateTranslate(self, k1, k2, time); // Set the new position widgetReposition(self, pos.x, pos.y); break; } case ANI_TYPE_ROTATE: // Update the widgets rotation self->rotate = widgetAnimationInterpolateRotate(self, k1, k2, time); break; case ANI_TYPE_SCALE: // Update the widgets scale factor self->scale = widgetAnimationInterpolateScale(self, k1, k2, time); break; case ANI_TYPE_ALPHA: // Update the widgets alpha self->alpha = widgetAnimationInterpolateAlpha(self, k1, k2, time); break; } // Make a note that we did interpolate didInterpolate = true; } } // If there was no interpolation then the animation is over if (!didInterpolate) { // Remove ourself (the event handler) widgetRemoveEventHandler(self, handlerId); } } else if (evt->type == EVT_DESTRUCT) { animationFrame *lastFrame[ANI_TYPE_COUNT] = { NULL }; // Find the last frame of each animation type for (i = 0; i < vectorSize(frames); i++) { currFrame = vectorAt(frames, i); lastFrame[currFrame->type] = currFrame; } // Set the position/rotation/scale/alpha to that of the final frame for (i = 0; i < ANI_TYPE_COUNT; i++) { if (lastFrame[i]) switch (i) { case ANI_TYPE_TRANSLATE: self->offset = lastFrame[ANI_TYPE_TRANSLATE]->data.translate; break; case ANI_TYPE_ROTATE: self->rotate = lastFrame[ANI_TYPE_ROTATE]->data.rotate; break; case ANI_TYPE_SCALE: self->scale = lastFrame[ANI_TYPE_SCALE]->data.scale; break; case ANI_TYPE_ALPHA: self->alpha = lastFrame[ANI_TYPE_ALPHA]->data.alpha; break; default: break; } } // Free the frames vector vectorMapAndDestroy(frames, free); } return true; }