Update the widget animation callback to use widgetReposition as opposed to setting the position directly.

git-svn-id: svn+ssh://svn.gna.org/svn/warzone/trunk@5932 4a71c877-e1ca-e34f-864e-861f7616d084
master
Freddie Witherden 2008-09-06 12:26:27 +00:00
parent 906f766b8a
commit 04e2f5f82b
3 changed files with 217 additions and 6 deletions

View File

@ -240,10 +240,16 @@ static bool widgetAnimationTimerCallback(widget *self, const event *evt,
switch (i)
{
case ANI_TYPE_TRANSLATE:
// Update the widgets position
self->offset = widgetAnimationInterpolateTranslate(self, k1,
k2, time);
{
// 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,

View File

@ -44,6 +44,7 @@ static void windowInitVtbl(window *self)
vtbl.widgetVtbl.addChild = windowAddChildImpl;
vtbl.widgetVtbl.doLayout = windowDoLayoutImpl;
vtbl.widgetVtbl.doDraw = windowDoDrawImpl;
vtbl.widgetVtbl.resize = windowResizeImpl;
vtbl.widgetVtbl.getMinSize = windowGetMinSizeImpl;
vtbl.widgetVtbl.getMaxSize = windowGetMaxSizeImpl;
@ -77,6 +78,11 @@ void windowInit(window *self, const char *id, int w, int h)
// Set our size to (w,h)
widgetResize(WIDGET(self), w, h);
// Default anchor state is static (as opposed to dynamic)
self->anchorState = ANCHOR_STATIC;
self->anchorWindow = NULL;
self->anchorRepositionId = self->anchorResizeId = -1;
}
void windowDestroyImpl(widget *self)
@ -240,9 +246,36 @@ void windowRepositionFromScreen(window *self, hAlign hAlign, int xOffset,
widgetReposition(WIDGET(self), x, y);
}
void windowRepositionFromAnchor(window *self, const window *anchor,
hAlign hAlign, int xOffset,
vAlign vAlign, int yOffset)
void windowSetAnchorState(window *self, anchorState state)
{
// If the anchor is being disabled, remove any active event handlers
if (state == ANCHOR_STATIC && self->anchorWindow)
{
widget *anchorWidget = WIDGET(self->anchorWindow);
// Remove the reposition event handler
if (widgetIsEventHandler(anchorWidget, self->anchorRepositionId))
{
widgetRemoveEventHandler(anchorWidget, self->anchorRepositionId);
}
// Remove the resize event handler
if (widgetIsEventHandler(anchorWidget, self->anchorResizeId))
{
widgetRemoveEventHandler(anchorWidget, self->anchorResizeId);
}
// We no longer have an anchor window
self->anchorWindow = NULL;
}
// Update the state
self->anchorState = state;
}
static void windowDoRepositionFromAnchor(window *self, const window *anchor,
hAlign hAlign, int xOffset,
vAlign vAlign, int yOffset)
{
int x = 0, y = 0;
size anchorSize = WIDGET(anchor)->size;
@ -285,3 +318,109 @@ void windowRepositionFromAnchor(window *self, const window *anchor,
// Reposition
widgetReposition(WIDGET(self), x, y);
}
void windowResizeImpl(widget *self, int w, int h)
{
window *windowSelf = WINDOW(self);
// Call our parents resize method
widgetResizeImpl(self, w, h);
// If dynamic anchoring is enabled, reposition ourself
if (windowSelf->anchorState == ANCHOR_DYNAMIC && windowSelf->anchorWindow)
{
windowDoRepositionFromAnchor(windowSelf, windowSelf->anchorWindow,
windowSelf->anchorHAlign,
windowSelf->anchorXOffset,
windowSelf->anchorVAlign,
windowSelf->anchorYOffset);
}
}
static bool windowAnchorCallback(widget *self, const event *evt, int handlerId,
void *userData)
{
// The window to be repositioned is stored in userData
window *anchoredWindow = WINDOW(userData);
// We should only be called to respond to resize and reposition eventd
assert(evt->type == EVT_REPOSITION || evt->type == EVT_RESIZE);
// Call windowDoRepositionFromAnchor to update the position
windowDoRepositionFromAnchor(anchoredWindow, WINDOW(self),
anchoredWindow->anchorHAlign,
anchoredWindow->anchorXOffset,
anchoredWindow->anchorVAlign,
anchoredWindow->anchorYOffset);
return true;
}
static bool windowAnchorDestroyCallback(widget *self, const event *evt,
int handlerId, void *userData)
{
// The window that installed us is in userData
window *anchoredWindow = WINDOW(userData);
// Make sure the event is a destruct event
assert(evt->type == EVT_DESTRUCT);
// We are being removed and therefore are no longer anchored
anchoredWindow->anchorWindow = NULL;
anchoredWindow->anchorRepositionId = anchoredWindow->anchorResizeId = -1;
return true;
}
void windowRepositionFromAnchor(window *self, const window *anchor,
hAlign hAlign, int xOffset,
vAlign vAlign, int yOffset)
{
// If dynamic anchors are enabled, set up dynamic anchoring
if (self->anchorState == ANCHOR_DYNAMIC)
{
// Get the current anchor (so that we may remove the event handlers)
widget *anchorWidget = WIDGET(self->anchorWindow);
if (anchorWidget)
{
// Remove any current event handlers we've installed
if (widgetIsEventHandler(anchorWidget, self->anchorRepositionId))
{
widgetRemoveEventHandler(anchorWidget, self->anchorRepositionId);
}
if (widgetIsEventHandler(anchorWidget, self->anchorResizeId))
{
widgetRemoveEventHandler(anchorWidget, self->anchorResizeId);
}
}
// Save the window/alignment/offsets
self->anchorWindow = self;
self->anchorHAlign = hAlign;
self->anchorXOffset = xOffset;
self->anchorVAlign = vAlign;
self->anchorYOffset = yOffset;
/*
* Install the event handlers, which are required to track changes to
* the size and position of the anchor window.
*
* Here we make the assumption that the event handlers when removed,
* will be done so in pairs (and therefore only need to install a single
* destructor). The same callback is used for both resize and reposition
* events.
*/
self->anchorRepositionId = widgetAddEventHandler(WIDGET(anchor), EVT_REPOSITION,
windowAnchorCallback,
NULL, self);
self->anchorResizeId = widgetAddEventHandler(WIDGET(anchor), EVT_RESIZE,
windowAnchorCallback,
windowAnchorDestroyCallback,
self);
}
// Reposition the window
windowDoRepositionFromAnchor(self, anchor, hAlign, xOffset, vAlign, yOffset);
}

View File

@ -29,6 +29,18 @@
typedef struct _window window;
typedef struct _windowVtbl windowVtbl;
/**
* The possible ways in which windowRepositionFromAnchor can act
*/
typedef enum
{
/// The window does not track changes in the anchor windows
ANCHOR_STATIC,
/// The window tracks and updates to changes in the anchor window
ANCHOR_DYNAMIC
} anchorState;
struct _windowVtbl
{
widgetVtbl widgetVtbl;
@ -47,6 +59,42 @@ struct _window
* Our vtable
*/
windowVtbl *vtbl;
/**
* Current anchor state
*/
anchorState anchorState;
/**
* Anchor window
*/
window *anchorWindow;
/**
* Anchor horizontal alignment
*/
hAlign anchorHAlign;
/**
* Anchor horizontal offset
*/
int anchorXOffset;
/**
* Anchor vertical alignment
*/
vAlign anchorVAlign;
/**
* Anchor vertical offset
*/
int anchorYOffset;
/**
* Event handler IDs for anchor events
*/
int anchorRepositionId;
int anchorResizeId;
};
/*
@ -68,6 +116,7 @@ void windowDestroyImpl(widget *self);
bool windowDoLayoutImpl(widget *self);
void windowDoDrawImpl(widget *self);
bool windowAddChildImpl(widget *self, widget *child);
void windowResizeImpl(widget *self, int w, int h);
size windowGetMinSizeImpl(widget *self);
size windowGetMaxSizeImpl(widget *self);
@ -130,6 +179,23 @@ void windowSetScreenSize(int w, int h);
void windowRepositionFromScreen(window *self, hAlign hAlign, int xOffset,
vAlign vAlign, int yOffset);
/**
* Sets the behaviour of windowRepositionFromAchor (with the default being
* ANCHOR_STATIC) to state. If the state is the same as the current anchor state
* then this method is a no-op.
*
* It is important to note that:
* - setting the state to ANCHOR_STATIC will break the current anchor (if any);
* - a state of ANCHOR_DYNAMIC will only take effect after the next call to
* windowRepositionFromAnchor;
* - calling widgetReposition with an anchor state of ANCHOR_DYNAMIC will cause
* strange behaviour - the anchor should be set to ANCHOR_STATIC first.
*
* @param self The window to set the anchor state for.
* @param state The new state to set the anchor behaviour to.
*/
void windowSetAnchorState(window *self, anchorState state);
/**
* Positions the window relative to the position of another window, anchor.
*