Aggressive use WIDGET macro.
[midnight-commander.git] / lib / widget / menu.c
blob61b32c928c7c024325829a4b83b80653c3c3b903
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 Widget *w = WIDGET (menubar);
104 const Menu *menu = g_list_nth_data (menubar->menu, menubar->selected);
105 const menu_entry_t *entry = g_list_nth_data (menu->entries, idx);
106 const int y = 2 + idx;
107 int x = menu->start_x;
109 if (x + menu->max_entry_len + 4 > (gsize) w->cols)
110 x = w->cols - menu->max_entry_len - 4;
112 if (entry == NULL)
114 /* menu separator */
115 tty_setcolor (MENU_ENTRY_COLOR);
117 widget_move (w, y, x - 1);
118 tty_print_alt_char (ACS_LTEE, FALSE);
119 tty_draw_hline (w->y + y, w->x + x, ACS_HLINE, menu->max_entry_len + 3);
120 widget_move (w, y, x + menu->max_entry_len + 3);
121 tty_print_alt_char (ACS_RTEE, FALSE);
123 else
125 int yt, xt;
127 /* menu text */
128 tty_setcolor (color);
129 widget_move (w, y, x);
130 tty_print_char ((unsigned char) entry->first_letter);
131 tty_getyx (&yt, &xt);
132 tty_draw_hline (yt, xt, ' ', menu->max_entry_len + 2); /* clear line */
133 tty_print_string (entry->text.start);
135 if (entry->text.hotkey != NULL)
137 tty_setcolor (color == MENU_SELECTED_COLOR ? MENU_HOTSEL_COLOR : MENU_HOT_COLOR);
138 tty_print_string (entry->text.hotkey);
139 tty_setcolor (color);
142 if (entry->text.end != NULL)
143 tty_print_string (entry->text.end);
145 if (entry->shortcut != NULL)
147 widget_move (w, y, x + menu->max_hotkey_len + 3);
148 tty_print_string (entry->shortcut);
151 /* move cursor to the start of entry text */
152 widget_move (w, y, x + 1);
156 /* --------------------------------------------------------------------------------------------- */
158 static void
159 menubar_draw_drop (WMenuBar * menubar)
161 Widget *w = WIDGET (menubar);
162 const Menu *menu = g_list_nth_data (menubar->menu, menubar->selected);
163 const unsigned int count = g_list_length (menu->entries);
164 int column = menu->start_x - 1;
165 unsigned int i;
167 if (column + menu->max_entry_len + 5 > (gsize) w->cols)
168 column = w->cols - menu->max_entry_len - 5;
170 tty_setcolor (MENU_ENTRY_COLOR);
171 draw_box (w->owner, w->y + 1, w->x + column, 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 Widget *w = WIDGET (menubar);
197 GList *i;
199 /* First draw the complete menubar */
200 tty_setcolor (menubar->is_active ? MENU_ENTRY_COLOR : MENU_INACTIVE_COLOR);
201 tty_draw_hline (w->y, w->x, ' ', w->cols);
203 /* Now each one of the entries */
204 for (i = menubar->menu; i != NULL; i = g_list_next (i))
206 Menu *menu = i->data;
207 gboolean is_selected = (menubar->selected == (gsize) g_list_position (menubar->menu, i));
209 menubar_set_color (menubar, is_selected, FALSE);
210 widget_move (w, 0, menu->start_x);
212 tty_print_char (' ');
213 tty_print_string (menu->text.start);
215 if (menu->text.hotkey != NULL)
217 menubar_set_color (menubar, is_selected, TRUE);
218 tty_print_string (menu->text.hotkey);
219 menubar_set_color (menubar, is_selected, FALSE);
222 if (menu->text.end != NULL)
223 tty_print_string (menu->text.end);
225 tty_print_char (' ');
228 if (menubar->is_dropped)
229 menubar_draw_drop (menubar);
230 else
231 widget_move (w, 0,
232 ((Menu *) g_list_nth_data (menubar->menu, menubar->selected))->start_x);
235 /* --------------------------------------------------------------------------------------------- */
237 static void
238 menubar_remove (WMenuBar * menubar)
240 Dlg_head *h;
242 if (!menubar->is_dropped)
243 return;
245 /* HACK: before refresh the dialog, change the current widget to keep the order
246 of overlapped widgets. This is useful in multi-window editor.
247 In general, menubar should be a special object, not an ordinary widget
248 in the current dialog. */
249 h = WIDGET (menubar)->owner;
250 h->current = g_list_find (h->widgets, dlg_find_by_id (h, menubar->previous_widget));
252 menubar->is_dropped = FALSE;
253 do_refresh ();
254 menubar->is_dropped = TRUE;
256 /* restore current widget */
257 h->current = g_list_find (h->widgets, menubar);
260 /* --------------------------------------------------------------------------------------------- */
262 static void
263 menubar_left (WMenuBar * menubar)
265 menubar_remove (menubar);
266 if (menubar->selected == 0)
267 menubar->selected = g_list_length (menubar->menu) - 1;
268 else
269 menubar->selected--;
270 menubar_draw (menubar);
273 /* --------------------------------------------------------------------------------------------- */
275 static void
276 menubar_right (WMenuBar * menubar)
278 menubar_remove (menubar);
279 menubar->selected = (menubar->selected + 1) % g_list_length (menubar->menu);
280 menubar_draw (menubar);
283 /* --------------------------------------------------------------------------------------------- */
285 static void
286 menubar_finish (WMenuBar * menubar)
288 Widget *w = WIDGET (menubar);
290 menubar->is_dropped = FALSE;
291 menubar->is_active = FALSE;
292 w->lines = 1;
293 widget_want_hotkey (w, 0);
295 dlg_select_by_id (w->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 Widget *w = WIDGET (menubar);
321 mc_global.widget.is_right = (menubar->selected != 0);
322 menubar_finish (menubar);
323 w->owner->callback (w->owner, w, DLG_ACTION, entry->command, NULL);
324 do_refresh ();
328 /* --------------------------------------------------------------------------------------------- */
330 static void
331 menubar_down (WMenuBar * menubar)
333 Menu *menu = g_list_nth_data (menubar->menu, menubar->selected);
334 const unsigned int len = g_list_length (menu->entries);
335 menu_entry_t *entry;
337 menubar_paint_idx (menubar, menu->selected, MENU_ENTRY_COLOR);
341 menu->selected = (menu->selected + 1) % len;
342 entry = (menu_entry_t *) g_list_nth_data (menu->entries, menu->selected);
344 while ((entry == NULL) || (entry->command == CK_IgnoreKey));
346 menubar_paint_idx (menubar, menu->selected, MENU_SELECTED_COLOR);
349 /* --------------------------------------------------------------------------------------------- */
351 static void
352 menubar_up (WMenuBar * menubar)
354 Menu *menu = g_list_nth_data (menubar->menu, menubar->selected);
355 const unsigned int len = g_list_length (menu->entries);
356 menu_entry_t *entry;
358 menubar_paint_idx (menubar, menu->selected, MENU_ENTRY_COLOR);
362 if (menu->selected == 0)
363 menu->selected = len - 1;
364 else
365 menu->selected--;
366 entry = (menu_entry_t *) g_list_nth_data (menu->entries, menu->selected);
368 while ((entry == NULL) || (entry->command == CK_IgnoreKey));
370 menubar_paint_idx (menubar, menu->selected, MENU_SELECTED_COLOR);
373 /* --------------------------------------------------------------------------------------------- */
375 static void
376 menubar_first (WMenuBar * menubar)
378 Menu *menu = g_list_nth_data (menubar->menu, menubar->selected);
379 menu_entry_t *entry;
381 if (menu->selected == 0)
382 return;
384 menubar_paint_idx (menubar, menu->selected, MENU_ENTRY_COLOR);
386 menu->selected = 0;
388 while (TRUE)
390 entry = (menu_entry_t *) g_list_nth_data (menu->entries, menu->selected);
392 if ((entry == NULL) || (entry->command == CK_IgnoreKey))
393 menu->selected++;
394 else
395 break;
398 menubar_paint_idx (menubar, menu->selected, MENU_SELECTED_COLOR);
401 /* --------------------------------------------------------------------------------------------- */
403 static void
404 menubar_last (WMenuBar * menubar)
406 Menu *menu = g_list_nth_data (menubar->menu, menubar->selected);
407 const unsigned int len = g_list_length (menu->entries);
408 menu_entry_t *entry;
410 if (menu->selected == len - 1)
411 return;
413 menubar_paint_idx (menubar, menu->selected, MENU_ENTRY_COLOR);
415 menu->selected = len;
419 menu->selected--;
420 entry = (menu_entry_t *) g_list_nth_data (menu->entries, menu->selected);
422 while ((entry == NULL) || (entry->command == CK_IgnoreKey));
424 menubar_paint_idx (menubar, menu->selected, MENU_SELECTED_COLOR);
427 /* --------------------------------------------------------------------------------------------- */
429 static int
430 menubar_handle_key (WMenuBar * menubar, int key)
432 /* Lowercase */
433 if (isascii (key))
434 key = g_ascii_tolower (key);
436 if (is_abort_char (key))
438 menubar_finish (menubar);
439 return 1;
442 /* menubar help or menubar navigation */
443 switch (key)
445 case KEY_F (1):
447 ev_help_t event_data = { NULL, NULL };
449 if (menubar->is_dropped)
450 event_data.node =
451 ((Menu *) g_list_nth_data (menubar->menu, menubar->selected))->help_node;
452 else
453 event_data.node = "[Menu Bar]";
455 mc_event_raise (MCEVENT_GROUP_CORE, "help", &event_data);
456 menubar_draw (menubar);
457 return 1;
459 case KEY_LEFT:
460 case XCTRL ('b'):
461 menubar_left (menubar);
462 return 1;
464 case KEY_RIGHT:
465 case XCTRL ('f'):
466 menubar_right (menubar);
467 return 1;
470 if (!menubar->is_dropped)
472 GList *i;
474 /* drop menu by hotkey */
475 for (i = menubar->menu; i != NULL; i = g_list_next (i))
477 Menu *menu = i->data;
479 if ((menu->text.hotkey != NULL) && (key == g_ascii_tolower (menu->text.hotkey[0])))
481 menubar_drop (menubar, g_list_position (menubar->menu, i));
482 return 1;
486 /* drop menu by Enter or Dowwn key */
487 if (key == KEY_ENTER || key == XCTRL ('n') || key == KEY_DOWN || key == '\n')
488 menubar_drop (menubar, menubar->selected);
490 return 1;
494 Menu *menu = g_list_nth_data (menubar->menu, menubar->selected);
495 GList *i;
497 /* execute menu command by hotkey */
498 for (i = menu->entries; i != NULL; i = g_list_next (i))
500 const menu_entry_t *entry = i->data;
502 if ((entry != NULL) && (entry->command != CK_IgnoreKey)
503 && (entry->text.hotkey != NULL) && (key == g_ascii_tolower (entry->text.hotkey[0])))
505 menu->selected = g_list_position (menu->entries, i);
506 menubar_execute (menubar);
507 return 1;
511 /* menu execute by Enter or menu navigation */
512 switch (key)
514 case KEY_ENTER:
515 case '\n':
516 menubar_execute (menubar);
517 return 1;
519 case KEY_HOME:
520 case ALT ('<'):
521 menubar_first (menubar);
522 break;
524 case KEY_END:
525 case ALT ('>'):
526 menubar_last (menubar);
527 break;
529 case KEY_DOWN:
530 case XCTRL ('n'):
531 menubar_down (menubar);
532 break;
534 case KEY_UP:
535 case XCTRL ('p'):
536 menubar_up (menubar);
537 break;
541 return 0;
544 /* --------------------------------------------------------------------------------------------- */
546 static cb_ret_t
547 menubar_callback (Widget * w, widget_msg_t msg, int parm)
549 WMenuBar *menubar = (WMenuBar *) w;
551 switch (msg)
553 /* We do not want the focus unless we have been activated */
554 case WIDGET_FOCUS:
555 if (!menubar->is_active)
556 return MSG_NOT_HANDLED;
558 /* Trick to get all the mouse events */
559 w->lines = LINES;
561 /* Trick to get all of the hotkeys */
562 widget_want_hotkey (w, 1);
563 menubar_draw (menubar);
564 return MSG_HANDLED;
566 /* We don't want the buttonbar to activate while using the menubar */
567 case WIDGET_HOTKEY:
568 case WIDGET_KEY:
569 if (menubar->is_active)
571 menubar_handle_key (menubar, parm);
572 return MSG_HANDLED;
574 return MSG_NOT_HANDLED;
576 case WIDGET_CURSOR:
577 /* Put the cursor in a suitable place */
578 return MSG_NOT_HANDLED;
580 case WIDGET_UNFOCUS:
581 return menubar->is_active ? MSG_NOT_HANDLED : MSG_HANDLED;
583 case WIDGET_DRAW:
584 if (menubar->is_visible)
586 menubar_draw (menubar);
587 return MSG_HANDLED;
589 /* fall through */
591 case WIDGET_RESIZED:
592 /* try show menu after screen resize */
593 send_message (w, WIDGET_FOCUS, 0);
594 return MSG_HANDLED;
597 case WIDGET_DESTROY:
598 menubar_set_menu (menubar, NULL);
599 return MSG_HANDLED;
601 default:
602 return default_proc (msg, parm);
606 /* --------------------------------------------------------------------------------------------- */
608 static int
609 menubar_event (Gpm_Event * event, void *data)
611 WMenuBar *menubar = (WMenuBar *) data;
612 Widget *w = WIDGET (data);
613 gboolean was_active = TRUE;
614 int left_x, right_x, bottom_y;
615 Menu *menu;
616 Gpm_Event local;
618 if (!mouse_global_in_widget (event, w))
619 return MOU_UNHANDLED;
621 /* ignore unsupported events */
622 if ((event->type & (GPM_UP | GPM_DOWN | GPM_DRAG)) == 0)
623 return MOU_NORMAL;
625 /* ignore wheel events if menu is inactive */
626 if (!menubar->is_active && ((event->buttons & (GPM_B_MIDDLE | GPM_B_UP | GPM_B_DOWN)) != 0))
627 return MOU_NORMAL;
629 local = mouse_get_local (event, w);
631 if (local.y == 1 && (local.type & GPM_UP) != 0)
632 return MOU_NORMAL;
634 if (!menubar->is_dropped)
636 menubar->previous_widget = dlg_get_current_widget_id (w->owner);
637 menubar->is_active = TRUE;
638 menubar->is_dropped = TRUE;
639 was_active = FALSE;
642 /* Mouse operations on the menubar */
643 if (local.y == 1 || !was_active)
645 /* wheel events on menubar */
646 if ((local.buttons & GPM_B_UP) != 0)
647 menubar_left (menubar);
648 else if ((local.buttons & GPM_B_DOWN) != 0)
649 menubar_right (menubar);
650 else
652 const unsigned int len = g_list_length (menubar->menu);
653 unsigned int new_selection = 0;
655 while ((new_selection < len)
656 && (local.x > ((Menu *) g_list_nth_data (menubar->menu,
657 new_selection))->start_x))
658 new_selection++;
660 if (new_selection != 0) /* Don't set the invalid value -1 */
661 new_selection--;
663 if (!was_active)
665 menubar->selected = new_selection;
666 dlg_select_widget (menubar);
668 else
670 menubar_remove (menubar);
671 menubar->selected = new_selection;
673 menubar_draw (menubar);
675 return MOU_NORMAL;
678 if (!menubar->is_dropped || (local.y < 2))
679 return MOU_NORMAL;
681 /* middle click -- everywhere */
682 if (((local.buttons & GPM_B_MIDDLE) != 0) && ((local.type & GPM_DOWN) != 0))
684 menubar_execute (menubar);
685 return MOU_NORMAL;
688 /* the mouse operation is on the menus or it is not */
689 menu = (Menu *) g_list_nth_data (menubar->menu, menubar->selected);
690 left_x = menu->start_x;
691 right_x = left_x + menu->max_entry_len + 3;
692 if (right_x > w->cols)
694 left_x = w->cols - menu->max_entry_len - 3;
695 right_x = w->cols;
698 bottom_y = g_list_length (menu->entries) + 3;
700 if ((local.x >= left_x) && (local.x <= right_x) && (local.y <= bottom_y))
702 int pos = local.y - 3;
703 const menu_entry_t *entry = g_list_nth_data (menu->entries, pos);
705 /* mouse wheel */
706 if ((local.buttons & GPM_B_UP) != 0 && (local.type & GPM_DOWN) != 0)
708 menubar_up (menubar);
709 return MOU_NORMAL;
711 if ((local.buttons & GPM_B_DOWN) != 0 && (local.type & GPM_DOWN) != 0)
713 menubar_down (menubar);
714 return MOU_NORMAL;
717 /* ignore events above and below dropped down menu */
718 if ((pos < 0) || (pos >= bottom_y - 3))
719 return MOU_NORMAL;
721 if ((entry != NULL) && (entry->command != CK_IgnoreKey))
723 menubar_paint_idx (menubar, menu->selected, MENU_ENTRY_COLOR);
724 menu->selected = pos;
725 menubar_paint_idx (menubar, menu->selected, MENU_SELECTED_COLOR);
727 if ((event->type & GPM_UP) != 0)
728 menubar_execute (menubar);
731 else if (((local.type & GPM_DOWN) != 0) && ((local.buttons & (GPM_B_UP | GPM_B_DOWN)) == 0))
733 /* use click not wheel to close menu */
734 menubar_finish (menubar);
737 return MOU_NORMAL;
740 /* --------------------------------------------------------------------------------------------- */
741 /*** public functions ****************************************************************************/
742 /* --------------------------------------------------------------------------------------------- */
744 menu_entry_t *
745 menu_entry_create (const char *name, unsigned long command)
747 menu_entry_t *entry;
749 entry = g_new (menu_entry_t, 1);
750 entry->first_letter = ' ';
751 entry->text = parse_hotkey (name);
752 entry->command = command;
753 entry->shortcut = NULL;
755 return entry;
758 /* --------------------------------------------------------------------------------------------- */
760 void
761 menu_entry_free (menu_entry_t * entry)
763 if (entry != NULL)
765 release_hotkey (entry->text);
766 g_free (entry->shortcut);
767 g_free (entry);
771 /* --------------------------------------------------------------------------------------------- */
773 Menu *
774 create_menu (const char *name, GList * entries, const char *help_node)
776 Menu *menu;
778 menu = g_new (Menu, 1);
779 menu->start_x = 0;
780 menu->text = parse_hotkey (name);
781 menu->entries = entries;
782 menu->max_entry_len = 1;
783 menu->max_hotkey_len = 0;
784 menu->selected = 0;
785 menu->help_node = g_strdup (help_node);
787 return menu;
790 /* --------------------------------------------------------------------------------------------- */
792 void
793 menu_set_name (Menu * menu, const char *name)
795 release_hotkey (menu->text);
796 menu->text = parse_hotkey (name);
799 /* --------------------------------------------------------------------------------------------- */
801 void
802 destroy_menu (Menu * menu)
804 release_hotkey (menu->text);
805 g_list_foreach (menu->entries, (GFunc) menu_entry_free, NULL);
806 g_list_free (menu->entries);
807 g_free (menu->help_node);
808 g_free (menu);
811 /* --------------------------------------------------------------------------------------------- */
813 WMenuBar *
814 menubar_new (int y, int x, int cols, GList * menu)
816 WMenuBar *menubar;
817 Widget *w;
819 menubar = g_new0 (WMenuBar, 1);
820 w = WIDGET (menubar);
821 init_widget (w, y, x, 1, cols, menubar_callback, menubar_event);
823 menubar->is_visible = TRUE; /* by default */
824 widget_want_cursor (w, FALSE);
825 menubar_set_menu (menubar, menu);
827 return menubar;
830 /* --------------------------------------------------------------------------------------------- */
832 void
833 menubar_set_menu (WMenuBar * menubar, GList * menu)
835 /* delete previous menu */
836 if (menubar->menu != NULL)
838 g_list_foreach (menubar->menu, (GFunc) destroy_menu, NULL);
839 g_list_free (menubar->menu);
841 /* add new menu */
842 menubar->is_active = FALSE;
843 menubar->is_dropped = FALSE;
844 menubar->menu = menu;
845 menubar->selected = 0;
846 menubar_arrange (menubar);
849 /* --------------------------------------------------------------------------------------------- */
851 void
852 menubar_add_menu (WMenuBar * menubar, Menu * menu)
854 if (menu != NULL)
856 menu_arrange (menu, WIDGET (menubar)->owner->get_shortcut);
857 menubar->menu = g_list_append (menubar->menu, menu);
860 menubar_arrange (menubar);
863 /* --------------------------------------------------------------------------------------------- */
865 * Properly space menubar items. Should be called when menubar is created
866 * and also when widget width is changed (i.e. upon xterm resize).
869 void
870 menubar_arrange (WMenuBar * menubar)
872 int start_x = 1;
873 GList *i;
874 int gap;
876 if (menubar->menu == NULL)
877 return;
879 gap = WIDGET (menubar)->cols - 2;
881 /* First, calculate gap between items... */
882 for (i = menubar->menu; i != NULL; i = g_list_next (i))
884 Menu *menu = (Menu *) i->data;
885 /* preserve length here, to be used below */
886 menu->start_x = hotkey_width (menu->text) + 2;
887 gap -= menu->start_x;
890 if (g_list_next (menubar->menu) == NULL)
891 gap = 1;
892 else
893 gap /= (g_list_length (menubar->menu) - 1);
895 if (gap <= 0)
897 /* We are out of luck - window is too narrow... */
898 gap = 1;
900 else if (gap >= 3)
901 gap = 3;
903 /* ...and now fix start positions of menubar items */
904 for (i = menubar->menu; i != NULL; i = g_list_next (i))
906 Menu *menu = (Menu *) i->data;
907 int len = menu->start_x;
909 menu->start_x = start_x;
910 start_x += len + gap;
914 /* --------------------------------------------------------------------------------------------- */
915 /** Find MenuBar widget in the dialog */
917 WMenuBar *
918 find_menubar (const Dlg_head * h)
920 return (WMenuBar *) find_widget_type (h, menubar_callback);
923 /* --------------------------------------------------------------------------------------------- */