Exemple #1
0
void widgetRemoveChildImpl(widget *self, widget *child)
{
	int i;

	for (i = 0; i < vectorSize(self->children); i++)
	{
		// If the child is the to-be-removed widget, remove it
		if (vectorAt(self->children, i) == child)
		{
			// Call the destructor for the widget
			widgetDestroy(vectorAt(self->children, i));

			// Remove it from the list of children
			vectorRemoveAt(self->children, i);

			// Re-layout the window (so long as we are part of one)
			if (self->size.x != -1.0f && self->size.y != -1.0f)
			{
				widgetDoLayout(widgetGetRoot(self));
			}
		}
		// See if it is one of its children
		else if (child->parent != self)
		{
			widgetRemoveChild(vectorAt(self->children, i), child);
		}
	}
}
Exemple #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;
}
Exemple #3
0
void widgetDisableImpl(widget *self)
{
	int i;
	eventMisc evt;

	// If we are currently disabled, return
	if (!self->isEnabled)
	{
		return;
	}

	// Disable ourself
	self->isEnabled = false;

	// Fire any on-disable callbacks
	evt.event = widgetCreateEvent(EVT_DISABLE);
	widgetFireCallbacks(self, (event *) &evt);

	// Disable our children
	for (i = 0; i < vectorSize(self->children); i++)
	{
		widgetDisable(vectorAt(self->children, i));
	}

}
Exemple #4
0
widget *widgetFindById(widget *self, const char *id)
{
	// See if we have that ID
	if (strcmp(self->id, id) == 0)
	{
		return self;
	}
	// Try our children
	else
	{
		int i;

		for (i = 0; i < vectorSize(self->children); i++)
		{
			// Get the child widget
			widget *child = vectorAt(self->children, i);

			// Call its findById method
			widget *match = widgetFindById(child, id);

			// If it matched, return
			if (match)
			{
				return match;
			}
		}
	}

	// If we found nothing return NULL
	return NULL;
}
Exemple #5
0
bool widgetFireCallbacksImpl(widget *self, const event *evt)
{
	int i;
	bool ret;

	for (i = 0; i < vectorSize(self->eventVtbl); i++)
	{
		eventTableEntry *handler = vectorAt(self->eventVtbl, i);

		// If handler is registered to handle evt
		if (handler->type == evt->type)
		{
			// Fire the callback
			ret = handler->callback(self, evt, handler->id, handler->userData);

			// Update the last called time
			handler->lastCalled = evt->time;

			// Break if the handler returned false
			if (!ret)
			{
				break;
			}
		}
	}

	// FIXME
	return true;
}
Exemple #6
0
/**
 * Returns the (spanning) column with the greatest difference between
 * childSize.x and the sum of the columns it spans (divided by the number of
 * columns it spans).
 *
 * @param self  The table to determine the most undersized column of.
 * @param rowHeight An array containing the current column heights of the column
 *                  in the table.
 * @param childSize The desired (min/max) size of the children in the table.
 * @return The offset of the most undersized column in the table in the
 *         WIDGET(self)->children array, or -1 if there are no such rows.
 * @see tableGetMostOversizedRow
 */
static int tableGetMostOversizedColumn(const table *self,
                                       const int *columnWidth,
                                       const size *childSize)
{
	int i;
	float maxDelta = 0.0f;
	int maxDeltaIndex = -1;
	const int numChildren = vectorSize(WIDGET(self)->children);
	
	for (i = 0; i < numChildren; i++)
	{
		const childPositionInfo *pos = vectorAt(self->childPositions, i);
		
		// See if the column is a spanning column
		if (pos->colspan != 1)
		{
			float sum = tablePartialSum(columnWidth, pos->column - 1, pos->colspan);
			
			// If the column is wider than the sum of its spanned columns
			if (childSize[i].x > sum)
			{
				float delta = (childSize[i].x - sum) / (float) pos->colspan;
				
				if (delta > maxDelta)
				{
					maxDelta = delta;
					maxDeltaIndex = i;
				}
			}
		}
	}
	
	return maxDeltaIndex;
}
Exemple #7
0
void widgetRemoveEventHandlerImpl(widget *self, int id)
{
	int i;

	// Search for the handler with the id
	for (i = 0; i < vectorSize(self->eventVtbl); i++)
	{
		eventTableEntry *handler = vectorAt(self->eventVtbl, i);

		// If the handler matches, remove it
		if (handler->id == id)
		{
			// If there is a destructor; call it
			if (handler->destructor)
			{
				// Generate an EVT_DESTRUCT event
				eventMisc evtDestruct;
				evtDestruct.event = widgetCreateEvent(EVT_DESTRUCT);

				handler->destructor(self, (event *) &evtDestruct, handler->id,
				                    handler->userData);
			}

			// Release the handler
			free(handler);

			// Finally, remove the event handler from the table
			vectorRemoveAt(self->eventVtbl, i);
			break;
		}
	}
}
Exemple #8
0
/**
 * Returns the (spanning) row with the greatest difference between childSize.y
 * and the sum of the rows it spans (divided by the number of rows it spans).
 *
 * This function is integral to solving the problem about how to decide which
 * rows to increase the height of when handing spanning rows. This is because
 * the order in which we increase the size of rows affects the final layout.
 *
 * @param self  The table to determine the most undersized row of.
 * @param rowHeight An array containing the current row heights of the rows in
 *                  the table.
 * @param childSize The desired (min/max) size of the children in the table.
 * @return The offset of the most undersized row in the table in the
 *         WIDGET(self)->children array, or -1 if there are no such rows.
 */
