]> git.decadent.org.uk Git - ion3.git/blob - mod_tiling/splitfloat.c
Imported Upstream version 20090110
[ion3.git] / mod_tiling / splitfloat.c
1 /*
2  * ion/mod_tiling/splitext.c
3  *
4  * Copyright (c) Tuomo Valkonen 1999-2009. 
5  *
6  * See the included file LICENSE for details.
7  */
8
9 #include <string.h>
10 #include <limits.h>
11 #include <libtu/objp.h>
12 #include <libtu/minmax.h>
13 #include <ioncore/common.h>
14 #include <ioncore/global.h>
15 #include <ioncore/rootwin.h>
16 #include <ioncore/xwindow.h>
17 #include <ioncore/window.h>
18
19 #include "tiling.h"
20 #include "split.h"
21 #include "splitfloat.h"
22 #include "panehandle.h"
23
24
25 #define GEOM(X) (((WSplit*)(X))->geom)
26
27
28 /*{{{ Init/deinit */
29
30
31 static void splitfloat_set_borderlines(WSplitFloat *split)
32 {
33     int dir=split->ssplit.dir;
34     
35     split->tlpwin->bline=(dir==SPLIT_HORIZONTAL
36                           ? GR_BORDERLINE_RIGHT
37                           : GR_BORDERLINE_BOTTOM);
38
39     split->brpwin->bline=(dir==SPLIT_HORIZONTAL
40                           ? GR_BORDERLINE_LEFT
41                           : GR_BORDERLINE_TOP);
42 }
43
44
45 bool splitfloat_init(WSplitFloat *split, const WRectangle *geom, 
46                      WTiling *ws, int dir)
47 {
48     WFitParams fp;
49     WWindow *par=REGION_PARENT(ws);
50     
51     assert(par!=NULL);
52
53     fp.g=*geom;
54     fp.mode=REGION_FIT_EXACT;
55     split->tlpwin=create_panehandle(par, &fp);
56     if(split->tlpwin==NULL)
57         return FALSE;
58
59     fp.g=*geom;
60     fp.mode=REGION_FIT_EXACT;
61     split->brpwin=create_panehandle(par, &fp);
62     if(split->brpwin==NULL){
63         destroy_obj((Obj*)split->tlpwin);
64         return FALSE;
65     }
66     
67     ((WRegion*)split->brpwin)->flags|=REGION_SKIP_FOCUS;
68     ((WRegion*)split->tlpwin)->flags|=REGION_SKIP_FOCUS;
69     
70     if(!splitsplit_init(&(split->ssplit), geom, dir)){
71         destroy_obj((Obj*)split->brpwin);
72         destroy_obj((Obj*)split->tlpwin);
73         return FALSE;
74     }
75
76     split->tlpwin->splitfloat=split;
77     split->brpwin->splitfloat=split;
78     
79     splitfloat_set_borderlines(split);
80
81     if(REGION_IS_MAPPED(ws)){
82         region_map((WRegion*)(split->tlpwin));
83         region_map((WRegion*)(split->brpwin));
84     }
85     
86     return TRUE;
87 }
88
89
90 WSplitFloat *create_splitfloat(const WRectangle *geom, WTiling *ws, int dir)
91 {
92     CREATEOBJ_IMPL(WSplitFloat, splitfloat, (p, geom, ws, dir));
93 }
94
95
96 void splitfloat_deinit(WSplitFloat *split)
97 {
98     if(split->tlpwin!=NULL){
99         WPaneHandle *tmp=split->tlpwin;
100         split->tlpwin=NULL;
101         tmp->splitfloat=NULL;
102         destroy_obj((Obj*)tmp);
103     }
104
105     if(split->brpwin!=NULL){
106         WPaneHandle *tmp=split->brpwin;
107         split->brpwin=NULL;
108         tmp->splitfloat=NULL;
109         destroy_obj((Obj*)tmp);
110     }
111     
112     splitsplit_deinit(&(split->ssplit));
113 }
114
115
116 /*}}}*/
117
118
119 /*{{{ X window handling */
120
121
122 static void stack_stacking_reg(WRegion *reg, 
123                                Window *bottomret, Window *topret)
124 {
125     Window b=None, t=None;
126     
127     if(reg!=NULL){
128         region_stacking(reg, &b, &t);
129         if(*bottomret==None)
130             *bottomret=b;
131         if(t!=None)
132             *topret=t;
133     }
134 }
135
136
137 static void stack_stacking_split(WSplit *split,
138                                  Window *bottomret, Window *topret)
139 {
140     Window b=None, t=None;
141     
142     if(split!=NULL){
143         split_stacking(split, &b, &t);
144         if(*bottomret==None)
145             *bottomret=b;
146         if(t!=None)
147             *topret=t;
148     }
149 }
150
151
152 static void splitfloat_stacking(WSplitFloat *split, 
153                                 Window *bottomret, Window *topret)
154 {
155     *bottomret=None;
156     *topret=None;
157     
158     if(split->ssplit.current!=SPLIT_CURRENT_TL){
159         stack_stacking_reg((WRegion*)split->tlpwin, bottomret, topret);
160         stack_stacking_split(split->ssplit.tl, bottomret, topret);
161         stack_stacking_reg((WRegion*)split->brpwin, bottomret, topret);
162         stack_stacking_split(split->ssplit.br, bottomret, topret);
163     }else{
164         stack_stacking_reg((WRegion*)split->brpwin, bottomret, topret);
165         stack_stacking_split(split->ssplit.br, bottomret, topret);
166         stack_stacking_reg((WRegion*)split->tlpwin, bottomret, topret);
167         stack_stacking_split(split->ssplit.tl, bottomret, topret);
168     }
169 }
170
171
172 static void stack_restack_reg(WRegion *reg, Window *other, int *mode)
173 {
174     Window b=None, t=None;
175     
176     if(reg!=NULL){
177         region_restack(reg, *other, *mode);
178         region_stacking(reg, &b, &t);
179         if(t!=None){
180             *other=t;
181             *mode=Above;
182         }
183     }
184 }
185
186
187 static void stack_restack_split(WSplit *split, Window *other, int *mode)
188 {
189     Window b=None, t=None;
190     
191     if(split!=NULL){
192         split_restack(split, *other, *mode);
193         split_stacking(split, &b, &t);
194         if(t!=None){
195             *other=t;
196             *mode=Above;
197         }
198     }
199 }
200
201
202
203 static void splitfloat_restack(WSplitFloat *split, Window other, int mode)
204 {
205     if(split->ssplit.current!=SPLIT_CURRENT_TL){
206         stack_restack_reg((WRegion*)split->tlpwin, &other, &mode);
207         stack_restack_split(split->ssplit.tl, &other, &mode);
208         stack_restack_reg((WRegion*)split->brpwin, &other, &mode);
209         stack_restack_split(split->ssplit.br, &other, &mode);
210     }else{
211         stack_restack_reg((WRegion*)split->brpwin, &other, &mode);
212         stack_restack_split(split->ssplit.br, &other, &mode);
213         stack_restack_reg((WRegion*)split->tlpwin, &other, &mode);
214         stack_restack_split(split->ssplit.tl, &other, &mode);
215     }
216 }
217
218
219 static void splitfloat_map(WSplitFloat *split)
220 {
221     region_map((WRegion*)(split->tlpwin));
222     region_map((WRegion*)(split->brpwin));
223     splitinner_forall((WSplitInner*)split, split_map);
224 }
225
226
227 static void splitfloat_unmap(WSplitFloat *split)
228 {
229     region_unmap((WRegion*)(split->tlpwin));
230     region_unmap((WRegion*)(split->brpwin));
231     splitinner_forall((WSplitInner*)split, split_unmap);
232 }
233
234
235 static void reparentreg(WRegion *reg, WWindow *target)
236 {
237     WRectangle g=REGION_GEOM(reg);
238     region_reparent(reg, target, &g, REGION_FIT_EXACT);
239 }
240
241
242 static void splitfloat_reparent(WSplitFloat *split, WWindow *target)
243 {
244     if(split->ssplit.current!=SPLIT_CURRENT_TL){
245         reparentreg((WRegion*)split->tlpwin, target);
246         split_reparent(split->ssplit.tl, target);
247         reparentreg((WRegion*)split->brpwin, target);
248         split_reparent(split->ssplit.br, target);
249     }else{
250         reparentreg((WRegion*)split->brpwin, target);
251         split_reparent(split->ssplit.br, target);
252         reparentreg((WRegion*)split->tlpwin, target);
253         split_reparent(split->ssplit.tl, target);
254     }
255 }
256
257
258 /*}}}*/
259
260
261 /*{{{ Geometry */
262
263
264 #define TL_BORDER(SF) ((SF)->ssplit.dir==SPLIT_VERTICAL \
265                        ? (SF)->tlpwin->bdw.bottom       \
266                        : (SF)->tlpwin->bdw.right)
267
268 #define BR_BORDER(SF) ((SF)->ssplit.dir==SPLIT_VERTICAL \
269                        ? (SF)->brpwin->bdw.top          \
270                        : (SF)->brpwin->bdw.left)
271
272
273 void splitfloat_tl_pwin_to_cnt(WSplitFloat *split, WRectangle *g)
274 {
275     if(split->ssplit.dir==SPLIT_HORIZONTAL)
276         g->w=maxof(1, g->w-split->tlpwin->bdw.right);
277     else
278         g->h=maxof(1, g->h-split->tlpwin->bdw.bottom);
279 }
280
281
282 void splitfloat_br_pwin_to_cnt(WSplitFloat *split, WRectangle *g)
283 {
284     if(split->ssplit.dir==SPLIT_HORIZONTAL){
285         int delta=split->tlpwin->bdw.left;
286         g->w=maxof(1, g->w-delta);
287         g->x+=delta;
288     }else{
289         int delta=split->tlpwin->bdw.top;
290         g->h=maxof(1, g->h-delta);
291         g->y+=delta;
292     }
293 }
294
295
296 void splitfloat_tl_cnt_to_pwin(WSplitFloat *split, WRectangle *g)
297 {
298     if(split->ssplit.dir==SPLIT_HORIZONTAL)
299         g->w=maxof(1, g->w+split->tlpwin->bdw.right);
300     else
301         g->h=maxof(1, g->h+split->tlpwin->bdw.bottom);
302 }
303
304
305 void splitfloat_br_cnt_to_pwin(WSplitFloat *split, WRectangle *g)
306 {
307     if(split->ssplit.dir==SPLIT_HORIZONTAL){
308         int delta=split->tlpwin->bdw.left;
309         g->w=maxof(1, g->w+delta);
310         g->x-=delta;
311     }else{
312         int delta=split->tlpwin->bdw.top;
313         g->h=maxof(1, g->h+delta);
314         g->y-=delta;
315     }
316 }
317
318     
319 static int infadd(int x, int y)
320 {
321     return ((x==INT_MAX || y==INT_MAX) ? INT_MAX : (x+y));
322 }
323
324
325 static int splitfloat_get_handle(WSplitFloat *split, int dir, 
326                                   WSplit *other)
327 {
328     assert(other==split->ssplit.tl || other==split->ssplit.br);
329     
330     if(dir!=split->ssplit.dir)
331         return 0;
332
333     if(dir==SPLIT_VERTICAL){
334         if(other==split->ssplit.tl)
335             return split->tlpwin->bdw.right;
336         else if(other==split->ssplit.br)
337             return split->tlpwin->bdw.left;
338     }else{
339         if(other==split->ssplit.tl)
340             return split->tlpwin->bdw.bottom;
341         else if(other==split->ssplit.br)
342             return split->tlpwin->bdw.top;
343     }
344     
345     return 0;
346 }
347
348
349 static int splitfloat_get_max(WSplitFloat *split, int dir, WSplit *other)
350 {
351     return infadd((dir==SPLIT_VERTICAL ? other->max_h : other->max_w),
352                   splitfloat_get_handle(split, dir, other));
353 }
354
355
356 static int splitfloat_get_min(WSplitFloat *split, int dir, WSplit *other)
357 {
358     return ((dir==SPLIT_VERTICAL ? other->min_h : other->min_w)
359             +splitfloat_get_handle(split, dir, other));
360 }
361
362
363 static void splitfloat_update_bounds(WSplitFloat *split, bool recursive)
364 {
365     WSplit *tl=split->ssplit.tl, *br=split->ssplit.br;
366     WSplit *node=(WSplit*)split;
367     int tl_max_w, br_max_w, tl_max_h, br_max_h;
368     int tl_min_w, br_min_w, tl_min_h, br_min_h;
369     
370     if(recursive){
371         split_update_bounds(tl, recursive);
372         split_update_bounds(br, recursive);
373     }
374
375     tl_max_w=splitfloat_get_max(split, SPLIT_HORIZONTAL, tl);
376     br_max_w=splitfloat_get_max(split, SPLIT_HORIZONTAL, br);
377     tl_max_h=splitfloat_get_max(split, SPLIT_VERTICAL, tl);
378     br_max_h=splitfloat_get_max(split, SPLIT_VERTICAL, br);
379     tl_min_w=splitfloat_get_min(split, SPLIT_HORIZONTAL, tl);
380     br_min_w=splitfloat_get_min(split, SPLIT_HORIZONTAL, br);
381     tl_min_h=splitfloat_get_min(split, SPLIT_VERTICAL, tl);
382     br_min_h=splitfloat_get_min(split, SPLIT_VERTICAL, br);
383     
384     if(split->ssplit.dir==SPLIT_HORIZONTAL){
385         node->max_w=infadd(tl_max_w, br_max_w);
386         node->min_w=minof(tl_min_w, br_min_w);
387         node->unused_w=0;
388         node->min_h=maxof(tl_min_h, br_min_h);
389         node->max_h=maxof(minof(tl_max_h, br_max_h), node->min_h);
390         node->unused_h=minof(tl->unused_h, br->unused_h);
391     }else{
392         node->max_h=infadd(tl_max_h, br_max_h);
393         node->min_h=minof(tl_min_h, br_min_h);
394         node->unused_h=0;
395         node->min_w=maxof(tl_min_w, br_min_w);
396         node->max_w=maxof(minof(tl_max_w, br_max_w), node->min_w);
397         node->unused_w=minof(tl->unused_w, br->unused_w);
398     }
399 }
400
401
402 void splitfloat_update_handles(WSplitFloat *split, const WRectangle *tlg_,
403                                const WRectangle *brg_)
404 {
405     WRectangle tlg=*tlg_, brg=*brg_;
406     
407     if(split->ssplit.dir==SPLIT_HORIZONTAL){
408         tlg.w=split->tlpwin->bdw.right;
409         tlg.x=tlg_->x+tlg_->w-tlg.w;
410         brg.w=split->brpwin->bdw.left;
411     }else{
412         tlg.h=split->tlpwin->bdw.bottom;
413         tlg.y=tlg_->y+tlg_->h-tlg.h;
414         brg.h=split->brpwin->bdw.top;
415     }
416     
417     region_fit((WRegion*)split->tlpwin, &tlg, REGION_FIT_EXACT);
418     region_fit((WRegion*)split->brpwin, &brg, REGION_FIT_EXACT);
419 }
420
421
422 static void bound(int *what, int min, int max)
423 {
424     if(*what<min)
425         *what=min;
426     else if(*what>max)
427         *what=max;
428 }
429
430
431 static void adjust_sizes(int *tls_, int *brs_, int nsize, 
432                          int tlmin, int brmin, int tlmax, int brmax,
433                          int primn)
434 {
435     int tls=maxof(0, *tls_);
436     int brs=maxof(0, *brs_);
437     nsize=maxof(1, nsize);
438     
439     if(primn==PRIMN_TL){
440         tls=maxof(1, nsize-brs);
441         bound(&tls, tlmin, tlmax);
442         brs=nsize-tls;
443         bound(&brs, brmin, brmax);
444         tls=nsize-brs;
445         bound(&tls, tlmin, tlmax);
446     }else if(primn==PRIMN_BR){
447         brs=maxof(1, nsize-tls);
448         bound(&brs, brmin, brmax);
449         tls=nsize-brs;
450         bound(&tls, tlmin, tlmax);
451         brs=nsize-tls;
452         bound(&brs, brmin, brmax);
453     }else{ /* && PRIMN_ANY */
454         tls=tls*nsize/maxof(2, tls+brs);
455         bound(&tls, tlmin, tlmax);
456         brs=nsize-tls;
457         bound(&brs, brmin, brmax);
458         tls=nsize-brs;
459         bound(&tls, tlmin, tlmax);
460     }
461     
462     *tls_=tls;
463     *brs_=brs;
464 }
465
466
467 static void adjust_size(int *sz, int dir, WSplitFloat *f, WSplit *s)
468 {
469     int mi=splitfloat_get_min(f, dir, s);
470     int ma=splitfloat_get_max(f, dir, s);
471     *sz=maxof(mi, minof(*sz, ma));
472 }
473
474
475 static void splitfloat_do_resize(WSplitFloat *split, const WRectangle *ng, 
476                                  int hprimn, int vprimn, bool transpose)
477 {
478     WRectangle tlg=GEOM(split->ssplit.tl);
479     WRectangle brg=GEOM(split->ssplit.br);
480     WRectangle ntlg=*ng, nbrg=*ng;
481     WRectangle *og=&((WSplit*)split)->geom;
482     int dir=split->ssplit.dir;
483     bool adjust=TRUE;
484     
485     splitfloat_tl_cnt_to_pwin(split, &tlg);
486     splitfloat_br_cnt_to_pwin(split, &brg);
487
488     if(transpose){
489         if(dir==SPLIT_VERTICAL){
490             dir=SPLIT_HORIZONTAL;
491             split->tlpwin->bline=GR_BORDERLINE_RIGHT;
492             split->brpwin->bline=GR_BORDERLINE_LEFT;
493         }else{
494             dir=SPLIT_VERTICAL;
495             split->tlpwin->bline=GR_BORDERLINE_BOTTOM;
496             split->brpwin->bline=GR_BORDERLINE_TOP;
497         }
498         split->ssplit.dir=dir;
499     }
500
501     if(dir==SPLIT_VERTICAL){
502         if(ng->h<=tlg.h+brg.h){
503             if(transpose){
504                 ntlg.h=minof(tlg.w, ng->h*2/3);
505                 nbrg.h=minof(brg.w, ng->h*2/3);
506                 adjust_size(&ntlg.h, dir, split, split->ssplit.tl);
507                 adjust_size(&nbrg.h, dir, split, split->ssplit.br);
508                 adjust=(ng->h>ntlg.h+nbrg.h);
509             }else{
510                 ntlg.h=minof(ng->h, tlg.h);
511                 nbrg.h=minof(ng->h, brg.h);
512                 adjust=FALSE;
513             }
514         }else{
515             ntlg.h=tlg.h;
516             nbrg.h=brg.h;
517         }
518
519         if(adjust){
520             adjust_sizes(&ntlg.h, &nbrg.h, ng->h,
521                          splitfloat_get_min(split, dir, split->ssplit.tl),
522                          splitfloat_get_min(split, dir, split->ssplit.br),
523                          splitfloat_get_max(split, dir, split->ssplit.tl),
524                          splitfloat_get_max(split, dir, split->ssplit.br),
525                          vprimn);
526         }
527         
528         nbrg.y=ng->y+ng->h-nbrg.h;
529     }else{
530         if(ng->w<=tlg.w+brg.w){
531             if(transpose){
532                 ntlg.w=minof(tlg.h, ng->w*2/3);
533                 nbrg.w=minof(brg.h, ng->w*2/3);
534                 adjust_size(&ntlg.w, dir, split, split->ssplit.tl);
535                 adjust_size(&nbrg.w, dir, split, split->ssplit.br);
536                 adjust=(ng->w>ntlg.w+nbrg.w);
537             }else{
538                 ntlg.w=minof(ng->w, tlg.w);
539                 nbrg.w=minof(ng->w, brg.w);
540                 adjust=FALSE;
541             }
542         }else{
543             ntlg.w=tlg.w;
544             nbrg.w=brg.w;
545         }
546         
547         if(adjust){
548             adjust_sizes(&ntlg.w, &nbrg.w, ng->w,
549                          splitfloat_get_min(split, dir, split->ssplit.tl),
550                          splitfloat_get_min(split, dir, split->ssplit.br),
551                          splitfloat_get_max(split, dir, split->ssplit.tl),
552                          splitfloat_get_max(split, dir, split->ssplit.br),
553                          hprimn);
554         }
555         
556         nbrg.x=ng->x+ng->w-nbrg.w;
557     }
558
559     GEOM(split)=*ng;
560
561     splitfloat_update_handles(split, &ntlg, &nbrg);
562
563     splitfloat_tl_pwin_to_cnt(split, &ntlg);
564     split_do_resize(split->ssplit.tl, &ntlg, hprimn, vprimn, transpose);
565     splitfloat_br_pwin_to_cnt(split, &nbrg);
566     split_do_resize(split->ssplit.br, &nbrg, hprimn, vprimn, transpose);
567 }
568
569
570 static void calc_amount(int *amount, int *oamount,
571                         int rs, WSplitSplit *p, int omax,
572                         const WRectangle *ng, const WRectangle *og)
573 {
574     *oamount=0;
575     
576     if(rs>=0){
577         if(p->dir==SPLIT_VERTICAL)
578             *amount=maxof(0, minof(rs, GEOM(p).h-ng->h));
579         else
580             *amount=maxof(0, minof(rs, GEOM(p).w-ng->w));
581     }else{
582         if(p->dir==SPLIT_VERTICAL){
583             int overlap=maxof(0, og->h-(GEOM(p).h-ng->h));
584             *amount=-minof(-rs, overlap);
585             *oamount=maxof(0, minof(*amount-rs, omax-og->h));
586             *amount-=*oamount;
587         }else{
588             int overlap=maxof(0, og->w-(GEOM(p).w-ng->w));
589             *amount=-minof(-rs, overlap);
590             *oamount=maxof(0, minof(*amount-rs, omax-og->w));
591             *amount-=*oamount;
592         }
593     }
594 }
595
596
597 static void splitfloat_do_rqsize(WSplitFloat *split, WSplit *node, 
598                                  RootwardAmount *ha, RootwardAmount *va, 
599                                  WRectangle *rg, bool tryonly)
600 {
601     int hprimn=PRIMN_ANY, vprimn=PRIMN_ANY;
602     WRectangle pg, og, ng, nog, nng;
603     RootwardAmount *ca;
604     WSplit *other;
605     int amount=0, oamount=0, omax;
606     int thisnode;
607     WSplitSplit *p=&(split->ssplit);
608     
609     assert(!ha->any || ha->tl==0);
610     assert(!va->any || va->tl==0);
611     assert(p->tl==node || p->br==node);
612     
613     if(p->tl==node){
614         other=p->br;
615         thisnode=PRIMN_TL;
616     }else{
617         other=p->tl;
618         thisnode=PRIMN_BR;
619     }
620
621     ng=GEOM(node);
622     og=GEOM(other);
623     
624     if(thisnode==PRIMN_TL){
625         splitfloat_tl_cnt_to_pwin(split, &ng);
626         splitfloat_br_cnt_to_pwin(split, &og);
627     }else{
628         splitfloat_br_cnt_to_pwin(split, &ng);
629         splitfloat_tl_cnt_to_pwin(split, &og);
630     }
631
632     ca=(p->dir==SPLIT_VERTICAL ? va : ha);
633     
634     omax=splitfloat_get_max(split, p->dir, other);
635     
636     if(thisnode==PRIMN_TL || ca->any){
637         calc_amount(&amount, &oamount, ca->br, p, omax, &ng, &og);
638         ca->br-=amount;
639     }else/*if(thisnode==PRIMN_BR)*/{
640         calc_amount(&amount, &oamount, ca->tl, p, omax, &ng, &og);
641         ca->tl-=amount;
642     }
643     
644     if(((WSplit*)p)->parent==NULL /*|| 
645        (ha->tl==0 && ha->br==0 && va->tl==0 && va->br==0)*/){
646         pg=((WSplit*)p)->geom;
647     }else{
648         splitinner_do_rqsize(((WSplit*)p)->parent, (WSplit*)p, ha, va,
649                              &pg, tryonly);
650     }
651     
652     assert(pg.w>=0 && pg.h>=0);
653
654     nog=pg;
655     nng=pg;
656
657     if(p->dir==SPLIT_VERTICAL){
658         nog.h=minof(pg.h, maxof(0, og.h+oamount));
659         nng.h=minof(pg.h, maxof(0, ng.h+amount+pg.h-GEOM(p).h));
660         if(thisnode==PRIMN_TL)
661             nog.y=pg.y+pg.h-nog.h;
662         else
663             nng.y=pg.y+pg.h-nng.h;
664         vprimn=thisnode;
665     }else{
666         nog.w=minof(pg.w, maxof(0, og.w+oamount));
667         nng.w=minof(pg.w, maxof(0, ng.w+amount+pg.w-GEOM(p).w));
668         if(thisnode==PRIMN_TL)
669             nog.x=pg.x+pg.w-nog.w;
670         else
671             nng.x=pg.x+pg.w-nng.w;
672         hprimn=thisnode;
673     }
674     
675     if(!tryonly){
676         GEOM(p)=pg;
677
678         if(thisnode==PRIMN_TL){
679             splitfloat_update_handles(split, &nng, &nog);
680             splitfloat_br_pwin_to_cnt(split, &nog);
681         }else{
682             splitfloat_update_handles(split, &nog, &nng);
683             splitfloat_tl_pwin_to_cnt(split, &nog);
684         }
685             
686         /* Entä jos 'other' on stdisp? */
687         split_do_resize(other, &nog, hprimn, vprimn, FALSE);
688     }
689     
690     *rg=nng;
691     if(thisnode==PRIMN_TL)
692         splitfloat_tl_pwin_to_cnt(split, rg);
693     else
694         splitfloat_br_pwin_to_cnt(split, rg);
695 }
696
697
698 void splitfloat_flip(WSplitFloat *split)
699 {
700     WRectangle tlg, brg;
701     
702     splitsplit_flip_default(&split->ssplit);
703     
704     tlg=split->ssplit.tl->geom;
705     brg=split->ssplit.br->geom;
706
707     splitfloat_tl_cnt_to_pwin(split, &tlg);
708     splitfloat_br_cnt_to_pwin(split, &brg);
709     splitfloat_update_handles(split, &tlg, &brg);
710 }
711
712
713 /*}}}*/
714
715
716 /*{{{ Loading code */
717
718
719 #define MINS 8
720
721 static void adjust_tls_brs(int *tls, int *brs, int total)
722 {
723     if(*tls<=0)
724         *tls=MINS;
725     if(*brs<=0)
726         *brs=MINS;
727     
728     if(*tls+*brs<total){
729         *tls=total*(*tls)/(*tls+*brs);
730         *brs=total-(*tls);
731     }
732         
733     *tls=minof(maxof(MINS, *tls), total);
734     *brs=minof(maxof(MINS, *brs), total);
735 }
736
737
738 static void calc_tlg_brg(const WRectangle *geom, int tls, int brs, int dir,
739                          WRectangle *tlg, WRectangle *brg)
740 {
741     *tlg=*geom;
742     *brg=*geom;
743     
744     if(dir==SPLIT_HORIZONTAL){
745         adjust_tls_brs(&tls, &brs, geom->w);
746         tlg->w=tls;
747         brg->w=brs;
748         brg->x=geom->x+geom->w-brs;
749     }else{
750         adjust_tls_brs(&tls, &brs, geom->h);
751         tlg->h=tls;
752         brg->h=brs;
753         brg->y=geom->y+geom->h-brs;
754     }
755 }
756
757
758 WSplit *load_splitfloat(WTiling *ws, const WRectangle *geom, ExtlTab tab)
759 {
760     WSplit *tl=NULL, *br=NULL;
761     WSplitFloat *split;
762     char *dir_str;
763     int dir, brs, tls;
764     ExtlTab subtab;
765     WRectangle tlg, brg;
766     int set=0;
767
768     set+=(extl_table_gets_i(tab, "tls", &tls)==TRUE);
769     set+=(extl_table_gets_i(tab, "brs", &brs)==TRUE);
770     set+=(extl_table_gets_s(tab, "dir", &dir_str)==TRUE);
771     
772     if(set!=3)
773         return NULL;
774     
775     if(strcmp(dir_str, "vertical")==0){
776         dir=SPLIT_VERTICAL;
777     }else if(strcmp(dir_str, "horizontal")==0){
778         dir=SPLIT_HORIZONTAL;
779     }else{
780         warn(TR("Invalid direction."));
781         free(dir_str);
782         return NULL;
783     }
784     free(dir_str);
785
786     split=create_splitfloat(geom, ws, dir);
787     if(split==NULL)
788         return NULL;
789
790     if(!extl_table_is_bool_set(tab, "tls_brs_incl_handles")){
791         if(split->ssplit.dir==SPLIT_HORIZONTAL){
792             tls+=split->tlpwin->bdw.right;
793             brs+=split->brpwin->bdw.left;
794         }else{
795             tls+=split->tlpwin->bdw.bottom;
796             brs+=split->brpwin->bdw.top;
797         }
798     }
799                                
800     calc_tlg_brg(geom, tls, brs, dir, &tlg, &brg);
801     
802     splitfloat_update_handles(split, &tlg, &brg);
803     
804     if(extl_table_gets_t(tab, "tl", &subtab)){
805         WRectangle g=tlg;
806         splitfloat_tl_pwin_to_cnt(split, &g);
807         tl=tiling_load_node(ws, &g, subtab);
808         extl_unref_table(subtab);
809     }
810     
811     if(extl_table_gets_t(tab, "br", &subtab)){
812         WRectangle g;
813         if(tl==NULL){
814             g=*geom;
815         }else{
816             g=brg;
817             splitfloat_br_pwin_to_cnt(split, &g);
818         }
819         br=tiling_load_node(ws, &g, subtab);
820         extl_unref_table(subtab);
821     }
822     
823     if(tl==NULL || br==NULL){
824         destroy_obj((Obj*)split);
825         if(tl!=NULL){
826             split_do_resize(tl, geom, PRIMN_ANY, PRIMN_ANY, FALSE);
827             return tl;
828         }
829         if(br!=NULL){
830             split_do_resize(br, geom, PRIMN_ANY, PRIMN_ANY, FALSE);
831             return br;
832         }
833         return NULL;
834     }
835     
836     tl->parent=(WSplitInner*)split;
837     br->parent=(WSplitInner*)split;
838
839     split->ssplit.tl=tl;
840     split->ssplit.br=br;
841     
842     return (WSplit*)split;
843 }
844
845
846 /*}}}*/
847
848
849 /*{{{ Split */
850
851
852 WSplitRegion *splittree_split_floating(WSplit *node, int dir, int primn,
853                                        int nmins, WRegionSimpleCreateFn *fn, 
854                                        WTiling *ws)
855 {
856     WSplitFloat *sf;
857     int omins, mins;
858     int sn, so, s, rs;
859     int bn, bo;
860     WRectangle gn, go, gnc, goc;
861     WFitParams fp;
862     WRegion *nreg;
863     WSplitRegion *nnode;
864     WSplitInner *psplit;
865     
866     if(primn!=PRIMN_TL && primn!=PRIMN_BR)
867         primn=PRIMN_BR;
868
869     split_update_bounds(split_find_root(node), TRUE);
870     
871     sf=create_splitfloat(&node->geom, ws, dir);
872     
873     if(sf==NULL)
874         return NULL;
875     
876     omins=(dir==SPLIT_VERTICAL ? node->min_h : node->min_w);
877     s=split_size(node, dir);
878     
879     if(primn==PRIMN_BR){
880         bn=BR_BORDER(sf);
881         bo=TL_BORDER(sf);
882     }else{
883         bn=TL_BORDER(sf);
884         bo=BR_BORDER(sf);
885     }
886     
887     mins=maxof(omins+bo, nmins+bn);
888
889     /* Potentially resize old node. */
890     
891     splittree_begin_resize();
892
893     if(mins>s){
894         WRectangle ng=node->geom, rg;
895         if(dir==SPLIT_VERTICAL)
896             ng.h=mins;
897         else
898             ng.w=mins;
899         
900         split_do_rqgeom_(node, &ng, TRUE, TRUE, &rg, TRUE);
901         rs=(dir==SPLIT_VERTICAL ? rg.h : rg.w);
902         if(rs<mins){
903             warn(TR("Unable to split: not enough free space."));
904             destroy_obj((Obj*)sf);
905             return NULL;
906         }
907         split_do_rqgeom_(node, &ng, TRUE, TRUE, &rg, FALSE);
908         s=split_size(node, dir);
909     }else{
910         splittree_scan_stdisp_rootward(node);
911     }
912     
913     /* Calculate geometries. */
914     
915     sn=maxof(nmins+bn, s/2);
916     so=maxof(omins+bo, s-s/2);
917
918     ((WSplit*)sf)->geom=node->geom;
919     
920     if(primn==PRIMN_TL){
921         calc_tlg_brg(&(node->geom), sn, so, dir, &gn, &go);
922         splitfloat_update_handles(sf, &gn, &go);
923         gnc=gn; splitfloat_tl_pwin_to_cnt(sf, &gnc);
924         goc=go; splitfloat_br_pwin_to_cnt(sf, &goc);
925     }else{
926         calc_tlg_brg(&(node->geom), so, sn, dir, &go, &gn);
927         splitfloat_update_handles(sf, &go, &gn);
928         goc=go; splitfloat_tl_pwin_to_cnt(sf, &goc);
929         gnc=gn; splitfloat_br_pwin_to_cnt(sf, &gnc);
930     }
931
932     /* Create the region. */
933     
934     fp.mode=REGION_FIT_EXACT;
935     fp.g=gnc;
936     
937     nreg=fn(REGION_PARENT(ws), &fp);
938     
939     if(nreg==NULL){
940         destroy_obj((Obj*)sf);
941         return NULL;
942     }
943
944     nnode=create_splitregion(&(fp.g), nreg);
945     if(nnode==NULL){
946         destroy_obj((Obj*)nreg);
947         destroy_obj((Obj*)sf);
948         return NULL;
949     }
950     
951     /* Now that everything's ok, resize and move original node. */    
952     
953     split_do_resize(node, &goc, 
954                     (dir==SPLIT_HORIZONTAL ? primn : PRIMN_ANY),
955                     (dir==SPLIT_VERTICAL ? primn : PRIMN_ANY),
956                     FALSE);
957
958     /* Set up split structure. */
959     
960     psplit=node->parent;
961     
962     if(psplit!=NULL)
963         splitinner_replace(psplit, node, (WSplit*)sf);
964     else
965         splittree_changeroot(node, (WSplit*)sf);
966
967     node->parent=(WSplitInner*)sf;
968     ((WSplit*)nnode)->parent=(WSplitInner*)sf;
969     
970     if(primn==PRIMN_BR){
971         sf->ssplit.tl=node;
972         sf->ssplit.br=(WSplit*)nnode;
973     }else{
974         sf->ssplit.tl=(WSplit*)nnode;
975         sf->ssplit.br=node;
976     }
977     
978     /*splittree_end_resize();*/
979     
980     return nnode;
981 }
982
983
984 /*}}}*/
985
986
987 /*{{{ The class */
988
989
990 static DynFunTab splitfloat_dynfuntab[]={
991     {split_update_bounds, splitfloat_update_bounds},
992     {split_do_resize, splitfloat_do_resize},
993     {splitinner_do_rqsize, splitfloat_do_rqsize},
994     {split_stacking, splitfloat_stacking},
995     {split_restack, splitfloat_restack},
996     {split_reparent, splitfloat_reparent},
997     {split_map, splitfloat_map},
998     {split_unmap, splitfloat_unmap},
999     {splitsplit_flip, splitfloat_flip},
1000     END_DYNFUNTAB,
1001 };
1002
1003
1004 EXTL_EXPORT
1005 IMPLCLASS(WSplitFloat, WSplitSplit, splitfloat_deinit, splitfloat_dynfuntab);
1006
1007
1008 /*}}}*/
1009