]> git.decadent.org.uk Git - ion3.git/blob - ioncore/float-placement.c
3f6a64d0089ed8b6a10b81ff277a143e4d364ae0
[ion3.git] / ioncore / float-placement.c
1 /*
2  * ion/ioncore/float-placement.c
3  *
4  * Copyright (c) Tuomo Valkonen 1999-2007. 
5  *
6  * Ion is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation; either version 2.1 of the License, or
9  * (at your option) any later version.
10  */
11
12 #include <string.h>
13
14 #include "common.h"
15 #include "group.h"
16 #include "float-placement.h"
17
18
19 WFloatPlacement ioncore_placement_method=PLACEMENT_LRUD;
20
21
22 static void random_placement(WRectangle box, WRectangle *g)
23 {
24     box.w-=g->w;
25     box.h-=g->h;
26     g->x=box.x+(box.w<=0 ? 0 : rand()%box.w);
27     g->y=box.y+(box.h<=0 ? 0 : rand()%box.h);
28 }
29
30
31 static void ggeom(WRegion *reg, WRectangle *geom)
32 {
33     *geom=REGION_GEOM(reg);
34 }
35
36
37 static bool st_filt(WStacking *st, void *lvl)
38 {
39     uint level=*(uint*)lvl;
40     
41     return (st->reg!=NULL && 
42             REGION_IS_MAPPED(st->reg) && 
43             st->level==level);
44 }
45
46
47 #define FOR_ALL_STACKING_NODES(VAR, WS, LVL, TMP)          \
48     for(stacking_iter_init(&(TMP), group_get_stacking(ws), \
49                           st_filt, &LVL),                  \
50         VAR=stacking_iter_nodes(&(TMP));                   \
51         VAR!=NULL;                                         \
52         VAR=stacking_iter_nodes(&(TMP)))
53
54
55 #define IGNORE_ST(ST, WS) ((ST)->reg==NULL || (ST)==(WS)->bottom)
56
57
58 static WRegion* is_occupied(WGroup *ws, uint level, const WRectangle *r)
59 {
60     WStackingIterTmp tmp;
61     WStacking *st;
62     WRectangle p;
63     
64     FOR_ALL_STACKING_NODES(st, ws, level, tmp){
65         ggeom(st->reg, &p);
66         
67         if(r->x>=p.x+p.w)
68             continue;
69         if(r->y>=p.y+p.h)
70             continue;
71         if(r->x+r->w<=p.x)
72             continue;
73         if(r->y+r->h<=p.y)
74             continue;
75         return st->reg;
76     }
77     
78     return NULL;
79 }
80
81
82 static int next_least_x(WGroup *ws, uint level, int x)
83 {
84     WRectangle p;
85     int retx=REGION_GEOM(ws).x+REGION_GEOM(ws).w;
86     WStackingIterTmp tmp;
87     WStacking *st;
88     
89     FOR_ALL_STACKING_NODES(st, ws, level, tmp){
90         ggeom(st->reg, &p);
91         
92         if(p.x+p.w>x && p.x+p.w<retx)
93             retx=p.x+p.w;
94     }
95     
96     return retx+1;
97 }
98
99
100
101 static int next_lowest_y(WGroup *ws, uint level, int y)
102 {
103     WRectangle p;
104     int rety=REGION_GEOM(ws).y+REGION_GEOM(ws).h;
105     WStackingIterTmp tmp;
106     WStacking *st;
107     
108     FOR_ALL_STACKING_NODES(st, ws, level, tmp){
109         ggeom(st->reg, &p);
110         
111         if(p.y+p.h>y && p.y+p.h<rety)
112             rety=p.y+p.h;
113     }
114     
115     return rety+1;
116 }
117
118
119 static bool tiling_placement(WGroup *ws, uint level, WRectangle *g)
120 {
121     WRegion *p;
122     WRectangle r, r2;
123     int maxx, maxy;
124     
125     r=REGION_GEOM(ws);
126     r.w=g->w;
127     r.h=g->h;
128
129     maxx=REGION_GEOM(ws).x+REGION_GEOM(ws).w;
130     maxy=REGION_GEOM(ws).y+REGION_GEOM(ws).h;
131     
132     if(ioncore_placement_method==PLACEMENT_UDLR){
133         while(r.x<maxx){
134             p=is_occupied(ws, level, &r);
135             while(p!=NULL && r.y+r.h<maxy){
136                 ggeom(p, &r2);
137                 r.y=r2.y+r2.h+1;
138                 p=is_occupied(ws, level, &r);
139             }
140             if(r.y+r.h<maxy && r.x+r.w<maxx){
141                 g->x=r.x;
142                 g->y=r.y;
143                 return TRUE;
144             }else{
145                 r.x=next_least_x(ws, level, r.x);
146                 r.y=0;
147             }
148         }
149     }else{
150         while(r.y<maxy){
151             p=is_occupied(ws, level, &r);
152             while(p!=NULL && r.x+r.w<maxx){
153                 ggeom(p, &r2);
154                 r.x=r2.x+r2.w+1;
155                 p=is_occupied(ws, level, &r);
156             }
157             if(r.y+r.h<maxy && r.x+r.w<maxx){
158                 g->x=r.x;
159                 g->y=r.y;
160                 return TRUE;
161             }else{
162                 r.y=next_lowest_y(ws, level, r.y);
163                 r.x=0;
164             }
165         }
166     }
167
168     return FALSE;
169
170 }
171
172
173 void group_calc_placement(WGroup *ws, uint level, WRectangle *geom)
174 {
175     if(ioncore_placement_method!=PLACEMENT_RANDOM){
176         if(tiling_placement(ws, level, geom))
177             return;
178     }
179     random_placement(REGION_GEOM(ws), geom);
180 }
181