Menubar: ignore GPM_UP event.
[midnight-commander.git] / lib / widget / menu.c
blobabf64382e22da96a12cce5b44e6e096fc081cbc9
1 /*
2 Pulldown menu code
4 Copyright (C) 1994, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
5 2007, 2009, 2011, 2012
6 The Free Software Foundation, Inc.
8 Written by:
9 Andrew Borodin <aborodin@vmail.ru>, 2012
11 This file is part of the Midnight Commander.
13 The Midnight Commander is free software: you can redistribute it
14 and/or modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation, either version 3 of the License,
16 or (at your option) any later version.
18 The Midnight Commander is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
23 You should have received a copy of the GNU General Public License
24 along with this program. If not, see <http://www.gnu.org/licenses/>.
27 /** \file menu.c
28 * \brief Source: pulldown menu code
31 #include <config.h>
33 #include <ctype.h>
34 #include <stdarg.h>
35 #include <string.h>
36 #include <sys/types.h>
38 #include "lib/global.h"
40 #include "lib/tty/tty.h"
41 #include "lib/skin.h"
42 #include "lib/tty/mouse.h"
43 #include "lib/tty/key.h" /* key macros */
44 #include "lib/strutil.h"
45 #include "lib/widget.h"
46 #include "lib/event.h" /* mc_event_raise() */
48 /*** global variables ****************************************************************************/
50 /*** file scope macro definitions ****************************************************************/
52 /*** file scope type declarations ****************************************************************/
54 /*** file scope variables ************************************************************************/
56 static cb_ret_t menubar_callback (Widget * w, widget_msg_t msg, int parm);
58 /*** file scope functions ************************************************************************/
59 /* --------------------------------------------------------------------------------------------- */
61 static void
62 menu_arrange (Menu * menu, dlg_shortcut_str get_shortcut)
64 if (menu != NULL)
66 GList *i;
67 size_t max_shortcut_len = 0;
69 menu->max_entry_len = 1;
70 menu->max_hotkey_len = 1;
72 for (i = menu->entries; i != NULL; i = g_list_next (i))
74 menu_entry_t *entry = i->data;
76 if (entry != NULL)
78 size_t len;
80 len = (size_t) hotkey_width (entry->text);
81 menu->max_hotkey_len = max (menu->max_hotkey_len, len);
83 if (get_shortcut != NULL)
84 entry->shortcut = get_shortcut (entry->command);
86 if (entry->shortcut != NULL)
88 len = (size_t) str_term_width1 (entry->shortcut);
89 max_shortcut_len = max (max_shortcut_len, len);
94 menu->max_entry_len = menu->max_hotkey_len + max_shortcut_len;
98 /* --------------------------------------------------------------------------------------------- */
100 static void
101 menubar_paint_idx (WMenuBar * menubar, unsigned int idx, int color)
103 const Menu *menu = g_list_nth_data (menubar->menu, menubar->selected);
104 const menu_entry_t *entry = g_list_nth_data (menu->entries, idx);
105 const int y = 2 + idx;
106 int x = menu->start_x;
108 if (x + menu->max_entry_len + 4 > (gsize) menubar->widget.cols)
109 x = menubar->widget.cols - menu->max_entry_len - 4;
111 if (entry == NULL)
113 /* menu separator */
114 tty_setcolor (MENU_ENTRY_COLOR);
116 widget_move (&menubar->widget, y, x - 1);
117 tty_print_alt_char (ACS_LTEE, FALSE);
119 tty_draw_hline (menubar->widget.y + y, menubar->widget.x + x,
120 ACS_HLINE, menu->max_entry_len + 3);
122 widget_move (&menubar->widget, y, x + menu->max_entry_len + 3);
123 tty_print_alt_char (ACS_RTEE, FALSE);
125 else
127 int yt, xt;
129 /* menu text */
130 tty_setcolor (color);
131 widget_move (&menubar->widget, y, x);
132 tty_print_char ((unsigned char) entry->first_letter);
133 tty_getyx (&yt, &xt);
134 tty_draw_hline (yt, xt, ' ', menu->max_entry_len + 2); /* clear line */
135 tty_print_string (entry->text.start);
137 if (entry->text.hotkey != NULL)
139 tty_setcolor (color == MENU_SELECTED_COLOR ? MENU_HOTSEL_COLOR : MENU_HOT_COLOR);
140 tty_print_string (entry->text.hotkey);
141 tty_setcolor (color);
144 if (entry->text.end != NULL)
145 tty_print_string (entry->text.end);
147 if (entry->shortcut != NULL)
149 widget_move (&menubar->widget, y, x + menu->max_hotkey_len + 3);
150 tty_print_string (entry->shortcut);
153 /* move cursor to the start of entry text */
154 widget_move (&menubar->widget, y, x + 1);
158 /* --------------------------------------------------------------------------------------------- */
160 static void
161 menubar_draw_drop (WMenuBar * menubar)
163 const Menu *menu = g_list_nth_data (menubar->menu, menubar->selected);
164 const unsigned int count = g_list_length (menu->entries);
165 int column = menu->start_x - 1;
166 unsigned int i;
168 if (column + menu->max_entry_len + 5 > (gsize) menubar->widget.cols)
169 column = menubar->widget.cols - menu->max_entry_len - 5;
171 tty_setcolor (MENU_ENTRY_COLOR);
172 draw_box (menubar->widget.owner,
173 menubar->widget.y + 1, menubar->widget.x + column,
174 count + 2, menu->max_entry_len + 5, FALSE);
176 for (i = 0; i < count; i++)
177 menubar_paint_idx (menubar, i,
178 i == menu->selected ? MENU_SELECTED_COLOR : MENU_ENTRY_COLOR);
181 /* --------------------------------------------------------------------------------------------- */
183 static void
184 menubar_set_color (WMenuBar * menubar, gboolean current, gboolean hotkey)
186 if (!menubar->is_active)
187 tty_setcolor (MENU_INACTIVE_COLOR);
188 else if (current)
189 tty_setcolor (hotkey ? MENU_HOTSEL_COLOR : MENU_SELECTED_COLOR);
190 else
191 tty_setcolor (hotkey ? MENU_HOT_COLOR : MENU_ENTRY_COLOR);
194 /* --------------------------------------------------------------------------------------------- */
196 static void
197 menubar_draw (WMenuBar * menubar)
199 GList *i;
201 /* First draw the complete menubar */
202 tty_setcolor (menubar->is_active ? MENU_ENTRY_COLOR : MENU_INACTIVE_COLOR);
203 tty_draw_hline (menubar->widget.y, menubar->widget.x, ' ', menubar->widget.cols);
205 /* Now each one of the entries */
206 for (i = menubar->menu; i != NULL; i = g_list_next (i))
208 Menu *menu = i->data;
209 gboolean is_selected = (menubar->selected == (gsize) g_list_position (menubar->menu, i));
211 menubar_set_color (menubar, is_selected, FALSE);
212 widget_move (&menubar->widget, 0, menu->start_x);
214 tty_print_char (' ');
215 tty_print_string (menu->text.start);
217 if (menu->text.hotkey != NULL)
219 menubar_set_color (menubar, is_selected, TRUE);
220 tty_print_string (menu->text.hotkey);
221 menubar_set_color (menubar, is_selected, FALSE);
224 if (menu->text.end != NULL)
225 tty_print_string (menu->text.end);
227 tty_print_char (' ');
230 if (menubar->is_dropped)
231 menubar_draw_drop (menubar);
232 else
233 widget_move (&menubar->widget, 0,
234 ((Menu *) g_list_nth_data (menubar->menu, menubar->selected))->start_x);
237 /* --------------------------------------------------------------------------------------------- */
239 static void
240 menubar_remove (WMenuBar * menubar)
242 Dlg_head *h;
244 if (!menubar->is_dropped)
245 return;
247 /* HACK: before refresh the dialog, change the current widget to keep the order
248 of overlapped widgets. This is useful in multi-window editor.
249 In general, menubar should be a special object, not an ordinary widget
250 in the current dialog. */
251 h = menubar->widget.owner;
252 h->current = g_list_find (h->widgets, dlg_find_by_id (h, menubar->previous_widget));
254 menubar->is_dropped = FALSE;
255 do_refresh ();
256 menubar->is_dropped = TRUE;
258 /* restore current widget */
259 h->current = g_list_find (h->widgets, menubar);
262 /* --------------------------------------------------------------------------------------------- */
264 static void
265 menubar_left (WMenuBar * menubar)
267 menubar_remove (menubar);
268 if (menubar->selected == 0)
269 menubar->selected = g_list_length (menubar->menu) - 1;
270 else
271 menubar->selected--;
272 menubar_draw (menubar);
275 /* --------------------------------------------------------------------------------------------- */
277 static void
278 menubar_right (WMenuBar * menubar)
280 menubar_remove (menubar);
281 menubar->selected = (menubar->selected + 1) % g_list_length (menubar->menu);
282 menubar_draw (menubar);
285 /* --------------------------------------------------------------------------------------------- */
287 static void
288 menubar_finish (WMenuBar * menubar)
290 menubar->is_dropped = FALSE;
291 menubar->is_active = FALSE;
292 menubar->widget.lines = 1;
293 widget_want_hotkey (menubar->widget, 0);
295 dlg_select_by_id (menubar->widget.owner, menubar->previous_widget);
296 do_refresh ();
299 /* --------------------------------------------------------------------------------------------- */
301 static void
302 menubar_drop (WMenuBar * menubar, unsigned int selected)
304 menubar->is_dropped = TRUE;
305 menubar->selected = selected;
306 menubar_draw (menubar);
309 /* --------------------------------------------------------------------------------------------- */
311 static void
312 menubar_execute (WMenuBar * menubar)
314 const Menu *menu = g_list_nth_data (menubar->menu, menubar->selected);
315 const menu_entry_t *entry = g_list_nth_data (menu->entries, menu->selected);
317 if ((entry != NULL) && (entry->command != CK_IgnoreKey))
319 mc_global.widget.is_right = (menubar->selected != 0);
320 menubar_finish (menubar);
321 menubar->widget.owner->callback (menubar->widget.owner, &menubar->widget,
322 DLG_ACTION, entry->command, NULL);
323 do_refresh ();
327 /* --------------------------------------------------------------------------------------------- */
329 static void
330 menubar_down (WMenuBar * menubar)
332 Menu *menu = g_list_nth_data (menubar->menu, menubar->selected);
333 const unsigned int len = g_list_length (menu->entries);
334 menu_entry_t *entry;
336 menubar_paint_idx (menubar, menu->selected, MENU_ENTRY_COLOR);
340 menu->selected = (menu->selected + 1) % len;
341 entry = (menu_entry_t *) g_list_nth_data (menu->entries, menu->selected);
343 while ((entry == NULL) || (entry->command == CK_IgnoreKey));
345 menubar_paint_idx (menubar, menu->selected, MENU_SELECTED_COLOR);
348 /* --------------------------------------------------------------------------------------------- */
350 static void
351 menubar_up (WMenuBar * menubar)
353 Menu *menu = g_list_nth_data (menubar->menu, menubar->selected);
354 const unsigned int len = g_list_length (menu->entries);
355 menu_entry_t *entry;
357 menubar_paint_idx (menubar, menu->selected, MENU_ENTRY_COLOR);
361 if (menu->selected == 0)
362 menu->selected = len - 1;
363 else
364 menu->selected--;
365 entry = (menu_entry_t *) g_list_nth_data (menu->entries, menu->selected);
367 while ((entry == NULL) || (entry->command == CK_IgnoreKey));
369 menubar_paint_idx (menubar, menu->selected, MENU_SELECTED_COLOR);
372 /* --------------------------------------------------------------------------------------------- */
374 static void
375 menubar_first (WMenuBar * menubar)
377 Menu *menu = g_list_nth_data (menubar->menu, menubar->selected);
378 menu_entry_t *entry;
380 if (menu->selected == 0)
381 return;
383 menubar_paint_idx (menubar, menu->selected, MENU_ENTRY_COLOR);
385 menu->selected = 0;
387 while (TRUE)
389 entry = (menu_entry_t *) g_list_nth_data (menu->entries, menu->selected);
391 if ((entry == NULL) || (entry->command == CK_IgnoreKey))
392 menu->selected++;
393 else
394 break;
397 menubar_paint_idx (menubar, menu->selected, MENU_SELECTED_COLOR);
400 /* --------------------------------------------------------------------------------------------- */
402 static void
403 menubar_last (WMenuBar * menubar)
405 Menu *menu = g_list_nth_data (menubar->menu, menubar->selected);
406 const unsigned int len = g_list_length (menu->entries);
407 menu_entry_t *entry;
409 if (menu->selected == len - 1)
410 return;
412 menubar_paint_idx (menubar, menu->selected, MENU_ENTRY_COLOR);
414 menu->selected = len;
418 menu->selected--;
419 entry = (menu_entry_t *) g_list_nth_data (menu->entries, menu->selected);
421 while ((entry == NULL) || (entry->command == CK_IgnoreKey));
423 menubar_paint_idx (menubar, menu->selected, MENU_SELECTED_COLOR);
426 /* --------------------------------------------------------------------------------------------- */
428 static int
429 menubar_handle_key (WMenuBar * menubar, int key)
431 /* Lowercase */
432 if (isascii (key))
433 key = g_ascii_tolower (key);
435 if (is_abort_char (key))
437 menubar_finish (menubar);
438 return 1;
441 /* menubar help or menubar navigation */
442 switch (key)
444 case KEY_F (1):
446 ev_help_t event_data = { NULL, NULL };
448 if (menubar->is_dropped)
449 event_data.node =
450 ((Menu *) g_list_nth_data (menubar->menu, menubar->selected))->help_node;
451 else
452 event_data.node = "[Menu Bar]";
454 mc_event_raise (MCEVENT_GROUP_CORE, "help", &event_data);
455 menubar_draw (menubar);
456 return 1;
458 case KEY_LEFT:
459 case XCTRL ('b'):
460 menubar_left (menubar);
461 return 1;
463 case KEY_RIGHT:
464 case XCTRL ('f'):
465 menubar_right (menubar);
466 return 1;
469 if (!menubar->is_dropped)
471 GList *i;
473 /* drop menu by hotkey */
474 for (i = menubar->menu; i != NULL; i = g_list_next (i))
476 Menu *menu = i->data;
478 if ((menu->text.hotkey != NULL) && (key == g_ascii_tolower (menu->text.hotkey[0])))
480 menubar_drop (menubar, g_list_position (menubar->menu, i));
481 return 1;
485 /* drop menu by Enter or Dowwn key */
486 if (key == KEY_ENTER || key == XCTRL ('n') || key == KEY_DOWN || key == '\n')
487 menubar_drop (menubar, menubar->selected);
489 return 1;
493 Menu *menu = g_list_nth_data (menubar->menu, menubar->selected);
494 GList *i;
496 /* execute menu command by hotkey */
497 for (i = menu->entries; i != NULL; i = g_list_next (i))
499 const menu_entry_t *entry = i->data;
501 if ((entry != NULL) && (entry->command != CK_IgnoreKey)
502 && (entry->text.hotkey != NULL) && (key == g_ascii_tolower (entry->text.hotkey[0])))
504 menu->selected = g_list_position (menu->entries, i);
505 menubar_execute (menubar);
506 return 1;
510 /* menu execute by Enter or menu navigation */
511 switch (key)
513 case KEY_ENTER:
514 case '\n':
515 menubar_execute (menubar);
516 return 1;
518 case KEY_HOME:
519 case ALT ('<'):
520 menubar_first (menubar);
521 break;
523 case KEY_END:
524 case ALT ('>'):
525 menubar_last (menubar);
526 break;
528 case KEY_DOWN:
529 case XCTRL ('n'):
530 menubar_down (menubar);
531 break;
533 case KEY_UP:
534 case XCTRL ('p'):
535 menubar_up (menubar);
536 break;
540 return 0;
543 /* --------------------------------------------------------------------------------------------- */
545 static cb_ret_t
546 menubar_callback (Widget * w, widget_msg_t msg, int parm)
548 WMenuBar *menubar = (WMenuBar *) w;
550 switch (msg)
552 /* We do not want the focus unless we have been activated */
553 case WIDGET_FOCUS:
554 if (!menubar->is_active)
555 return MSG_NOT_HANDLED;
557 /* Trick to get all the mouse events */
558 menubar->widget.lines = LINES;
560 /* Trick to get all of the hotkeys */
561 widget_want_hotkey (menubar->widget, 1);
562 menubar_draw (menubar);
563 return MSG_HANDLED;
565 /* We don't want the buttonbar to activate while using the menubar */
566 case WIDGET_HOTKEY:
567 case WIDGET_KEY:
568 if (menubar->is_active)
570 menubar_handle_key (menubar, parm);
571 return MSG_HANDLED;
573 return MSG_NOT_HANDLED;
575 case WIDGET_CURSOR:
576 /* Put the cursor in a suitable place */
577 return MSG_NOT_HANDLED;
579 case WIDGET_UNFOCUS:
580 return menubar->is_active ? MSG_NOT_HANDLED : MSG_HANDLED;
582 case WIDGET_DRAW:
583 if (menubar->is_visible)
585 menubar_draw (menubar);
586 return MSG_HANDLED;
588 /* fall through */
590 case WIDGET_RESIZED:
591 /* try show menu after screen resize */
592 send_message (w, WIDGET_FOCUS, 0);
593 return MSG_HANDLED;
596 case WIDGET_DESTROY:
597 menubar_set_menu (menubar, NULL);
598 return MSG_HANDLED;
600 default:
601 return default_proc (msg, parm);
605 /* --------------------------------------------------------------------------------------------- */
607 static int
608 menubar_event (Gpm_Event * event, void *data)
610 WMenuBar *menubar = (WMenuBar *) data;
611 Widget *w = (Widget *) data;
612 gboolean was_active = TRUE;
613 int left_x, right_x, bottom_y;
614 Menu *menu;
615 Gpm_Event local;
617 if (!mouse_global_in_widget (event, w))
618 return MOU_UNHANDLED;
620 /* ignore unsupported events */
621 if ((event->type & (GPM_UP | GPM_DOWN | GPM_DRAG)) == 0)
622 return MOU_NORMAL;
624 /* ignore wheel events if menu is inactive */
625 if (!menubar->is_active && ((event->buttons & (GPM_B_MIDDLE | GPM_B_UP | GPM_B_DOWN)) != 0))
626 return MOU_NORMAL;
628 local = mouse_get_local (event, w);
630 if (local.y == 1 && (local.type & GPM_UP) != 0)
631 return MOU_NORMAL;
633 if (!menubar->is_dropped)
635 menubar->previous_widget = dlg_get_current_widget_id (w->owner);
636 menubar->is_active = TRUE;
637 menubar->is_dropped = TRUE;
638 was_active = FALSE;
641 /* Mouse operations on the menubar */
642 if (local.y == 1 || !was_active)
644 /* wheel events on menubar */
645 if ((local.buttons & GPM_B_UP) != 0)
646 menubar_left (menubar);
647 else if ((local.buttons & GPM_B_DOWN) != 0)
648 menubar_right (menubar);
649 else
651 const unsigned int len = g_list_length (menubar->menu);
652 unsigned int new_selection = 0;
654 while ((new_selection < len)
655 && (local.x > ((Menu *) g_list_nth_data (menubar->menu,
656 new_selection))->start_x))
657 new_selection++;
659 if (new_selection != 0) /* Don't set the invalid value -1 */
660 new_selection--;
662 if (!was_active)
664 menubar->selected = new_selection;
665 dlg_select_widget (menubar);
667 else
669 menubar_remove (menubar);
670 menubar->selected = new_selection;
672 menubar_draw (menubar);
674 return MOU_NORMAL;
677 if (!menubar->is_dropped || (local.y < 2))
678 return MOU_NORMAL;
680 /* middle click -- everywhere */
681 if (((local.buttons & GPM_B_MIDDLE) != 0) && ((local.type & GPM_DOWN) != 0))
683 menubar_execute (menubar);
684 return MOU_NORMAL;
687 /* the mouse operation is on the menus or it is not */
688 menu = (Menu *) g_list_nth_data (menubar->menu, menubar->selected);
689 left_x = menu->start_x;
690 right_x = left_x + menu->max_entry_len + 3;
691 if (right_x > menubar->widget.cols)
693 left_x = menubar->widget.cols - menu->max_entry_len - 3;
694 right_x = menubar->widget.cols;
697 bottom_y = g_list_length (menu->entries) + 3;
699 if ((local.x >= left_x) && (local.x <= right_x) && (local.y <= bottom_y))
701 int pos = local.y - 3;
702 const menu_entry_t *entry = g_list_nth_data (menu->entries, pos);
704 /* mouse wheel */
705 if ((local.buttons & GPM_B_UP) != 0 && (local.type & GPM_DOWN) != 0)
707 menubar_up (menubar);
708 return MOU_NORMAL;
710 if ((local.buttons & GPM_B_DOWN) != 0 && (local.type & GPM_DOWN) != 0)
712 menubar_down (menubar);
713 return MOU_NORMAL;
716 /* ignore events above and below dropped down menu */
717 if ((pos < 0) || (pos >= bottom_y - 3))
718 return MOU_NORMAL;
720 if ((entry != NULL) && (entry->command != CK_IgnoreKey))
722 menubar_paint_idx (menubar, menu->selected, MENU_ENTRY_COLOR);
723 menu->selected = pos;
724 menubar_paint_idx (menubar, menu->selected, MENU_SELECTED_COLOR);
726 if ((event->type & GPM_UP) != 0)
727 menubar_execute (menubar);
730 else if (((local.type & GPM_DOWN) != 0) && ((local.buttons & (GPM_B_UP | GPM_B_DOWN)) == 0))
732 /* use click not wheel to close menu */
733 menubar_finish (menubar);
736 return MOU_NORMAL;
739 /* --------------------------------------------------------------------------------------------- */
740 /*** public functions ****************************************************************************/
741 /* --------------------------------------------------------------------------------------------- */
743 menu_entry_t *
744 menu_entry_create (const char *name, unsigned long command)
746 menu_entry_t *entry;
748 entry = g_new (menu_entry_t, 1);
749 entry->first_letter = ' ';
750 entry->text = parse_hotkey (name);
751 entry->command = command;
752 entry->shortcut = NULL;
754 return entry;
757 /* --------------------------------------------------------------------------------------------- */
759 void
760 menu_entry_free (menu_entry_t * entry)
762 if (entry != NULL)
764 release_hotkey (entry->text);
765 g_free (entry->shortcut);
766 g_free (entry);
770 /* --------------------------------------------------------------------------------------------- */
772 Menu *
773 create_menu (const char *name, GList * entries, const char *help_node)
775 Menu *menu;
777 menu = g_new (Menu, 1);
778 menu->start_x = 0;
779 menu->text = parse_hotkey (name);
780 menu->entries = entries;
781 menu->max_entry_len = 1;
782 menu->max_hotkey_len = 0;
783 menu->selected = 0;
784 menu->help_node = g_strdup (help_node);
786 return menu;
789 /* --------------------------------------------------------------------------------------------- */
791 void
792 menu_set_name (Menu * menu, const char *name)
794 release_hotkey (menu->text);
795 menu->text = parse_hotkey (name);
798 /* --------------------------------------------------------------------------------------------- */
800 void
801 destroy_menu (Menu * menu)
803 release_hotkey (menu->text);
804 g_list_foreach (menu->entries, (GFunc) menu_entry_free, NULL);
805 g_list_free (menu->entries);
806 g_free (menu->help_node);
807 g_free (menu);
810 /* --------------------------------------------------------------------------------------------- */
812 WMenuBar *
813 menubar_new (int y, int x, int cols, GList * menu)
815 WMenuBar *menubar;
817 menubar = g_new0 (WMenuBar, 1);
818 init_widget (&menubar->widget, y, x, 1, cols, menubar_callback, menubar_event);
819 widget_want_cursor (menubar->widget, FALSE);
820 menubar->is_visible = TRUE; /* by default */
821 menubar_set_menu (menubar, menu);
823 return menubar;
826 /* --------------------------------------------------------------------------------------------- */
828 void
829 menubar_set_menu (WMenuBar * menubar, GList * menu)
831 /* delete previous menu */
832 if (menubar->menu != NULL)
834 g_list_foreach (menubar->menu, (GFunc) destroy_menu, NULL);
835 g_list_free (menubar->menu);
837 /* add new menu */
838 menubar->is_active = FALSE;
839 menubar->is_dropped = FALSE;
840 menubar->menu = menu;
841 menubar->selected = 0;
842 menubar_arrange (menubar);
845 /* --------------------------------------------------------------------------------------------- */
847 void
848 menubar_add_menu (WMenuBar * menubar, Menu * menu)
850 if (menu != NULL)
852 menu_arrange (menu, menubar->widget.owner->get_shortcut);
853 menubar->menu = g_list_append (menubar->menu, menu);
856 menubar_arrange (menubar);
859 /* --------------------------------------------------------------------------------------------- */
861 * Properly space menubar items. Should be called when menubar is created
862 * and also when widget width is changed (i.e. upon xterm resize).
865 void
866 menubar_arrange (WMenuBar * menubar)
868 int start_x = 1;
869 GList *i;
870 int gap;
872 if (menubar->menu == NULL)
873 return;
875 gap = menubar->widget.cols - 2;
877 /* First, calculate gap between items... */
878 for (i = menubar->menu; i != NULL; i = g_list_next (i))
880 Menu *menu = (Menu *) i->data;
881 /* preserve length here, to be used below */
882 menu->start_x = hotkey_width (menu->text) + 2;
883 gap -= menu->start_x;
886 if (g_list_next (menubar->menu) == NULL)
887 gap = 1;
888 else
889 gap /= (g_list_length (menubar->menu) - 1);
891 if (gap <= 0)
893 /* We are out of luck - window is too narrow... */
894 gap = 1;
896 else if (gap >= 3)
897 gap = 3;
899 /* ...and now fix start positions of menubar items */
900 for (i = menubar->menu; i != NULL; i = g_list_next (i))
902 Menu *menu = (Menu *) i->data;
903 int len = menu->start_x;
905 menu->start_x = start_x;
906 start_x += len + gap;
910 /* --------------------------------------------------------------------------------------------- */
911 /** Find MenuBar widget in the dialog */
913 WMenuBar *
914 find_menubar (const Dlg_head * h)
916 return (WMenuBar *) find_widget_type (h, menubar_callback);
919 /* --------------------------------------------------------------------------------------------- */