static int tableGetMostOversizedRow(const table *self, const int *rowHeight,
                                    const size *childSize)
{
	int i;
	float maxDelta = 0.0f;
	int maxDeltaIndex = -1;
	const int numChildren = vectorSize(WIDGET(self)->children);
	
	for (i = 0; i < numChildren; i++)
	{
		const childPositionInfo *pos = vectorAt(self->childPositions, i);
		
		// See if the row is a spanning row
		if (pos->rowspan != 1)
		{
			float sum = tablePartialSum(rowHeight, pos->row - 1, pos->rowspan);
			
			// If the row is higher than the sum of its spanned rows
			if (childSize[i].y > sum)
			{
				float delta = (childSize[i].y - sum) / (float) pos->rowspan;
				
				if (delta > maxDelta)
				{
					maxDelta = delta;
					maxDeltaIndex = i;
				}
			}
		}
	}
	
	return maxDeltaIndex;
}
Exemple #9
0
void widgetCompositeImpl(widget *self)
{
	float blendColour[4];
	int i;

	// Do not composite unless we are visible
	if (!self->isVisible)
	{
		return;
	}

	// Save the current model-view matrix
	glPushMatrix();

	// Translate such that (0,0) is the top-left of ourself
	glTranslatef(self->offset.x, self->offset.y, 0.0f);

	// Scale if necessary
	glScalef(self->scale.x,  self->scale.y,  1.0f);

	// Rotate ourself
	glRotatef(self->rotate, 0.0f, 0.0f, 1.0f);

	// Set our alpha (blend colour)
	glGetFloatv(GL_BLEND_COLOR, blendColour);
	glBlendColor(1.0f, 1.0f, 1.0f, blendColour[3] * self->alpha);

	// Composite ourself
	glBindTexture(GL_TEXTURE_RECTANGLE_ARB, self->textureId);

	glBegin(GL_TRIANGLE_STRIP);
		glTexCoord2f(0.0f, self->size.y);
		glVertex2f(0.0f, self->size.y);

		glTexCoord2f(0.0f, 0.0f);
		glVertex2f(0.0f, 0.0f);

		glTexCoord2f(self->size.x, self->size.y);
		glVertex2f(self->size.x, self->size.y);

		glTexCoord2f(self->size.x, 0.0f);
		glVertex2f(self->size.x, 0.0f);
	glEnd();

	// Now our children
	for (i = 0; i < vectorSize(self->children); i++)
	{
		widget *child = vectorAt(self->children, i);

		// Composite
		widgetComposite(child);
	}

	// Restore the model-view matrix
	glPopMatrix();

	// Restore the blend colour
	glBlendColor(1.0f, 1.0f, 1.0f, blendColour[3]);
}
Exemple #10
0
void widgetDraw(widget *self)
{
	int i;

	// See if we need to be redrawn
	if (self->needsRedraw)
	{
		void *bits = cairo_image_surface_get_data(cairo_get_target(self->cr));

		self->needsRedraw = false;

		// Mark the texture as needing uploading
		self->textureNeedsUploading = true;

		// Clear the current context
		cairo_set_operator(self->cr, CAIRO_OPERATOR_SOURCE);
		cairo_set_source_rgba(self->cr, 0.0, 0.0, 0.0, 0.0);
		cairo_paint(self->cr);

		// Restore the compositing operator back to the default
		cairo_set_operator(self->cr, CAIRO_OPERATOR_OVER);

		// Save (push) the current context
		cairo_save(self->cr);

		// Redaw ourself
		widgetDoDraw(self);

		// Restore the context
		cairo_restore(self->cr);

		// Update the texture if widgetEndGL has not done it for us
		if (self->textureNeedsUploading)
		{
			// Flush the cairo surface to ensure that all drawing is completed
			cairo_surface_flush(cairo_get_target(self->cr));

			glBindTexture(GL_TEXTURE_RECTANGLE_ARB, self->textureId);

			glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, self->size.x,
			             self->size.y, 0, GL_BGRA, GL_UNSIGNED_BYTE, bits);

			self->textureNeedsUploading = false;
		}

	}

	// Draw our children (even if we did not need redrawing our children might)
	for (i = 0; i < vectorSize(self->children); i++)
	{
		widget *child = vectorAt(self->children, i);

		// Ask the child to re-draw itself
		widgetDraw(child);
	}
}
Exemple #11
0
tReal tPropSurface::hubRadiusAt(tReal /*x*/)
{
  // Spaeter mal durch interpolation eines Splines ersetzen.
  // return hubDiameter*0.5*fDiameter*fScale;

  tVector X;
  X = vectorAt(0,0);
  X = X.toCylCOS(tVector(0,0,0),tVector(1,0,0),tVector(0,1,0));
  return X.y;
}
Exemple #12
0
void tableRemoveChildImpl(widget *self, widget *child)
{
	// If we are not the childs parent, delegate to widgetRemoveChildImpl
	if (self != child->parent)
	{
		widgetRemoveChildImpl(self, child);
	}
	// We are the childs parent, so there is some bookkeeping to tend to
	else
	{
		int i;
		
		// Find the index of the child
		for (i = 0; i < vectorSize(self->children); i++)
		{
			if (child == vectorAt(self->children, i))
			{
				break;
			}
		}
		
		// Call the child's destructor and remove it
		widgetDestroy(vectorAt(self->children, i));
		vectorRemoveAt(self->children, i);
		
		// Remove the childs positional information
		free(vectorAt(TABLE(self)->childPositions, i));
		vectorRemoveAt(TABLE(self)->childPositions, i);
		
		// Remove any empty rows/columns
		tableRemoveEmptyRows(TABLE(self));
		tableRemoveEmptyColumns(TABLE(self));
		
		// Redo the layout of the window
		if (self->size.x != -1 && self->size.y != -1)
		{
			widgetDoLayout(widgetGetRoot(self));
		}
	}
}
Exemple #13
0
/**
 * Passes the event, evt, onto each child of self.
 *
 * @param self  The widget to dispatch the event for.
 * @param evt   The event to dispatch.
 * @return True if any child widgets of self handled the event, false if self
 *         either has no children or if none of them handled the event.
 */
