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 int stdisp_recommended_w(WSplitST
*stdisp
)
56 if(stdisp
->regnode
.reg
==NULL
)
57 return CF_STDISP_MIN_SZ
;
59 if(stdisp
->fullsize
&& stdisp
->orientation
==REGION_ORIENTATION_HORIZONTAL
){
60 WTiling
*ws
=REGION_MANAGER_CHK(stdisp
->regnode
.reg
, WTiling
);
62 return REGION_GEOM(ws
).w
;
65 return MAXOF(CF_STDISP_MIN_SZ
, region_min_w(stdisp
->regnode
.reg
));
69 int stdisp_recommended_h(WSplitST
*stdisp
)
71 if(stdisp
->regnode
.reg
==NULL
)
72 return CF_STDISP_MIN_SZ
;
74 if(stdisp
->fullsize
&& stdisp
->orientation
==REGION_ORIENTATION_VERTICAL
){
75 WTiling
*ws
=REGION_MANAGER_CHK(stdisp
->regnode
.reg
, WTiling
);
77 return REGION_GEOM(ws
).h
;
80 return MAXOF(CF_STDISP_MIN_SZ
, region_min_h(stdisp
->regnode
.reg
));
84 static bool stdisp_dir_ok(WSplitSplit
*p
, WSplitST
*stdisp
)
86 assert(p
->tl
==(WSplit
*)stdisp
|| p
->br
==(WSplit
*)stdisp
);
88 return (IMPLIES(STDISP_IS_HORIZONTAL(stdisp
), p
->dir
==SPLIT_VERTICAL
) &&
89 IMPLIES(STDISP_IS_VERTICAL(stdisp
), p
->dir
==SPLIT_HORIZONTAL
));
96 /*{{{ New rotation and flipping primitives */
99 static void replace(WSplitSplit
*a
, WSplitSplit
*p
)
101 if(((WSplit
*)a
)->parent
!=NULL
)
102 splitinner_replace(((WSplit
*)a
)->parent
, (WSplit
*)a
, (WSplit
*)p
);
104 splittree_changeroot((WSplit
*)a
, (WSplit
*)p
);
108 /* Yes, it is overparametrised */
109 static void rotate_right(WSplitSplit
*a
, WSplitSplit
*p
, WSplit
*y
)
111 assert(a
->tl
==(WSplit
*)p
&& p
->tl
==y
);
122 a
->tl
->parent
=(WSplitInner
*)a
;
125 ((WSplit
*)a
)->parent
=(WSplitInner
*)p
;
129 static void rot_rs_rotate_right(WSplitSplit
*a
, WSplitSplit
*p
, WSplit
*y
)
131 WRectangle xg
, yg
, pg
, ag
, qg
;
132 WSplit
*x
=a
->br
, *q
=p
->br
;
134 assert(a
->dir
==other_dir(p
->dir
));
142 if(a
->dir
==SPLIT_HORIZONTAL
){
167 rotate_right(a
, p
, y
);
172 split_do_resize(x
, &xg
, PRIMN_TL
, PRIMN_TL
, FALSE
);
173 split_do_resize(y
, &yg
, PRIMN_BR
, PRIMN_BR
, FALSE
);
178 static void rotate_left(WSplitSplit
*a
, WSplitSplit
*p
, WSplit
*y
)
180 assert(a
->br
==(WSplit
*)p
&& p
->br
==y
);
191 a
->br
->parent
=(WSplitInner
*)a
;
194 ((WSplit
*)a
)->parent
=(WSplitInner
*)p
;
198 static void rot_rs_rotate_left(WSplitSplit
*a
, WSplitSplit
*p
, WSplit
*y
)
200 WRectangle xg
, yg
, pg
, ag
, qg
;
201 WSplit
*x
=a
->tl
, *q
=p
->tl
;
203 assert(a
->dir
==other_dir(p
->dir
));
211 if(a
->dir
==SPLIT_HORIZONTAL
){
236 rotate_left(a
, p
, y
);
241 split_do_resize(x
, &xg
, PRIMN_BR
, PRIMN_BR
, FALSE
);
242 split_do_resize(y
, &yg
, PRIMN_TL
, PRIMN_TL
, FALSE
);
247 static void flip_right(WSplitSplit
*a
, WSplitSplit
*p
)
249 assert(a
->tl
==(WSplit
*)p
);
260 a
->tl
->parent
=(WSplitInner
*)a
;
263 ((WSplit
*)a
)->parent
=(WSplitInner
*)p
;
267 static void rot_rs_flip_right(WSplitSplit
*a
, WSplitSplit
*p
)
269 WRectangle xg
, yg
, pg
, ag
, qg
;
270 WSplit
*x
=a
->br
, *q
=p
->tl
, *y
=p
->br
;
272 assert(a
->dir
==other_dir(p
->dir
));
280 if(a
->dir
==SPLIT_HORIZONTAL
){
306 split_do_resize(x
, &xg
, PRIMN_BR
, PRIMN_BR
, FALSE
);
307 split_do_resize(y
, &yg
, PRIMN_BR
, PRIMN_BR
, FALSE
);
311 static void flip_left(WSplitSplit
*a
, WSplitSplit
*p
)
313 assert(a
->br
==(WSplit
*)p
);
324 a
->br
->parent
=(WSplitInner
*)a
;
327 ((WSplit
*)a
)->parent
=(WSplitInner
*)p
;
331 static void rot_rs_flip_left(WSplitSplit
*a
, WSplitSplit
*p
)
333 WRectangle xg
, yg
, pg
, ag
, qg
;
334 WSplit
*x
=a
->tl
, *q
=p
->br
, *y
=p
->tl
;
336 assert(a
->dir
==other_dir(p
->dir
));
344 if(a
->dir
==SPLIT_HORIZONTAL
){
378 split_do_resize(x
, &xg
, PRIMN_TL
, PRIMN_TL
, FALSE
);
379 split_do_resize(y
, &yg
, PRIMN_TL
, PRIMN_TL
, FALSE
);
383 static void rot_para_right(WSplitSplit
*a
, WSplitSplit
*p
,
386 rotate_right(a
, p
, y
);
387 if(a
->dir
==SPLIT_VERTICAL
){
390 GEOM(a
).y
=GEOM(a
->tl
).y
;
391 GEOM(a
).h
=GEOM(a
->br
).y
+GEOM(a
->br
).h
-GEOM(a
).y
;
395 GEOM(a
).x
=GEOM(a
->tl
).x
;
396 GEOM(a
).w
=GEOM(a
->br
).x
+GEOM(a
->br
).w
-GEOM(a
).x
;
401 static void rot_para_left(WSplitSplit
*a
, WSplitSplit
*p
,
404 rotate_left(a
, p
, y
);
405 if(a
->dir
==SPLIT_VERTICAL
){
408 GEOM(a
).h
=GEOM(a
->br
).y
+GEOM(a
->br
).h
-GEOM(a
).y
;
412 GEOM(a
).w
=GEOM(a
->br
).x
+GEOM(a
->br
).w
-GEOM(a
).x
;
423 static bool do_try_sink_stdisp_orth(WSplitSplit
*p
, WSplitST
*stdisp
,
424 WSplitSplit
*other
, bool force
)
428 assert(p
->dir
==other_dir(other
->dir
));
429 assert(stdisp_dir_ok(p
, stdisp
));
431 if(STDISP_GROWS_T_TO_B(stdisp
) || STDISP_GROWS_L_TO_R(stdisp
)){
432 if(STDISP_GROWS_L_TO_R(stdisp
)){
433 assert(other
->dir
==SPLIT_HORIZONTAL
);
434 if(other
->tl
->geom
.w
>=stdisp_recommended_w(stdisp
))
436 }else{ /* STDISP_GROWS_T_TO_B */
437 assert(other
->dir
==SPLIT_VERTICAL
);
438 if(other
->tl
->geom
.h
>=stdisp_recommended_h(stdisp
))
443 if(p
->br
==(WSplit
*)stdisp
)
444 rot_rs_flip_right(p
, other
);
445 else /* p->tl==stdisp */
446 rot_rs_rotate_left(p
, other
, other
->br
);
448 }else{ /* STDISP_GROWS_B_TO_T or STDISP_GROW_R_TO_L */
449 if(STDISP_GROWS_R_TO_L(stdisp
)){
450 assert(other
->dir
==SPLIT_HORIZONTAL
);
451 if(other
->br
->geom
.w
>=stdisp_recommended_w(stdisp
))
453 }else{ /* STDISP_GROWS_B_TO_T */
454 assert(other
->dir
==SPLIT_VERTICAL
);
455 if(other
->br
->geom
.h
>=stdisp_recommended_h(stdisp
))
460 if(p
->tl
==(WSplit
*)stdisp
)
461 rot_rs_flip_left(p
, other
);
462 else /* p->br==stdisp */
463 rot_rs_rotate_right(p
, other
, other
->tl
);
471 static bool do_try_sink_stdisp_para(WSplitSplit
*p
, WSplitST
*stdisp
,
472 WSplitSplit
*other
, bool force
)
475 if(STDISP_IS_HORIZONTAL(stdisp
)){
476 if(stdisp_recommended_w(stdisp
)>=GEOM(p
).w
)
479 if(stdisp_recommended_h(stdisp
)>=GEOM(p
).h
)
484 if(p
->tl
==(WSplit
*)stdisp
)
485 rot_para_left(p
, other
, other
->br
);
487 rot_para_right(p
, other
, other
->tl
);
493 bool split_try_sink_stdisp(WSplitSplit
*node
, bool iterate
, bool force
)
495 bool didsomething
=FALSE
;
498 /*assert(OBJ_IS_EXACTLY(node, WSplitSplit));*/
503 WSplitSplit
*other
=NULL
;
506 if(OBJ_IS(tl
, WSplitST
)){
508 other
=OBJ_CAST(br
, WSplitSplit
);
509 }else if(OBJ_IS(br
, WSplitST
)){
511 other
=OBJ_CAST(tl
, WSplitSplit
);
519 if(!stdisp_dir_ok(node
, st
))
522 if(other
->dir
==other_dir(node
->dir
)){
523 if(!do_try_sink_stdisp_orth(node
, st
, other
, force
))
525 }else /*if(br->dir==node->dir)*/{
526 if(!do_try_sink_stdisp_para(node
, st
, other
, force
))
543 static bool do_try_unsink_stdisp_orth(WSplitSplit
*a
, WSplitSplit
*p
,
544 WSplitST
*stdisp
, bool force
)
548 assert(p
->dir
==other_dir(a
->dir
));
549 assert(stdisp_dir_ok(p
, stdisp
));
551 if(STDISP_GROWS_T_TO_B(stdisp
) || STDISP_GROWS_L_TO_R(stdisp
)){
552 if(STDISP_GROWS_L_TO_R(stdisp
)){
553 assert(a
->dir
==SPLIT_HORIZONTAL
);
554 if(GEOM(stdisp
).w
<stdisp_recommended_w(stdisp
))
556 }else{ /* STDISP_GROWS_T_TO_B */
557 assert(a
->dir
==SPLIT_VERTICAL
);
558 if(GEOM(stdisp
).h
<stdisp_recommended_h(stdisp
))
563 if((WSplit
*)p
==a
->tl
){
564 if((WSplit
*)stdisp
==p
->br
)
565 rot_rs_flip_right(a
, p
);
566 else /*stdisp==p->tl*/
567 rot_rs_rotate_right(a
, p
, (WSplit
*)stdisp
);
570 /* abnormal cases. */
571 warn(TR("Status display in bad split configuration."));
574 if((WSplit
*)stdisp
==p
->br
)
575 rot_rs_rotate_left(a
, p
, (WSplit
*)stdisp
);
576 else /*stdisp==p->tl*/
577 rot_rs_flip_left(a
, p
);
581 }else{ /*STDISP_GROWS_B_TO_T || STDISP_GROWS_R_TO_L*/
582 if(STDISP_GROWS_R_TO_L(stdisp
)){
583 assert(a
->dir
==SPLIT_HORIZONTAL
);
584 if(GEOM(stdisp
).w
<stdisp_recommended_w(stdisp
))
586 }else{ /* STDISP_GROWS_B_TO_T */
587 assert(a
->dir
==SPLIT_VERTICAL
);
588 if(GEOM(stdisp
).h
<stdisp_recommended_h(stdisp
))
593 if((WSplit
*)p
==a
->tl
){
595 /* abnormal cases. */
596 warn(TR("Status display in bad split configuration."));
599 if((WSplit
*)stdisp
==p
->br
)
600 rot_rs_flip_right(a
, p
);
601 else /*stdisp==p->tl*/
602 rot_rs_rotate_right(a
, p
, (WSplit
*)stdisp
);
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
);
617 static bool do_try_unsink_stdisp_para(WSplitSplit
*a
, WSplitSplit
*p
,
618 WSplitST
*stdisp
, bool force
)
621 if(STDISP_IS_HORIZONTAL(stdisp
)){
622 if(stdisp_recommended_w(stdisp
)<=GEOM(p
).w
)
625 if(stdisp_recommended_h(stdisp
)<=GEOM(p
).h
)
631 if(a
->tl
==(WSplit
*)p
&& p
->tl
==(WSplit
*)stdisp
){
632 rot_para_right(a
, p
, (WSplit
*)stdisp
);
633 }else if(a
->br
==(WSplit
*)p
&& p
->br
==(WSplit
*)stdisp
){
634 rot_para_left(a
, p
, (WSplit
*)stdisp
);
636 warn(TR("Status display badly located in split tree."));
644 bool split_try_unsink_stdisp(WSplitSplit
*node
, bool iterate
, bool force
)
646 bool didsomething
=FALSE
;
649 /*assert(OBJ_IS_EXACTLY(node, WSplitSplit));*/
652 WSplitSplit
*p
=OBJ_CAST(((WSplit
*)node
)->parent
, WSplitSplit
);
660 if(OBJ_IS(tl
, WSplitST
))
662 else if(OBJ_IS(br
, WSplitST
))
667 if(!stdisp_dir_ok(node
, st
))
670 if(p
->dir
==other_dir(node
->dir
)){
671 if(!do_try_unsink_stdisp_orth(p
, node
, st
, force
))
673 }else /*if(p->dir==node->dir)*/{
674 if(!do_try_unsink_stdisp_para(p
, node
, st
, force
))
689 /*{{{ Sink or unsink */
692 bool split_regularise_stdisp(WSplitST
*stdisp
)
694 WSplitSplit
*node
=OBJ_CAST(((WSplit
*)stdisp
)->parent
, WSplitSplit
);
699 if(STDISP_IS_HORIZONTAL(stdisp
)){
700 if(GEOM(stdisp
).w
<stdisp_recommended_w(stdisp
))
701 return split_try_unsink_stdisp(node
, TRUE
, FALSE
);
702 else if(GEOM(stdisp
).w
>stdisp_recommended_w(stdisp
))
703 return split_try_sink_stdisp(node
, TRUE
, FALSE
);
705 if(GEOM(stdisp
).h
<stdisp_recommended_h(stdisp
))
706 return split_try_unsink_stdisp(node
, TRUE
, FALSE
);
707 else if(GEOM(stdisp
).h
>stdisp_recommended_h(stdisp
))
708 return split_try_sink_stdisp(node
, TRUE
, FALSE
);