View2D: Code cleanup - UI_view2d_status_enforce()
authorJoshua Leung <aligorith@gmail.com>
Sat, 6 Dec 2008 09:25:42 +0000 (09:25 +0000)
committerJoshua Leung <aligorith@gmail.com>
Sat, 6 Dec 2008 09:25:42 +0000 (09:25 +0000)
This commit *should* bring UI_view2d_status_enforce() (formerly known in pre 2.5 as test_view2d) under control again.
I've attempted to reduce the amount of duplicated code here, so hopefully there won't be any nasty bugs that will show up in some of the other views when they are ported.

Summary of changes:
* Restored V2D_KEEPZOOM flag which I had previously removed, having misunderstood its function.
* Fixed bugs with resizing Outliner window
* Outliner width is now columns + 1 again. Documented reasons for this (otherwise, stuff gets covered by scrollbars, but we cannot see it)

source/blender/blenloader/intern/readfile.c
source/blender/editors/include/UI_view2d.h
source/blender/editors/interface/view2d.c
source/blender/editors/space_outliner/space_outliner.c
source/blender/makesdna/DNA_view2d_types.h

index c79e7ea53caa31258f5382b383c8e193f8ec715e..9029653ba1424a23d41592aeead6bfa0880ed3f8 100644 (file)
@@ -5074,6 +5074,7 @@ static void do_versions_windowmanager_2_50(bScreen *screen)
                                SpaceOops *soops= sa->spacedata.first;
                                
                                memcpy(&ar->v2d, &soops->v2d, sizeof(View2D));
+                               
                                ar->v2d.scroll &= ~V2D_SCROLL_LEFT;
                                ar->v2d.scroll |= V2D_SCROLL_RIGHT;
                                ar->v2d.align = (V2D_ALIGN_NO_NEG_X|V2D_ALIGN_NO_POS_Y);
index 02cf4b1f4cc9cfc6f9455e870c9547ead72455f4..c2c52c2d190bb5e55afe66587d3d1e24bcb8ad33 100644 (file)
@@ -85,7 +85,7 @@ typedef struct View2DScrollers View2DScrollers;
 /* refresh and validation (of view rects) */
        // XXX rename these...
 void UI_view2d_size_update(struct View2D *v2d, int winx, int winy);
-void UI_view2d_status_enforce(struct View2D *v2d, int winx, int winy);
+void UI_view2d_status_enforce(struct View2D *v2d);
 
 void UI_view2d_totRect_set(struct View2D *v2d, int width, int height);
 void UI_view2d_curRect_reset(struct View2D *v2d);
index 84bcd7c7da5a8f09165766e8bed99acd93013ab7..17bd13eda8a63859f96f77cf62f3142bd63efb92 100644 (file)
@@ -103,101 +103,75 @@ void UI_view2d_size_update(View2D *v2d, int winx, int winy)
  */
 // XXX pre2.5 -> this used to be called  test_view2d()
 // XXX FIXME - this is an old mess function... let's rewrite!