static bool widgetDispatchEventToChildren(widget *self, const event *evt)
{
	int i;
	const int numChildren = vectorSize(self->children);
	bool handled = false;

	for (i = 0; i < numChildren; i++)
	{
		// 'We' handled the event if any of our children handled it
		if (widgetHandleEvent(vectorAt(self->children, i), evt))
		{
			handled = true;
		}
	}

	return handled;
}
Exemple #14
0
bool widgetFireTimerCallbacksImpl(widget *self, const event *evt)
{
	int i;
	bool ret;
	eventTimer evtTimer = *((eventTimer *) evt);

	// We should only be passed EVT_TIMER events
	assert(evt->type == EVT_TIMER);

	for (i = 0; i < vectorSize(self->eventVtbl); i++)
	{
		eventTableEntry *handler = vectorAt(self->eventVtbl, i);

		// See if the handler is registered to handle timer events
		if (handler->type == EVT_TIMER_SINGLE_SHOT
		 || handler->type == EVT_TIMER_PERSISTENT)
		{
			// See if the event needs to be fired
			if (evt->time >= (handler->lastCalled + handler->interval))
			{
				// Ensure the type of our custom event matches
				evtTimer.event.type = handler->type;

				// Fire the associated callback
				ret = handler->callback(self, (event *) &evtTimer, handler->id,
				                        handler->userData);

				// Update the last called time
				handler->lastCalled = evt->time;

				// If the event is single shot then remove it
				if (handler->type == EVT_TIMER_SINGLE_SHOT)
				{
					widgetRemoveEventHandler(self, handler->id);
				}
			}
		}
	}

	// FIXME
	return true;
}
Exemple #15
0
/**
 * Returns a pointer to the event handler with an id of id. Should id be invalid
 * then NULL is returned.
 *
 * @param self  The widget whose event handler table to search.
 * @param id    The id of the desired event handler.
 * @return A pointer to the event handler, or NULL if id is invalid.
 */
