2 * ion/ioncore/sizepolicy.c
4 * Copyright (c) Tuomo Valkonen 1999-2007.
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.
12 #include <libtu/minmax.h>
19 #include "sizepolicy.h"
23 static int fit_x(int x, int w, const WRectangle *max_geom)
25 int mw=maxof(max_geom->w, 1);
27 return minof(maxof(x, max_geom->x), max_geom->x+mw-w);
31 static int fit_y(int y, int h, const WRectangle *max_geom)
33 int mh=maxof(max_geom->h, 1);
35 return minof(maxof(y, max_geom->y), max_geom->y+mh-h);
39 static void do_gravity(const WRectangle *max_geom, int szplcy,
42 /* Assumed: width and height already adjusted within limits */
48 switch(szplcy&SIZEPOLICY_HORIZ_MASK){
49 case SIZEPOLICY_HORIZ_LEFT:
53 case SIZEPOLICY_HORIZ_RIGHT:
54 geom->x=max_geom->x+max_geom->w-geom->w;
57 case SIZEPOLICY_HORIZ_CENTER:
58 geom->x=max_geom->x+max_geom->w/2-geom->w/2;
62 geom->x=fit_x(geom->x, geom->w, max_geom);
65 switch(szplcy&SIZEPOLICY_VERT_MASK){
66 case SIZEPOLICY_VERT_TOP:
70 case SIZEPOLICY_VERT_BOTTOM:
71 geom->y=max_geom->y+max_geom->h-geom->h;
74 case SIZEPOLICY_VERT_CENTER:
75 geom->y=max_geom->y+max_geom->h/2-geom->h/2;
79 geom->y=fit_x(geom->y, geom->h, max_geom);
84 static void gravity_stretch_policy(int szplcy, WRegion *reg,
85 const WRectangle *rq_geom, WFitParams *fp,
88 WRectangle max_geom=fp->g;
93 w=(ws ? max_geom.w : minof(rq_geom->w, max_geom.w));
94 h=(hs ? max_geom.h : minof(rq_geom->h, max_geom.h));
97 region_size_hints_correct(reg, &w, &h, FALSE);
102 do_gravity(&max_geom, szplcy, &(fp->g));
106 static void sizepolicy_free_snap(WSizePolicy *szplcy, WRegion *reg,
107 WRectangle *rq_geom, int rq_flags,
110 WRectangle max_geom=fp->g;
111 bool fullw=((rq_flags®ION_RQGEOM_WEAK_W) &&
112 (*szplcy&SIZEPOLICY_HORIZ_MASK)==SIZEPOLICY_HORIZ_CENTER);
113 bool fullh=((rq_flags®ION_RQGEOM_WEAK_H) &&
114 (*szplcy&SIZEPOLICY_VERT_MASK)==SIZEPOLICY_VERT_CENTER);
116 int w=(fullw ? max_geom.w : minof(rq_geom->w, max_geom.w));
117 int h=(fullh ? max_geom.h : minof(rq_geom->h, max_geom.h));
121 if(!(rq_flags®ION_RQGEOM_WEAK_X)
122 && rq_flags®ION_RQGEOM_WEAK_W){
123 x_=fit_x(rq_geom->x, 1, &max_geom);
124 if(((*szplcy)&SIZEPOLICY_HORIZ_MASK)==SIZEPOLICY_HORIZ_RIGHT)
125 w=max_geom.x+max_geom.w-x_;
127 w=minof(w, max_geom.x+max_geom.w-x_);
130 if(!(rq_flags®ION_RQGEOM_WEAK_Y)
131 && rq_flags®ION_RQGEOM_WEAK_H){
132 y_=fit_x(rq_geom->y, 1, &max_geom);
133 if(((*szplcy)&SIZEPOLICY_VERT_MASK)==SIZEPOLICY_VERT_BOTTOM)
134 h=max_geom.y+max_geom.h-y_;
136 h=minof(h, max_geom.y+max_geom.h-y_);
140 region_size_hints_correct(reg, &w, &h, FALSE);
145 if(!(rq_flags®ION_RQGEOM_WEAK_X)
146 && rq_flags®ION_RQGEOM_WEAK_W){
148 }else if(rq_flags®ION_RQGEOM_WEAK_X){
149 switch((*szplcy)&SIZEPOLICY_HORIZ_MASK){
150 case SIZEPOLICY_HORIZ_CENTER:
151 fp->g.x=max_geom.x+(max_geom.w-w)/2;
154 case SIZEPOLICY_HORIZ_LEFT:
158 case SIZEPOLICY_HORIZ_RIGHT:
159 fp->g.x=max_geom.x+max_geom.w-w;
163 fp->g.x=fit_x(rq_geom->x, w, &max_geom);
167 fp->g.x=fit_x(rq_geom->x, w, &max_geom);
170 if(!(rq_flags®ION_RQGEOM_WEAK_Y)
171 && rq_flags®ION_RQGEOM_WEAK_H){
173 }else if(rq_flags®ION_RQGEOM_WEAK_Y){
174 switch((*szplcy)&SIZEPOLICY_VERT_MASK){
175 case SIZEPOLICY_VERT_CENTER:
176 fp->g.y=max_geom.y+(max_geom.h-h)/2;
179 case SIZEPOLICY_VERT_TOP:
183 case SIZEPOLICY_VERT_BOTTOM:
184 fp->g.y=max_geom.y+max_geom.h-h;
188 fp->g.y=fit_y(rq_geom->y, h, &max_geom);
192 fp->g.y=fit_y(rq_geom->y, h, &max_geom);
195 (*szplcy)&=~(SIZEPOLICY_VERT_MASK|SIZEPOLICY_HORIZ_MASK);
197 *szplcy|=( (fullw || fp->g.x<=max_geom.x ? SIZEPOLICY_HORIZ_LEFT : 0)
198 |(fullw || fp->g.x+fp->g.w>=max_geom.x+max_geom.w ? SIZEPOLICY_HORIZ_RIGHT : 0)
199 |(fullh || fp->g.y<=max_geom.y ? SIZEPOLICY_VERT_TOP : 0)
200 |(fullh || fp->g.y+fp->g.h>=max_geom.y+max_geom.h ? SIZEPOLICY_VERT_BOTTOM : 0));
204 void sizepolicy(WSizePolicy *szplcy, WRegion *reg,
205 const WRectangle *rq_geom, int rq_flags,
208 uint extra=fp->mode®ION_FIT_ROTATE;
214 tmp=REGION_GEOM(reg);
218 if((*szplcy)&SIZEPOLICY_SHRUNK){
220 tmp.w=region_min_w(reg);
221 tmp.h=region_min_h(reg);
226 rq_flags&=~(REGION_RQGEOM_WEAK_W|REGION_RQGEOM_WEAK_H);
229 fp->mode=REGION_FIT_EXACT|extra;
231 switch((*szplcy)&SIZEPOLICY_MASK){
232 case SIZEPOLICY_GRAVITY:
233 gravity_stretch_policy(*szplcy, reg, &tmp, fp, FALSE, FALSE);
236 case SIZEPOLICY_STRETCH_LEFT:
237 gravity_stretch_policy(SIZEPOLICY_HORIZ_LEFT|SIZEPOLICY_VERT_CENTER,
238 reg, &tmp, fp, FALSE, TRUE);
241 case SIZEPOLICY_STRETCH_RIGHT:
242 gravity_stretch_policy(SIZEPOLICY_HORIZ_RIGHT|SIZEPOLICY_VERT_CENTER,
243 reg, &tmp, fp, FALSE, TRUE);
246 case SIZEPOLICY_STRETCH_TOP:
247 gravity_stretch_policy(SIZEPOLICY_VERT_TOP|SIZEPOLICY_HORIZ_CENTER,
248 reg, &tmp, fp, TRUE, FALSE);
251 case SIZEPOLICY_STRETCH_BOTTOM:
252 gravity_stretch_policy(SIZEPOLICY_VERT_BOTTOM|SIZEPOLICY_HORIZ_CENTER,
253 reg, &tmp, fp, TRUE, FALSE);
256 case SIZEPOLICY_FULL_EXACT:
257 gravity_stretch_policy(SIZEPOLICY_VERT_CENTER|SIZEPOLICY_HORIZ_CENTER,
258 reg, &tmp, fp, TRUE, TRUE);
261 case SIZEPOLICY_FREE:
262 rectangle_constrain(&tmp, &(fp->g));
264 region_size_hints_correct(reg, &tmp.w, &tmp.h, FALSE);
268 case SIZEPOLICY_UNCONSTRAINED:
270 region_size_hints_correct(reg, &tmp.w, &tmp.h, TRUE);
274 case SIZEPOLICY_FREE_GLUE:
275 sizepolicy_free_snap(szplcy, reg, &tmp, rq_flags, fp);
278 case SIZEPOLICY_FULL_BOUNDS:
280 fp->mode=REGION_FIT_BOUNDS|extra;
292 /* translation table for sizepolicy specifications */
293 static struct szplcy_spec szplcy_specs[] = {
294 {"default", SIZEPOLICY_DEFAULT},
295 {"full", SIZEPOLICY_FULL_EXACT},
296 {"full_bounds", SIZEPOLICY_FULL_BOUNDS},
297 {"free", SIZEPOLICY_FREE},
298 {"free_glue", SIZEPOLICY_FREE_GLUE},
299 {"northwest", SIZEPOLICY_GRAVITY_NORTHWEST},
300 {"north", SIZEPOLICY_GRAVITY_NORTH},
301 {"northeast", SIZEPOLICY_GRAVITY_NORTHEAST},
302 {"west", SIZEPOLICY_GRAVITY_WEST},
303 {"center", SIZEPOLICY_GRAVITY_CENTER},
304 {"east", SIZEPOLICY_GRAVITY_EAST},
305 {"southwest", SIZEPOLICY_GRAVITY_SOUTHWEST},
306 {"south", SIZEPOLICY_GRAVITY_SOUTH},
307 {"southeast", SIZEPOLICY_GRAVITY_SOUTHEAST},
308 {"stretch_top", SIZEPOLICY_STRETCH_TOP},
309 {"stretch_bottom", SIZEPOLICY_STRETCH_BOTTOM},
310 {"stretch_left", SIZEPOLICY_STRETCH_LEFT},
311 {"stretch_right", SIZEPOLICY_STRETCH_RIGHT},
312 {"free_glue_northwest", SIZEPOLICY_FREE_GLUE__NORTHWEST},
313 {"free_glue_north", SIZEPOLICY_FREE_GLUE__NORTH},
314 {"free_glue_northeast", SIZEPOLICY_FREE_GLUE__NORTHEAST},
315 {"free_glue_west", SIZEPOLICY_FREE_GLUE__WEST},
316 {"free_glue_center", SIZEPOLICY_FREE_GLUE__CENTER},
317 {"free_glue_east", SIZEPOLICY_FREE_GLUE__EAST},
318 {"free_glue_southwest", SIZEPOLICY_FREE_GLUE__SOUTHWEST},
319 {"free_glue_south", SIZEPOLICY_FREE_GLUE__SOUTH},
320 {"free_glue_southeast", SIZEPOLICY_FREE_GLUE__SOUTHEAST},
321 { NULL, SIZEPOLICY_DEFAULT} /* end marker */
325 bool string2sizepolicy(const char *szplcy, WSizePolicy *value)
327 const struct szplcy_spec *sp;
329 *value=SIZEPOLICY_DEFAULT;
331 for(sp=szplcy_specs; sp->spec; ++sp){
332 if(strcasecmp(szplcy,sp->spec)==0){