]> git.decadent.org.uk Git - ion3.git/blobdiff - mod_query/wedln.c
Imported Upstream version 20090110
[ion3.git] / mod_query / wedln.c
index 094f22cc45a702c8f4a49c15d3bb607bd0c90936..1c43db2a7cf3402241ce00bf80bf25741e2c71c7 100644 (file)
@@ -1,12 +1,9 @@
 /*
  * ion/mod_query/wedln.c
  *
- * Copyright (c) Tuomo Valkonen 1999-2006
+ * Copyright (c) Tuomo Valkonen 1999-2009
  *
- * 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>
@@ -25,6 +22,9 @@
 #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"
@@ -50,12 +50,14 @@ static int calc_text_y(WEdln *wedln, const WRectangle *geom)
 
 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);
 }
@@ -73,9 +75,34 @@ static void dispu(const char* s, int l)
 }
 #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,
@@ -83,43 +110,30 @@ 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;
@@ -150,7 +164,8 @@ static void wedln_draw_str_box(WEdln *wedln, const WRectangle *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);
 
@@ -209,14 +224,12 @@ static bool wedln_update_cursor(WEdln *wedln, int iw)
 
 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;
 }
 
 
@@ -339,28 +352,37 @@ static void wedln_calc_size(WEdln *wedln, WRectangle *geom)
 }
 
 
+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));
     }
 }
 
@@ -369,7 +391,6 @@ void wedln_draw_textarea(WEdln *wedln)
 {
     WRectangle geom;
     int ty;
-    const char *style=(REGION_IS_ACTIVE(wedln) ? "active" : "inactive");
 
     if(WEDLN_BRUSH(wedln)==NULL)
         return;
@@ -378,30 +399,29 @@ void wedln_draw_textarea(WEdln *wedln)
     
     /*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);
     
@@ -412,7 +432,7 @@ void wedln_draw_textarea(WEdln *wedln)
 }
 
 
-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);
@@ -424,13 +444,24 @@ void wedln_draw(WEdln *wedln, bool complete)
     
     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);
+}
+
 /*}}} */
 
 
@@ -464,7 +495,7 @@ static void wedln_set_info(WEdln *wedln, const char *info)
     get_textarea_geom(wedln, G_CURRENT, &tageom);
     wedln_update_cursor(wedln, tageom.w);
     
-    wedln_draw_textarea(wedln);
+    wedln_draw_(wedln, FALSE, FALSE);
 }
 
 
@@ -488,7 +519,7 @@ static void wedln_show_completions(WEdln *wedln, char **strs, int nstrs,
 
     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);
 }
 
 
@@ -506,7 +537,7 @@ void wedln_scrollup_completions(WEdln *wedln)
     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);
 }
 
 
@@ -515,7 +546,7 @@ void wedln_scrolldown_completions(WEdln *wedln)
     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);
 }
 
 
@@ -526,7 +557,8 @@ static void free_completions(char **ptr, int i)
 {
     while(i>0){
         i--;
-        free(ptr[i]);
+        if(ptr[i]!=NULL)
+            free(ptr[i]);
     }
     free(ptr);
 }
@@ -595,26 +627,21 @@ void wedln_set_completions(WEdln *wedln, ExtlTab completions, int cycle)
     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],
@@ -757,11 +784,12 @@ bool wedln_prev_completion(WEdln *wedln)
 /*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)
@@ -899,6 +927,8 @@ static bool wedln_init(WEdln *wedln, WWindow *par, const WFitParams *fp,
 {
     wedln->vstart=0;
 
+    init_attr();
+    
     if(!wedln_init_prompt(wedln, params->prompt))
         return FALSE;
     
@@ -995,8 +1025,7 @@ static void wedln_do_finish(WEdln *wedln)
     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);
@@ -1061,6 +1090,7 @@ static DynFunTab wedln_dynfuntab[]={
     {input_scrolldown, wedln_scrolldown_completions},
     {window_insstr, wedln_insstr},
     {(DynFun*)input_style, (DynFun*)wedln_style},
+    {region_size_hints, wedln_size_hints},
     END_DYNFUNTAB
 };