aboutsummaryrefslogtreecommitdiffstats
path: root/src/gwin
diff options
context:
space:
mode:
authorinmarket <andrewh@inmarket.com.au>2015-01-03 18:44:27 +1000
committerinmarket <andrewh@inmarket.com.au>2015-01-03 18:44:27 +1000
commit5a4e0b7b4db5dcb4ff16840163e65786b96771ed (patch)
tree05beb59f7169847f86a78bd168685be6de230a39 /src/gwin
parentda13b83737e85e2d8ed9c737ed641037a8c8ae5e (diff)
downloaduGFX-5a4e0b7b4db5dcb4ff16840163e65786b96771ed.tar.gz
uGFX-5a4e0b7b4db5dcb4ff16840163e65786b96771ed.tar.bz2
uGFX-5a4e0b7b4db5dcb4ff16840163e65786b96771ed.zip
Fix a serious problem with moving and sizing containers, and some visibility issues
Diffstat (limited to 'src/gwin')
-rw-r--r--src/gwin/gwin_class.h11
-rw-r--r--src/gwin/gwin_wm.c149
2 files changed, 102 insertions, 58 deletions
diff --git a/src/gwin/gwin_class.h b/src/gwin/gwin_class.h
index 4dde3624..8cb17ac8 100644
--- a/src/gwin/gwin_class.h
+++ b/src/gwin/gwin_class.h
@@ -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
diff --git a/src/gwin/gwin_wm.c b/src/gwin/gwin_wm.c
index 92d68c7b..6d860f23 100644
--- a/src/gwin/gwin_wm.c
+++ b/src/gwin/gwin_wm.c
@@ -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
}