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