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
));