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