/*
* ion/mod_menu/menu.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/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"
}
+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;
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);
}
{
WRectangle igeom;
int i, mx;
-
+
if(menu->entry_brush==NULL)
return;
-
+
get_inner_geom(menu, &igeom);
mx=menu->first_entry+menu->vis_entries;
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;
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);
}
+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;
+}
+
+
/*}}}*/
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);
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);
}
}
}
+static void deinit_entries(WMenu *menu);
+
bool menu_init(WMenu *menu, WWindow *par, const WFitParams *fp,
const WMenuCreateParams *params)
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;
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);
fail:
extl_unref_table(menu->tab);
extl_unref_fn(menu->handler);
- free(menu->entries);
+ deinit_entries(menu);
return FALSE;
}
}
-
-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);
}
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);
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);
}
{window_insstr, menu_insstr},
{region_restack, menu_restack},
{region_stacking, menu_stacking},
+ {region_size_hints, menu_size_hints},
END_DYNFUNTAB
};