]> git.decadent.org.uk Git - ion3.git/blobdiff - mod_menu/menu.c
Imported Upstream version 20090110
[ion3.git] / mod_menu / menu.c
index b8ec9cfa446984102770562de2ba244c45ccd5eb..6c1287fdb79bcb96a7b57e65be78273ca380df90 100644 (file)
@@ -1,12 +1,9 @@
 /*
  * ion/mod_menu/menu.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>
 #include <ioncore/event.h>
 #include <ioncore/xwindow.h>
 #include <ioncore/names.h>
+#include <ioncore/gr.h>
+#include <ioncore/gr-util.h>
+#include <ioncore/sizehint.h>
+#include <ioncore/resize.h>
 #include "menu.h"
 #include "main.h"
 
@@ -85,22 +86,35 @@ static void get_inner_geom(WMenu *menu, WRectangle *geom)
 }
 
 
+GR_DEFATTR(active);
+GR_DEFATTR(inactive);
+GR_DEFATTR(selected);
+GR_DEFATTR(unselected);
+GR_DEFATTR(normal);
+GR_DEFATTR(submenu);
+
+
+static void init_attr()
+{
+    GR_ALLOCATTR_BEGIN;
+    GR_ALLOCATTR(active);
+    GR_ALLOCATTR(inactive);
+    GR_ALLOCATTR(selected);
+    GR_ALLOCATTR(unselected);
+    GR_ALLOCATTR(normal);
+    GR_ALLOCATTR(submenu);
+    GR_ALLOCATTR_END;
+}
+
+
 static void menu_draw_entry(WMenu *menu, int i, const WRectangle *igeom,
                             bool complete)
 {
     WRectangle geom;
-    int a;
-
-    static const char *attrs[]={
-        "active-selected-normal",
-        "active-selected-submenu",
-        "active-unselected-normal",
-        "active-unselected-submenu",
-        "inactive-selected-normal",
-        "inactive-selected-submenu",
-        "inactive-unselected-normal",
-        "inactive-unselected-submenu",
-    };
+    GrAttr sa, aa;
+
+    aa=(REGION_IS_ACTIVE(menu) ? GR_ATTR(active) : GR_ATTR(inactive));
+    sa=(menu->selected_entry==i ? GR_ATTR(selected) : GR_ATTR(unselected));
     
     if(menu->entry_brush==NULL)
         return;
@@ -109,14 +123,15 @@ static void menu_draw_entry(WMenu *menu, int i, const WRectangle *igeom,
     geom.h=menu->entry_h;
     geom.y+=(i-menu->first_entry)*(menu->entry_h+menu->entry_spacing);
     
-    a=((REGION_IS_ACTIVE(menu) ? 0 : 4)
-       |(menu->selected_entry==i ? 0 : 2)
-       |(menu->entries[i].flags&WMENUENTRY_SUBMENU ? 1 : 0));
-
-    grbrush_begin(menu->entry_brush, &geom, GRBRUSH_AMEND);
+    grbrush_begin(menu->entry_brush, &geom, GRBRUSH_AMEND|GRBRUSH_KEEP_ATTR);
+    
+    grbrush_init_attr(menu->entry_brush, &menu->entries[i].attr);
+    
+    grbrush_set_attr(menu->entry_brush, aa);
+    grbrush_set_attr(menu->entry_brush, sa);
 
     grbrush_draw_textbox(menu->entry_brush, &geom, menu->entries[i].title, 
-                         attrs[a], complete);
+                         complete);
     
     grbrush_end(menu->entry_brush);
 }
@@ -126,10 +141,10 @@ void menu_draw_entries(WMenu *menu, bool complete)
 {
     WRectangle igeom;
     int i, mx;
-
+    
     if(menu->entry_brush==NULL)
         return;
-    
+        
     get_inner_geom(menu, &igeom);
     
     mx=menu->first_entry+menu->vis_entries;
@@ -142,8 +157,8 @@ void menu_draw_entries(WMenu *menu, bool complete)
 
 void menu_draw(WMenu *menu, bool complete)
 {
+    GrAttr aa=(REGION_IS_ACTIVE(menu) ? GR_ATTR(active) : GR_ATTR(inactive));
     WRectangle geom;
-    const char *substyle=(REGION_IS_ACTIVE(menu) ? "active" : "inactive");
     
     if(menu->brush==NULL)
         return;
@@ -153,7 +168,9 @@ void menu_draw(WMenu *menu, bool complete)
     grbrush_begin(menu->brush, &geom, 
                   (complete ? 0 : GRBRUSH_NO_CLEAR_OK));
     
-    grbrush_draw_border(menu->brush, &geom, substyle);
+    grbrush_set_attr(menu->brush, aa);
+    
+    grbrush_draw_border(menu->brush, &geom);
     
     menu_draw_entries(menu, FALSE);
     
@@ -373,6 +390,26 @@ bool menu_fitrep(WMenu *menu, WWindow *par, const WFitParams *fp)
 }
 
 
+void menu_size_hints(WMenu *menu, WSizeHints *hints_ret)
+{
+    int n=menu->n_entries;
+    int w=menu->max_entry_w;
+    int h=menu->entry_h*n + menu->entry_spacing*maxof(0, n-1);
+
+    if(menu->brush!=NULL){
+        GrBorderWidths bdw;
+        grbrush_get_border_widths(menu->brush, &bdw);
+        
+        w+=bdw.left+bdw.right;
+        h+=bdw.top+bdw.bottom;
+    }
+    
+    hints_ret->min_set=TRUE;
+    hints_ret->min_width=w;
+    hints_ret->min_height=h;
+}
+
+
 /*}}}*/
 
 
