]> git.decadent.org.uk Git - ion3.git/blobdiff - mod_tiling/split.c
Imported Upstream version 20090110
[ion3.git] / mod_tiling / split.c
index 54864d7b93bfbb2ea71b711cf5b773e44f69144c..5e1abb47dcb9961145032f6210eb30cb95ae5f0c 100644 (file)
@@ -1,12 +1,9 @@
 /*
  * ion/mod_tiling/split.c
  *
- * Copyright (c) Tuomo Valkonen 1999-2006
+ * Copyright (c) Tuomo Valkonen 1999-2009
  *
- * Ion is free software; you can redistribute it and/or modify it under
- * the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
+ * See the included file LICENSE for details.
  */
 
 #include <limits.h>
@@ -474,28 +471,28 @@ void splittree_scan_stdisp_rootward(WSplit *node)
 }
 
 
-static WSplitSplit *splittree_scan_stdisp_parent(WSplit *node_, bool set_saw)
+static WSplitST *splittree_scan_stdisp(WSplit *node_, bool set_saw)
 {
-    WSplitSplit *r, *node=OBJ_CAST(node_, WSplitSplit);
+    WSplitST *r=NULL;
+    WSplitSplit *node=OBJ_CAST(node_, WSplitSplit);
     
     if(node==NULL)
         return NULL;
     
-    if(OBJ_IS(node->tl, WSplitST)){
-        if(set_saw)
-            saw_stdisp=(WSplitST*)node->tl;
-        return node;
-    }
-
-    if(OBJ_IS(node->br, WSplitST)){
+    r=OBJ_CAST(node->tl, WSplitST);
+    if(r==NULL)
+        r=OBJ_CAST(node->br, WSplitST);
+    
+    if(r!=NULL){
         if(set_saw)
-            saw_stdisp=(WSplitST*)node->br;
-        return node;
+            saw_stdisp=r;
+        return r;
     }
-
-    r=splittree_scan_stdisp_parent(node->tl, set_saw);
+    
+    r=splittree_scan_stdisp(node->tl, set_saw);
     if(r==NULL)
-        r=splittree_scan_stdisp_parent(node->br, set_saw);
+        r=splittree_scan_stdisp(node->br, set_saw);
+    
     return r;
 }
 
@@ -507,26 +504,41 @@ static bool stdisp_immediate_child(WSplitSplit *node)
 }
 
 
-static WSplit *move_stdisp_out_of_way(WSplit *node)
+static WSplit *dodge_stdisp(WSplit *node, bool keep_within)
 {
+    WSplitST *stdisp;
     WSplitSplit *stdispp;
     
-    if(!OBJ_IS(node, WSplitSplit))
+    stdisp=splittree_scan_stdisp(node, TRUE);
+    
+    if(stdisp==NULL)
         return node;
     
-    stdispp=splittree_scan_stdisp_parent(node, TRUE);
-        
+    stdispp=OBJ_CAST(((WSplit*)stdisp)->parent, WSplitSplit);
+    
     if(stdispp==NULL)
         return node;
-        
-    while(stdispp->tl!=node && stdispp->br!=node){
+    
+    if((WSplit*)stdispp==node){
+        /* Node itself immediately contains stdisp. Due to the way
+         * try_unsink works, stdisp this will not change, so another
+         * node must be used, if we want to fully dodge stdisp.
+         */
+        return (keep_within
+                ? node
+                : (stdispp->tl==(WSplit*)stdisp 
+                   ? stdispp->br 
+                   : stdispp->tl));
+    }
+    
+    do{
         if(!split_try_unsink_stdisp(stdispp, FALSE, TRUE)){
             warn(TR("Unable to move the status display out of way."));
             return NULL;
         }
-    }
+    }while(stdispp->tl!=node && stdispp->br!=node);
     
-    return (WSplit*)stdispp;
+    return node;
 }
 
 
