Ticket #2384: allow rebind Fx keys in the file manager.
[midnight-commander.git] / lib / widget / menu.c
blob67a2683f709bc19531ec7319f4ef41fab552e4a1
1 /*
2 Pulldown menu code
4 Copyright (C) 1994, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
5 2007, 2009, 2011
6 The Free Software Foundation, Inc.
8 This file is part of the Midnight Commander.
10 The Midnight Commander is free software: you can redistribute it
11 and/or modify it under the terms of the GNU General Public License as
12 published by the Free Software Foundation, either version 3 of the License,
13 or (at your option) any later version.
15 The Midnight Commander is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 /** \file menu.c
25 * \brief Source: pulldown menu code
28 #include <config.h>
30 #include <ctype.h>
31 #include <stdarg.h>
32 #include <string.h>
33 #include <sys/types.h>
35 #include "lib/global.h"
37 #include "lib/tty/tty.h"
38 #include "lib/skin.h"
39 #include "lib/tty/mouse.h"
40 #include "lib/tty/key.h" /* key macros */
41 #include "lib/strutil.h"
42 #include "lib/widget.h"
43 #include "lib/event.h" /* mc_event_raise() */
45 /*** global variables ****************************************************************************/
47 /*** file scope macro definitions ****************************************************************/
49 /*** file scope type declarations ****************************************************************/
51 /*** file scope variables ************************************************************************/
53 static cb_ret_t menubar_callback (Widget * w, widget_msg_t msg, int parm);
55 /*** file scope functions ************************************************************************/
56 /* --------------------------------------------------------------------------------------------- */
58 static void
59 menu_arrange (Menu * menu, dlg_shortcut_str get_shortcut)
61 if (menu != NULL)
63 GList *i;
64 size_t max_shortcut_len = 0;
66 menu->max_entry_len = 1;
67 menu->max_hotkey_len = 1;
69 for (i = menu->entries; i != NULL; i = g_list_next (i))
71 menu_entry_t *entry = i->data;
73 if (entry != NULL)
75 size_t len;
77 len = (size_t) hotkey_width (entry->text);
78 menu->max_hotkey_len = max (menu->max_hotkey_len, len);
80 if (get_shortcut != NULL)
81 entry->shortcut = get_shortcut (entry->command);
83 if (entry->shortcut != NULL)
85 len = (size_t) str_term_width1 (entry->shortcut);
86 max_shortcut_len = max (max_shortcut_len, len);
91 menu->max_entry_len = menu->max_hotkey_len + max_shortcut_len;
95 /* --------------------------------------------------------------------------------------------- */
97 static void
98 menubar_paint_idx (WMenuBar * menubar, unsigned int idx, int color)
100 const Menu *menu = g_list_nth_data (menubar->menu, menubar->selected);
101 const menu_entry_t *entry = g_list_nth_data (menu->entries, idx);
102 const int y = 2 + idx;
103 int x = menu->start_x;
105 if (x + menu->max_entry_len + 4 > (gsize) menubar->widget.cols)
106 x = menubar->widget.cols - menu->max_entry_len - 4;
108 if (entry == NULL)
110 /* menu separator */
111 tty_setcolor (MENU_ENTRY_COLOR);
113 widget_move (&menubar->widget, y, x - 1);
114 tty_print_alt_char (ACS_LTEE, FALSE);
116 tty_draw_hline (menubar->widget.y + y, menubar->widget.x + x,
117 ACS_HLINE, menu->max_entry_len + 3);
119 widget_move (&menubar->widget, y, x + menu->max_entry_len + 3);
120 tty_print_alt_char (ACS_RTEE, FALSE);
122 else
124 int yt, xt;
126 /* menu text */
127 tty_setcolor (color);
128 widget_move (&menubar->widget, y, x);
129 tty_print_char ((unsigned char) entry->first_letter);
130 tty_getyx (&yt, &xt);
131 tty_draw_hline (yt, xt, ' ', menu->max_entry_len + 2); /* clear line */
132 tty_print_string (entry->text.start);
134 if (entry->text.hotkey != NULL)
136 tty_setcolor (color == MENU_SELECTED_COLOR ? MENU_HOTSEL_COLOR : MENU_HOT_COLOR);
137 tty_print_string (entry->text.hotkey);
138 tty_setcolor (color);
141 if (entry->text.end != NULL)
142 tty_print_string (entry->text.end);
144 if (entry->shortcut != NULL)
146 widget_move (&menubar->widget, y, x + menu->max_hotkey_len + 3);
147 tty_print_string (entry->shortcut);
150 /* move cursor to the start of entry text */
151 widget_move (&menubar->widget, y, x + 1);
155 /* --------------------------------------------------------------------------------------------- */
157 static void
158 menubar_draw_drop (WMenuBar * menubar)
160 const Menu *menu = g_list_nth_data (menubar->menu, menubar->selected);
161 const unsigned int count = g_list_length (menu->entries);
162 int column = menu->start_x - 1;
163 unsigned int i;
165 if (column + menu->max_entry_len + 5 > (gsize) menubar->widget.cols)
166 column = menubar->widget.cols - menu->max_entry_len - 5;
168 tty_setcolor (MENU_ENTRY_COLOR);
169 draw_box (menubar->widget.owner,
170 menubar->widget.y + 1, menubar->widget.x + column,
171 count + 2, menu->max_entry_len + 5, FALSE);
173 for (i = 0; i < count; i++)
174 menubar_paint_idx (menubar, i,
175 i == menu->selected ? MENU_SELECTED_COLOR : MENU_ENTRY_COLOR);
178 /* --------------------------------------------------------------------------------------------- */
180 static void
181 menubar_set_color (WMenuBar * menubar, gboolean current, gboolean hotkey)
183 if (!menubar->is_active)
184 tty_setcolor (MENU_INACTIVE_COLOR);
185 else if (current)
186 tty_setcolor (hotkey ? MENU_HOTSEL_COLOR : MENU_SELECTED_COLOR);
187 else
188 tty_setcolor (hotkey ? MENU_HOT_COLOR : MENU_ENTRY_COLOR);
191 /* --------------------------------------------------------------------------------------------- */
193 static void
194 menubar_draw (WMenuBar * menubar)
196 GList *i;
198 /* First draw the complete menubar */
199 tty_setcolor (menubar->is_active ? MENU_ENTRY_COLOR : MENU_INACTIVE_COLOR);
200 tty_draw_hline (menubar->widget.y, menubar->widget.x, ' ', menubar->widget.cols);
202 /* Now each one of the entries */
203 for (i = menubar->menu; i != NULL; i = g_list_next (i))
205 Menu *menu = i->data;
206 gboolean is_selected = (menubar->selected == (gsize) g_list_position (menubar->menu, i));
208 menubar_set_color (menubar, is_selected, FALSE);
209 widget_move (&menubar->widget, 0, menu->start_x);
211 tty_print_char (' ');
212 tty_print_string (menu->text.start);
214 if (menu->text.hotkey != NULL)
216 menubar_set_color (menubar, is_selected, TRUE);
217 tty_print_string (menu->text.hotkey);
218 menubar_set_color (menubar, is_selected, FALSE);
221 if (menu->text.end != NULL)
222 tty_print_string (menu->text.end);
224 tty_print_char (' ');
227 if (menubar->is_dropped)
228 menubar_draw_drop (menubar);
229 else
230 widget_move (&menubar->widget, 0,
231 ((Menu *) g_list_nth_data (menubar->menu, menubar->selected))->start_x);
234 /* --------------------------------------------------------------------------------------------- */
236 static void
237 menubar_remove (WMenuBar * menubar)
239 Dlg_head *h;
241 if (!menubar->is_dropped)
242 return;
244 /* HACK: before refresh the dialog, change the current widget to keep the order
245 of overlapped widgets. This is useful in multi-window editor.
246 In general, menubar should be a special object, not an ordinary widget
247 in the current dialog. */
248 h = menubar->widget.owner;
249 h->current = g_list_find (h->widgets, dlg_find_by_id (h, menubar->previous_widget));
251 menubar->is_dropped = FALSE;
252 do_refresh ();
253 menubar->is_dropped = TRUE;
255 /* restore current widget */
256 h->current = g_list_find (h->widgets, menubar);
259 /* --------------------------------------------------------------------------------------------- */
261 static void
262 menubar_left (WMenuBar * menubar)
264 menubar_remove (menubar);
265 if (menubar->selected == 0)
266 menubar->selected = g_list_length (menubar->menu) - 1;
267 else
268 menubar->selected--;
269 menubar_draw (menubar);
272 /* --------------------------------------------------------------------------------------------- */
274 static void
275 menubar_right (WMenuBar * menubar)
277 menubar_remove (menubar);
278 menubar->selected = (menubar->selected + 1) % g_list_length (menubar->menu);
279 menubar_draw (menubar);
282 /* --------------------------------------------------------------------------------------------- */
284 static void
285 menubar_finish (WMenuBar * menubar)
287 menubar->is_dropped = FALSE;
288 menubar->is_active = FALSE;
289 menubar->widget.lines = 1;
290 widget_want_hotkey (menubar->widget, 0);
292 dlg_select_by_id (menubar->widget.owner, menubar->previous_widget);
293 do_refresh ();
296 /* --------------------------------------------------------------------------------------------- */
298 static void
299 menubar_drop (WMenuBar * menubar, unsigned int selected)
301 menubar->is_dropped = TRUE;
302 menubar->selected = selected;
303 menubar_draw (menubar);
306 /* --------------------------------------------------------------------------------------------- */
308 static void
309 menubar_execute (WMenuBar * menubar)
311 const Menu *menu = g_list_nth_data (menubar->menu, menubar->selected);
312 const menu_entry_t *entry = g_list_nth_data (menu->entries, menu->selected);
314 if ((entry != NULL) && (entry->command != CK_IgnoreKey))
316 mc_global.widget.is_right = (menubar->selected != 0);
317 menubar_finish (menubar);
318 menubar->widget.owner->callback (menubar->widget.owner, &menubar->widget,
319 DLG_ACTION, entry->command, NULL);
320 do_refresh ();
324 /* --------------------------------------------------------------------------------------------- */
326 static void
327 menubar_down (WMenuBar * menubar)
329 Menu *menu = g_list_nth_data (menubar->menu, menubar->selected);
330 const unsigned int len = g_list_length (menu->entries);
331 menu_entry_t *entry;
333 menubar_paint_idx (menubar, menu->selected, MENU_ENTRY_COLOR);
337 menu->selected = (menu->selected + 1) % len;
338 entry = (menu_entry_t *) g_list_nth_data (menu->entries, menu->selected);
340 while ((entry == NULL) || (entry->command == CK_IgnoreKey));
342 menubar_paint_idx (menubar, menu->selected, MENU_SELECTED_COLOR);
345 /* --------------------------------------------------------------------------------------------- */
347 static void
348 menubar_up (WMenuBar * menubar)
350 Menu *menu = g_list_nth_data (menubar->menu, menubar->selected);
351 const unsigned int len = g_list_length (menu->entries);
352 menu_entry_t *entry;
354 menubar_paint_idx (menubar, menu->selected, MENU_ENTRY_COLOR);
358 if (menu->selected == 0)
359 menu->selected = len - 1;
360 else
361 menu->selected--;
362 entry = (menu_entry_t *) g_list_nth_data (menu->entries, menu->selected);
364 while ((entry == NULL) || (entry->command == CK_IgnoreKey));
366 menubar_paint_idx (menubar, menu->selected, MENU_SELECTED_COLOR);
369 /* --------------------------------------------------------------------------------------------- */
371 static void
372 menubar_first (WMenuBar * menubar)
374 Menu *menu = g_list_nth_data (menubar->menu, menubar->selected);
375 menu_entry_t *entry;
377 if (menu->selected == 0)
378 return;
380 menubar_paint_idx (menubar, menu->selected, MENU_ENTRY_COLOR);
382 menu->selected = 0;
384 while (TRUE)
386 entry = (menu_entry_t *) g_list_nth_data (menu->entries, menu->selected);
388 if ((entry == NULL) || (entry->command == CK_IgnoreKey))
389 menu->selected++;
390 else
391 break;
394 menubar_paint_idx (menubar, menu->selected, MENU_SELECTED_COLOR);
397 /* --------------------------------------------------------------------------------------------- */
399 static void
400 menubar_last (WMenuBar * menubar)
402 Menu *menu = g_list_nth_data (menubar->menu, menubar->selected);
403 const unsigned int len = g_list_length (menu->entries);
404 menu_entry_t *entry;
406 if (menu->selected == len - 1)
407 return;
409 menubar_paint_idx (menubar, menu->selected, MENU_ENTRY_COLOR);
411 menu->selected = len;
415 menu->selected--;
416 entry = (menu_entry_t *) g_list_nth_data (menu->entries, menu->selected);
418 while ((entry == NULL) || (entry->command == CK_IgnoreKey));
420 menubar_paint_idx (menubar, menu->selected, MENU_SELECTED_COLOR);
423 /* --------------------------------------------------------------------------------------------- */
425 static int
426 menubar_handle_key (WMenuBar * menubar, int key)
428 /* Lowercase */
429 if (isascii (key))
430 key = g_ascii_tolower (key);
432 if (is_abort_char (key))
434 menubar_finish (menubar);
435 return 1;
438 /* menubar help or menubar navigation */
439 switch (key)
441 case KEY_F (1):
443 ev_help_t event_data = { NULL, NULL };
445 if (menubar->is_dropped)
446 event_data.node =
447 ((Menu *) g_list_nth_data (menubar->menu, menubar->selected))->help_node;
448 else
449 event_data.node = "[Menu Bar]";
451 mc_event_raise (MCEVENT_GROUP_CORE, "help", &event_data);
452 menubar_draw (menubar);
453 return 1;
455 case KEY_LEFT:
456 case XCTRL ('b'):
457 menubar_left (menubar);
458 return 1;
460 case KEY_RIGHT:
461 case XCTRL ('f'):
462 menubar_right (menubar);
463 return 1;
466 if (!menubar->is_dropped)
468 GList *i;
470 /* drop menu by hotkey */
471 for (i = menubar->menu; i != NULL; i = g_list_next (i))
473 Menu *menu = i->data;
475 if ((menu->text.hotkey != NULL) && (key == g_ascii_tolower (menu->text.hotkey[0])))
477 menubar_drop (menubar, g_list_position (menubar->menu, i));
478 return 1;
482 /* drop menu by Enter or Dowwn key */
483 if (key == KEY_ENTER || key == XCTRL ('n') || key == KEY_DOWN || key == '\n')
484 menubar_drop (menubar, menubar->selected);
486 return 1;
490 Menu *menu = g_list_nth_data (menubar->menu, menubar->selected);
491 GList *i;
493 /* execute menu command by hotkey */
494 for (i = menu->entries; i != NULL; i = g_list_next (i))
496 const menu_entry_t *entry = i->data;
498 if ((entry != NULL) && (entry->command != CK_IgnoreKey)
499 && (entry->text.hotkey != NULL) && (key == g_ascii_tolower (entry->text.hotkey[0])))
501 menu->selected = g_list_position (menu->entries, i);
502 menubar_execute (menubar);
503 return 1;
507 /* menu execute by Enter or menu navigation */
508 switch (key)
510 case KEY_ENTER:
511 case '\n':
512 menubar_execute (menubar);
513 return 1;
515 case KEY_HOME:
516 case ALT ('<'):
517 menubar_first (menubar);
518 break;
520 case KEY_END:
521 case ALT ('>'):
522 menubar_last (menubar);
523 break;
525 case KEY_DOWN:
526 case XCTRL ('n'):
527 menubar_down (menubar);
528 break;
530 case KEY_UP:
531 case XCTRL ('p'):
532 menubar_up (menubar);
533 break;
537 return 0;
540 /* --------------------------------------------------------------------------------------------- */
542 static cb_ret_t
543 menubar_callback (Widget * w, widget_msg_t msg, int parm)
545 WMenuBar *menubar = (WMenuBar *) w;
547 switch (msg)
549 /* We do not want the focus unless we have been activated */
550 case WIDGET_FOCUS:
551 if (!menubar->is_active)
552 return MSG_NOT_HANDLED;
554 /* Trick to get all the mouse events */
555 menubar->widget.lines = LINES;
557 /* Trick to get all of the hotkeys */
558 widget_want_hotkey (menubar->widget, 1);
559 menubar_draw (menubar);
560 return MSG_HANDLED;
562 /* We don't want the buttonbar to activate while using the menubar */
563 case WIDGET_HOTKEY:
564 case WIDGET_KEY:
565 if (menubar->is_active)
567 menubar_handle_key (menubar, parm);
568 return MSG_HANDLED;
570 return MSG_NOT_HANDLED;
572 case WIDGET_CURSOR:
573 /* Put the cursor in a suitable place */
574 return MSG_NOT_HANDLED;
576 case WIDGET_UNFOCUS:
577 return menubar->is_active ? MSG_NOT_HANDLED : MSG_HANDLED;
579 case WIDGET_DRAW:
580 if (menubar->is_visible)
582 menubar_draw (menubar);
583 return MSG_HANDLED;
585 /* fall through */
587 case WIDGET_RESIZED:
588 /* try show menu after screen resize */
589 send_message (w, WIDGET_FOCUS, 0);
590 return MSG_HANDLED;
593 case WIDGET_DESTROY:
594 menubar_set_menu (menubar, NULL);
595 return MSG_HANDLED;
597 default:
598 return default_proc (msg, parm);
602 /* --------------------------------------------------------------------------------------------- */
604 static int
605 menubar_event (Gpm_Event * event, void *data)
607 WMenuBar *menubar = (WMenuBar *) data;
608 Widget *w = (Widget *) data;
609 gboolean was_active = TRUE;
610 int left_x, right_x, bottom_y;
611 Menu *menu;
612 Gpm_Event local;
614 if (!mouse_global_in_widget (event, w))
615 return MOU_UNHANDLED;
617 /* ignore unsupported events */
618 if ((event->type & (GPM_UP | GPM_DOWN | GPM_DRAG)) == 0)
619 return MOU_NORMAL;
621 /* ignore wheel events if menu is inactive */
622 if (!menubar->is_active && ((event->buttons & (GPM_B_MIDDLE | GPM_B_UP | GPM_B_DOWN)) != 0))
623 return MOU_NORMAL;
625 if (!menubar->is_dropped)
627 menubar->previous_widget = dlg_get_current_widget_id (w->owner);
628 menubar->is_active = TRUE;
629 menubar->is_dropped = TRUE;
630 was_active = FALSE;
633 local = mouse_get_local (event, w);
635 /* Mouse operations on the menubar */
636 if (local.y == 1 || !was_active)
638 if ((local.type & GPM_UP) != 0)
639 return MOU_NORMAL;
641 /* wheel events on menubar */
642 if ((local.buttons & GPM_B_UP) != 0)
643 menubar_left (menubar);
644 else if ((local.buttons & GPM_B_DOWN) != 0)
645 menubar_right (menubar);
646 else
648 const unsigned int len = g_list_length (menubar->menu);
649 unsigned int new_selection = 0;
651 while ((new_selection < len)
652 && (local.x > ((Menu *) g_list_nth_data (menubar->menu,
653 new_selection))->start_x))
654 new_selection++;
656 if (new_selection != 0) /* Don't set the invalid value -1 */
657 new_selection--;
659 if (!was_active)
661 menubar->selected = new_selection;
662 dlg_select_widget (menubar);
664 else
666 menubar_remove (menubar);
667 menubar->selected = new_selection;
669 menubar_draw (menubar);
671 return MOU_NORMAL;
674 if (!menubar->is_dropped || (local.y < 2))
675 return MOU_NORMAL;
677 /* middle click -- everywhere */
678 if (((local.buttons & GPM_B_MIDDLE) != 0) && ((local.type & GPM_DOWN) != 0))
680 menubar_execute (menubar);
681 return MOU_NORMAL;
684 /* the mouse operation is on the menus or it is not */
685 menu = (Menu *) g_list_nth_data (menubar->menu, menubar->selected);
686 left_x = menu->start_x;
687 right_x = left_x + menu->max_entry_len + 3;
688 if (right_x > menubar->widget.cols)
690 left_x = menubar->widget.cols - menu->max_entry_len - 3;
691 right_x = menubar->widget.cols;
694 bottom_y = g_list_length (menu->entries) + 3;
696 if ((local.x >= left_x) && (local.x <= right_x) && (local.y <= bottom_y))
698 int pos = local.y - 3;
699 const menu_entry_t *entry = g_list_nth_data (menu->entries, pos);
701 /* mouse wheel */
702 if ((local.buttons & GPM_B_UP) != 0 && (local.type & GPM_DOWN) != 0)
704 menubar_up (menubar);
705 return MOU_NORMAL;
707 if ((local.buttons & GPM_B_DOWN) != 0 && (local.type & GPM_DOWN) != 0)
709 menubar_down (menubar);
710 return MOU_NORMAL;
713 /* ignore events above and below dropped down menu */
714 if ((pos < 0) || (pos >= bottom_y - 3))
715 return MOU_NORMAL;
717 if ((entry != NULL) && (entry->command != CK_IgnoreKey))
719 menubar_paint_idx (menubar, menu->selected, MENU_ENTRY_COLOR);
720 menu->selected = pos;
721 menubar_paint_idx (menubar, menu->selected, MENU_SELECTED_COLOR);
723 if ((event->type & GPM_UP) != 0)
724 menubar_execute (menubar);
727 else if (((local.type & GPM_DOWN) != 0) && ((local.buttons & (GPM_B_UP | GPM_B_DOWN)) == 0))
729 /* use click not wheel to close menu */
730 menubar_finish (menubar);
733 return MOU_NORMAL;
736 /* --------------------------------------------------------------------------------------------- */
737 /*** public functions ****************************************************************************/
738 /* --------------------------------------------------------------------------------------------- */
740 menu_entry_t *
741 menu_entry_create (const char *name, unsigned long command)
743 menu_entry_t *entry;
745 entry = g_new (menu_entry_t, 1);
746 entry->first_letter = ' ';
747 entry->text = parse_hotkey (name);
748 entry->command = command;
749 entry->shortcut = NULL;
751 return entry;
754 /* --------------------------------------------------------------------------------------------- */
756 void
757 menu_entry_free (menu_entry_t * entry)
759 if (entry != NULL)
761 release_hotkey (entry->text);
762 g_free (entry->shortcut);
763 g_free (entry);
767 /* --------------------------------------------------------------------------------------------- */
769 Menu *
770 create_menu (const char *name, GList * entries, const char *help_node)
772 Menu *menu;
774 menu = g_new (Menu, 1);
775 menu->start_x = 0;
776 menu->text = parse_hotkey (name);
777 menu->entries = entries;
778 menu->max_entry_len = 1;
779 menu->max_hotkey_len = 0;
780 menu->selected = 0;
781 menu->help_node = g_strdup (help_node);
783 return menu;
786 /* --------------------------------------------------------------------------------------------- */
788 void
789 menu_set_name (Menu * menu, const char *name)
791 release_hotkey (menu->text);
792 menu->text = parse_hotkey (name);
795 /* --------------------------------------------------------------------------------------------- */
797 void
798 destroy_menu (Menu * menu)
800 release_hotkey (menu->text);
801 g_list_foreach (menu->entries, (GFunc) menu_entry_free, NULL);
802 g_list_free (menu->entries);
803 g_free (menu->help_node);
804 g_free (menu);
807 /* --------------------------------------------------------------------------------------------- */
809 WMenuBar *
810 menubar_new (int y, int x, int cols, GList * menu)
812 WMenuBar *menubar;
814 menubar = g_new0 (WMenuBar, 1);
815 init_widget (&menubar->widget, y, x, 1, cols, menubar_callback, menubar_event);
816 widget_want_cursor (menubar->widget, FALSE);
817 menubar->is_visible = TRUE; /* by default */
818 menubar_set_menu (menubar, menu);
820 return menubar;
823 /* --------------------------------------------------------------------------------------------- */
825 void
826 menubar_set_menu (WMenuBar * menubar, GList * menu)
828 /* delete previous menu */
829 if (menubar->menu != NULL)
831 g_list_foreach (menubar->menu, (GFunc) destroy_menu, NULL);
832 g_list_free (menubar->menu);
834 /* add new menu */
835 menubar->is_active = FALSE;
836 menubar->is_dropped = FALSE;
837 menubar->menu = menu;
838 menubar->selected = 0;
839 menubar_arrange (menubar);
842 /* --------------------------------------------------------------------------------------------- */
844 void
845 menubar_add_menu (WMenuBar * menubar, Menu * menu)
847 if (menu != NULL)
849 menu_arrange (menu, menubar->widget.owner->get_shortcut);
850 menubar->menu = g_list_append (menubar->menu, menu);
853 menubar_arrange (menubar);
856 /* --------------------------------------------------------------------------------------------- */
858 * Properly space menubar items. Should be called when menubar is created
859 * and also when widget width is changed (i.e. upon xterm resize).
862 void
863 menubar_arrange (WMenuBar * menubar)
865 int start_x = 1;
866 GList *i;
867 int gap;
869 if (menubar->menu == NULL)
870 return;
872 gap = menubar->widget.cols - 2;
874 /* First, calculate gap between items... */
875 for (i = menubar->menu; i != NULL; i = g_list_next (i))
877 Menu *menu = (Menu *) i->data;
878 /* preserve length here, to be used below */
879 menu->start_x = hotkey_width (menu->text) + 2;
880 gap -= menu->start_x;
883 if (g_list_next (menubar->menu) == NULL)
884 gap = 1;
885 else
886 gap /= (g_list_length (menubar->menu) - 1);
888 if (gap <= 0)
890 /* We are out of luck - window is too narrow... */
891 gap = 1;
893 else if (gap >= 3)
894 gap = 3;
896 /* ...and now fix start positions of menubar items */
897 for (i = menubar->menu; i != NULL; i = g_list_next (i))
899 Menu *menu = (Menu *) i->data;
900 int len = menu->start_x;
902 menu->start_x = start_x;
903 start_x += len + gap;
907 /* --------------------------------------------------------------------------------------------- */
908 /** Find MenuBar widget in the dialog */
910 WMenuBar *
911 find_menubar (const Dlg_head * h)
913 return (WMenuBar *) find_widget_type (h, menubar_callback);
916 /* --------------------------------------------------------------------------------------------- */