@@ -491,9 +528,8 @@ static void menu_release_gr(WMenu *menu)
 
 static WMenuEntry *preprocess_menu(ExtlTab tab, int *n_entries)
 {
-    ExtlTab entry, sub;
-    ExtlFn fn;
     WMenuEntry *entries;
+    ExtlTab entry;
     int i, n;
     
     n=extl_table_get_n(tab);
@@ -506,17 +542,40 @@ static WMenuEntry *preprocess_menu(ExtlTab tab, int *n_entries)
     
     if(entries==NULL)
         return NULL;
-
+        
+    init_attr();
+    
     /* Initialise entries and check submenus */
     for(i=1; i<=n; i++){
-        entries[i-1].title=NULL;
-        entries[i-1].flags=0;
-        if(extl_table_getis(tab, i, "submenu_fn", 'f', &fn)){
-            entries[i-1].flags|=WMENUENTRY_SUBMENU;
-            extl_unref_fn(fn);
-        }else if(extl_table_getis(tab, i, "submenu", 't', &sub)){
-            entries[i-1].flags|=WMENUENTRY_SUBMENU;
-            extl_unref_table(sub);
+        WMenuEntry *ent=&entries[i-1];
+        
+        ent->title=NULL;
+        ent->flags=0;
+        
+        gr_stylespec_init(&ent->attr);
+        
+        if(extl_table_geti_t(tab, i, &entry)){
+            char *attr;
+            ExtlTab sub;
+            ExtlFn fn;
+            
+            if(extl_table_gets_s(entry, "attr", &attr)){
+                gr_stylespec_load_(&ent->attr, attr, TRUE);
+                free(attr);
+            }
+            
+            if(extl_table_gets_f(entry, "submenu_fn", &fn)){
+                ent->flags|=WMENUENTRY_SUBMENU;
+                extl_unref_fn(fn);
+            }else if(extl_table_gets_t(entry, "submenu", &sub)){
+                ent->flags|=WMENUENTRY_SUBMENU;
+                extl_unref_table(sub);
+            }
+            
+            if(ent->flags&WMENUENTRY_SUBMENU)
+                gr_stylespec_set(&ent->attr, GR_ATTR(submenu));
+            
+            extl_unref_table(entry);
         }
     }
     
@@ -524,6 +583,8 @@ static WMenuEntry *preprocess_menu(ExtlTab tab, int *n_entries)
 }
 
 
+static void deinit_entries(WMenu *menu);
+
 
 bool menu_init(WMenu *menu, WWindow *par, const WFitParams *fp,
                const WMenuCreateParams *params)
@@ -542,12 +603,13 @@ bool menu_init(WMenu *menu, WWindow *par, const WFitParams *fp,
     menu->handler=extl_ref_fn(params->handler);
     menu->pmenu_mode=params->pmenu_mode;
     menu->big_mode=params->big_mode;
-
+    /*menu->cycle_bindmap=NULL;*/
+    
     menu->last_fp=*fp;
     
-    if(params->pmenu_mode)
+    if(params->pmenu_mode){
         menu->selected_entry=-1;
-    else{
+    }else{
         menu->selected_entry=params->initial-1;
         if(menu->selected_entry<0)
            menu->selected_entry=0;
@@ -575,7 +637,9 @@ bool menu_init(WMenu *menu, WWindow *par, const WFitParams *fp,
     
     if(!menu_init_gr(menu, region_rootwin_of((WRegion*)par), win))
         goto fail2;
-
+        
+    init_attr();
+    
     menu_firstfit(menu, params->submenu_mode, &(params->refg));
     
     window_select_input(&(menu->win), IONCORE_EVENTMASK_NORMAL);
@@ -591,7 +655,7 @@ fail2:
 fail:
     extl_unref_table(menu->tab);
     extl_unref_fn(menu->handler);
-    free(menu->entries);
+    deinit_entries(menu);
     return FALSE;
 }
 
@@ -603,24 +667,37 @@ WMenu *create_menu(WWindow *par, const WFitParams *fp,
 }
 
 
-
-void menu_deinit(WMenu *menu)
+static void deinit_entries(WMenu *menu)
 {
     int i;
     
+    for(i=0; i<menu->n_entries; i++){
+        gr_stylespec_unalloc(&menu->entries[i].attr);
+        if(menu->entries[i].title!=NULL)
+            free(menu->entries[i].title);
+    }
+    
+    free(menu->entries);
+}
+
+
+void menu_deinit(WMenu *menu)
+{
     menu_typeahead_clear(menu);
     
     if(menu->submenu!=NULL)
         destroy_obj((Obj*)menu->submenu);
     
+    /*if(menu->cycle_bindmap!=NULL)
+        bindmap_destroy(menu->cycle_bindmap);*/
+
     extl_unref_table(menu->tab);
     extl_unref_fn(menu->handler);
     
-    for(i=0; i<menu->n_entries; i++)
-        free(menu->entries[i].title);
-    free(menu->entries);
+    deinit_entries(menu);
     
     menu_release_gr(menu);
+    
     window_deinit((WWindow*)menu);
 }
 
@@ -891,10 +968,10 @@ static void menu_do_finish(WMenu *menu)
     
     ok=extl_table_geti_t(menu->tab, menu->selected_entry+1, &tab);
     
-    if(region_manager_allows_destroying((WRegion*)head))
-        destroy_obj((Obj*)head);
-    else if(head->submenu!=NULL)
-        destroy_obj((Obj*)head->submenu);
+    if(!region_rqdispose((WRegion*)head)){
+        if(head->submenu!=NULL)
+            destroy_obj((Obj*)head->submenu);
+    }
     
     if(ok)
         extl_call(handler, "t", NULL, tab);
@@ -930,8 +1007,7 @@ void menu_finish(WMenu *menu)
 EXTL_EXPORT_MEMBER
 void menu_cancel(WMenu *menu)
 {
-    if(region_manager_allows_destroying((WRegion*)menu))
-        mainloop_defer_destroy((Obj*)menu);
+    region_defer_rqdispose((WRegion*)menu);
 }
 
 
@@ -960,7 +1036,7 @@ static void reset_scroll_timer()
  * 
  * \begin{tabularx}{\linewidth}{lX}
  *  \tabhead{Field & Description}
- *  \var{scroll_amount} & Number of pixels to scroll at a time 
+ *  \var{scroll_amount} & Number of pixels to scroll at a time in
  *                        pointer-controlled menus when one extends
  *                        beyond a border of the screen and the pointer
  *                        touches that border. \\
@@ -1362,6 +1438,7 @@ static DynFunTab menu_dynfuntab[]={
     {window_insstr, menu_insstr},
     {region_restack, menu_restack},
     {region_stacking, menu_stacking},
+    {region_size_hints, menu_size_hints},
     END_DYNFUNTAB
 };