2 * ion/mod_tiling/split-stdisp.c
4 * Copyright (c) Tuomo Valkonen 1999-2007.
6 * Ion is free software; you can redistribute it and/or modify it under
7 * the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
12 #include <libtu/minmax.h>
13 #include <ioncore/common.h>
14 #include <ioncore/mplex.h>
15 #include <ioncore/resize.h>
17 #include "split-stdisp.h"
21 /*{{{ Helper routines */
24 #define STDISP_IS_HORIZONTAL(STDISP) \
25 ((STDISP)->orientation==REGION_ORIENTATION_HORIZONTAL)
27 #define STDISP_IS_VERTICAL(STDISP) \
28 ((STDISP)->orientation==REGION_ORIENTATION_VERTICAL)
30 #define STDISP_GROWS_L_TO_R(STDISP) (STDISP_IS_HORIZONTAL(STDISP) && \
31 ((STDISP)->corner==MPLEX_STDISP_TL || \
32 (STDISP)->corner==MPLEX_STDISP_BL))
34 #define STDISP_GROWS_R_TO_L(STDISP) (STDISP_IS_HORIZONTAL(STDISP) && \
35 ((STDISP)->corner==MPLEX_STDISP_TR || \
36 (STDISP)->corner==MPLEX_STDISP_BR))
38 #define STDISP_GROWS_T_TO_B(STDISP) (STDISP_IS_VERTICAL(STDISP) && \
39 ((STDISP)->corner==MPLEX_STDISP_TL || \
40 (STDISP)->corner==MPLEX_STDISP_TR))
42 #define STDISP_GROWS_B_TO_T(STDISP) (STDISP_IS_VERTICAL(STDISP) && \
43 ((STDISP)->corner==MPLEX_STDISP_BL || \
44 (STDISP)->corner==MPLEX_STDISP_BR))
46 #define GEOM(S) (((WSplit*)S)->geom)
48 #define IMPLIES(X, Y) (!(X) || (Y))
51 static int other_dir(int dir)
53 return (dir==SPLIT_VERTICAL ? SPLIT_HORIZONTAL : SPLIT_VERTICAL);
57 static void swap(int *x, int *y)
65 static void swapptr(WSplit **x, WSplit **y)
73 static void swapgeom(WRectangle *g, WRectangle *h)
81 int stdisp_recommended_w(WSplitST *stdisp)
83 if(stdisp->regnode.reg==NULL)
84 return CF_STDISP_MIN_SZ;
86 if(stdisp->fullsize && stdisp->orientation==REGION_ORIENTATION_HORIZONTAL){
87 WTiling *ws=REGION_MANAGER_CHK(stdisp->regnode.reg, WTiling);
89 return REGION_GEOM(ws).w;
92 return maxof(CF_STDISP_MIN_SZ, region_min_w(stdisp->regnode.reg));
96 int stdisp_recommended_h(WSplitST *stdisp)
98 if(stdisp->regnode.reg==NULL)
99 return CF_STDISP_MIN_SZ;
101 if(stdisp->fullsize && stdisp->orientation==REGION_ORIENTATION_VERTICAL){
102 WTiling *ws=REGION_MANAGER_CHK(stdisp->regnode.reg, WTiling);
104 return REGION_GEOM(ws).h;
107 return maxof(CF_STDISP_MIN_SZ, region_min_h(stdisp->regnode.reg));
111 static bool stdisp_dir_ok(WSplitSplit *p, WSplitST *stdisp)
113 assert(p->tl==(WSplit*)stdisp || p->br==(WSplit*)stdisp);
115 return (IMPLIES(STDISP_IS_HORIZONTAL(stdisp), p->dir==SPLIT_VERTICAL) &&
116 IMPLIES(STDISP_IS_VERTICAL(stdisp), p->dir==SPLIT_HORIZONTAL));
123 /*{{{ New rotation and flipping primitives */
126 static void replace(WSplitSplit *a, WSplitSplit *p)
128 if(((WSplit*)a)->parent!=NULL)
129 splitinner_replace(((WSplit*)a)->parent, (WSplit*)a, (WSplit*)p);
131 splittree_changeroot((WSplit*)a, (WSplit*)p);
135 /* Yes, it is overparametrised */
136 static void rotate_right(WSplitSplit *a, WSplitSplit *p, WSplit *y)
138 assert(a->tl==(WSplit*)p && p->tl==y);
149 a->tl->parent=(WSplitInner*)a;
152 ((WSplit*)a)->parent=(WSplitInner*)p;
156 static void rot_rs_rotate_right(WSplitSplit *a, WSplitSplit *p, WSplit *y)
158 WRectangle xg, yg, pg, ag, qg;
159 WSplit *x=a->br, *q=p->br;
161 assert(a->dir==other_dir(p->dir));
169 if(a->dir==SPLIT_HORIZONTAL){
194 rotate_right(a, p, y);
199 split_do_resize(x, &xg, PRIMN_TL, PRIMN_TL, FALSE);
200 split_do_resize(y, &yg, PRIMN_BR, PRIMN_BR, FALSE);
205 static void rotate_left(WSplitSplit *a, WSplitSplit *p, WSplit *y)
207 assert(a->br==(WSplit*)p && p->br==y);
218 a->br->parent=(WSplitInner*)a;
221 ((WSplit*)a)->parent=(WSplitInner*)p;
225 static void rot_rs_rotate_left(WSplitSplit *a, WSplitSplit *p, WSplit *y)
227 WRectangle xg, yg, pg, ag, qg;
228 WSplit *x=a->tl, *q=p->tl;
230 assert(a->dir==other_dir(p->dir));
238 if(a->dir==SPLIT_HORIZONTAL){
263 rotate_left(a, p, y);
268 split_do_resize(x, &xg, PRIMN_BR, PRIMN_BR, FALSE);
269 split_do_resize(y, &yg, PRIMN_TL, PRIMN_TL, FALSE);
274 static void flip_right(WSplitSplit *a, WSplitSplit *p)
278 assert(a->tl==(WSplit*)p);
289 a->tl->parent=(WSplitInner*)a;
292 ((WSplit*)a)->parent=(WSplitInner*)p;
296 static void rot_rs_flip_right(WSplitSplit *a, WSplitSplit *p)
298 WRectangle xg, yg, pg, ag, qg;
299 WSplit *x=a->br, *q=p->tl, *y=p->br;
301 assert(a->dir==other_dir(p->dir));
309 if(a->dir==SPLIT_HORIZONTAL){
335 split_do_resize(x, &xg, PRIMN_BR, PRIMN_BR, FALSE);
336 split_do_resize(y, &yg, PRIMN_BR, PRIMN_BR, FALSE);
340 static void flip_left(WSplitSplit *a, WSplitSplit *p)
344 assert(a->br==(WSplit*)p);
355 a->br->parent=(WSplitInner*)a;
358 ((WSplit*)a)->parent=(WSplitInner*)p;
362 static void rot_rs_flip_left(WSplitSplit *a, WSplitSplit *p)
364 WRectangle xg, yg, pg, ag, qg;
365 WSplit *x=a->tl, *q=p->br, *y=p->tl;
367 assert(a->dir==other_dir(p->dir));
375 if(a->dir==SPLIT_HORIZONTAL){
409 split_do_resize(x, &xg, PRIMN_TL, PRIMN_TL, FALSE);
410 split_do_resize(y, &yg, PRIMN_TL, PRIMN_TL, FALSE);
414 static void rot_para_right(WSplitSplit *a, WSplitSplit *p,
417 rotate_right(a, p, y);
418 if(a->dir==SPLIT_VERTICAL){
421 GEOM(a).y=GEOM(a->tl).y;
422 GEOM(a).h=GEOM(a->br).y+GEOM(a->br).h-GEOM(a).y;
426 GEOM(a).x=GEOM(a->tl).x;
427 GEOM(a).w=GEOM(a->br).x+GEOM(a->br).w-GEOM(a).x;
432 static void rot_para_left(WSplitSplit *a, WSplitSplit *p,
435 rotate_left(a, p, y);
436 if(a->dir==SPLIT_VERTICAL){
439 GEOM(a).h=GEOM(a->br).y+GEOM(a->br).h-GEOM(a).y;
443 GEOM(a).w=GEOM(a->br).x+GEOM(a->br).w-GEOM(a).x;
454 static bool do_try_sink_stdisp_orth(WSplitSplit *p, WSplitST *stdisp,
455 WSplitSplit *other, bool force)
459 assert(p->dir==other_dir(other->dir));
460 assert(stdisp_dir_ok(p, stdisp));
462 if(STDISP_GROWS_T_TO_B(stdisp) || STDISP_GROWS_L_TO_R(stdisp)){
463 if(STDISP_GROWS_L_TO_R(stdisp)){
464 assert(other->dir==SPLIT_HORIZONTAL);
465 if(other->tl->geom.w>=stdisp_recommended_w(stdisp))
467 }else{ /* STDISP_GROWS_T_TO_B */
468 assert(other->dir==SPLIT_VERTICAL);
469 if(other->tl->geom.h>=stdisp_recommended_h(stdisp))
474 if(p->br==(WSplit*)stdisp)
475 rot_rs_flip_right(p, other);
476 else /* p->tl==stdisp */
477 rot_rs_rotate_left(p, other, other->br);
479 }else{ /* STDISP_GROWS_B_TO_T or STDISP_GROW_R_TO_L */
480 if(STDISP_GROWS_R_TO_L(stdisp)){
481 assert(other->dir==SPLIT_HORIZONTAL);
482 if(other->br->geom.w>=stdisp_recommended_w(stdisp))
484 }else{ /* STDISP_GROWS_B_TO_T */
485 assert(other->dir==SPLIT_VERTICAL);
486 if(other->br->geom.h>=stdisp_recommended_h(stdisp))
491 if(p->tl==(WSplit*)stdisp)
492 rot_rs_flip_left(p, other);
493 else /* p->br==stdisp */
494 rot_rs_rotate_right(p, other, other->tl);
502 static bool do_try_sink_stdisp_para(WSplitSplit *p, WSplitST *stdisp,
503 WSplitSplit *other, bool force)
506 if(STDISP_IS_HORIZONTAL(stdisp)){
507 if(stdisp_recommended_w(stdisp)>=GEOM(p).w)
510 if(stdisp_recommended_h(stdisp)>=GEOM(p).h)
515 if(p->tl==(WSplit*)stdisp)
516 rot_para_left(p, other, other->br);
518 rot_para_right(p, other, other->tl);
524 bool split_try_sink_stdisp(WSplitSplit *node, bool iterate, bool force)
526 bool didsomething=FALSE;
529 /*assert(OBJ_IS_EXACTLY(node, WSplitSplit));*/
534 WSplitSplit *other=NULL;
537 if(OBJ_IS(tl, WSplitST)){
539 other=OBJ_CAST(br, WSplitSplit);
540 }else if(OBJ_IS(br, WSplitST)){
542 other=OBJ_CAST(tl, WSplitSplit);
550 if(!stdisp_dir_ok(node, st))
553 if(other->dir==other_dir(node->dir)){
554 if(!do_try_sink_stdisp_orth(node, st, other, force))
556 }else /*if(br->dir==node->dir)*/{
557 if(!do_try_sink_stdisp_para(node, st, other, force))
574 static bool do_try_unsink_stdisp_orth(WSplitSplit *a, WSplitSplit *p,
575 WSplitST *stdisp, bool force)
579 assert(p->dir==other_dir(a->dir));
580 assert(stdisp_dir_ok(p, stdisp));
582 if(STDISP_GROWS_T_TO_B(stdisp) || STDISP_GROWS_L_TO_R(stdisp)){
583 if(STDISP_GROWS_L_TO_R(stdisp)){
584 assert(a->dir==SPLIT_HORIZONTAL);
585 if(GEOM(stdisp).w<stdisp_recommended_w(stdisp))
587 }else{ /* STDISP_GROWS_T_TO_B */
588 assert(a->dir==SPLIT_VERTICAL);
589 if(GEOM(stdisp).h<stdisp_recommended_h(stdisp))
594 if((WSplit*)p==a->tl){
595 if((WSplit*)stdisp==p->br)
596 rot_rs_flip_right(a, p);
597 else /*stdisp==p->tl*/
598 rot_rs_rotate_right(a, p, (WSplit*)stdisp);
601 /* abnormal cases. */
602 warn(TR("Status display in bad split configuration."));
605 if((WSplit*)stdisp==p->br)
606 rot_rs_rotate_left(a, p, (WSplit*)stdisp);
607 else /*stdisp==p->tl*/
608 rot_rs_flip_left(a, p);
612 }else{ /*STDISP_GROWS_B_TO_T || STDISP_GROWS_R_TO_L*/
613 if(STDISP_GROWS_R_TO_L(stdisp)){
614 assert(a->dir==SPLIT_HORIZONTAL);
615 if(GEOM(stdisp).w<stdisp_recommended_w(stdisp))
617 }else{ /* STDISP_GROWS_B_TO_T */
618 assert(a->dir==SPLIT_VERTICAL);
619 if(GEOM(stdisp).h<stdisp_recommended_h(stdisp))
624 if((WSplit*)p==a->tl){
626 /* abnormal cases. */
627 warn(TR("Status display in bad split configuration."));
630 if((WSplit*)stdisp==p->br)
631 rot_rs_flip_right(a, p);
632 else /*stdisp==p->tl*/
633 rot_rs_rotate_right(a, p, (WSplit*)stdisp);
636 if((WSplit*)stdisp==p->br)
637 rot_rs_rotate_left(a, p, (WSplit*)stdisp);
638 else /*stdisp==p->tl*/
639 rot_rs_flip_left(a, p);
648 static bool do_try_unsink_stdisp_para(WSplitSplit *a, WSplitSplit *p,
649 WSplitST *stdisp, bool force)
652 if(STDISP_IS_HORIZONTAL(stdisp)){
653 if(stdisp_recommended_w(stdisp)<=GEOM(p).w)
656 if(stdisp_recommended_h(stdisp)<=GEOM(p).h)
662 if(a->tl==(WSplit*)p && p->tl==(WSplit*)stdisp){
663 rot_para_right(a, p, (WSplit*)stdisp);
664 }else if(a->br==(WSplit*)p && p->br==(WSplit*)stdisp){
665 rot_para_left(a, p, (WSplit*)stdisp);
667 warn(TR("Status display badly located in split tree."));
675 bool split_try_unsink_stdisp(WSplitSplit *node, bool iterate, bool force)
677 bool didsomething=FALSE;
680 /*assert(OBJ_IS_EXACTLY(node, WSplitSplit));*/
683 WSplitSplit *p=OBJ_CAST(((WSplit*)node)->parent, WSplitSplit);
691 if(OBJ_IS(tl, WSplitST))
693 else if(OBJ_IS(br, WSplitST))
698 if(!stdisp_dir_ok(node, st))
701 if(p->dir==other_dir(node->dir)){
702 if(!do_try_unsink_stdisp_orth(p, node, st, force))
704 }else /*if(p->dir==node->dir)*/{
705 if(!do_try_unsink_stdisp_para(p, node, st, force))
720 /*{{{ Sink or unsink */
723 bool split_regularise_stdisp(WSplitST *stdisp)
725 WSplitSplit *node=OBJ_CAST(((WSplit*)stdisp)->parent, WSplitSplit);
730 if(STDISP_IS_HORIZONTAL(stdisp)){
731 if(GEOM(stdisp).w<stdisp_recommended_w(stdisp))
732 return split_try_unsink_stdisp(node, TRUE, FALSE);
733 else if(GEOM(stdisp).w>stdisp_recommended_w(stdisp))
734 return split_try_sink_stdisp(node, TRUE, FALSE);
736 if(GEOM(stdisp).h<stdisp_recommended_h(stdisp))
737 return split_try_unsink_stdisp(node, TRUE, FALSE);
738 else if(GEOM(stdisp).h>stdisp_recommended_h(stdisp))
739 return split_try_sink_stdisp(node, TRUE, FALSE);