/*
* ion/mod_query/wedln.c
*
- * Copyright (c) Tuomo Valkonen 1999-2006.
+ * Copyright (c) Tuomo Valkonen 1999-2007.
*
- * Ion is free software; you can redistribute it and/or modify it under
- * the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
+ * See the included file LICENSE for details.
*/
#include <string.h>
#include <ioncore/selection.h>
#include <ioncore/event.h>
#include <ioncore/regbind.h>
+#include <ioncore/gr-util.h>
+#include <ioncore/sizehint.h>
+#include <ioncore/resize.h>
#include "edln.h"
#include "wedln.h"
#include "inputp.h"
static int wedln_draw_strsect(WEdln *wedln, const WRectangle *geom,
int x, int y, const char *str, int len,
- const char *attr)
+ GrAttr a)
{
if(len==0)
return 0;
- grbrush_draw_string(WEDLN_BRUSH(wedln), x, y, str, len, TRUE, attr);
+ grbrush_set_attr(WEDLN_BRUSH(wedln), a);
+ grbrush_draw_string(WEDLN_BRUSH(wedln), x, y, str, len, TRUE);
+ grbrush_unset_attr(WEDLN_BRUSH(wedln), a);
return grbrush_get_text_width(WEDLN_BRUSH(wedln), str, len);
}
}
#endif
-#define DSTRSECT(LEN, INV) \
- if(LEN>0){tx+=wedln_draw_strsect(wedln, geom, geom->x+tx, ty, str, LEN, INV); \
- str+=LEN; len-=LEN;}
+#define DSTRSECT(LEN, A) \
+ if(LEN>0){ \
+ tx+=wedln_draw_strsect(wedln, geom, geom->x+tx, ty, \
+ str, LEN, GR_ATTR(A)); \
+ str+=LEN; len-=LEN; \
+ }
+
+
+GR_DEFATTR(active);
+GR_DEFATTR(inactive);
+GR_DEFATTR(normal);
+GR_DEFATTR(selection);
+GR_DEFATTR(cursor);
+GR_DEFATTR(prompt);
+GR_DEFATTR(info);
+
+static void init_attr()
+{
+ GR_ALLOCATTR_BEGIN;
+ GR_ALLOCATTR(active);
+ GR_ALLOCATTR(inactive);
+ GR_ALLOCATTR(normal);
+ GR_ALLOCATTR(selection);
+ GR_ALLOCATTR(cursor);
+ GR_ALLOCATTR(prompt);
+ GR_ALLOCATTR(info);
+ GR_ALLOCATTR_END;
+}
static void wedln_do_draw_str_box(WEdln *wedln, const WRectangle *geom,
int mark, int tx)
{
int len=strlen(str), ll=0, ty=0;
- const char *normalstyle=(REGION_IS_ACTIVE(wedln)
- ? "active-normal" : "inactive-normal");
- const char *selectionstyle=(REGION_IS_ACTIVE(wedln)
- ? "active-selection" : "inactive-selection");
- const char *cursorstyle=(REGION_IS_ACTIVE(wedln)
- ? "active-cursor" : "inactive-cursor");
-
- /*if(tx<geom->w){
- WRectangle g=*geom;
- g.x+=tx;
- g.w-=tx;
- grbrush_clear_area(WEDLN_BRUSH(wedln), &g);
- }*/
ty=calc_text_y(wedln, geom);
if(mark<=cursor){
if(mark>=0){
- DSTRSECT(mark, normalstyle);
- DSTRSECT(cursor-mark, selectionstyle);
+ DSTRSECT(mark, normal);
+ DSTRSECT(cursor-mark, selection);
}else{
- DSTRSECT(cursor, normalstyle);
+ DSTRSECT(cursor, normal);
}
if(len==0){
tx+=wedln_draw_strsect(wedln, geom, geom->x+tx, ty,
- " ", 1, cursorstyle);
+ " ", 1, GR_ATTR(cursor));
}else{
ll=str_nextoff(str, 0);
- DSTRSECT(ll, cursorstyle);
+ DSTRSECT(ll, cursor);
}
}else{
- DSTRSECT(cursor, normalstyle);
+ DSTRSECT(cursor, normal);
ll=str_nextoff(str, 0);
- DSTRSECT(ll, cursorstyle);
- DSTRSECT(mark-cursor-ll, selectionstyle);
+ DSTRSECT(ll, cursor);
+ DSTRSECT(mark-cursor-ll, selection);
}
- DSTRSECT(len, normalstyle);
+ DSTRSECT(len, normal);
if(tx<geom->w){
WRectangle g=*geom;
if(dstart!=0)
tx=grbrush_get_text_width(WEDLN_BRUSH(wedln), str+vstart, dstart);
- grbrush_begin(WEDLN_BRUSH(wedln), geom, GRBRUSH_AMEND|GRBRUSH_NEED_CLIP);
+ grbrush_begin(WEDLN_BRUSH(wedln), geom,
+ GRBRUSH_AMEND|GRBRUSH_KEEP_ATTR|GRBRUSH_NEED_CLIP);
wedln_do_draw_str_box(wedln, geom, str+vstart+dstart, point, mark, tx);
static int get_textarea_height(WEdln *wedln, bool with_spacing)
{
- GrBorderWidths bdw;
- GrFontExtents fnte;
+ int w=1, h=1;
- grbrush_get_border_widths(WEDLN_BRUSH(wedln), &bdw);
- grbrush_get_font_extents(WEDLN_BRUSH(wedln), &fnte);
+ if(WEDLN_BRUSH(wedln)!=NULL)
+ mod_query_get_minimum_extents(WEDLN_BRUSH(wedln), with_spacing, &w, &h);
- return (fnte.max_height+bdw.top+bdw.bottom+
- (with_spacing ? bdw.spacing : 0));
+ return h;
}
}
+void wedln_size_hints(WEdln *wedln, WSizeHints *hints_ret)
+{
+ int w=1, h=1;
+
+ if(WEDLN_BRUSH(wedln)!=NULL){
+ mod_query_get_minimum_extents(WEDLN_BRUSH(wedln), FALSE, &w, &h);
+ w+=wedln->prompt_w+wedln->info_w;
+ w+=grbrush_get_text_width(WEDLN_BRUSH(wedln), "xxxxxxxxxx", 10);
+ }
+
+ hints_ret->min_set=TRUE;
+ hints_ret->min_width=w;
+ hints_ret->min_height=h;
+}
+
+
/*}}}*/
/*{{{ Draw */
-void wedln_draw_completions(WEdln *wedln, bool complete)
+void wedln_draw_completions(WEdln *wedln, int mode)
{
WRectangle geom;
if(wedln->compl_list.strs!=NULL && WEDLN_BRUSH(wedln)!=NULL){
- const char *style=(REGION_IS_ACTIVE(wedln)
- ? "active"
- : "inactive");
- const char *selstyle=(REGION_IS_ACTIVE(wedln)
- ? "active-selection"
- : "inactive-selection");
-
get_completions_geom(wedln, G_CURRENT, &geom);
draw_listing(WEDLN_BRUSH(wedln), &geom, &(wedln->compl_list),
- complete, style, selstyle);
+ mode, GR_ATTR(selection));
}
}
{
WRectangle geom;
int ty;
- const char *style=(REGION_IS_ACTIVE(wedln) ? "active" : "inactive");
if(WEDLN_BRUSH(wedln)==NULL)
return;
/*grbrush_begin(WEDLN_BRUSH(wedln), &geom, GRBRUSH_AMEND);*/
- grbrush_draw_border(WEDLN_BRUSH(wedln), &geom, style);
+ grbrush_draw_border(WEDLN_BRUSH(wedln), &geom);
get_inner_geom(wedln, G_CURRENT, &geom);
ty=calc_text_y(wedln, &geom);
+ grbrush_set_attr(WEDLN_BRUSH(wedln), GR_ATTR(prompt));
+
if(wedln->prompt!=NULL){
- const char *promptstyle=(REGION_IS_ACTIVE(wedln)
- ? "active-prompt"
- : "inactive-prompt");
grbrush_draw_string(WEDLN_BRUSH(wedln), geom.x, ty,
- wedln->prompt, wedln->prompt_len, TRUE,
- promptstyle);
+ wedln->prompt, wedln->prompt_len, TRUE);
}
if(wedln->info!=NULL){
int x=geom.x+geom.w-wedln->info_w;
- const char *promptstyle=(REGION_IS_ACTIVE(wedln)
- ? "active-prompt-info"
- : "inactive-prompt-info");
+
+ grbrush_set_attr(WEDLN_BRUSH(wedln), GR_ATTR(info));
grbrush_draw_string(WEDLN_BRUSH(wedln), x, ty,
- wedln->info, wedln->info_len, TRUE,
- promptstyle);
+ wedln->info, wedln->info_len, TRUE);
+ grbrush_unset_attr(WEDLN_BRUSH(wedln), GR_ATTR(info));
}
+
+ grbrush_unset_attr(WEDLN_BRUSH(wedln), GR_ATTR(prompt));
get_textarea_geom(wedln, G_CURRENT, &geom);
}
-void wedln_draw(WEdln *wedln, bool complete)
+static void wedln_draw_(WEdln *wedln, bool complete, bool completions)
{
WRectangle g;
int f=(complete ? 0 : GRBRUSH_NO_CLEAR_OK);
grbrush_begin(WEDLN_BRUSH(wedln), &g, f);
- wedln_draw_completions(wedln, FALSE);
+ grbrush_set_attr(WEDLN_BRUSH(wedln), REGION_IS_ACTIVE(wedln)
+ ? GR_ATTR(active)
+ : GR_ATTR(inactive));
+
+ if(completions)
+ wedln_draw_completions(wedln, LISTING_DRAW_ALL);
+
wedln_draw_textarea(wedln);
grbrush_end(WEDLN_BRUSH(wedln));
}
+void wedln_draw(WEdln *wedln, bool complete)
+{
+ wedln_draw_(wedln, complete, TRUE);
+}
+
/*}}} */
get_textarea_geom(wedln, G_CURRENT, &tageom);
wedln_update_cursor(wedln, tageom.w);
- wedln_draw_textarea(wedln);
+ wedln_draw_(wedln, FALSE, FALSE);
}
input_refit((WInput*)wedln);
if(w==REGION_GEOM(wedln).w && h==REGION_GEOM(wedln).h)
- wedln_draw_completions(wedln, TRUE);
+ wedln_draw_completions(wedln, LISTING_DRAW_COMPLETE);
}
if(wedln->compl_list.strs==NULL)
return;
if(scrollup_listing(&(wedln->compl_list)))
- wedln_draw_completions(wedln, TRUE);
+ wedln_draw_completions(wedln, LISTING_DRAW_COMPLETE);
}
if(wedln->compl_list.strs==NULL)
return;
if(scrolldown_listing(&(wedln->compl_list)))
- wedln_draw_completions(wedln, TRUE);
+ wedln_draw_completions(wedln, LISTING_DRAW_COMPLETE);
}
{
while(i>0){
i--;
- free(ptr[i]);
+ if(ptr[i]!=NULL)
+ free(ptr[i]);
}
free(ptr);
}
extl_table_gets_s(completions, "common_beg", &beg);
extl_table_gets_s(completions, "common_end", &end);
- if(wedln_do_set_completions(wedln, ptr, n, beg, end, cycle, FALSE))
- return;
+ if(!wedln_do_set_completions(wedln, ptr, n, beg, end, cycle, FALSE))
+ wedln_hide_completions(wedln);
+
+ return;
allocfail:
wedln_hide_completions(wedln);
free_completions(ptr, i);
- while(i>0){
- i--;
- /* edln_do_completions may NULL things */
- if(ptr[i]!=NULL)
- free(ptr[i]);
- }
- free(ptr);
}
static void wedln_do_select_completion(WEdln *wedln, int n)
{
- bool complredraw=listing_select(&(wedln->compl_list), n);
- wedln_draw_completions(wedln, complredraw);
+ bool redraw=listing_select(&(wedln->compl_list), n);
+ wedln_draw_completions(wedln, redraw);
update_nocompl++;
edln_set_completion(&(wedln->edln), wedln->compl_list.strs[n],
/*EXTL_DOC
* Call completion handler with the text between the beginning of line and
* current cursor position, or select next/previous completion from list if in
- * auto-show-completions mode and \var{cycle} is set to ``next'' or ``prev'',
- * respectively. The \var{mode} may be ``history'' or ``normal''. If it is
+ * auto-show-completions mode and \var{cycle} is set to \codestr{next} or
+ * \codestr{prev}, respectively.
+ * The \var{mode} may be \codestr{history} or \codestr{normal}. If it is
* not set, the previous mode is used. Normally next entry is not cycled to
* despite the setting of \var{cycle} if mode switch occurs. To override
- * this, use ``next-always'' and ``prev-always'' for \var{cycle}.
+ * this, use \codestr{next-always} and \codestr{prev-always} for \var{cycle}.
*/
EXTL_EXPORT_MEMBER
void wedln_complete(WEdln *wedln, const char *cycle, const char *mode)
{
wedln->vstart=0;
+ init_attr();
+
if(!wedln_init_prompt(wedln, params->prompt))
return FALSE;
wedln->handler=extl_fn_none();
p=edln_finish(&(wedln->edln));
- if(region_manager_allows_destroying((WRegion*)wedln))
- destroy_obj((Obj*)wedln);
+ region_rqdispose((WRegion*)wedln);
if(p!=NULL)
extl_call(handler, "s", NULL, p);
{input_scrolldown, wedln_scrolldown_completions},
{window_insstr, wedln_insstr},
{(DynFun*)input_style, (DynFun*)wedln_style},
+ {region_size_hints, wedln_size_hints},
END_DYNFUNTAB
};