@@ -1029,6 +1041,7 @@ err:
 void splittree_changeroot(WSplit *root, WSplit *node)
 {
     WTiling *ws=(WTiling*)(root->ws_if_root);
+    
     assert(ws!=NULL);
     assert(ws->split_tree==root);
     root->ws_if_root=NULL;
@@ -1078,16 +1091,18 @@ WSplitRegion *splittree_split(WSplit *node, int dir, WPrimn primn,
     
     assert(node!=NULL && parent!=NULL);
     
+    splittree_begin_resize();
+    
+    node=dodge_stdisp(node, FALSE);
+    
+    if(node==NULL)
+        return NULL;
+    
     if(OBJ_IS(node, WSplitST)){
         warn(TR("Splitting the status display is not allowed."));
         return NULL;
     }
 
-    splittree_begin_resize();
-    
-    if(!move_stdisp_out_of_way(node))
-        return NULL;
-
     if(primn!=PRIMN_TL && primn!=PRIMN_BR)
         primn=PRIMN_BR;
     if(dir!=SPLIT_HORIZONTAL && dir!=SPLIT_VERTICAL)
@@ -1219,13 +1234,23 @@ static void splitsplit_remove(WSplitSplit *node, WSplit *child,
     static int nstdisp=0;
     WSplitInner *parent;
     WSplit *other;
+    int hprimn=PRIMN_ANY, vprimn=PRIMN_ANY;
     
     assert(node->tl==child || node->br==child);
     
-    if(node->tl==child)
+    if(node->tl==child){
         other=node->br;
-    else
+        if(node->dir==SPLIT_VERTICAL)
+            vprimn=PRIMN_TL;
+        else
+            hprimn=PRIMN_TL;
+    }else{
         other=node->tl;
+        if(node->dir==SPLIT_VERTICAL)
+            vprimn=PRIMN_BR;
+        else
+            hprimn=PRIMN_BR;
+    }
     
     assert(other!=NULL);
 
@@ -1247,7 +1272,7 @@ static void splitsplit_remove(WSplitSplit *node, WSplit *child,
         splittree_changeroot((WSplit*)node, other);
     
     if(reclaim_space)
-        split_resize(other, &(((WSplit*)node)->geom), PRIMN_ANY, PRIMN_ANY);
+        split_resize(other, &(((WSplit*)node)->geom), hprimn, vprimn);
     
     child->parent=NULL;
     
@@ -1340,6 +1365,11 @@ WSplit *split_current_todir(WSplit *node, WPrimn hprimn, WPrimn vprimn,
 }
 
 
+/* Note: both hprimn and vprimn are inverted when descending.  Therefore
+ * one should be either PRIMN_NONE or PRIMN_ANY for sensible geometric 
+ * navigation. (Both are PRIMN_TL or PRIMN_BR for pseudo-linear 
+ * next/previous navigation.)
+ */
 WSplit *splitsplit_nextto(WSplitSplit *node, WSplit *child,
                           WPrimn hprimn, WPrimn vprimn, 
                           WSplitFilter *filter)
@@ -1347,26 +1377,21 @@ WSplit *splitsplit_nextto(WSplitSplit *node, WSplit *child,
     WPrimn primn=(node->dir==SPLIT_HORIZONTAL ? hprimn : vprimn);
     WSplit *split=NULL, *nnode=NULL;
     
-    if(node->tl==child && (primn==PRIMN_BR || primn==PRIMN_ANY)){
+    if(node->tl==child && (primn==PRIMN_BR || primn==PRIMN_ANY))
         split=node->br;
-        primn=PRIMN_TL;
-    }else if(node->br==child && (primn==PRIMN_TL || primn==PRIMN_ANY)){
+    else if(node->br==child && (primn==PRIMN_TL || primn==PRIMN_ANY))
         split=node->tl;
-        primn=PRIMN_BR;
-    }
     
     if(split!=NULL){
-        if(node->dir==SPLIT_HORIZONTAL){
-            hprimn=primn;
-            vprimn=primn_none2any(vprimn);
-        }else{
-            vprimn=primn;
-            hprimn=primn_none2any(vprimn);
-        }
-        
-        nnode=split_current_todir(split, hprimn, vprimn, filter);
+        nnode=split_current_todir(split, 
+                                  primn_none2any(primn_invert(hprimn)),
+                                  primn_none2any(primn_invert(vprimn)),
+                                  filter);
     }
-   
+    
+    if(nnode==NULL)
+        nnode=split_nextto((WSplit*)node, hprimn, vprimn, filter);
+        
     return nnode;
 }
 
@@ -1639,14 +1664,16 @@ static void splitsplit_flip_(WSplitSplit *split)
 
 
 /*EXTL_DOC
- * Flip contents of \var{node}.
+ * Flip contents of \var{split}.
  */
 EXTL_EXPORT_MEMBER
 void splitsplit_flip(WSplitSplit *split)
 {
     splittree_begin_resize();
 
-    if(!move_stdisp_out_of_way((WSplit*)split))
+    split=OBJ_CAST(dodge_stdisp((WSplit*)split, FALSE), WSplitSplit);
+    
+    if(split==NULL)
         return;
     
     splitsplit_flip_(split);
@@ -1709,19 +1736,19 @@ static bool split_fliptrans_to(WSplit *node, const WRectangle *geom,
      * geometry calculation we move it immediately below node, and
      * resize stdisp's fixed parent node instead.
      */
-    node2=move_stdisp_out_of_way(node);
+    node2=dodge_stdisp(node, TRUE);
     
-    if(node2==NULL)
+    if(node==NULL || node2!=node)
         return FALSE;
     
-    split_update_bounds(node2, TRUE);
+    split_update_bounds(node, TRUE);
     
-    split_do_rqgeom_(node2, geom, PRIMN_ANY, PRIMN_ANY, &rg, FALSE);
+    split_do_rqgeom_(node, geom, PRIMN_ANY, PRIMN_ANY, &rg, FALSE);
     
-    split_do_resize(node2, &rg, PRIMN_ANY, PRIMN_ANY, trans);
+    split_do_resize(node, &rg, PRIMN_ANY, PRIMN_ANY, trans);
     
     if(flip!=FLIP_NONE)
-        splittree_flip_dir(node2, flip);
+        splittree_flip_dir(node, flip);
 
     splittree_end_resize();
     
@@ -1817,8 +1844,8 @@ WSplit *splitsplit_br(WSplitSplit *split)
 }
 
 /*EXTL_DOC
- * Returns the direction of \var{split}; either ''vertical'' or
- * ''horizontal''.
+ * Returns the direction of \var{split}; either \codestr{vertical} or
+ * \codestr{horizontal}.
  */
 EXTL_SAFE
 EXTL_EXPORT_MEMBER