static eventTableEntry *widgetGetEventHandlerById(const widget *self, int id)
{
	int i;
	eventTableEntry *entry = NULL;

	// Search the event handler table
	for (i = 0; i < vectorSize(self->eventVtbl); i++)
	{
		eventTableEntry *currEntry = vectorAt(self->eventVtbl, id);

		// See if the id matches
		if (currEntry->id == id)
		{
			entry = currEntry;
			break;
		}
	}

	return entry;
}
Exemple #16
0
widget *widgetGetCurrentlyFocused(widget *self)
{
	int i;

	if (!self->hasFocus)
	{
		return NULL;
	}

	for (i = 0; i < vectorSize(self->children); i++)
	{
		widget *child = vectorAt(self->children, i);

		if (child->hasFocus)
		{
			return widgetGetCurrentlyFocused(child);
		}
	}

	// None of our children are focused, return ourself
	return self;
}
Exemple #17
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--;
		}
	}
}
Exemple #18
0
widget *widgetGetCurrentlyMousedOver(widget *self)
{
	int i;

	// Make sure we have the mouse
	if (!self->hasMouse)
	{
		return NULL;
	}

	// See if any of our children are moused over
	for (i = 0; i < vectorSize(self->children); i++)
	{
		widget *child = vectorAt(self->children, i);

		if (child->hasMouse)
		{
			return widgetGetCurrentlyMousedOver(child);
		}
	}

	// None of our children have the mouse; return ourself
	return self;
}
Exemple #19
0
void widgetEnableImpl(widget *self)
{
	int i;
	eventMisc evt;

	// First make sure our parent is enabled
	if (self->parent && !self->parent->isEnabled)
	{
		return;
	}

	// Enable ourself
	self->isEnabled = true;

	// Fire any on-enable callbacks
	evt.event = widgetCreateEvent(EVT_ENABLE);
	widgetFireCallbacks(self, (event *) &evt);

	// Enable all of our children
	for (i = 0; i < vectorSize(self->children); i++)
	{
		widgetEnable(vectorAt(self->children, i));
	}
}
Exemple #20
0
void widgetFocusImpl(widget *self)
{
	eventMisc evt;

	// Check that we are not currently focused
	if (self->hasFocus)
	{
		int i;

		// Blur any of our currently focused child widgets
		for (i = 0; i < vectorSize(self->children); i++)
		{
			widget *child = vectorAt(self->children, i);

			if (child->hasFocus)
			{
				widgetBlur(child);
			}
		}

		return;
	}

	// If we have a parent, focus it
	if (self->parent)
	{
		widgetFocus(self->parent);
	}

	// Focus ourself
	self->hasFocus = true;

	// Fire our on-focus callbacks
	evt.event = widgetCreateEvent(EVT_FOCUS);
	widgetFireCallbacks(self, (event *) &evt);
}
Exemple #21
0
void *vectorHead(vector *v)
{
	return vectorAt(v, v->head - 1);
}
int main(int argc, char *argv[])
{
	SDL_Surface *screen;
	SDL_Event sdlEvent;
	bool quit = false;
	lua_State* L;

	// Make sure everything is cleaned up on quit
	atexit(SDL_Quit);

	// Init SDL
	if (SDL_Init(SDL_INIT_VIDEO) < -1)
	{
		fprintf(stderr, "SDL_init: %s\n", SDL_GetError());
		exit(1);
	}

	// Enable UNICODE support (for key events)
	SDL_EnableUNICODE(true);

	// Enable double-buffering
	SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);

	// Enable sync-to-vblank
	SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 1);

	// 800x600 true colour
	screen = SDL_SetVideoMode(800, 600, 32, SDL_OPENGL);
	if (screen == NULL)
	{
		fprintf(stderr, "SDL_SetVideoMode: %s\n", SDL_GetError());
		exit(1);
	}

	SDL_WM_SetCaption("Warzone UI Simulator", NULL);

	// Init OpenGL
	glClearColor(0.3f, 0.3f, 0.3f, 0.0f);
	glCullFace(GL_BACK);
	glEnable(GL_BLEND);
	glBlendFunc(GL_CONSTANT_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glBlendColor(1.0f, 1.0f, 1.0f, 1.0f);
	glEnable(GL_TEXTURE_RECTANGLE_ARB);

	glViewport(0, 0, 800, 600);

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(0.0, 800, 600, 0.0, -1.0, 1.0);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	/*
	 * Create the GUI
	 */
	widgetSDLInit();
	L = lua_open_betawidget();
	createGUI(L);

	// Main event loop
	while (!quit)
	{
		int i;

		while (SDL_PollEvent(&sdlEvent))
		{
			if (sdlEvent.type == SDL_QUIT)
			{
				quit = true;
			}
			else
			{
				widgetHandleSDLEvent(&sdlEvent);
			}
		}

		// Fire timer events
		widgetFireTimers();

		glClear(GL_COLOR_BUFFER_BIT);

		for (i = 0; i < vectorSize(windowGetWindowVector()); i++)
		{
			window *wnd = vectorAt(windowGetWindowVector(), i);

			widgetDraw(WIDGET(wnd));
			widgetComposite(WIDGET(wnd));
		}


		SDL_GL_SwapBuffers();
	}

	lua_close(L);
	widgetSDLQuit();

	return EXIT_SUCCESS;
}
Exemple #23
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;
}
Exemple #24
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]++;
		}
	}
}
Exemple #25
0
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;
}