2 * ion/mod_tiling/split-stdisp.c
4 * Copyright (c) Tuomo Valkonen 1999-2009.
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
)
273 assert(a
->tl
==(WSplit
*)p
);
284 a
->tl
->parent
=(WSplitInner
*)a
;
287 ((WSplit
*)a
)->parent
=(WSplitInner
*)p
;
291 static void rot_rs_flip_right(WSplitSplit
*a
, WSplitSplit
*p
)
293 WRectangle xg
, yg
, pg
, ag
, qg
;
294 WSplit
*x
=a
->br
, *q
=p
->tl
, *y
=p
->br
;
296 assert(a
->dir
==other_dir(p
->dir
));
304 if(a
->dir
==SPLIT_HORIZONTAL
){
330 split_do_resize(x
, &xg
, PRIMN_BR
, PRIMN_BR
, FALSE
);
331 split_do_resize(y
, &yg
, PRIMN_BR
, PRIMN_BR
, FALSE
);
335 static void flip_left(WSplitSplit
*a
, WSplitSplit
*p
)
337 assert(a
->br
==(WSplit
*)p
);
348 a
->br
->parent
=(WSplitInner
*)a
;
351 ((WSplit
*)a
)->parent
=(WSplitInner
*)p
;
355 static void rot_rs_flip_left(WSplitSplit
*a
, WSplitSplit
*p
)
357 WRectangle xg
, yg
, pg
, ag
, qg
;
358 WSplit
*x
=a
->tl
, *q
=p
->br
, *y
=p
->tl
;
360 assert(a
->dir
==other_dir(p
->dir
));
368 if(a
->dir
==SPLIT_HORIZONTAL
){
402 split_do_resize(x
, &xg
, PRIMN_TL
, PRIMN_TL
, FALSE
);
403 split_do_resize(y
, &yg
, PRIMN_TL
, PRIMN_TL
, FALSE
);
407 static void rot_para_right(WSplitSplit
*a
, WSplitSplit
*p
,
410 rotate_right(a
, p
, y
);
411 if(a
->dir
==SPLIT_VERTICAL
){
414 GEOM(a
).y
=GEOM(a
->tl
).y
;
415 GEOM(a
).h
=GEOM(a
->br
).y
+GEOM(a
->br
).h
-GEOM(a
).y
;
419 GEOM(a
).x
=GEOM(a
->tl
).x
;
420 GEOM(a
).w
=GEOM(a
->br
).x
+GEOM(a
->br
).w
-GEOM(a
).x
;
425 static void rot_para_left(WSplitSplit
*a
, WSplitSplit
*p
,
428 rotate_left(a
, p
, y
);
429 if(a
->dir
==SPLIT_VERTICAL
){
432 GEOM(a
).h
=GEOM(a
->br
).y
+GEOM(a
->br
).h
-GEOM(a
).y
;
436 GEOM(a
).w
=GEOM(a
->br
).x
+GEOM(a
->br
).w
-GEOM(a
).x
;
447 static bool do_try_sink_stdisp_orth(WSplitSplit
*p
, WSplitST
*stdisp
,
448 WSplitSplit
*other
, bool force
)
452 assert(p
->dir
==other_dir(other
->dir
));
453 assert(stdisp_dir_ok(p
, stdisp
));
455 if(STDISP_GROWS_T_TO_B(stdisp
) || STDISP_GROWS_L_TO_R(stdisp
)){
456 if(STDISP_GROWS_L_TO_R(stdisp
)){
457 assert(other
->dir
==SPLIT_HORIZONTAL
);
458 if(other
->tl
->geom
.w
>=stdisp_recommended_w(stdisp
))
460 }else{ /* STDISP_GROWS_T_TO_B */
461 assert(other
->dir
==SPLIT_VERTICAL
);
462 if(other
->tl
->geom
.h
>=stdisp_recommended_h(stdisp
))
467 if(p
->br
==(WSplit
*)stdisp
)
468 rot_rs_flip_right(p
, other
);
469 else /* p->tl==stdisp */
470 rot_rs_rotate_left(p
, other
, other
->br
);
472 }else{ /* STDISP_GROWS_B_TO_T or STDISP_GROW_R_TO_L */
473 if(STDISP_GROWS_R_TO_L(stdisp
)){
474 assert(other
->dir
==SPLIT_HORIZONTAL
);
475 if(other
->br
->geom
.w
>=stdisp_recommended_w(stdisp
))
477 }else{ /* STDISP_GROWS_B_TO_T */
478 assert(other
->dir
==SPLIT_VERTICAL
);
479 if(other
->br
->geom
.h
>=stdisp_recommended_h(stdisp
))
484 if(p
->tl
==(WSplit
*)stdisp
)
485 rot_rs_flip_left(p
, other
);
486 else /* p->br==stdisp */
487 rot_rs_rotate_right(p
, other
, other
->tl
);
495 static bool do_try_sink_stdisp_para(WSplitSplit
*p
, WSplitST
*stdisp
,
496 WSplitSplit
*other
, bool force
)
499 if(STDISP_IS_HORIZONTAL(stdisp
)){
500 if(stdisp_recommended_w(stdisp
)>=GEOM(p
).w
)
503 if(stdisp_recommended_h(stdisp
)>=GEOM(p
).h
)
508 if(p
->tl
==(WSplit
*)stdisp
)
509 rot_para_left(p
, other
, other
->br
);
511 rot_para_right(p
, other
, other
->tl
);
517 bool split_try_sink_stdisp(WSplitSplit
*node
, bool iterate
, bool force
)
519 bool didsomething
=FALSE
;
522 /*assert(OBJ_IS_EXACTLY(node, WSplitSplit));*/
527 WSplitSplit
*other
=NULL
;
530 if(OBJ_IS(tl
, WSplitST
)){
532 other
=OBJ_CAST(br
, WSplitSplit
);
533 }else if(OBJ_IS(br
, WSplitST
)){
535 other
=OBJ_CAST(tl
, WSplitSplit
);
543 if(!stdisp_dir_ok(node
, st
))
546 if(other
->dir
==other_dir(node
->dir
)){
547 if(!do_try_sink_stdisp_orth(node
, st
, other
, force
))
549 }else /*if(br->dir==node->dir)*/{
550 if(!do_try_sink_stdisp_para(node
, st
, other
, force
))
567 static bool do_try_unsink_stdisp_orth(WSplitSplit
*a
, WSplitSplit
*p
,
568 WSplitST
*stdisp
, bool force
)
572 assert(p
->dir
==other_dir(a
->dir
));
573 assert(stdisp_dir_ok(p
, stdisp
));
575 if(STDISP_GROWS_T_TO_B(stdisp
) || STDISP_GROWS_L_TO_R(stdisp
)){
576 if(STDISP_GROWS_L_TO_R(stdisp
)){
577 assert(a
->dir
==SPLIT_HORIZONTAL
);
578 if(GEOM(stdisp
).w
<stdisp_recommended_w(stdisp
))
580 }else{ /* STDISP_GROWS_T_TO_B */
581 assert(a
->dir
==SPLIT_VERTICAL
);
582 if(GEOM(stdisp
).h
<stdisp_recommended_h(stdisp
))
587 if((WSplit
*)p
==a
->tl
){
588 if((WSplit
*)stdisp
==p
->br
)
589 rot_rs_flip_right(a
, p
);
590 else /*stdisp==p->tl*/
591 rot_rs_rotate_right(a
, p
, (WSplit
*)stdisp
);
594 /* abnormal cases. */
595 warn(TR("Status display in bad split configuration."));
598 if((WSplit
*)stdisp
==p
->br
)
599 rot_rs_rotate_left(a
, p
, (WSplit
*)stdisp
);
600 else /*stdisp==p->tl*/
601 rot_rs_flip_left(a
, p
);
605 }else{ /*STDISP_GROWS_B_TO_T || STDISP_GROWS_R_TO_L*/
606 if(STDISP_GROWS_R_TO_L(stdisp
)){
607 assert(a
->dir
==SPLIT_HORIZONTAL
);
608 if(GEOM(stdisp
).w
<stdisp_recommended_w(stdisp
))
610 }else{ /* STDISP_GROWS_B_TO_T */
611 assert(a
->dir
==SPLIT_VERTICAL
);
612 if(GEOM(stdisp
).h
<stdisp_recommended_h(stdisp
))
617 if((WSplit
*)p
==a
->tl
){
619 /* abnormal cases. */
620 warn(TR("Status display in bad split configuration."));
623 if((WSplit
*)stdisp
==p
->br
)
624 rot_rs_flip_right(a
, p
);
625 else /*stdisp==p->tl*/
626 rot_rs_rotate_right(a
, p
, (WSplit
*)stdisp
);
629 if((WSplit
*)stdisp
==p
->br
)
630 rot_rs_rotate_left(a
, p
, (WSplit
*)stdisp
);
631 else /*stdisp==p->tl*/
632 rot_rs_flip_left(a
, p
);
641 static bool do_try_unsink_stdisp_para(WSplitSplit
*a
, WSplitSplit
*p
,
642 WSplitST
*stdisp
, bool force
)
645 if(STDISP_IS_HORIZONTAL(stdisp
)){
646 if(stdisp_recommended_w(stdisp
)<=GEOM(p
).w
)
649 if(stdisp_recommended_h(stdisp
)<=GEOM(p
).h
)
655 if(a
->tl
==(WSplit
*)p
&& p
->tl
==(WSplit
*)stdisp
){
656 rot_para_right(a
, p
, (WSplit
*)stdisp
);
657 }else if(a
->br
==(WSplit
*)p
&& p
->br
==(WSplit
*)stdisp
){
658 rot_para_left(a
, p
, (WSplit
*)stdisp
);
660 warn(TR("Status display badly located in split tree."));
668 bool split_try_unsink_stdisp(WSplitSplit
*node
, bool iterate
, bool force
)
670 bool didsomething
=FALSE
;
673 /*assert(OBJ_IS_EXACTLY(node, WSplitSplit));*/
676 WSplitSplit
*p
=OBJ_CAST(((WSplit
*)node
)->parent
, WSplitSplit
);
684 if(OBJ_IS(tl
, WSplitST
))
686 else if(OBJ_IS(br
, WSplitST
))
691 if(!stdisp_dir_ok(node
, st
))
694 if(p
->dir
==other_dir(node
->dir
)){
695 if(!do_try_unsink_stdisp_orth(p
, node
, st
, force
))
697 }else /*if(p->dir==node->dir)*/{
698 if(!do_try_unsink_stdisp_para(p
, node
, st
, force
))
713 /*{{{ Sink or unsink */
716 bool split_regularise_stdisp(WSplitST
*stdisp
)
718 WSplitSplit
*node
=OBJ_CAST(((WSplit
*)stdisp
)->parent
, WSplitSplit
);
723 if(STDISP_IS_HORIZONTAL(stdisp
)){
724 if(GEOM(stdisp
).w
<stdisp_recommended_w(stdisp
))
725 return split_try_unsink_stdisp(node
, TRUE
, FALSE
);
726 else if(GEOM(stdisp
).w
>stdisp_recommended_w(stdisp
))
727 return split_try_sink_stdisp(node
, TRUE
, FALSE
);
729 if(GEOM(stdisp
).h
<stdisp_recommended_h(stdisp
))
730 return split_try_unsink_stdisp(node
, TRUE
, FALSE
);
731 else if(GEOM(stdisp
).h
>stdisp_recommended_h(stdisp
))
732 return split_try_sink_stdisp(node
, TRUE
, FALSE
);