-void UI_view2d_status_enforce(View2D *v2d, int winx, int winy)
+void UI_view2d_status_enforce(View2D *v2d)
 {
        /* cur is not allowed to be larger than max, smaller than min, or outside of tot */
+       float totwidth, totheight, curwidth, curheight, width, height;
+       int winx, winy;
        rctf *cur, *tot;
-       float dx, dy, temp, fac, zoom;
-       
-       /* correct winx for scrollbars */
-       if (v2d->scroll & V2D_SCROLL_LEFT) winx-= V2D_SCROLL_WIDTH;
-       if (v2d->scroll & (V2D_SCROLL_BOTTOM|V2D_SCROLL_BOTTOM_O)) winy-= V2D_SCROLL_HEIGHT;
        
-       /* header completely closed window */
-       if (winy <= 0) return;
+       /* use mask as size of region that View2D resides in, as it takes into account scrollbars already  */
+       winx= v2d->mask.xmax - v2d->mask.xmin + 1;
+       winy= v2d->mask.ymax - v2d->mask.ymin + 1;
        
-       /* get pointers */
+       /* get pointers to rcts for less typing */
        cur= &v2d->cur;
        tot= &v2d->tot;
        
-       /* dx, dy are width and height of v2d->cur, respectively */
-       dx= cur->xmax - cur->xmin;
-       dy= cur->ymax - cur->ymin;
+       /* we must satisfy the following constraints (in decreasing order of importance):
+        *      - cur must not fall outside of tot
+        *      - axis locks (zoom and offset) must be maintained
+        *      - zoom must not be excessive (check either sizes or zoom values)
+        *      - aspect ratio should be respected
+        */
        
-       /* keepzoom - restore old zoom */
-       if (v2d->keepzoom) {    
-               /* keepzoom on x or y axis - reset size of current-viewable area to size of region (i.e. no zooming happened) */
-               if (v2d->keepzoom & V2D_LOCKZOOM_Y)
-                       cur->ymax= cur->ymin + ((float)winy);
-               if (v2d->keepzoom & V2D_LOCKZOOM_X)
-                       cur->xmax= cur->xmin + ((float)winx);
+       /* Step 1: if keepzoom, adjust the sizes of the rects only
+        *      - firstly, we calculate the sizes of the rects
+        *      - curwidth and curheight are saved as reference... modify width and height values here
+        */
+       totwidth= tot->xmax - tot->xmin;
+       totheight= tot->ymax - tot->ymin;
+       curwidth= width= cur->xmax - cur->xmin;
+       curheight= height= cur->ymax - cur->ymin;
+       
+       /* if zoom is locked, size on the appropriate axis is reset to mask size */
+       if (v2d->keepzoom & V2D_LOCKZOOM_X)
+               width= (float)winy;
+       if (v2d->keepzoom & V2D_LOCKZOOM_Y)
+               height= (float)winx;
                
-               /* calculate zoom-factor for x */
-               zoom= ((float)winx)/dx;
+       /* keepzoom (V2D_KEEPZOOM set), indicates that zoom level on each axis must not exceed limits 
+        * NOTE: in general, it is not expected that the lock-zoom will be used in conjunction with this
+        */
+       if (v2d->keepzoom & V2D_KEEPZOOM) {
+               float zoom, fac;
                
-               /* if zoom factor is excessive, normalise it and calculate new width */
+               /* check if excessive zoom on x-axis */
+               zoom= (float)winx / width;
                if ((zoom < v2d->minzoom) || (zoom > v2d->maxzoom)) {
-                       if (zoom < v2d->minzoom) fac= zoom / v2d->minzoom;
-                       else fac= zoom / v2d->maxzoom;
-                       
-                       dx *= fac;
-                       temp= 0.5f * (cur->xmax + cur->xmin);
-                       
-                       cur->xmin= temp - (0.5f * dx);
-                       cur->xmax= temp + (0.5f * dx);
+                       fac= (zoom < v2d->minzoom) ? (zoom / v2d->minzoom) : (zoom / v2d->maxzoom);
+                       width *= fac;
                }
                
-               /* calculate zoom-factor for y */
-               zoom= ((float)winy)/dy;
-               
-               /* if zoom factor is excessive, normalise it and calculate new width */
+               /* check if excessive zoom on y-axis */
+               zoom= (float)winy / height;
                if ((zoom < v2d->minzoom) || (zoom > v2d->maxzoom)) {
-                       if (zoom < v2d->minzoom) fac= zoom / v2d->minzoom;
-                       else fac= zoom / v2d->maxzoom;
-                       
-                       dy *= fac;
-                       temp= 0.5f * (cur->ymax + cur->ymin);
-                       
-                       cur->ymin= temp - (0.5f * dy);
-                       cur->ymax= temp + (0.5f * dy);
+                       fac= (zoom < v2d->minzoom) ? (zoom / v2d->minzoom) : (zoom / v2d->maxzoom);
+                       height *= fac;
                }
        }
        else {
-               /* if extents of cur are below or above what's acceptable, interpolate extent to lie halfway */
-               if (dx < v2d->min[0]) {
-                       dx= v2d->min[0];
-                       temp= 0.5f * (cur->xmax + cur->xmin);
-                       
-                       cur->xmin= temp - (0.5f * dx);
-                       cur->xmax= temp + (0.5f * dx);
-               }
-               else if (dx > v2d->max[0]) {
-                       dx= v2d->max[0];
-                       temp= 0.5f * (cur->xmax + cur->xmin);
-                       
-                       cur->xmin= temp - (0.5f * dx);
-                       cur->xmax= temp + (0.5f * dx);
-               }
-               
-               if (dy < v2d->min[1]) {
-                       dy= v2d->min[1];
-                       temp= 0.5f * (cur->ymax + cur->ymin);
-                       
-                       cur->ymin= temp - (0.5f * dy);
-                       cur->ymax= temp + (0.5f * dy);
-               }
-               else if (dy > v2d->max[1]) {
-                       dy= v2d->max[1];
-                       temp= 0.5f * (cur->ymax + cur->ymin);
-                       cur->ymin= temp-0.5*dy;
-                       cur->ymax= temp+0.5*dy;
-               }
+               /* make sure sizes don't exceed that of the min/max sizes (even though we're not doing zoom clamping) */
+               CLAMP(width, v2d->min[0], v2d->max[0]);
+               CLAMP(height, v2d->min[1], v2d->max[1]);
        }
        
-       /* keep aspect - maintain aspect ratio */
+       /* check if we should restore aspect ratio (if view size changed) */
        if (v2d->keepaspect) {
-               short do_x=0, do_y=0;
+               short do_x=0, do_y=0, do_cur, do_win;
+               float curRatio, winRatio;
                
+                       // XXX this is old code here to be cleaned up still
                /* when a window edge changes, the aspect ratio can't be used to
                 * find which is the best new 'cur' rect. thats why it stores 'old' 
                 */
@@ -205,43 +179,48 @@ void UI_view2d_status_enforce(View2D *v2d, int winx, int winy)
                if (winy != v2d->oldwiny) do_y= 1;
                
                /* here dx is cur ratio, while dy is win ratio */
-               dx= (cur->ymax - cur->ymin) / (cur->xmax - cur->xmin);
-               dy= ((float)winy) / ((float)winx);
+               curRatio= height / width;
+               winRatio= ((float)winy) / ((float)winx);
                
                /* both sizes change (area/region maximised)  */
                if (do_x == do_y) {
-                       if ((do_x==1) && (do_y==1)) {
+                       if (do_x && do_y) {
+                               /* here is 1,1 case, so all others must be 0,0 */
                                if (ABS(winx - v2d->oldwinx) > ABS(winy - v2d->oldwiny)) do_y= 0;
                                else do_x= 0;
                        }
-                       else if (dy > 1.0f) do_x= 0; 
+                       else if (winRatio > 1.0f) do_x= 0; 
                        else do_x= 1;
                }
+               do_cur= do_x;
+               do_win= do_y;
                
-               if (do_x) {
+               if (do_cur) {
                        if ((v2d->keeptot == 2) && (winx != v2d->oldwinx)) {
-                               /* This is a special hack for the outliner, to ensure that the 
-                                * outliner contents will stay in their relative place in the view 
-                                * when the view is resized
+                               /* special exception for Outliner (and later channel-lists):
+                                *      - The view may be moved left to avoid contents being pushed out of view when view shrinks. 
+                                *      - The keeptot code will make sure cur->xmin will not be less than tot->xmin (which cannot be allowed)
+                                *      - width is not adjusted for changed ratios here...
                                 */
-                               cur->xmax -= cur->xmin;
-                               cur->xmin= 0.0f;
-                       } 
+                               if (winx < v2d->oldwinx) {
+                                       float temp = v2d->oldwinx - winx;
+                                       
+                                       cur->xmin -= temp;
+                                       cur->xmax -= temp;
+                                       
+                                       /* width does not get modified, as keepaspect here is just set to make 
+                                        * sure visible area adjusts to changing view shape! 
+                                        */
+                               }
+                       }
                        else {
                                /* portrait window: correct for x */
-                               dx= cur->ymax - cur->ymin;
-                               temp= cur->xmax + cur->xmin;
-                               
-                               cur->xmin= (temp / 2.0f) - (0.5f * dx / dy);
-                               cur->xmax= (temp / 2.0f) + (0.5f * dx / dy);
+                               width= height / winRatio;
                        }
                }
                else {
-                       dx= cur->xmax - cur->xmin;
-                       temp= cur->ymax + cur->ymin;
-                       
-                       cur->ymin= (temp / 2.0f) - (0.5f * dy * dx);
-                       cur->ymax= (temp / 2.0f) + (0.5f * dy * dx);
+                       /* landscape window: correct for y */
+                       height = width * winRatio;
                }
                
                /* store region size for next time */
@@ -249,81 +228,125 @@ void UI_view2d_status_enforce(View2D *v2d, int winx, int winy)
                v2d->oldwiny= winy;
        }
        
-       /* keeptot - make sure that size of cur doesn't exceed that of tot, otherwise, adjust! */
+       /* Step 2: apply new sizes of cur rect to cur rect */
+       if ((width != curwidth) || (height != curheight)) {
+               float temp, dh;
+               
+               /* resize around 'center' of frame */
+               // FIXME: maybe we should just scale down on min?
+               if (width != curwidth) {
+                       temp= (cur->xmax + cur->xmin) / 2.0f;
+                       dh= (width - curwidth) * 0.5f;
+                       
+                       cur->xmin -= dh;
+                       cur->xmax += dh;
+               }
+               if (height != curheight) {
+                       temp= (cur->ymax + cur->ymin) / 2.0f;
+                       dh= (height - curheight) * 0.5f;
+                       
+                       cur->ymin -= dh;
+                       cur->ymax += dh;
+               }
+       }
+       
+       /* Step 3: adjust so that it doesn't fall outside of bounds of tot */
        if (v2d->keeptot) {
-               /* calculate extents of cur */
-               dx= cur->xmax - cur->xmin;
-               dy= cur->ymax - cur->ymin;
+               float temp;
+               
+               /* recalculate extents of cur */
+               curwidth= cur->xmax - cur->xmin;
+               curheight= cur->ymax - cur->ymin;
                
-               /* cur is wider than tot? */
-               if (dx > (tot->xmax - tot->xmin)) {
-                       if (v2d->keepzoom == 0) {
-                               if (cur->xmin < tot->xmin) cur->xmin= tot->xmin;
-                               if (cur->xmax > tot->xmax) cur->xmax= tot->xmax;
+               /* width */
+               if ((curwidth > totwidth) && (v2d->keepzoom == 0)) {
+                       /* if zoom doesn't have to be maintained, just clamp edges */
+                       if (cur->xmin < tot->xmin) cur->xmin= tot->xmin;
+                       if (cur->xmax > tot->xmax) cur->xmax= tot->xmax;
+               }
+               else if (v2d->keeptot == 2) {
+                       /* This is an exception for the outliner (and later channel-lists) 
+                        *      - must clamp within tot rect (absolutely no excuses)
+                        *      --> therefore, cur->xmin must not be less than tot->xmin
+                        */
+                       if (cur->xmin < tot->xmin) {
+                               /* move cur across so that it sits at minimum of tot */
+                               temp= tot->xmin - cur->xmin;
+                               
+                               cur->xmin += temp;
+                               cur->xmax += temp;
                        }
-                       else {
-                               /* maintaining zoom, so restore cur to tot size */
-                               if (cur->xmax < tot->xmax) {
-                                       dx= tot->xmax - cur->xmax;
+                       else if (cur->xmax > tot->xmax) {
+                               /* - only offset by difference of cur-xmax and tot-xmax if that would not move 
+                                *      cur-xmin to lie past tot-xmin
+                                * - otherwise, simply shift to tot-xmin???
+                                */
+                               temp= cur->xmax - tot->xmax;
+                               
+                               if ((cur->xmin - temp) < tot->xmin) {
+                                       temp= cur->xmin - tot->xmin;
                                        
-                                       cur->xmin+= dx;
-                                       cur->xmax+= dx;
+                                       cur->xmin -= temp;
+                                       cur->xmax -= temp;
                                }
-                               else if (cur->xmin > tot->xmin) {
-                                       dx= cur->xmin - tot->xmin;
-                                       
-                                       cur->xmin-= dx;
-                                       cur->xmax-= dx;
+                               else {
+                                       cur->xmin -= temp;
+                                       cur->xmax -= temp;
                                }
                        }
                }
                else {
-                       /* cur is smaller than tot, but cur cannot be outside of tot */
-                       if (cur->xmin < tot->xmin) {
-                               dx= tot->xmin - cur->xmin;
+                       /* This here occurs when:
+                        *      - width too big, but maintaining zoom (i.e. widths cannot be changed)
+                        *      - width is OK, but need to check if outside of boundaries
+                        * 
+                        * So, resolution is to just shift view by the gap between the extremities.
+                        * We favour moving the 'minimum' across, as that's origin for most things
+                        * (XXX - in the past, max was favoured... if there are bugs, swap!)
+                        */
+                       if (cur->xmin > tot->xmin) {
+                               /* there's still space remaining, so shift left */
+                               temp= cur->xmin - tot->xmin;
                                
-                               cur->xmin += dx;
-                               cur->xmax += dx;
+                               cur->xmin -= temp;
+                               cur->xmax -= temp;
                        }
-                       else if ((v2d->keeptot != 2) && (cur->xmax > tot->xmax)) {
-                               /* NOTE: keeptot is 2, as keeptot!=0 makes sure it does get
-                                *              too freely scrolled on x-axis, but keeptot=1 will result
-                                *              in a snap-back when clicking on elements
-                                */
-                               dx= cur->xmax - tot->xmax;
-                               cur->xmin -= dx;
-                               cur->xmax -= dx;
+                       else if (cur->xmax < tot->xmax) {
+                               /* there's still space remaining, so shift right */
+                               temp= tot->xmax - cur->xmax;
+                               
+                               cur->xmin += temp;
+                               cur->xmax += temp;
                        }
                }
                
-               if (dy > (tot->ymax - tot->ymin)) {
-                       if (v2d->keepzoom==0) {
-                               if (cur->ymin < tot->ymin) cur->ymin= tot->ymin;
-                               if (cur->ymax > tot->ymax) cur->ymax= tot->ymax;
-                       }
-                       else {
-                               if (cur->ymax < tot->ymax) {
-                                       dy= tot->ymax - cur->ymax;
-                                       cur->ymin+= dy;
-                                       cur->ymax+= dy;
-                               }
-                               else if (cur->ymin > tot->ymin) {
-                                       dy= cur->ymin - tot->ymin;
-                                       cur->ymin -= dy;
-                                       cur->ymax -= dy;
-                               }
-                       }
+               /* height */
+               if ((curheight > totheight) && (v2d->keepzoom == 0)) {
+                       /* if zoom doesn't have to be maintained, just clamp edges */
+                       if (cur->ymin < tot->ymin) cur->ymin= tot->ymin;
+                       if (cur->ymax > tot->ymax) cur->ymax= tot->ymax;
                }
                else {
+                       /* This here occurs when:
+                        *      - height too big, but maintaining zoom (i.e. heights cannot be changed)
+                        *      - height is OK, but need to check if outside of boundaries
+                        * 
+                        * So, resolution is to just shift view by the gap between the extremities.
+                        * We favour moving the 'minimum' across, as that's origin for most things
+                        */
                        if (cur->ymin < tot->ymin) {
-                               dy= tot->ymin - cur->ymin;
-                               cur->ymin += dy;
-                               cur->ymax += dy;
+                               /* there's still space remaining, so shift up */
+                               temp= tot->ymin - cur->ymin;
+                               
+                               cur->ymin += temp;
+                               cur->ymax += temp;
                        }
                        else if (cur->ymax > tot->ymax) {
-                               dy= cur->ymax - tot->ymax;
-                               cur->ymin-= dy;
-                               cur->ymax-= dy;
+                               /* there's still space remaining, so shift up */
+                               temp= cur->ymax - tot->ymax;
+                               
+                               cur->ymin -= temp;
+                               cur->ymax -= temp;
                        }
                }
        }
index 6039bee3db576e46ec143126fc0672419fc27260..c568741f0ab2866c534aa6bf6b841cc38e60c9f2 100644 (file)
@@ -390,14 +390,19 @@ static void outliner_main_area_draw(const bContext *C, ARegion *ar)
        }
 
        RNA_property_collection_end(&cell.iter);
-
+       
+       /* determine extents of data
+        *      - height must be at least the height of the mask area
+        *      - width is columns + 1, as otherwise, part of last column 
+        *        will be obscured by scrollers
+        */
        if ((rows*ROW_HEIGHT) > height)
                height= rows * ROW_HEIGHT;
-       width= cols * COLUMN_WIDTH;
+       width= (cols + 1) * COLUMN_WIDTH;
        
        /* need to validate view2d after updating size of tot */
        UI_view2d_totRect_set(v2d, width, height);
-       UI_view2d_status_enforce(v2d, awidth, aheight);
+       UI_view2d_status_enforce(v2d);
        
        rct.xmin= 0;
        rct.ymin= -height;
index 9af50f7dd60c3329b5c3ecc18fa47faf0ace81b3..34a329a06464481984b078fe9747376fd574826e 100644 (file)
@@ -41,12 +41,13 @@ typedef struct View2D {
        rcti vert, hor;                                 /* vert - vertical scrollbar region; hor - horizontal scrollbar region */
        rcti mask;                                              /* mask - region (in screenspace) within which 'cur' can be viewed */
        
-       float min[2], max[2];                   /* min/max sizes? */
-       float minzoom, maxzoom;                 /* self explanatory. allowable zoom factor range */
+       float min[2], max[2];                   /* min/max sizes of 'cur' rect (only when keepzoom not set) */
+       float minzoom, maxzoom;                 /* self explanatory. allowable zoom factor range (only when keepzoom set) */
        
        short scroll;                                   /* scroll - scrollbars to display (bitflag) */
-       short keeptot;                                  /* keeptot - 'tot' rect  */
-       short keepaspect, keepzoom;             /* axes that zoomimg cannot occur on, and need to maintain aspect ratio */
+       short keeptot;                                  /* keeptot - 'cur' rect cannot move outside the 'tot' rect? */
+       short keepaspect;                               /* keepaspect - need to maintain aspect ratio (0 or 1 boolean only) */
+       short keepzoom;                                 /* keepzoom - axes that zooming cannot occur on, and also clamp within zoom-limits */
        short keepofs;                                  /* keepofs - axes that translation is not allowed to occur on */
        
        short flag;                                             /* settings */
@@ -62,6 +63,7 @@ typedef struct View2D {
 /* ---------------------------------- */
 
 /* view zooming restrictions, per axis (v2d->keepzoom) */
+#define V2D_KEEPZOOM           0x0001
 #define V2D_LOCKZOOM_X         0x0100
 #define V2D_LOCKZOOM_Y         0x0200