4 * Copyright (c) Tuomo Valkonen 2006-2009.
6 * See the included file LICENSE for details.
11 #include <libtu/objp.h>
19 WRegion *region_navi_first(WRegion *reg, WRegionNavi nh,
20 WRegionNaviData *data)
23 CALL_DYN_RET(ret, WRegion*, region_navi_first, reg,
29 WRegion *region_navi_next(WRegion *reg, WRegion *mgd, WRegionNavi nh,
30 WRegionNaviData *data)
33 CALL_DYN_RET(ret, WRegion*, region_navi_next, reg,
34 (reg, mgd, nh, data));
39 bool ioncore_string_to_navi(const char *str, WRegionNavi *nh)
42 warn(TR("Invalid parameter."));
46 if(!strcmp(str, "any")){
48 }else if (!strcmp(str, "end") ||
49 !strcmp(str, "last") ||
50 !strcmp(str, "next")){
52 }else if (!strcmp(str, "beg") ||
53 !strcmp(str, "first") ||
54 !strcmp(str, "prev")){
56 }else if(!strcmp(str, "left")){
58 }else if(!strcmp(str, "right")){
59 *nh=REGION_NAVI_RIGHT;
60 }else if(!strcmp(str, "top") ||
61 !strcmp(str, "above") ||
64 }else if(!strcmp(str, "bottom") ||
65 !strcmp(str, "below") ||
66 !strcmp(str, "down")){
67 *nh=REGION_NAVI_BOTTOM;
69 warn(TR("Invalid direction parameter."));
77 WRegionNavi ioncore_navi_reverse(WRegionNavi nh)
79 if(nh==REGION_NAVI_BEG)
80 return REGION_NAVI_END;
81 else if(nh==REGION_NAVI_END)
82 return REGION_NAVI_BEG;
83 else if(nh==REGION_NAVI_LEFT)
84 return REGION_NAVI_RIGHT;
85 else if(nh==REGION_NAVI_RIGHT)
86 return REGION_NAVI_LEFT;
87 else if(nh==REGION_NAVI_TOP)
88 return REGION_NAVI_BOTTOM;
89 else if(nh==REGION_NAVI_BOTTOM)
90 return REGION_NAVI_TOP;
92 return REGION_NAVI_ANY;
96 DECLSTRUCT(WRegionNaviData){
100 ExtlFn descend_filter;
109 static bool may_ascend(WRegion *to, WRegion *from, WRegionNaviData *data)
111 if(data->ascend_filter!=extl_fn_none()){
114 r=extl_call(data->ascend_filter, "oo", "b", to, from, &v);
115 extl_unprotect(NULL);
117 }else if(data->no_ascend!=NULL){
118 return (data->no_ascend!=(Obj*)from);
120 /* Set to TRUE for cycling out of nested workspaces etc. */
121 return !OBJ_IS(from, WMPlex);
126 static bool may_descend(WRegion *to, WRegion *from, WRegionNaviData *data)
128 if(data->descend_filter!=extl_fn_none()){
131 r=extl_call(data->descend_filter, "oo", "b", to, from, &v);
132 extl_unprotect(NULL);
134 }else if(data->no_descend!=NULL){
135 return (data->no_descend!=(Obj*)from);
137 /* Set to TRUE for cycling into nested workspaces etc. */
138 return !OBJ_IS(to, WMPlex);
143 static WRegion *region_navi_descend(WRegion *reg, WRegionNaviData *data)
146 return region_navi_first(reg, data->nh, data);
151 data->nh=ioncore_navi_reverse(data->nh);
153 nxt=region_navi_first(reg, data->nh, data);
156 data->nh=ioncore_navi_reverse(data->nh);
163 WRegion *region_navi_cont(WRegion *reg, WRegion *res, WRegionNaviData *data)
167 return (reg==data->startpoint ? NULL : reg);
169 WRegion *mgr=REGION_MANAGER(reg);
172 if(mgr!=NULL && may_ascend(mgr, reg, data)){
174 /* tail-recursive case */
175 return region_navi_next(mgr, reg, data->nh, data);
177 nxt=region_navi_next(mgr, reg, data->nh, data);
181 if(nxt==NULL && !data->nowrap){
183 nxt=region_navi_descend(reg, data);
189 if(may_descend(res, reg, data)){
190 return region_navi_descend(res, data);
198 static bool get_param(WRegionNaviData *data, const char *dirstr, ExtlTab param)
200 if(!ioncore_string_to_navi(dirstr, &data->nh))
203 data->ascend_filter=extl_fn_none();
204 data->descend_filter=extl_fn_none();
205 data->no_ascend=NULL;
206 data->no_descend=NULL;
208 extl_table_gets_o(param, "no_ascend", &data->no_ascend);
209 extl_table_gets_o(param, "no_descend", &data->no_descend);
210 extl_table_gets_f(param, "ascend_filter", &data->ascend_filter);
211 extl_table_gets_f(param, "descend_filter", &data->descend_filter);
212 data->nowrap=extl_table_is_bool_set(param, "nowrap");
213 data->nofront=extl_table_is_bool_set(param, "nofront");
219 static WRegion *release(WRegionNaviData *data, WRegion *res)
221 extl_unref_fn(data->ascend_filter);
222 extl_unref_fn(data->descend_filter);
229 * Find region next from \var{reg} in direction \var{dirstr}
230 * (\codestr{up}, \codestr{down}, \codestr{left}, \codestr{right},
231 * \codestr{next}, \codestr{prev}, or \codestr{any}). The table \var{param}
232 * may contain the boolean field \var{nowrap}, instructing not to wrap
233 * around, and the \type{WRegion}s \var{no_ascend} and \var{no_descend},
234 * and boolean functions \var{ascend_filter} and \var{descend_filter}
235 * on \var{WRegion} pairs (\var{to}, \var{from}), are used to decide when
236 * to descend or ascend into another region.
239 WRegion *ioncore_navi_next(WRegion *reg, const char *dirstr, ExtlTab param)
241 WRegionNaviData data;
249 if(!get_param(&data, dirstr, param))
252 mgr=REGION_MANAGER(reg);
260 return release(&data, region_navi_next(mgr, reg, data.nh, &data));
265 * Find first region within \var{reg} in direction \var{dirstr}.
266 * For information on \var{param}, see \fnref{ioncore.navi_next}.
269 WRegion *ioncore_navi_first(WRegion *reg, const char *dirstr, ExtlTab param)
271 WRegionNaviData data;
276 if(!get_param(&data, dirstr, param))
282 return release(&data, region_navi_first(reg, data.nh, &data));
286 static WRegion *do_goto(WRegion *res)
296 * Go to region next from \var{reg} in direction \var{dirstr}.
297 * For information on \var{param}, see \fnref{ioncore.navi_next}.
298 * Additionally this function supports the boolean \var{nofront}
299 * field, for not bringing the object to front.
302 WRegion *ioncore_goto_next(WRegion *reg, const char *dirstr, ExtlTab param)
304 return do_goto(ioncore_navi_next(reg, dirstr, param));
309 * Go to first region within \var{reg} in direction \var{dirstr}.
310 * For information on \var{param}, see \fnref{ioncore.navi_next}.
311 * Additionally this function supports the boolean \var{nofront} field,
312 * for not bringing the object to front.
315 WRegion *ioncore_goto_first(WRegion *reg, const char *dirstr, ExtlTab param)
317 return do_goto(ioncore_navi_first(reg, dirstr, param));