Remove unused mod_query parameters
[notion.git] / mod_query / wedln.c
blob3f10dc91be6aa04df2a65920931df49b33022a0c
1 /*
2 * ion/mod_query/wedln.c
4 * Copyright (c) Tuomo Valkonen 1999-2009.
6 * See the included file LICENSE for details.
7 */
9 #include <string.h>
11 #include <libtu/objp.h>
12 #include <libtu/minmax.h>
13 #include <libtu/setparam.h>
14 #include <libextl/extl.h>
15 #include <libmainloop/defer.h>
16 #include <libmainloop/signal.h>
18 #include <ioncore/common.h>
19 #include <ioncore/global.h>
20 #include <ioncore/strings.h>
21 #include <ioncore/xic.h>
22 #include <ioncore/selection.h>
23 #include <ioncore/event.h>
24 #include <ioncore/regbind.h>
25 #include <ioncore/gr-util.h>
26 #include <ioncore/sizehint.h>
27 #include <ioncore/resize.h>
28 #include "edln.h"
29 #include "wedln.h"
30 #include "inputp.h"
31 #include "complete.h"
32 #include "main.h"
35 #define WEDLN_BRUSH(X) ((X)->input.brush)
38 /*{{{ Drawing primitives */
41 static int calc_text_y(WEdln *wedln, const WRectangle *geom)
43 GrFontExtents fnte;
45 grbrush_get_font_extents(WEDLN_BRUSH(wedln), &fnte);
47 return geom->y+geom->h/2-fnte.max_height/2+fnte.baseline;
51 static int wedln_draw_strsect(WEdln *wedln, int x, int y, const char *str,
52 int len, GrAttr a)
54 if(len==0)
55 return 0;
57 grbrush_set_attr(WEDLN_BRUSH(wedln), a);
58 grbrush_draw_string(WEDLN_BRUSH(wedln), x, y, str, len, TRUE);
59 grbrush_unset_attr(WEDLN_BRUSH(wedln), a);
61 return grbrush_get_text_width(WEDLN_BRUSH(wedln), str, len);
64 #if 0
65 static void dispu(const char* s, int l)
67 while(l>0){
68 int c=(unsigned char)*s;
69 fprintf(stderr, "%d[%c]", c, *s);
70 s++;
71 l--;
73 fprintf(stderr, "\n");
75 #endif
77 #define DSTRSECT(LEN, A) \
78 if(LEN>0){ \
79 tx+=wedln_draw_strsect(wedln, geom->x+tx, ty, \
80 str, LEN, GR_ATTR(A)); \
81 str+=LEN; len-=LEN; \
85 GR_DEFATTR(active);
86 GR_DEFATTR(inactive);
87 GR_DEFATTR(normal);
88 GR_DEFATTR(selection);
89 GR_DEFATTR(cursor);
90 GR_DEFATTR(prompt);
91 GR_DEFATTR(info);
93 static void init_attr()
95 GR_ALLOCATTR_BEGIN;
96 GR_ALLOCATTR(active);
97 GR_ALLOCATTR(inactive);
98 GR_ALLOCATTR(normal);
99 GR_ALLOCATTR(selection);
100 GR_ALLOCATTR(cursor);
101 GR_ALLOCATTR(prompt);
102 GR_ALLOCATTR(info);
103 GR_ALLOCATTR_END;
107 static void wedln_do_draw_str_box(WEdln *wedln, const WRectangle *geom,
108 const char *str, int cursor,
109 int mark, int tx)
111 int len=strlen(str), ll=0, ty=0;
113 ty=calc_text_y(wedln, geom);
115 if(mark<=cursor){
116 if(mark>=0){
117 DSTRSECT(mark, normal);
118 DSTRSECT(cursor-mark, selection);
119 }else{
120 DSTRSECT(cursor, normal);
122 if(len==0){
123 tx+=wedln_draw_strsect(wedln, geom->x+tx, ty,
124 " ", 1, GR_ATTR(cursor));
125 }else{
126 ll=str_nextoff(str, 0);
127 DSTRSECT(ll, cursor);
129 }else{
130 DSTRSECT(cursor, normal);
131 ll=str_nextoff(str, 0);
132 DSTRSECT(ll, cursor);
133 DSTRSECT(mark-cursor-ll, selection);
135 DSTRSECT(len, normal);
137 if(tx<geom->w){
138 WRectangle g=*geom;
139 g.x+=tx;
140 g.w-=tx;
141 grbrush_clear_area(WEDLN_BRUSH(wedln), &g);
146 static void wedln_draw_str_box(WEdln *wedln, const WRectangle *geom,
147 int vstart, const char *str,
148 int dstart, int point, int mark)
150 int tx=0;
152 /* Some fonts and Xmb/utf8 routines don't work well with dstart!=0. */
153 dstart=0;
155 if(mark>=0){
156 mark-=vstart+dstart;
157 if(mark<0)
158 mark=0;
161 point-=vstart+dstart;
163 if(dstart!=0)
164 tx=grbrush_get_text_width(WEDLN_BRUSH(wedln), str+vstart, dstart);
166 grbrush_begin(WEDLN_BRUSH(wedln), geom,
167 GRBRUSH_AMEND|GRBRUSH_KEEP_ATTR|GRBRUSH_NEED_CLIP);
169 wedln_do_draw_str_box(wedln, geom, str+vstart+dstart, point, mark, tx);
171 grbrush_end(WEDLN_BRUSH(wedln));
175 static bool wedln_update_cursor(WEdln *wedln, int iw)
177 int cx, l;
178 int vstart=wedln->vstart;
179 int point=wedln->edln.point;
180 int len=wedln->edln.psize;
181 const char *str=wedln->edln.p;
182 bool ret;
184 if(point<wedln->vstart)
185 wedln->vstart=point;
187 if(wedln->vstart==point)
188 return FALSE;
190 while(vstart<point){
191 if(point==len){
192 cx=grbrush_get_text_width(WEDLN_BRUSH(wedln), str+vstart,
193 point-vstart);
194 cx+=grbrush_get_text_width(WEDLN_BRUSH(wedln), " ", 1);
195 }else{
196 int nxt=str_nextoff(str, point);
197 cx=grbrush_get_text_width(WEDLN_BRUSH(wedln), str+vstart,
198 point-vstart+nxt);
201 if(cx<iw)
202 break;
204 l=str_nextoff(str, vstart);
205 if(l==0)
206 break;
207 vstart+=l;
210 ret=(wedln->vstart!=vstart);
211 wedln->vstart=vstart;
213 return ret;
217 /*}}}*/
220 /*{{{ Size/location calc */
223 static int get_textarea_height(WEdln *wedln, bool with_spacing)
225 int w=1, h=1;
227 if(WEDLN_BRUSH(wedln)!=NULL)
228 mod_query_get_minimum_extents(WEDLN_BRUSH(wedln), with_spacing, &w, &h);
230 return h;
234 enum{G_NORESET, G_MAX, G_CURRENT};
237 static void get_geom(WEdln *wedln, int mode, WRectangle *geom)
239 if(mode==G_MAX)
240 *geom=wedln->input.last_fp.g;
241 else if(mode==G_CURRENT)
242 *geom=REGION_GEOM(wedln);
246 static void get_completions_geom(WEdln *wedln, int mode, WRectangle *geom)
248 get_geom(wedln, mode, geom);
249 geom->x=0;
250 geom->y=0;
252 geom->h-=get_textarea_height(wedln, TRUE);
253 if(geom->h<0)
254 geom->h=0;
258 static void get_outer_geom(WEdln *wedln, int mode, WRectangle *geom)
260 int th;
262 get_geom(wedln, mode, geom);
263 geom->x=0;
264 geom->y=0;
266 th=get_textarea_height(wedln, FALSE);
268 geom->y+=geom->h-th;
269 geom->h=th;
273 static void get_inner_geom(WEdln *wedln, int mode, WRectangle *geom)
275 GrBorderWidths bdw;
277 grbrush_get_border_widths(WEDLN_BRUSH(wedln), &bdw);
279 get_outer_geom(wedln, mode, geom);
281 geom->x+=bdw.left;
282 geom->w-=bdw.left+bdw.right;
283 geom->y+=bdw.top;
284 geom->h-=bdw.top+bdw.bottom;
285 geom->w=maxof(0, geom->w);
286 geom->h=maxof(0, geom->h);
290 static void get_textarea_geom(WEdln *wedln, int mode, WRectangle *geom)
292 get_inner_geom(wedln, mode, geom);
293 geom->x+=wedln->prompt_w;
294 geom->w=maxof(0, geom->w - wedln->prompt_w - wedln->info_w);
298 static void wedln_calc_size(WEdln *wedln, WRectangle *geom)
300 int h, th;
301 GrBorderWidths bdw;
302 WRectangle max_geom=*geom, tageom;
304 if(WEDLN_BRUSH(wedln)==NULL)
305 return;
307 if(wedln->prompt!=NULL){
308 wedln->prompt_w=grbrush_get_text_width(WEDLN_BRUSH(wedln),
309 wedln->prompt,
310 wedln->prompt_len);
313 if(wedln->info!=NULL){
314 wedln->info_w=grbrush_get_text_width(WEDLN_BRUSH(wedln),
315 wedln->info,
316 wedln->info_len);
319 th=get_textarea_height(wedln, wedln->compl_list.strs!=NULL);
321 if(wedln->compl_list.strs==NULL){
322 if(max_geom.h<th || !(wedln->input.last_fp.mode&REGION_FIT_BOUNDS))
323 geom->h=max_geom.h;
324 else
325 geom->h=th;
326 }else{
327 WRectangle g;
329 get_completions_geom(wedln, G_MAX, &g);
331 fit_listing(WEDLN_BRUSH(wedln), &g, &(wedln->compl_list));
333 grbrush_get_border_widths(WEDLN_BRUSH(wedln), &bdw);
335 h=wedln->compl_list.toth;
336 th+=bdw.top+bdw.bottom;
338 if(h+th>max_geom.h || !(wedln->input.last_fp.mode&REGION_FIT_BOUNDS))
339 h=max_geom.h-th;
340 geom->h=h+th;
343 geom->w=max_geom.w;
344 geom->y=max_geom.y+max_geom.h-geom->h;
345 geom->x=max_geom.x;
347 tageom=*geom;
348 get_textarea_geom(wedln, G_NORESET, &tageom);
349 wedln_update_cursor(wedln, tageom.w);
353 void wedln_size_hints(WEdln *wedln, WSizeHints *hints_ret)
355 int w=1, h=1;
357 if(WEDLN_BRUSH(wedln)!=NULL){
358 mod_query_get_minimum_extents(WEDLN_BRUSH(wedln), FALSE, &w, &h);
359 w+=wedln->prompt_w+wedln->info_w;
360 w+=grbrush_get_text_width(WEDLN_BRUSH(wedln), "xxxxxxxxxx", 10);
363 hints_ret->min_set=TRUE;
364 hints_ret->min_width=w;
365 hints_ret->min_height=h;
369 /*}}}*/
372 /*{{{ Draw */
375 void wedln_draw_completions(WEdln *wedln, int mode)
377 WRectangle geom;
379 if(wedln->compl_list.strs!=NULL && WEDLN_BRUSH(wedln)!=NULL){
380 get_completions_geom(wedln, G_CURRENT, &geom);
382 draw_listing(WEDLN_BRUSH(wedln), &geom, &(wedln->compl_list),
383 mode, GR_ATTR(selection));
388 void wedln_draw_textarea(WEdln *wedln)
390 WRectangle geom;
391 int ty;
393 if(WEDLN_BRUSH(wedln)==NULL)
394 return;
396 get_outer_geom(wedln, G_CURRENT, &geom);
398 /*grbrush_begin(WEDLN_BRUSH(wedln), &geom, GRBRUSH_AMEND);*/
400 grbrush_draw_border(WEDLN_BRUSH(wedln), &geom);
402 get_inner_geom(wedln, G_CURRENT, &geom);
404 ty=calc_text_y(wedln, &geom);
406 grbrush_set_attr(WEDLN_BRUSH(wedln), GR_ATTR(prompt));
408 if(wedln->prompt!=NULL){
409 grbrush_draw_string(WEDLN_BRUSH(wedln), geom.x, ty,
410 wedln->prompt, wedln->prompt_len, TRUE);
413 if(wedln->info!=NULL){
414 int x=geom.x+geom.w-wedln->info_w;
416 grbrush_set_attr(WEDLN_BRUSH(wedln), GR_ATTR(info));
417 grbrush_draw_string(WEDLN_BRUSH(wedln), x, ty,
418 wedln->info, wedln->info_len, TRUE);
419 grbrush_unset_attr(WEDLN_BRUSH(wedln), GR_ATTR(info));
422 grbrush_unset_attr(WEDLN_BRUSH(wedln), GR_ATTR(prompt));
424 get_textarea_geom(wedln, G_CURRENT, &geom);
426 wedln_draw_str_box(wedln, &geom, wedln->vstart, wedln->edln.p, 0,
427 wedln->edln.point, wedln->edln.mark);
429 /*grbrush_end(WEDLN_BRUSH(wedln));*/
433 static void wedln_draw_(WEdln *wedln, bool complete, bool completions)
435 WRectangle g;
436 int f=(complete ? 0 : GRBRUSH_NO_CLEAR_OK);
438 if(WEDLN_BRUSH(wedln)==NULL)
439 return;
441 get_geom(wedln, G_CURRENT, &g);
443 grbrush_begin(WEDLN_BRUSH(wedln), &g, f);
445 grbrush_set_attr(WEDLN_BRUSH(wedln), REGION_IS_ACTIVE(wedln)
446 ? GR_ATTR(active)
447 : GR_ATTR(inactive));
449 if(completions)
450 wedln_draw_completions(wedln, LISTING_DRAW_ALL);
452 wedln_draw_textarea(wedln);
454 grbrush_end(WEDLN_BRUSH(wedln));
458 void wedln_draw(WEdln *wedln, bool complete)
460 wedln_draw_(wedln, complete, TRUE);
463 /*}}} */
466 /*{{{ Info area */
469 static void wedln_set_info(WEdln *wedln, const char *info)
471 WRectangle tageom;
473 if(wedln->info!=NULL){
474 free(wedln->info);
475 wedln->info=NULL;
476 wedln->info_w=0;
477 wedln->info_len=0;
480 if(info!=NULL){
481 wedln->info=scat3(" [", info, "]");
482 if(wedln->info!=NULL){
483 wedln->info_len=strlen(wedln->info);
484 if(WEDLN_BRUSH(wedln)!=NULL){
485 wedln->info_w=grbrush_get_text_width(WEDLN_BRUSH(wedln),
486 wedln->info,
487 wedln->info_len);
492 get_textarea_geom(wedln, G_CURRENT, &tageom);
493 wedln_update_cursor(wedln, tageom.w);
495 wedln_draw_(wedln, FALSE, FALSE);
499 /*}}}*/
502 /*{{{ Completions */
505 static void wedln_show_completions(WEdln *wedln, char **strs, int nstrs,
506 int selected)
508 int w=REGION_GEOM(wedln).w;
509 int h=REGION_GEOM(wedln).h;
511 if(WEDLN_BRUSH(wedln)==NULL)
512 return;
514 setup_listing(&(wedln->compl_list), strs, nstrs, FALSE);
515 wedln->compl_list.selected_str=selected;
517 input_refit((WInput*)wedln);
518 if(w==REGION_GEOM(wedln).w && h==REGION_GEOM(wedln).h)
519 wedln_draw_completions(wedln, LISTING_DRAW_COMPLETE);
523 void wedln_hide_completions(WEdln *wedln)
525 if(wedln->compl_list.strs!=NULL){
526 deinit_listing(&(wedln->compl_list));
527 input_refit((WInput*)wedln);
532 void wedln_scrollup_completions(WEdln *wedln)
534 if(wedln->compl_list.strs==NULL)
535 return;
536 if(scrollup_listing(&(wedln->compl_list)))
537 wedln_draw_completions(wedln, LISTING_DRAW_COMPLETE);
541 void wedln_scrolldown_completions(WEdln *wedln)
543 if(wedln->compl_list.strs==NULL)
544 return;
545 if(scrolldown_listing(&(wedln->compl_list)))
546 wedln_draw_completions(wedln, LISTING_DRAW_COMPLETE);
550 static int update_nocompl=0;
553 static void free_completions(char **ptr, int i)
555 while(i>0){
556 i--;
557 if(ptr[i]!=NULL)
558 free(ptr[i]);
560 free(ptr);
564 bool wedln_do_set_completions(WEdln *wedln, char **ptr, int n,
565 char *beg, char *end, int cycle,
566 bool nosort)
568 int sel=-1;
570 if(wedln->compl_beg!=NULL)
571 free(wedln->compl_beg);
573 if(wedln->compl_end!=NULL)
574 free(wedln->compl_end);
576 wedln->compl_beg=beg;
577 wedln->compl_end=end;
578 wedln->compl_current_id=-1;
580 n=edln_do_completions(&(wedln->edln), ptr, n, beg, end,
581 !mod_query_config.autoshowcompl, nosort);
583 if(mod_query_config.autoshowcompl && n>0 && cycle!=0){
584 update_nocompl++;
585 sel=(cycle>0 ? 0 : n-1);
586 edln_set_completion(&(wedln->edln), ptr[sel], beg, end);
587 update_nocompl--;
590 if(n>1 || (mod_query_config.autoshowcompl && n>0)){
591 wedln_show_completions(wedln, ptr, n, sel);
592 return TRUE;
595 free_completions(ptr, n);
597 return FALSE;
601 void wedln_set_completions(WEdln *wedln, ExtlTab completions, int cycle)
603 int n=0, i=0;
604 char **ptr=NULL, *beg=NULL, *end=NULL, *p=NULL;
606 n=extl_table_get_n(completions);
608 if(n==0){
609 wedln_hide_completions(wedln);
610 return;
613 ptr=ALLOC_N(char*, n);
614 if(ptr==NULL)
615 goto allocfail;
617 for(i=0; i<n; i++){
618 if(!extl_table_geti_s(completions, i+1, &p)){
619 goto allocfail;
621 ptr[i]=p;
624 extl_table_gets_s(completions, "common_beg", &beg);
625 extl_table_gets_s(completions, "common_end", &end);
627 if(!wedln_do_set_completions(wedln, ptr, n, beg, end, cycle, FALSE))
628 wedln_hide_completions(wedln);
630 return;
632 allocfail:
633 wedln_hide_completions(wedln);
634 free_completions(ptr, i);
638 static void wedln_do_select_completion(WEdln *wedln, int n)
640 bool redraw=listing_select(&(wedln->compl_list), n);
641 wedln_draw_completions(wedln, redraw);
643 update_nocompl++;
644 edln_set_completion(&(wedln->edln), wedln->compl_list.strs[n],
645 wedln->compl_beg, wedln->compl_end);
646 update_nocompl--;
651 static ExtlExportedFn *sc_safe_fns[]={
652 (ExtlExportedFn*)&complproxy_set_completions,
653 NULL
657 static ExtlSafelist sc_safelist=EXTL_SAFELIST_INIT(sc_safe_fns);
660 static int wedln_alloc_compl_id(WEdln *wedln)
662 int id=wedln->compl_waiting_id+1;
663 wedln->compl_waiting_id=maxof(0, wedln->compl_waiting_id+1);
664 return id;
667 static bool wedln_do_call_completor(WEdln *wedln, int id, int cycle)
669 if(wedln->compl_history_mode){
670 uint n;
671 char **h=NULL;
673 wedln->compl_waiting_id=id;
675 n=edln_history_matches(&wedln->edln, &h);
677 if(n==0){
678 wedln_hide_completions(wedln);
679 return FALSE;
682 if(wedln_do_set_completions(wedln, h, n, NULL, NULL, cycle, TRUE)){
683 wedln->compl_current_id=id;
684 return TRUE;
687 return FALSE;
688 }else{
689 const char *p=wedln->edln.p;
690 int point=wedln->edln.point;
691 WComplProxy *proxy=create_complproxy(wedln, id, cycle);
693 if(proxy==NULL)
694 return FALSE;
696 /* Set Lua-side to own the proxy: it gets freed by Lua's GC */
697 ((Obj*)proxy)->flags|=OBJ_EXTL_OWNED;
699 if(p==NULL){
700 p="";
701 point=0;
704 extl_protect(&sc_safelist);
705 extl_call(wedln->completor, "osi", NULL, proxy, p, point);
706 extl_unprotect(&sc_safelist);
708 return TRUE;
713 static void timed_complete(WTimer *UNUSED(tmr), Obj *obj)
715 WEdln *wedln=(WEdln*)obj;
717 if(wedln!=NULL){
718 int id=wedln->compl_timed_id;
719 wedln->compl_timed_id=-1;
720 if(id==wedln->compl_waiting_id && id>=0)
721 wedln_do_call_completor((WEdln*)obj, id, FALSE);
726 /*EXTL_DOC
727 * Select next completion.
729 EXTL_EXPORT_MEMBER
730 bool wedln_next_completion(WEdln *wedln)
732 int n=-1;
734 if(wedln->compl_current_id!=wedln->compl_waiting_id)
735 return FALSE;
737 if(wedln->compl_list.nstrs<=0)
738 return FALSE;
740 if(wedln->compl_list.selected_str<0 ||
741 wedln->compl_list.selected_str+1>=wedln->compl_list.nstrs){
742 n=0;
743 }else{
744 n=wedln->compl_list.selected_str+1;
747 if(n!=wedln->compl_list.selected_str)
748 wedln_do_select_completion(wedln, n);
750 return TRUE;
754 /*EXTL_DOC
755 * Select previous completion.
757 EXTL_EXPORT_MEMBER
758 bool wedln_prev_completion(WEdln *wedln)
760 int n=-1;
762 if(wedln->compl_current_id!=wedln->compl_waiting_id)
763 return FALSE;
765 if(wedln->compl_list.nstrs<=0)
766 return FALSE;
768 if(wedln->compl_list.selected_str<=0){
769 n=wedln->compl_list.nstrs-1;
770 }else{
771 n=wedln->compl_list.selected_str-1;
774 if(n!=wedln->compl_list.selected_str)
775 wedln_do_select_completion(wedln, n);
777 return TRUE;
781 /*EXTL_DOC
782 * Call completion handler with the text between the beginning of line and
783 * current cursor position, or select next/previous completion from list if in
784 * auto-show-completions mode and \var{cycle} is set to \codestr{next} or
785 * \codestr{prev}, respectively.
786 * The \var{mode} may be \codestr{history} or \codestr{normal}. If it is
787 * not set, the previous mode is used. Normally next entry is not cycled to
788 * despite the setting of \var{cycle} if mode switch occurs. To override
789 * this, use \codestr{next-always} and \codestr{prev-always} for \var{cycle}.
791 EXTL_EXPORT_MEMBER
792 void wedln_complete(WEdln *wedln, const char *cycle, const char *mode)
794 bool valid=TRUE;
795 int cyclei=0;
797 if(mode!=NULL){
798 if(strcmp(mode, "history")==0){
799 valid=wedln->compl_history_mode;
800 wedln->compl_history_mode=TRUE;
801 }else if(strcmp(mode, "normal")==0){
802 valid=!wedln->compl_history_mode;
803 wedln->compl_history_mode=FALSE;
805 if(!valid){
806 wedln_set_info(wedln,
807 (wedln->compl_history_mode
808 ? TR("history")
809 : NULL));
813 if(cycle!=NULL){
814 if((valid && strcmp(cycle, "next")==0) ||
815 strcmp(cycle, "next-always")==0){
816 cyclei=1;
817 }else if((valid && strcmp(cycle, "prev")==0) ||
818 strcmp(cycle, "prev-always")==0){
819 cyclei=-1;
823 if(valid && cyclei!=0 && mod_query_config.autoshowcompl &&
824 wedln->compl_list.nstrs>0){
825 if(cyclei>0)
826 wedln_next_completion(wedln);
827 else
828 wedln_prev_completion(wedln);
829 }else{
830 int oldid=wedln->compl_waiting_id;
832 if(!wedln_do_call_completor(wedln, wedln_alloc_compl_id(wedln),
833 cyclei)){
834 wedln->compl_waiting_id=oldid;
840 /*EXTL_DOC
841 * Get history completion mode.
843 EXTL_EXPORT_MEMBER
844 bool wedln_is_histcompl(WEdln *wedln)
846 return wedln->compl_history_mode;
850 /*}}}*/
853 /*{{{ Update handler */
856 static void wedln_update_handler(WEdln *wedln, int from, int flags)
858 WRectangle geom;
860 if(WEDLN_BRUSH(wedln)==NULL)
861 return;
863 get_textarea_geom(wedln, G_CURRENT, &geom);
865 if(flags&EDLN_UPDATE_NEW)
866 wedln->vstart=0;
868 if(flags&EDLN_UPDATE_MOVED){
869 if(wedln_update_cursor(wedln, geom.w))
870 from=wedln->vstart;
873 from=maxof(0, from-wedln->vstart);
875 wedln_draw_str_box(wedln, &geom, wedln->vstart, wedln->edln.p, from,
876 wedln->edln.point, wedln->edln.mark);
878 if(update_nocompl==0 &&
879 mod_query_config.autoshowcompl &&
880 flags&EDLN_UPDATE_CHANGED){
881 wedln->compl_current_id=-1; /* invalidate */
882 if(wedln->autoshowcompl_timer==NULL)
883 wedln->autoshowcompl_timer=create_timer();
884 if(wedln->autoshowcompl_timer!=NULL){
885 wedln->compl_timed_id=wedln_alloc_compl_id(wedln);
886 timer_set(wedln->autoshowcompl_timer,
887 mod_query_config.autoshowcompl_delay,
888 timed_complete, (Obj*)wedln);
894 /*}}}*/
897 /*{{{ Init, deinit and config update */
900 static bool wedln_init_prompt(WEdln *wedln, const char *prompt)
902 char *p;
904 if(prompt!=NULL){
905 p=scat(prompt, " ");
907 if(p==NULL)
908 return FALSE;
910 wedln->prompt=p;
911 wedln->prompt_len=strlen(p);
912 }else{
913 wedln->prompt=NULL;
914 wedln->prompt_len=0;
916 wedln->prompt_w=0;
918 return TRUE;
922 static bool wedln_init(WEdln *wedln, WWindow *par, const WFitParams *fp,
923 WEdlnCreateParams *params)
925 wedln->vstart=0;
927 init_attr();
929 if(!wedln_init_prompt(wedln, params->prompt))
930 return FALSE;
932 if(!edln_init(&(wedln->edln), params->dflt)){
933 free(wedln->prompt);
934 return FALSE;
937 wedln->handler=extl_fn_none();
938 wedln->completor=extl_fn_none();
940 wedln->edln.uiptr=wedln;
941 wedln->edln.ui_update=(EdlnUpdateHandler*)wedln_update_handler;
943 wedln->autoshowcompl_timer=NULL;
945 init_listing(&(wedln->compl_list));
947 wedln->compl_waiting_id=-1;
948 wedln->compl_current_id=-1;
949 wedln->compl_timed_id=-1;
950 wedln->compl_beg=NULL;
951 wedln->compl_end=NULL;
952 wedln->compl_tab=FALSE;
953 wedln->compl_history_mode=FALSE;
955 wedln->info=NULL;
956 wedln->info_len=0;
957 wedln->info_w=0;
959 wedln->cycle_bindmap=NULL;
961 if(!input_init((WInput*)wedln, par, fp)){
962 edln_deinit(&(wedln->edln));
963 free(wedln->prompt);
964 return FALSE;
967 window_create_xic(&wedln->input.win);
969 wedln->handler=extl_ref_fn(params->handler);
970 wedln->completor=extl_ref_fn(params->completor);
972 region_add_bindmap((WRegion*)wedln, mod_query_wedln_bindmap);
974 return TRUE;
978 WEdln *create_wedln(WWindow *par, const WFitParams *fp,
979 WEdlnCreateParams *params)
981 CREATEOBJ_IMPL(WEdln, wedln, (p, par, fp, params));
985 static void wedln_deinit(WEdln *wedln)
987 if(wedln->prompt!=NULL)
988 free(wedln->prompt);
990 if(wedln->info!=NULL)
991 free(wedln->info);
993 if(wedln->compl_beg!=NULL)
994 free(wedln->compl_beg);
996 if(wedln->compl_end!=NULL)
997 free(wedln->compl_end);
999 if(wedln->compl_list.strs!=NULL)
1000 deinit_listing(&(wedln->compl_list));
1002 if(wedln->autoshowcompl_timer!=NULL)
1003 destroy_obj((Obj*)wedln->autoshowcompl_timer);
1005 if(wedln->cycle_bindmap!=NULL)
1006 bindmap_destroy(wedln->cycle_bindmap);
1008 extl_unref_fn(wedln->completor);
1009 extl_unref_fn(wedln->handler);
1011 edln_deinit(&(wedln->edln));
1012 input_deinit((WInput*)wedln);
1016 static void wedln_do_finish(WEdln *wedln)
1018 ExtlFn handler;
1019 char *p;
1021 handler=wedln->handler;
1022 wedln->handler=extl_fn_none();
1023 p=edln_finish(&(wedln->edln));
1025 region_rqdispose((WRegion*)wedln);
1027 if(p!=NULL)
1028 extl_call(handler, "s", NULL, p);
1030 free(p);
1031 extl_unref_fn(handler);
1035 /*EXTL_DOC
1036 * Close \var{wedln} and call any handlers.
1038 EXTL_EXPORT_MEMBER
1039 void wedln_finish(WEdln *wedln)
1041 mainloop_defer_action((Obj*)wedln, (WDeferredAction*)wedln_do_finish);
1045 /*}}}*/
1048 /*{{{ The rest */
1051 /*EXTL_DOC
1052 * Request selection from application holding such.
1054 * Note that this function is asynchronous; the selection will not
1055 * actually be inserted before Ion receives it. This will be no
1056 * earlier than Ion return to its main loop.
1058 EXTL_EXPORT_MEMBER
1059 void wedln_paste(WEdln *wedln)
1061 ioncore_request_selection_for(wedln->input.win.win);
1065 void wedln_insstr(WEdln *wedln, const char *buf, size_t n)
1067 edln_insstr_n(&(wedln->edln), buf, n, TRUE, TRUE);
1071 static const char *wedln_style(WEdln *UNUSED(wedln))
1073 return "input-edln";
1077 /*}}}*/
1080 /*{{{ Dynamic function table and class implementation */
1083 static DynFunTab wedln_dynfuntab[]={
1084 {window_draw, wedln_draw},
1085 {input_calc_size, wedln_calc_size},
1086 {input_scrollup, wedln_scrollup_completions},
1087 {input_scrolldown, wedln_scrolldown_completions},
1088 {window_insstr, wedln_insstr},
1089 {(DynFun*)input_style, (DynFun*)wedln_style},
1090 {region_size_hints, wedln_size_hints},
1091 END_DYNFUNTAB
1095 EXTL_EXPORT
1096 IMPLCLASS(WEdln, WInput, wedln_deinit, wedln_dynfuntab);
1099 /*}}}*/