4 * Copyright (c) Tuomo Valkonen 2006.
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 return !OBJ_IS(from, WMPlex);
128 static bool may_descend(WRegion *to, WRegion *from, WRegionNaviData *data)
130 if(data->descend_filter!=extl_fn_none()){
133 r=extl_call(data->descend_filter, "oo", "b", to, from, &v);
134 extl_unprotect(NULL);
136 }else if(data->no_descend!=NULL){
137 return (data->no_descend!=(Obj*)from);
139 return !OBJ_IS(to, WMPlex);
144 static WRegion *region_navi_descend(WRegion *reg, WRegionNaviData *data)
147 return region_navi_first(reg, data->nh, data);
152 data->nh=ioncore_navi_reverse(data->nh);
154 nxt=region_navi_first(reg, data->nh, data);
157 data->nh=ioncore_navi_reverse(data->nh);
164 WRegion *region_navi_cont(WRegion *reg, WRegion *res, WRegionNaviData *data)
168 return (reg==data->startpoint ? NULL : reg);
170 WRegion *mgr=REGION_MANAGER(reg);
173 if(mgr!=NULL && may_ascend(mgr, reg, data)){
175 /* tail-recursive case */
176 return region_navi_next(mgr, reg, data->nh, data);
178 nxt=region_navi_next(mgr, reg, data->nh, data);
182 if(nxt==NULL && !data->nowrap){
184 nxt=region_navi_descend(reg, data);
190 if(may_descend(res, reg, data)){
191 return region_navi_descend(res, data);
199 static bool get_param(WRegionNaviData *data, const char *dirstr, ExtlTab param)
201 if(!ioncore_string_to_navi(dirstr, &data->nh))
204 data->ascend_filter=extl_fn_none();
205 data->descend_filter=extl_fn_none();
206 data->no_ascend=NULL;
207 data->no_descend=NULL;
209 extl_table_gets_o(param, "no_ascend", &data->no_ascend);
210 extl_table_gets_o(param, "no_descend", &data->no_descend);
211 extl_table_gets_f(param, "ascend_filter", &data->ascend_filter);
212 extl_table_gets_f(param, "descend_filter", &data->descend_filter);
213 data->nowrap=extl_table_is_bool_set(param, "nowrap");
214 data->nofront=extl_table_is_bool_set(param, "nofront");
220 static WRegion *release(WRegionNaviData *data, WRegion *res)
222 extl_unref_fn(data->ascend_filter);
223 extl_unref_fn(data->descend_filter);
230 * Find region next from \var{reg} in direction \var{dirstr}
231 * (up/down/left/right/next/prev/any). The table param may
232 * 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 functions \var{ascend_filter} and \var{descend_filter} from
235 * \var{WRegion}s (\var{to}, \var{from}), used to decide when to descend
236 * or ascend into another region. (TODO: more detailed explanation.)
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 * (up/down/left/right/beg/end/any). For information on \var{param},
267 * see \fnref{ioncore.navi_next}.
270 WRegion *ioncore_navi_first(WRegion *reg, const char *dirstr, ExtlTab param)
272 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)
292 /* TODO: deep rqorder? */
293 region_rqorder(res, REGION_ORDER_FRONT);
301 * Go to region next from \var{reg} in direction \var{dirstr}
302 * (up/down/left/right/next/prev/any). For information on \var{param},
303 * see \fnref{ioncore.navi_next}. Additionally this function supports
304 * the boolean \var{nofront} field, for not bringing the object to
308 WRegion *ioncore_goto_next(WRegion *reg, const char *dirstr, ExtlTab param)
310 return do_goto(ioncore_navi_next(reg, dirstr, param));
315 * Go to first region within \var{reg} in direction \var{dirstr}
316 * (up/down/left/right/beg/end/any). For information on \var{param},
317 * see \fnref{ioncore.navi_next}. Additionally this function supports
318 * the boolean \var{nofront} field, for not bringing the object to
322 WRegion *ioncore_goto_first(WRegion *reg, const char *dirstr, ExtlTab param)
324 return do_goto(ioncore_navi_first(reg, dirstr, param));