Fix a serious problem with moving and sizing containers, and some visibility issues

ugfx_release_2.6
inmarket 2015-01-03 18:44:27 +10:00
parent da13b83737
commit 5a4e0b7b4d
2 changed files with 102 additions and 58 deletions

View File

@ -351,6 +351,17 @@ bool_t _gwinWMAdd(GHandle gh, const GWindowInit *pInit);
* @notapi
*/
#define _gcontainerRedraw _gwidgetRedraw
/**
* @brief The visibility of something has changed. Ripple the changes.
*
* @note Does not actually trigger the redraw. It just marks as ready for redraw any
* visibility changes.
*
* @notapi
*/
void _gwinRippleVisibility(void);
#endif
#ifdef __cplusplus

View File

@ -312,6 +312,40 @@ void _gwinUpdate(GHandle gh) {
TriggerRedraw();
}
#if GWIN_NEED_CONTAINERS
void _gwinRippleVisibility(void) {
GHandle gh;
// Check each window's visibility is consistent with its parents
for(gh = gwinGetNextWindow(0); gh; gh = gwinGetNextWindow(gh)) {
switch(gh->flags & (GWIN_FLG_SYSVISIBLE|GWIN_FLG_VISIBLE)) {
case GWIN_FLG_VISIBLE:
if (!gh->parent || (gh->parent->flags & GWIN_FLG_SYSVISIBLE)) {
// We have been made visible
gh->flags |= (GWIN_FLG_SYSVISIBLE|GWIN_FLG_NEEDREDRAW|GWIN_FLG_BGREDRAW);
RedrawPending |= DOREDRAW_VISIBLES;
}
break;
case (GWIN_FLG_VISIBLE|GWIN_FLG_SYSVISIBLE):
if (!gh->parent || (gh->parent->flags & GWIN_FLG_SYSVISIBLE))
break;
// Parent has been made invisible
gh->flags &= ~GWIN_FLG_SYSVISIBLE;
break;
case GWIN_FLG_SYSVISIBLE:
// We have been made invisible
gh->flags &= ~GWIN_FLG_SYSVISIBLE;
if (!gh->parent || (gh->parent->flags & GWIN_FLG_SYSVISIBLE)) {
// The parent is visible so we must clear the area we took
gh->flags |= (GWIN_FLG_NEEDREDRAW|GWIN_FLG_BGREDRAW);
RedrawPending |= DOREDRAW_INVISIBLES;
}
break;
}
}
}
#endif
bool_t _gwinDrawStart(GHandle gh) {
// This test should occur inside the lock. We do this
// here as well as an early out (more efficient).
@ -398,38 +432,15 @@ void gwinRedraw(GHandle gh) {
if (visible) {
// Mark us as visible
gh->flags |= GWIN_FLG_VISIBLE;
// Do we want to be added to the display
if (!(gh->flags & GWIN_FLG_SYSVISIBLE) && (!gh->parent || (gh->parent->flags & GWIN_FLG_SYSVISIBLE))) {
// Check each window's visibility is consistent with its parents
for(gh = gwinGetNextWindow(0); gh; gh = gwinGetNextWindow(gh)) {
if ((gh->flags & (GWIN_FLG_SYSVISIBLE|GWIN_FLG_VISIBLE)) == GWIN_FLG_VISIBLE && (!gh->parent || (gh->parent->flags & GWIN_FLG_SYSVISIBLE)))
gh->flags |= (GWIN_FLG_SYSVISIBLE|GWIN_FLG_NEEDREDRAW|GWIN_FLG_BGREDRAW); // Fix it and mark for redraw
}
// Mark for redraw
RedrawPending |= DOREDRAW_VISIBLES;
TriggerRedraw();
}
} else {
// Mark us as not visible
gh->flags &= ~GWIN_FLG_VISIBLE;
// Do we need to be removed from the display
if ((gh->flags & GWIN_FLG_SYSVISIBLE)) {
gh->flags |= (GWIN_FLG_NEEDREDRAW|GWIN_FLG_BGREDRAW);
// Check each window's visibility is consistent with its parents
for(gh = gwinGetNextWindow(0); gh; gh = gwinGetNextWindow(gh)) {
if ((gh->flags & GWIN_FLG_SYSVISIBLE) && (!(gh->flags & GWIN_FLG_VISIBLE) || (gh->parent && !(gh->parent->flags & GWIN_FLG_SYSVISIBLE))))
gh->flags &= ~GWIN_FLG_SYSVISIBLE; // Fix it
}
// Mark for redraw - no need to redraw children
RedrawPending |= DOREDRAW_INVISIBLES;
TriggerRedraw();
}
}
// Fix everything up
_gwinRippleVisibility();
if (RedrawPending)
TriggerRedraw();
}
#else
void gwinSetVisible(GHandle gh, bool_t visible) {
@ -639,18 +650,21 @@ static void WM_Redraw(GHandle gh) {
gh->vmt->AfterClear(gh);
}
// Redraw is done
gh->flags &= ~(GWIN_FLG_NEEDREDRAW|GWIN_FLG_BGREDRAW|GWIN_FLG_PARENTREVEAL);
#if GWIN_NEED_CONTAINERS
// If this is container but not a parent reveal, mark any visible children for redraw
// We redraw our children here as we have overwritten them in redrawing the parent
// as GDISP/GWIN doesn't yet support complex clipping regions.
// as GDISP/GWIN doesn't support complex clipping regions.
if ((gh->flags & (GWIN_FLG_CONTAINER|GWIN_FLG_PARENTREVEAL)) == GWIN_FLG_CONTAINER) {
// Container redraw is done
gh->flags &= ~(GWIN_FLG_NEEDREDRAW|GWIN_FLG_BGREDRAW|GWIN_FLG_PARENTREVEAL);
for(gh = gwinGetFirstChild(gh); gh; gh = gwinGetSibling(gh))
_gwinUpdate(gh);
return;
}
#endif
} else {
if ((gh->flags & GWIN_FLG_BGREDRAW)) {
GHandle gx;
@ -660,8 +674,15 @@ static void WM_Redraw(GHandle gh) {
// Child redraw is done
gh->flags &= ~(GWIN_FLG_NEEDREDRAW|GWIN_FLG_BGREDRAW|GWIN_FLG_PARENTREVEAL);
// Get the parent to redraw the area
gh = gh->parent;
// The parent is already marked for redraw - don't do it now.
if ((gh->flags & GWIN_FLG_NEEDREDRAW))
return;
// Use the existing clipping region and redraw now
gh->flags |= (GWIN_FLG_BGREDRAW|GWIN_FLG_PARENTREVEAL);
goto redo_redraw;
}
@ -682,11 +703,12 @@ static void WM_Redraw(GHandle gh) {
gdispGFillArea(gx->display, gx->x, gx->y, gx->width, gx->height, gx->bgcolor);
}
}
}
// Redraw is done
gh->flags &= ~(GWIN_FLG_NEEDREDRAW|GWIN_FLG_BGREDRAW|GWIN_FLG_PARENTREVEAL);
}
}
// Redraw is done
gh->flags &= ~(GWIN_FLG_NEEDREDRAW|GWIN_FLG_BGREDRAW|GWIN_FLG_PARENTREVEAL);
}
static void WM_Size(GHandle gh, coord_t w, coord_t h) {
@ -739,7 +761,7 @@ static void WM_Size(GHandle gh, coord_t w, coord_t h) {
// Move to their old relative location. THe WM_Move() will adjust as necessary
for(child = gwinGetFirstChild(gh); child; child = gwinGetSibling(child))
WM_Move(gh, child->x-gh->x-((const gcontainerVMT *)gh->parent->vmt)->LeftBorder(gh->parent), child->y-gh->y-((const gcontainerVMT *)gh->parent->vmt)->TopBorder(gh->parent));
WM_Move(child, child->x-gh->x-((const gcontainerVMT *)gh->vmt)->LeftBorder(gh), child->y-gh->y-((const gcontainerVMT *)gh->vmt)->TopBorder(gh));
}
#endif
@ -756,39 +778,50 @@ static void WM_Size(GHandle gh, coord_t w, coord_t h) {
// Move to their old relative location. THe WM_Move() will adjust as necessary
for(child = gwinGetFirstChild(gh); child; child = gwinGetSibling(child))
WM_Move(gh, child->x-gh->x-((const gcontainerVMT *)gh->parent->vmt)->LeftBorder(gh->parent), child->y-gh->y-((const gcontainerVMT *)gh->parent->vmt)->TopBorder(gh->parent));
WM_Move(child, child->x-gh->x-((const gcontainerVMT *)gh->vmt)->LeftBorder(gh), child->y-gh->y-((const gcontainerVMT *)gh->vmt)->TopBorder(gh));
}
#endif
}
}
static void WM_Move(GHandle gh, coord_t x, coord_t y) {
coord_t v;
coord_t u, v;
#if GWIN_NEED_CONTAINERS
if (gh->parent) {
// Clip to the parent size
v = gh->parent->width - ((const gcontainerVMT *)gh->parent->vmt)->LeftBorder(gh->parent) - ((const gcontainerVMT *)gh->parent->vmt)->RightBorder(gh->parent);
if (x+gh->width > v) x = v-gh->width;
u = gh->parent->width - ((const gcontainerVMT *)gh->parent->vmt)->LeftBorder(gh->parent) - ((const gcontainerVMT *)gh->parent->vmt)->RightBorder(gh->parent);
v = gh->parent->height - ((const gcontainerVMT *)gh->parent->vmt)->TopBorder(gh->parent) - ((const gcontainerVMT *)gh->parent->vmt)->BottomBorder(gh->parent);
if (y+gh->height > v) y = v-gh->height;
if (x < 0) x = 0;
if (y < 0) y = 0;
} else
#endif
{
// Clip to the screen
u = gdispGGetWidth(gh->display);
v = gdispGGetHeight(gh->display);
}
// Convert to absolute position
// Make sure we are positioned in the appropriate area
if (x+gh->width > u) x = u-gh->width;
if (x < 0) x = 0;
if (y+gh->height > v) y = v-gh->height;
if (y < 0) y = 0;
// Make sure we don't overflow the appropriate area
u -= x;
v -= y;
if (gh->width < u) u = gh->width;
if (gh->height < v) v = gh->height;
if (u != gh->width || v != gh->height)
WM_Size(gh, u, v);
#if GWIN_NEED_CONTAINERS
if (gh->parent) {
// Convert to a screen relative position
x += gh->parent->x + ((const gcontainerVMT *)gh->parent->vmt)->LeftBorder(gh->parent);
y += gh->parent->y + ((const gcontainerVMT *)gh->parent->vmt)->TopBorder(gh->parent);
}
#endif
// Clip to the screen
v = gdispGGetWidth(gh->display);
if (x+gh->width > v) x = v-gh->width;
v = gdispGGetHeight(gh->display);
if (y+gh->height > v) y = v-gh->height;
if (x < 0) x = 0;
if (y < 0) y = 0;
// If there has been no move just exit
if (gh->x == x && gh->y == y)
return;
@ -800,8 +833,8 @@ static void WM_Move(GHandle gh, coord_t x, coord_t y) {
_gwinFlushRedraws(REDRAW_WAIT);
// Do the move
v = gh->x; gh->x = x; x = v;
v = gh->y; gh->y = y; y = v;
u = gh->x; gh->x = x;
v = gh->y; gh->y = y;
#if GWIN_NEED_CONTAINERS
// Any children need to be moved
@ -810,14 +843,14 @@ static void WM_Move(GHandle gh, coord_t x, coord_t y) {
// Move to their old relative location. THe WM_Move() will adjust as necessary
for(child = gwinGetFirstChild(gh); child; child = gwinGetSibling(child))
WM_Move(gh, child->x-x-((const gcontainerVMT *)gh->parent->vmt)->LeftBorder(gh->parent), child->y-y-((const gcontainerVMT *)gh->parent->vmt)->TopBorder(gh->parent));
WM_Move(child, child->x-u-((const gcontainerVMT *)gh->vmt)->LeftBorder(gh), child->y-v-((const gcontainerVMT *)gh->vmt)->TopBorder(gh));
}
#endif
gwinSetVisible(gh, TRUE);
} else {
v = gh->x; gh->x = x; x = v;
v = gh->y; gh->y = y; y = v;
u = gh->x; gh->x = x;
v = gh->y; gh->y = y;
#if GWIN_NEED_CONTAINERS
// Any children need to be moved
@ -826,7 +859,7 @@ static void WM_Move(GHandle gh, coord_t x, coord_t y) {
// Move to their old relative location. THe WM_Move() will adjust as necessary
for(child = gwinGetFirstChild(gh); child; child = gwinGetSibling(child))
WM_Move(gh, child->x-x-((const gcontainerVMT *)gh->parent->vmt)->LeftBorder(gh->parent), child->y-y-((const gcontainerVMT *)gh->parent->vmt)->TopBorder(gh->parent));
WM_Move(child, child->x-u-((const gcontainerVMT *)gh->vmt)->LeftBorder(gh), child->y-v-((const gcontainerVMT *)gh->vmt)->TopBorder(gh));
}
#endif
}