4 * Copyright (c) Tuomo Valkonen 2006-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.
14 #include <libtu/objp.h>
22 WRegion *region_navi_first(WRegion *reg, WRegionNavi nh,
23 WRegionNaviData *data)
26 CALL_DYN_RET(ret, WRegion*, region_navi_first, reg,
32 WRegion *region_navi_next(WRegion *reg, WRegion *mgd, WRegionNavi nh,
33 WRegionNaviData *data)
36 CALL_DYN_RET(ret, WRegion*, region_navi_next, reg,
37 (reg, mgd, nh, data));
42 bool ioncore_string_to_navi(const char *str, WRegionNavi *nh)
45 warn(TR("Invalid parameter."));
49 if(!strcmp(str, "any")){
51 }else if (!strcmp(str, "end") ||
52 !strcmp(str, "last") ||
53 !strcmp(str, "next")){
55 }else if (!strcmp(str, "beg") ||
56 !strcmp(str, "first") ||
57 !strcmp(str, "prev")){
59 }else if(!strcmp(str, "left")){
61 }else if(!strcmp(str, "right")){
62 *nh=REGION_NAVI_RIGHT;
63 }else if(!strcmp(str, "top") ||
64 !strcmp(str, "above") ||
67 }else if(!strcmp(str, "bottom") ||
68 !strcmp(str, "below") ||
69 !strcmp(str, "down")){
70 *nh=REGION_NAVI_BOTTOM;
72 warn(TR("Invalid direction parameter."));
80 WRegionNavi ioncore_navi_reverse(WRegionNavi nh)
82 if(nh==REGION_NAVI_BEG)
83 return REGION_NAVI_END;
84 else if(nh==REGION_NAVI_END)
85 return REGION_NAVI_BEG;
86 else if(nh==REGION_NAVI_LEFT)
87 return REGION_NAVI_RIGHT;
88 else if(nh==REGION_NAVI_RIGHT)
89 return REGION_NAVI_LEFT;
90 else if(nh==REGION_NAVI_TOP)
91 return REGION_NAVI_BOTTOM;
92 else if(nh==REGION_NAVI_BOTTOM)
93 return REGION_NAVI_TOP;
95 return REGION_NAVI_ANY;
99 DECLSTRUCT(WRegionNaviData){
102 ExtlFn ascend_filter;
103 ExtlFn descend_filter;
112 static bool may_ascend(WRegion *to, WRegion *from, WRegionNaviData *data)
114 if(data->ascend_filter!=extl_fn_none()){
117 r=extl_call(data->ascend_filter, "oo", "b", to, from, &v);
118 extl_unprotect(NULL);
120 }else if(data->no_ascend!=NULL){
121 return (data->no_ascend!=(Obj*)from);
123 /* Set to TRUE for cycling out of nested workspaces etc. */
124 return !OBJ_IS(from, WMPlex);
129 static bool may_descend(WRegion *to, WRegion *from, WRegionNaviData *data)
131 if(data->descend_filter!=extl_fn_none()){
134 r=extl_call(data->descend_filter, "oo", "b", to, from, &v);
135 extl_unprotect(NULL);
137 }else if(data->no_descend!=NULL){
138 return (data->no_descend!=(Obj*)from);
140 /* Set to TRUE for cycling into nested workspaces etc. */
141 return !OBJ_IS(to, WMPlex);
146 static WRegion *region_navi_descend(WRegion *reg, WRegionNaviData *data)
149 return region_navi_first(reg, data->nh, data);
154 data->nh=ioncore_navi_reverse(data->nh);
156 nxt=region_navi_first(reg, data->nh, data);
159 data->nh=ioncore_navi_reverse(data->nh);
166 WRegion *region_navi_cont(WRegion *reg, WRegion *res, WRegionNaviData *data)
170 return (reg==data->startpoint ? NULL : reg);
172 WRegion *mgr=REGION_MANAGER(reg);
175 if(mgr!=NULL && may_ascend(mgr, reg, data)){
177 /* tail-recursive case */
178 return region_navi_next(mgr, reg, data->nh, data);
180 nxt=region_navi_next(mgr, reg, data->nh, data);
184 if(nxt==NULL && !data->nowrap){
186 nxt=region_navi_descend(reg, data);
192 if(may_descend(res, reg, data)){
193 return region_navi_descend(res, data);
201 static bool get_param(WRegionNaviData *data, const char *dirstr, ExtlTab param)
203 if(!ioncore_string_to_navi(dirstr, &data->nh))
206 data->ascend_filter=extl_fn_none();
207 data->descend_filter=extl_fn_none();
208 data->no_ascend=NULL;
209 data->no_descend=NULL;
211 extl_table_gets_o(param, "no_ascend", &data->no_ascend);
212 extl_table_gets_o(param, "no_descend", &data->no_descend);
213 extl_table_gets_f(param, "ascend_filter", &data->ascend_filter);
214 extl_table_gets_f(param, "descend_filter", &data->descend_filter);
215 data->nowrap=extl_table_is_bool_set(param, "nowrap");
216 data->nofront=extl_table_is_bool_set(param, "nofront");
222 static WRegion *release(WRegionNaviData *data, WRegion *res)
224 extl_unref_fn(data->ascend_filter);
225 extl_unref_fn(data->descend_filter);
232 * Find region next from \var{reg} in direction \var{dirstr}
233 * (up/down/left/right/next/prev/any). The table \var{param} may
234 * contain the boolean field \var{nowrap}, instructing not to wrap
235 * around, and the \type{WRegion}s \var{no_ascend} and \var{no_descend},
236 * and boolean functions \var{ascend_filter} and \var{descend_filter}
237 * on \var{WRegion} pairs (\var{to}, \var{from}), are used to decide when
238 * to descend or ascend into another region.
241 WRegion *ioncore_navi_next(WRegion *reg, const char *dirstr, ExtlTab param)
243 WRegionNaviData data;
251 if(!get_param(&data, dirstr, param))
254 mgr=REGION_MANAGER(reg);
262 return release(&data, region_navi_next(mgr, reg, data.nh, &data));
267 * Find first region within \var{reg} in direction \var{dirstr}
268 * (up/down/left/right/beg/end/any). For information on \var{param},
269 * see \fnref{ioncore.navi_next}.
272 WRegion *ioncore_navi_first(WRegion *reg, const char *dirstr, ExtlTab param)
274 WRegionNaviData data;
279 if(!get_param(&data, dirstr, param))
285 return release(&data, region_navi_first(reg, data.nh, &data));
289 static WRegion *do_goto(WRegion *res)
299 * Go to region next from \var{reg} in direction \var{dirstr}
300 * (up/down/left/right/next/prev/any). For information on \var{param},
301 * see \fnref{ioncore.navi_next}. Additionally this function supports
302 * the boolean \var{nofront} field, for not bringing the object to
306 WRegion *ioncore_goto_next(WRegion *reg, const char *dirstr, ExtlTab param)
308 return do_goto(ioncore_navi_next(reg, dirstr, param));
313 * Go to first region within \var{reg} in direction \var{dirstr}
314 * (up/down/left/right/beg/end/any). For information on \var{param},
315 * see \fnref{ioncore.navi_next}. Additionally this function supports
316 * the boolean \var{nofront} field, for not bringing the object to
320 WRegion *ioncore_goto_first(WRegion *reg, const char *dirstr, ExtlTab param)
322 return do_goto(ioncore_navi_first(reg, dirstr, param));