2 * ion/mod_tiling/split-stdisp.c
4 * Copyright (c) Tuomo Valkonen 1999-2007.
6 * See the included file LICENSE for details.
9 #include <libtu/minmax.h>
10 #include <ioncore/common.h>
11 #include <ioncore/mplex.h>
12 #include <ioncore/resize.h>
14 #include "split-stdisp.h"
18 /*{{{ Helper routines */
21 #define STDISP_IS_HORIZONTAL(STDISP) \
22 ((STDISP)->orientation==REGION_ORIENTATION_HORIZONTAL)
24 #define STDISP_IS_VERTICAL(STDISP) \
25 ((STDISP)->orientation==REGION_ORIENTATION_VERTICAL)
27 #define STDISP_GROWS_L_TO_R(STDISP) (STDISP_IS_HORIZONTAL(STDISP) && \
28 ((STDISP)->corner==MPLEX_STDISP_TL || \
29 (STDISP)->corner==MPLEX_STDISP_BL))
31 #define STDISP_GROWS_R_TO_L(STDISP) (STDISP_IS_HORIZONTAL(STDISP) && \
32 ((STDISP)->corner==MPLEX_STDISP_TR || \
33 (STDISP)->corner==MPLEX_STDISP_BR))
35 #define STDISP_GROWS_T_TO_B(STDISP) (STDISP_IS_VERTICAL(STDISP) && \
36 ((STDISP)->corner==MPLEX_STDISP_TL || \
37 (STDISP)->corner==MPLEX_STDISP_TR))
39 #define STDISP_GROWS_B_TO_T(STDISP) (STDISP_IS_VERTICAL(STDISP) && \
40 ((STDISP)->corner==MPLEX_STDISP_BL || \
41 (STDISP)->corner==MPLEX_STDISP_BR))
43 #define GEOM(S) (((WSplit*)S)->geom)
45 #define IMPLIES(X, Y) (!(X) || (Y))
48 static int other_dir(int dir)
50 return (dir==SPLIT_VERTICAL ? SPLIT_HORIZONTAL : SPLIT_VERTICAL);
54 static void swap(int *x, int *y)
62 static void swapptr(WSplit **x, WSplit **y)
70 static void swapgeom(WRectangle *g, WRectangle *h)
78 int stdisp_recommended_w(WSplitST *stdisp)
80 if(stdisp->regnode.reg==NULL)
81 return CF_STDISP_MIN_SZ;
83 if(stdisp->fullsize && stdisp->orientation==REGION_ORIENTATION_HORIZONTAL){
84 WTiling *ws=REGION_MANAGER_CHK(stdisp->regnode.reg, WTiling);
86 return REGION_GEOM(ws).w;
89 return maxof(CF_STDISP_MIN_SZ, region_min_w(stdisp->regnode.reg));
93 int stdisp_recommended_h(WSplitST *stdisp)
95 if(stdisp->regnode.reg==NULL)
96 return CF_STDISP_MIN_SZ;
98 if(stdisp->fullsize && stdisp->orientation==REGION_ORIENTATION_VERTICAL){
99 WTiling *ws=REGION_MANAGER_CHK(stdisp->regnode.reg, WTiling);
101 return REGION_GEOM(ws).h;
104 return maxof(CF_STDISP_MIN_SZ, region_min_h(stdisp->regnode.reg));
108 static bool stdisp_dir_ok(WSplitSplit *p, WSplitST *stdisp)
110 assert(p->tl==(WSplit*)stdisp || p->br==(WSplit*)stdisp);
112 return (IMPLIES(STDISP_IS_HORIZONTAL(stdisp), p->dir==SPLIT_VERTICAL) &&
113 IMPLIES(STDISP_IS_VERTICAL(stdisp), p->dir==SPLIT_HORIZONTAL));
120 /*{{{ New rotation and flipping primitives */
123 static void replace(WSplitSplit *a, WSplitSplit *p)
125 if(((WSplit*)a)->parent!=NULL)
126 splitinner_replace(((WSplit*)a)->parent, (WSplit*)a, (WSplit*)p);
128 splittree_changeroot((WSplit*)a, (WSplit*)p);
132 /* Yes, it is overparametrised */
133 static void rotate_right(WSplitSplit *a, WSplitSplit *p, WSplit *y)
135 assert(a->tl==(WSplit*)p && p->tl==y);
146 a->tl->parent=(WSplitInner*)a;
149 ((WSplit*)a)->parent=(WSplitInner*)p;
153 static void rot_rs_rotate_right(WSplitSplit *a, WSplitSplit *p, WSplit *y)
155 WRectangle xg, yg, pg, ag, qg;
156 WSplit *x=a->br, *q=p->br;
158 assert(a->dir==other_dir(p->dir));
166 if(a->dir==SPLIT_HORIZONTAL){
191 rotate_right(a, p, y);
196 split_do_resize(x, &xg, PRIMN_TL, PRIMN_TL, FALSE);
197 split_do_resize(y, &yg, PRIMN_BR, PRIMN_BR, FALSE);
202 static void rotate_left(WSplitSplit *a, WSplitSplit *p, WSplit *y)
204 assert(a->br==(WSplit*)p && p->br==y);
215 a->br->parent=(WSplitInner*)a;
218 ((WSplit*)a)->parent=(WSplitInner*)p;
222 static void rot_rs_rotate_left(WSplitSplit *a, WSplitSplit *p, WSplit *y)
224 WRectangle xg, yg, pg, ag, qg;
225 WSplit *x=a->tl, *q=p->tl;
227 assert(a->dir==other_dir(p->dir));
235 if(a->dir==SPLIT_HORIZONTAL){
260 rotate_left(a, p, y);
265 split_do_resize(x, &xg, PRIMN_BR, PRIMN_BR, FALSE);
266 split_do_resize(y, &yg, PRIMN_TL, PRIMN_TL, FALSE);
271 static void flip_right(WSplitSplit *a, WSplitSplit *p)
275 assert(a->tl==(WSplit*)p);
286 a->tl->parent=(WSplitInner*)a;
289 ((WSplit*)a)->parent=(WSplitInner*)p;
293 static void rot_rs_flip_right(WSplitSplit *a, WSplitSplit *p)
295 WRectangle xg, yg, pg, ag, qg;
296 WSplit *x=a->br, *q=p->tl, *y=p->br;
298 assert(a->dir==other_dir(p->dir));
306 if(a->dir==SPLIT_HORIZONTAL){
332 split_do_resize(x, &xg, PRIMN_BR, PRIMN_BR, FALSE);
333 split_do_resize(y, &yg, PRIMN_BR, PRIMN_BR, FALSE);
337 static void flip_left(WSplitSplit *a, WSplitSplit *p)
341 assert(a->br==(WSplit*)p);
352 a->br->parent=(WSplitInner*)a;
355 ((WSplit*)a)->parent=(WSplitInner*)p;
359 static void rot_rs_flip_left(WSplitSplit *a, WSplitSplit *p)
361 WRectangle xg, yg, pg, ag, qg;
362 WSplit *x=a->tl, *q=p->br, *y=p->tl;
364 assert(a->dir==other_dir(p->dir));
372 if(a->dir==SPLIT_HORIZONTAL){
406 split_do_resize(x, &xg, PRIMN_TL, PRIMN_TL, FALSE);
407 split_do_resize(y, &yg, PRIMN_TL, PRIMN_TL, FALSE);
411 static void rot_para_right(WSplitSplit *a, WSplitSplit *p,
414 rotate_right(a, p, y);
415 if(a->dir==SPLIT_VERTICAL){
418 GEOM(a).y=GEOM(a->tl).y;
419 GEOM(a).h=GEOM(a->br).y+GEOM(a->br).h-GEOM(a).y;
423 GEOM(a).x=GEOM(a->tl).x;
424 GEOM(a).w=GEOM(a->br).x+GEOM(a->br).w-GEOM(a).x;
429 static void rot_para_left(WSplitSplit *a, WSplitSplit *p,
432 rotate_left(a, p, y);
433 if(a->dir==SPLIT_VERTICAL){
436 GEOM(a).h=GEOM(a->br).y+GEOM(a->br).h-GEOM(a).y;
440 GEOM(a).w=GEOM(a->br).x+GEOM(a->br).w-GEOM(a).x;
451 static bool do_try_sink_stdisp_orth(WSplitSplit *p, WSplitST *stdisp,
452 WSplitSplit *other, bool force)
456 assert(p->dir==other_dir(other->dir));
457 assert(stdisp_dir_ok(p, stdisp));
459 if(STDISP_GROWS_T_TO_B(stdisp) || STDISP_GROWS_L_TO_R(stdisp)){
460 if(STDISP_GROWS_L_TO_R(stdisp)){
461 assert(other->dir==SPLIT_HORIZONTAL);
462 if(other->tl->geom.w>=stdisp_recommended_w(stdisp))
464 }else{ /* STDISP_GROWS_T_TO_B */
465 assert(other->dir==SPLIT_VERTICAL);
466 if(other->tl->geom.h>=stdisp_recommended_h(stdisp))
471 if(p->br==(WSplit*)stdisp)
472 rot_rs_flip_right(p, other);
473 else /* p->tl==stdisp */
474 rot_rs_rotate_left(p, other, other->br);
476 }else{ /* STDISP_GROWS_B_TO_T or STDISP_GROW_R_TO_L */
477 if(STDISP_GROWS_R_TO_L(stdisp)){
478 assert(other->dir==SPLIT_HORIZONTAL);
479 if(other->br->geom.w>=stdisp_recommended_w(stdisp))
481 }else{ /* STDISP_GROWS_B_TO_T */
482 assert(other->dir==SPLIT_VERTICAL);
483 if(other->br->geom.h>=stdisp_recommended_h(stdisp))
488 if(p->tl==(WSplit*)stdisp)
489 rot_rs_flip_left(p, other);
490 else /* p->br==stdisp */
491 rot_rs_rotate_right(p, other, other->tl);
499 static bool do_try_sink_stdisp_para(WSplitSplit *p, WSplitST *stdisp,
500 WSplitSplit *other, bool force)
503 if(STDISP_IS_HORIZONTAL(stdisp)){
504 if(stdisp_recommended_w(stdisp)>=GEOM(p).w)
507 if(stdisp_recommended_h(stdisp)>=GEOM(p).h)
512 if(p->tl==(WSplit*)stdisp)
513 rot_para_left(p, other, other->br);
515 rot_para_right(p, other, other->tl);
521 bool split_try_sink_stdisp(WSplitSplit *node, bool iterate, bool force)
523 bool didsomething=FALSE;
526 /*assert(OBJ_IS_EXACTLY(node, WSplitSplit));*/
531 WSplitSplit *other=NULL;
534 if(OBJ_IS(tl, WSplitST)){
536 other=OBJ_CAST(br, WSplitSplit);
537 }else if(OBJ_IS(br, WSplitST)){
539 other=OBJ_CAST(tl, WSplitSplit);
547 if(!stdisp_dir_ok(node, st))
550 if(other->dir==other_dir(node->dir)){
551 if(!do_try_sink_stdisp_orth(node, st, other, force))
553 }else /*if(br->dir==node->dir)*/{
554 if(!do_try_sink_stdisp_para(node, st, other, force))
571 static bool do_try_unsink_stdisp_orth(WSplitSplit *a, WSplitSplit *p,
572 WSplitST *stdisp, bool force)
576 assert(p->dir==other_dir(a->dir));
577 assert(stdisp_dir_ok(p, stdisp));
579 if(STDISP_GROWS_T_TO_B(stdisp) || STDISP_GROWS_L_TO_R(stdisp)){
580 if(STDISP_GROWS_L_TO_R(stdisp)){
581 assert(a->dir==SPLIT_HORIZONTAL);
582 if(GEOM(stdisp).w<stdisp_recommended_w(stdisp))
584 }else{ /* STDISP_GROWS_T_TO_B */
585 assert(a->dir==SPLIT_VERTICAL);
586 if(GEOM(stdisp).h<stdisp_recommended_h(stdisp))
591 if((WSplit*)p==a->tl){
592 if((WSplit*)stdisp==p->br)
593 rot_rs_flip_right(a, p);
594 else /*stdisp==p->tl*/
595 rot_rs_rotate_right(a, p, (WSplit*)stdisp);
598 /* abnormal cases. */
599 warn(TR("Status display in bad split configuration."));
602 if((WSplit*)stdisp==p->br)
603 rot_rs_rotate_left(a, p, (WSplit*)stdisp);
604 else /*stdisp==p->tl*/
605 rot_rs_flip_left(a, p);
609 }else{ /*STDISP_GROWS_B_TO_T || STDISP_GROWS_R_TO_L*/
610 if(STDISP_GROWS_R_TO_L(stdisp)){
611 assert(a->dir==SPLIT_HORIZONTAL);
612 if(GEOM(stdisp).w<stdisp_recommended_w(stdisp))
614 }else{ /* STDISP_GROWS_B_TO_T */
615 assert(a->dir==SPLIT_VERTICAL);
616 if(GEOM(stdisp).h<stdisp_recommended_h(stdisp))
621 if((WSplit*)p==a->tl){
623 /* abnormal cases. */
624 warn(TR("Status display in bad split configuration."));
627 if((WSplit*)stdisp==p->br)
628 rot_rs_flip_right(a, p);
629 else /*stdisp==p->tl*/
630 rot_rs_rotate_right(a, p, (WSplit*)stdisp);
633 if((WSplit*)stdisp==p->br)
634 rot_rs_rotate_left(a, p, (WSplit*)stdisp);
635 else /*stdisp==p->tl*/
636 rot_rs_flip_left(a, p);
645 static bool do_try_unsink_stdisp_para(WSplitSplit *a, WSplitSplit *p,
646 WSplitST *stdisp, bool force)
649 if(STDISP_IS_HORIZONTAL(stdisp)){
650 if(stdisp_recommended_w(stdisp)<=GEOM(p).w)
653 if(stdisp_recommended_h(stdisp)<=GEOM(p).h)
659 if(a->tl==(WSplit*)p && p->tl==(WSplit*)stdisp){
660 rot_para_right(a, p, (WSplit*)stdisp);
661 }else if(a->br==(WSplit*)p && p->br==(WSplit*)stdisp){
662 rot_para_left(a, p, (WSplit*)stdisp);
664 warn(TR("Status display badly located in split tree."));
672 bool split_try_unsink_stdisp(WSplitSplit *node, bool iterate, bool force)
674 bool didsomething=FALSE;
677 /*assert(OBJ_IS_EXACTLY(node, WSplitSplit));*/
680 WSplitSplit *p=OBJ_CAST(((WSplit*)node)->parent, WSplitSplit);
688 if(OBJ_IS(tl, WSplitST))
690 else if(OBJ_IS(br, WSplitST))
695 if(!stdisp_dir_ok(node, st))
698 if(p->dir==other_dir(node->dir)){
699 if(!do_try_unsink_stdisp_orth(p, node, st, force))
701 }else /*if(p->dir==node->dir)*/{
702 if(!do_try_unsink_stdisp_para(p, node, st, force))
717 /*{{{ Sink or unsink */
720 bool split_regularise_stdisp(WSplitST *stdisp)
722 WSplitSplit *node=OBJ_CAST(((WSplit*)stdisp)->parent, WSplitSplit);
727 if(STDISP_IS_HORIZONTAL(stdisp)){
728 if(GEOM(stdisp).w<stdisp_recommended_w(stdisp))
729 return split_try_unsink_stdisp(node, TRUE, FALSE);
730 else if(GEOM(stdisp).w>stdisp_recommended_w(stdisp))
731 return split_try_sink_stdisp(node, TRUE, FALSE);
733 if(GEOM(stdisp).h<stdisp_recommended_h(stdisp))
734 return split_try_unsink_stdisp(node, TRUE, FALSE);
735 else if(GEOM(stdisp).h>stdisp_recommended_h(stdisp))
736 return split_try_sink_stdisp(node, TRUE, FALSE);