2 * GNT - The GLib Ncurses Toolkit
4 * GNT is the legal property of its developers, whose names are too numerous
5 * to list here. Please refer to the COPYRIGHT file distributed with this
8 * This library is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
24 #include "gntmenuitemcheck.h"
42 static GntTreeClass
*parent_class
= NULL
;
44 static void (*org_draw
)(GntWidget
*wid
);
45 static void (*org_destroy
)(GntWidget
*wid
);
46 static void (*org_map
)(GntWidget
*wid
);
47 static void (*org_size_request
)(GntWidget
*wid
);
48 static gboolean (*org_key_pressed
)(GntWidget
*w
, const char *t
);
51 menu_hide_all(GntMenu
*menu
)
53 while (menu
->parentmenu
)
54 menu
= menu
->parentmenu
;
55 gnt_widget_hide(GNT_WIDGET(menu
));
59 gnt_menu_draw(GntWidget
*widget
)
61 GntMenu
*menu
= GNT_MENU(widget
);
66 if (menu
->type
== GNT_MENU_TOPLEVEL
) {
67 wbkgdset(widget
->window
, '\0' | gnt_color_pair(GNT_COLOR_HIGHLIGHT
));
68 werase(widget
->window
);
70 for (i
= 0, iter
= menu
->list
; iter
; iter
= iter
->next
, i
++) {
71 GntMenuItem
*item
= GNT_MENU_ITEM(iter
->data
);
72 type
= ' ' | gnt_color_pair(GNT_COLOR_HIGHLIGHT
);
73 if (i
== menu
->selected
)
75 item
->priv
.x
= getcurx(widget
->window
) + widget
->priv
.x
;
76 item
->priv
.y
= getcury(widget
->window
) + widget
->priv
.y
+ 1;
77 wbkgdset(widget
->window
, type
);
78 wprintw(widget
->window
, " %s ", item
->text
);
88 gnt_menu_size_request(GntWidget
*widget
)
90 GntMenu
*menu
= GNT_MENU(widget
);
92 if (menu
->type
== GNT_MENU_TOPLEVEL
) {
93 widget
->priv
.height
= 1;
94 widget
->priv
.width
= getmaxx(stdscr
);
96 org_size_request(widget
);
97 widget
->priv
.height
= g_list_length(menu
->list
) + 2;
102 menu_tree_add(GntMenu
*menu
, GntMenuItem
*item
, GntMenuItem
*parent
)
104 char trigger
[4] = "\0 )\0";
106 if ((trigger
[1] = gnt_menuitem_get_trigger(item
)) && trigger
[1] != ' ')
109 if (GNT_IS_MENU_ITEM_CHECK(item
)) {
110 gnt_tree_add_choice(GNT_TREE(menu
), item
,
111 gnt_tree_create_row(GNT_TREE(menu
), item
->text
, trigger
, " "), parent
, NULL
);
112 gnt_tree_set_choice(GNT_TREE(menu
), item
, gnt_menuitem_check_get_checked(GNT_MENU_ITEM_CHECK(item
)));
114 gnt_tree_add_row_last(GNT_TREE(menu
), item
,
115 gnt_tree_create_row(GNT_TREE(menu
), item
->text
, trigger
, item
->submenu
? ">" : " "), parent
);
117 if (0 && item
->submenu
) {
118 GntMenu
*sub
= GNT_MENU(item
->submenu
);
120 for (iter
= sub
->list
; iter
; iter
= iter
->next
) {
121 GntMenuItem
*it
= GNT_MENU_ITEM(iter
->data
);
122 menu_tree_add(menu
, it
, item
);
127 #define GET_VAL(ch) ((ch >= '0' && ch <= '9') ? (ch - '0') : (ch >= 'a' && ch <= 'z') ? (10 + ch - 'a') : 36)
130 assign_triggers(GntMenu
*menu
)
135 memset(bools
, 0, sizeof(bools
));
138 for (iter
= menu
->list
; iter
; iter
= iter
->next
) {
139 GntMenuItem
*item
= iter
->data
;
140 char trigger
= tolower(gnt_menuitem_get_trigger(item
));
141 if (trigger
== '\0' || trigger
== ' ')
143 bools
[(int)GET_VAL(trigger
)] = 1;
146 for (iter
= menu
->list
; iter
; iter
= iter
->next
) {
147 GntMenuItem
*item
= iter
->data
;
148 char trigger
= gnt_menuitem_get_trigger(item
);
149 const char *text
= item
->text
;
153 char ch
= tolower(*text
++);
154 if (ch
== ' ' || bools
[(int)GET_VAL(ch
)])
160 trigger
= item
->text
[0];
161 gnt_menuitem_set_trigger(item
, trigger
);
162 bools
[(int)GET_VAL(trigger
)] = 1;
167 gnt_menu_map(GntWidget
*widget
)
169 GntMenu
*menu
= GNT_MENU(widget
);
171 if (menu
->type
== GNT_MENU_TOPLEVEL
) {
172 gnt_widget_size_request(widget
);
174 /* Populate the tree */
176 gnt_tree_remove_all(GNT_TREE(widget
));
177 /* Try to assign some trigger for the items */
178 assign_triggers(menu
);
179 for (iter
= menu
->list
; iter
; iter
= iter
->next
) {
180 GntMenuItem
*item
= GNT_MENU_ITEM(iter
->data
);
181 menu_tree_add(menu
, item
, NULL
);
184 gnt_tree_adjust_columns(GNT_TREE(widget
));
190 menuitem_activate(GntMenu
*menu
, GntMenuItem
*item
)
195 if (gnt_menuitem_activate(item
)) {
199 GntMenu
*sub
= GNT_MENU(item
->submenu
);
201 sub
->type
= GNT_MENU_POPUP
; /* Submenus are *never* toplevel */
202 sub
->parentmenu
= menu
;
203 if (menu
->type
!= GNT_MENU_TOPLEVEL
) {
204 GntWidget
*widget
= GNT_WIDGET(menu
);
205 item
->priv
.x
= widget
->priv
.x
+ widget
->priv
.width
- 1;
206 item
->priv
.y
= widget
->priv
.y
+ gnt_tree_get_selection_visible_line(GNT_TREE(menu
));
208 gnt_widget_set_position(GNT_WIDGET(sub
), item
->priv
.x
, item
->priv
.y
);
209 GNT_WIDGET_UNSET_FLAGS(GNT_WIDGET(sub
), GNT_WIDGET_INVISIBLE
);
210 gnt_widget_draw(GNT_WIDGET(sub
));
218 find_item_with_trigger(GList
*start
, GList
*end
, char trigger
)
221 for (iter
= start
; iter
!= (end
? end
: NULL
); iter
= iter
->next
) {
222 if (gnt_menuitem_get_trigger(iter
->data
) == trigger
)
229 check_for_trigger(GntMenu
*menu
, char trigger
)
231 /* check for a trigger key */
234 GList
*nth
= g_list_find(menu
->list
, gnt_tree_get_selection_data(GNT_TREE(menu
)));
239 find
= find_item_with_trigger(nth
->next
, NULL
, trigger
);
241 find
= find_item_with_trigger(menu
->list
, nth
->next
, trigger
);
245 gnt_tree_set_selected(GNT_TREE(menu
), find
->data
);
246 iter
= find_item_with_trigger(find
->next
, NULL
, trigger
);
247 if (iter
!= NULL
&& iter
!= find
)
249 iter
= find_item_with_trigger(menu
->list
, nth
, trigger
);
250 if (iter
!= NULL
&& iter
!= find
)
253 gnt_widget_activate(GNT_WIDGET(menu
));
258 gnt_menu_key_pressed(GntWidget
*widget
, const char *text
)
260 GntMenu
*menu
= GNT_MENU(widget
);
261 int current
= menu
->selected
;
265 do sub
= sub
->submenu
; while (sub
->submenu
);
266 if (gnt_widget_key_pressed(GNT_WIDGET(sub
), text
))
270 if ((text
[0] == 27 && text
[1] == 0) ||
271 (menu
->type
!= GNT_MENU_TOPLEVEL
&& strcmp(text
, GNT_KEY_LEFT
) == 0)) {
272 /* Escape closes menu */
273 GntMenu
*par
= menu
->parentmenu
;
276 gnt_widget_hide(widget
);
278 gnt_widget_hide(widget
);
282 if (menu
->type
== GNT_MENU_TOPLEVEL
) {
283 if (strcmp(text
, GNT_KEY_LEFT
) == 0) {
285 if (menu
->selected
< 0)
286 menu
->selected
= g_list_length(menu
->list
) - 1;
287 } else if (strcmp(text
, GNT_KEY_RIGHT
) == 0) {
289 if (menu
->selected
>= g_list_length(menu
->list
))
291 } else if (strcmp(text
, GNT_KEY_ENTER
) == 0 ||
292 strcmp(text
, GNT_KEY_DOWN
) == 0) {
293 gnt_widget_activate(widget
);
296 if (current
!= menu
->selected
) {
297 GntMenu
*sub
= menu
->submenu
;
299 gnt_widget_hide(GNT_WIDGET(sub
));
300 gnt_widget_draw(widget
);
304 if (text
[1] == '\0') {
305 if (check_for_trigger(menu
, text
[0]))
307 } else if (strcmp(text
, GNT_KEY_RIGHT
) == 0) {
308 GntMenuItem
*item
= gnt_tree_get_selection_data(GNT_TREE(menu
));
309 if (item
&& item
->submenu
) {
310 menuitem_activate(menu
, item
);
314 return org_key_pressed(widget
, text
);
321 gnt_menu_destroy(GntWidget
*widget
)
323 GntMenu
*menu
= GNT_MENU(widget
);
324 g_list_foreach(menu
->list
, (GFunc
)g_object_unref
, NULL
);
325 g_list_free(menu
->list
);
330 gnt_menu_toggled(GntTree
*tree
, gpointer key
)
332 GntMenuItem
*item
= GNT_MENU_ITEM(key
);
333 GntMenu
*menu
= GNT_MENU(tree
);
334 gboolean check
= gnt_menuitem_check_get_checked(GNT_MENU_ITEM_CHECK(item
));
335 gnt_menuitem_check_set_checked(GNT_MENU_ITEM_CHECK(item
), !check
);
336 gnt_menuitem_activate(item
);
338 gnt_widget_hide(GNT_WIDGET(menu
));
339 menu
= menu
->parentmenu
;
344 gnt_menu_activate(GntWidget
*widget
)
346 GntMenu
*menu
= GNT_MENU(widget
);
349 if (menu
->type
== GNT_MENU_TOPLEVEL
) {
350 item
= g_list_nth_data(menu
->list
, menu
->selected
);
352 item
= gnt_tree_get_selection_data(GNT_TREE(menu
));
356 if (GNT_IS_MENU_ITEM_CHECK(item
))
357 gnt_menu_toggled(GNT_TREE(widget
), item
);
359 menuitem_activate(menu
, item
);
364 gnt_menu_hide(GntWidget
*widget
)
366 GntMenu
*sub
, *menu
= GNT_MENU(widget
);
368 while ((sub
= menu
->submenu
))
369 gnt_widget_hide(GNT_WIDGET(sub
));
370 if (menu
->parentmenu
)
371 menu
->parentmenu
->submenu
= NULL
;
375 gnt_menu_class_init(GntMenuClass
*klass
)
377 GntWidgetClass
*wid_class
= GNT_WIDGET_CLASS(klass
);
378 parent_class
= GNT_TREE_CLASS(klass
);
380 org_destroy
= wid_class
->destroy
;
381 org_map
= wid_class
->map
;
382 org_draw
= wid_class
->draw
;
383 org_key_pressed
= wid_class
->key_pressed
;
384 org_size_request
= wid_class
->size_request
;
386 wid_class
->destroy
= gnt_menu_destroy
;
387 wid_class
->draw
= gnt_menu_draw
;
388 wid_class
->map
= gnt_menu_map
;
389 wid_class
->size_request
= gnt_menu_size_request
;
390 wid_class
->key_pressed
= gnt_menu_key_pressed
;
391 wid_class
->activate
= gnt_menu_activate
;
392 wid_class
->hide
= gnt_menu_hide
;
394 parent_class
->toggled
= gnt_menu_toggled
;
400 gnt_menu_init(GTypeInstance
*instance
, gpointer
class)
402 GntWidget
*widget
= GNT_WIDGET(instance
);
403 GNT_WIDGET_SET_FLAGS(widget
, GNT_WIDGET_NO_SHADOW
| GNT_WIDGET_NO_BORDER
|
404 GNT_WIDGET_CAN_TAKE_FOCUS
| GNT_WIDGET_TRANSIENT
);
408 /******************************************************************************
410 *****************************************************************************/
412 gnt_menu_get_gtype(void)
414 static GType type
= 0;
418 static const GTypeInfo info
= {
419 sizeof(GntMenuClass
),
420 NULL
, /* base_init */
421 NULL
, /* base_finalize */
422 (GClassInitFunc
)gnt_menu_class_init
,
423 NULL
, /* class_finalize */
424 NULL
, /* class_data */
427 gnt_menu_init
, /* instance_init */
428 NULL
/* value_table */
431 type
= g_type_register_static(GNT_TYPE_TREE
,
439 GntWidget
*gnt_menu_new(GntMenuType type
)
441 GntWidget
*widget
= g_object_new(GNT_TYPE_MENU
, NULL
);
442 GntMenu
*menu
= GNT_MENU(widget
);
447 if (type
== GNT_MENU_TOPLEVEL
) {
451 GNT_TREE(widget
)->show_separator
= FALSE
;
452 g_object_set(G_OBJECT(widget
), "columns", NUM_COLUMNS
, NULL
);
453 gnt_tree_set_col_width(GNT_TREE(widget
), ITEM_TRIGGER
, 3);
454 gnt_tree_set_column_resizable(GNT_TREE(widget
), ITEM_TRIGGER
, FALSE
);
455 gnt_tree_set_col_width(GNT_TREE(widget
), ITEM_SUBMENU
, 1);
456 gnt_tree_set_column_resizable(GNT_TREE(widget
), ITEM_SUBMENU
, FALSE
);
457 GNT_WIDGET_UNSET_FLAGS(widget
, GNT_WIDGET_NO_BORDER
);
463 void gnt_menu_add_item(GntMenu
*menu
, GntMenuItem
*item
)
465 menu
->list
= g_list_append(menu
->list
, item
);
469 GntMenuItem
*gnt_menu_get_item(GntMenu
*menu
, const char *id
)
471 GntMenuItem
*item
= NULL
;
472 GList
*iter
= menu
->list
;
477 for (; iter
; iter
= iter
->next
) {
480 sub
= gnt_menuitem_get_submenu(item
);
482 item
= gnt_menu_get_item(sub
, id
);
486 const char *itid
= gnt_menuitem_get_id(item
);
487 if (itid
&& strcmp(itid
, id
) == 0)
489 /* XXX: Perhaps look at the menu-label as well? */
495 menuitem_activate(menu
, item
);