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
)
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
);