Ticket #???? (clock support)
[midnight-commander.git] / lib / widget / menu.c
blob705aecf309a0a2a3962d63410e8de234182839d3
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 (' ');
229 if (op_clock_type != NO_CLOCK)
231 mc_log ("show_clock\n");
232 clock_resume ();
233 show_clock ();
236 if (menubar->is_dropped)
237 menubar_draw_drop (menubar);
238 else
239 widget_move (&menubar->widget, 0,
240 ((Menu *) g_list_nth_data (menubar->menu, menubar->selected))->start_x);
243 /* --------------------------------------------------------------------------------------------- */
245 static void
246 menubar_remove (WMenuBar * menubar)
248 Dlg_head *h;
250 if (!menubar->is_dropped)
251 return;
253 /* HACK: before refresh the dialog, change the current widget to keep the order
254 of overlapped widgets. This is useful in multi-window editor.
255 In general, menubar should be a special object, not an ordinary widget
256 in the current dialog. */
257 h = menubar->widget.owner;
258 h->current = g_list_find (h->widgets, dlg_find_by_id (h, menubar->previous_widget));
260 menubar->is_dropped = FALSE;
261 do_refresh ();
262 menubar->is_dropped = TRUE;
264 /* restore current widget */
265 h->current = g_list_find (h->widgets, menubar);
268 /* --------------------------------------------------------------------------------------------- */
270 static void
271 menubar_left (WMenuBar * menubar)
273 menubar_remove (menubar);
274 if (menubar->selected == 0)
275 menubar->selected = g_list_length (menubar->menu) - 1;
276 else
277 menubar->selected--;
278 menubar_draw (menubar);
281 /* --------------------------------------------------------------------------------------------- */
283 static void
284 menubar_right (WMenuBar * menubar)
286 menubar_remove (menubar);
287 menubar->selected = (menubar->selected + 1) % g_list_length (menubar->menu);
288 menubar_draw (menubar);
291 /* --------------------------------------------------------------------------------------------- */
293 static void
294 menubar_finish (WMenuBar * menubar)
296 menubar->is_dropped = FALSE;
297 menubar->is_active = FALSE;
298 menubar->widget.lines = 1;
299 widget_want_hotkey (menubar->widget, 0);
301 dlg_select_by_id (menubar->widget.owner, menubar->previous_widget);
302 do_refresh ();
305 /* --------------------------------------------------------------------------------------------- */
307 static void
308 menubar_drop (WMenuBar * menubar, unsigned int selected)
310 menubar->is_dropped = TRUE;
311 menubar->selected = selected;
312 menubar_draw (menubar);
315 /* --------------------------------------------------------------------------------------------- */
317 static void
318 menubar_execute (WMenuBar * menubar)
320 const Menu *menu = g_list_nth_data (menubar->menu, menubar->selected);
321 const menu_entry_t *entry = g_list_nth_data (menu->entries, menu->selected);
323 if ((entry != NULL) && (entry->command != CK_IgnoreKey))
325 mc_global.widget.is_right = (menubar->selected != 0);
326 menubar_finish (menubar);
327 menubar->widget.owner->callback (menubar->widget.owner, &menubar->widget,
328 DLG_ACTION, entry->command, NULL);
329 do_refresh ();
333 /* --------------------------------------------------------------------------------------------- */
335 static void
336 menubar_down (WMenuBar * menubar)
338 Menu *menu = g_list_nth_data (menubar->menu, menubar->selected);
339 const unsigned int len = g_list_length (menu->entries);
340 menu_entry_t *entry;
342 menubar_paint_idx (menubar, menu->selected, MENU_ENTRY_COLOR);
346 menu->selected = (menu->selected + 1) % len;
347 entry = (menu_entry_t *) g_list_nth_data (menu->entries, menu->selected);
349 while ((entry == NULL) || (entry->command == CK_IgnoreKey));
351 menubar_paint_idx (menubar, menu->selected, MENU_SELECTED_COLOR);
354 /* --------------------------------------------------------------------------------------------- */
356 static void
357 menubar_up (WMenuBar * menubar)
359 Menu *menu = g_list_nth_data (menubar->menu, menubar->selected);
360 const unsigned int len = g_list_length (menu->entries);
361 menu_entry_t *entry;
363 menubar_paint_idx (menubar, menu->selected, MENU_ENTRY_COLOR);
367 if (menu->selected == 0)
368 menu->selected = len - 1;
369 else
370 menu->selected--;
371 entry = (menu_entry_t *) g_list_nth_data (menu->entries, menu->selected);
373 while ((entry == NULL) || (entry->command == CK_IgnoreKey));
375 menubar_paint_idx (menubar, menu->selected, MENU_SELECTED_COLOR);
378 /* --------------------------------------------------------------------------------------------- */
380 static void
381 menubar_first (WMenuBar * menubar)
383 Menu *menu = g_list_nth_data (menubar->menu, menubar->selected);
384 menu_entry_t *entry;
386 if (menu->selected == 0)
387 return;
389 menubar_paint_idx (menubar, menu->selected, MENU_ENTRY_COLOR);
391 menu->selected = 0;
393 while (TRUE)
395 entry = (menu_entry_t *) g_list_nth_data (menu->entries, menu->selected);
397 if ((entry == NULL) || (entry->command == CK_IgnoreKey))
398 menu->selected++;
399 else
400 break;
403 menubar_paint_idx (menubar, menu->selected, MENU_SELECTED_COLOR);
406 /* --------------------------------------------------------------------------------------------- */
408 static void
409 menubar_last (WMenuBar * menubar)
411 Menu *menu = g_list_nth_data (menubar->menu, menubar->selected);
412 const unsigned int len = g_list_length (menu->entries);
413 menu_entry_t *entry;
415 if (menu->selected == len - 1)
416 return;
418 menubar_paint_idx (menubar, menu->selected, MENU_ENTRY_COLOR);
420 menu->selected = len;
424 menu->selected--;
425 entry = (menu_entry_t *) g_list_nth_data (menu->entries, menu->selected);
427 while ((entry == NULL) || (entry->command == CK_IgnoreKey));
429 menubar_paint_idx (menubar, menu->selected, MENU_SELECTED_COLOR);
432 /* --------------------------------------------------------------------------------------------- */
434 static int
435 menubar_handle_key (WMenuBar * menubar, int key)
437 /* Lowercase */
438 if (isascii (key))
439 key = g_ascii_tolower (key);
441 if (is_abort_char (key))
443 menubar_finish (menubar);
444 return 1;
447 /* menubar help or menubar navigation */
448 switch (key)
450 case KEY_F (1):
452 ev_help_t event_data = { NULL, NULL };
454 if (menubar->is_dropped)
455 event_data.node =
456 ((Menu *) g_list_nth_data (menubar->menu, menubar->selected))->help_node;
457 else
458 event_data.node = "[Menu Bar]";
460 mc_event_raise (MCEVENT_GROUP_CORE, "help", &event_data);
461 menubar_draw (menubar);
462 return 1;
464 case KEY_LEFT:
465 case XCTRL ('b'):
466 menubar_left (menubar);
467 return 1;
469 case KEY_RIGHT:
470 case XCTRL ('f'):
471 menubar_right (menubar);
472 return 1;
475 if (!menubar->is_dropped)
477 GList *i;
479 /* drop menu by hotkey */
480 for (i = menubar->menu; i != NULL; i = g_list_next (i))
482 Menu *menu = i->data;
484 if ((menu->text.hotkey != NULL) && (key == g_ascii_tolower (menu->text.hotkey[0])))
486 menubar_drop (menubar, g_list_position (menubar->menu, i));
487 return 1;
491 /* drop menu by Enter or Dowwn key */
492 if (key == KEY_ENTER || key == XCTRL ('n') || key == KEY_DOWN || key == '\n')
493 menubar_drop (menubar, menubar->selected);
495 return 1;
499 Menu *menu = g_list_nth_data (menubar->menu, menubar->selected);
500 GList *i;
502 /* execute menu command by hotkey */
503 for (i = menu->entries; i != NULL; i = g_list_next (i))
505 const menu_entry_t *entry = i->data;
507 if ((entry != NULL) && (entry->command != CK_IgnoreKey)
508 && (entry->text.hotkey != NULL) && (key == g_ascii_tolower (entry->text.hotkey[0])))
510 menu->selected = g_list_position (menu->entries, i);
511 menubar_execute (menubar);
512 return 1;
516 /* menu execute by Enter or menu navigation */
517 switch (key)
519 case KEY_ENTER:
520 case '\n':
521 menubar_execute (menubar);
522 return 1;
524 case KEY_HOME:
525 case ALT ('<'):
526 menubar_first (menubar);
527 break;
529 case KEY_END:
530 case ALT ('>'):
531 menubar_last (menubar);
532 break;
534 case KEY_DOWN:
535 case XCTRL ('n'):
536 menubar_down (menubar);
537 break;
539 case KEY_UP:
540 case XCTRL ('p'):
541 menubar_up (menubar);
542 break;
546 return 0;
549 /* --------------------------------------------------------------------------------------------- */
551 static cb_ret_t
552 menubar_callback (Widget * w, widget_msg_t msg, int parm)
554 WMenuBar *menubar = (WMenuBar *) w;
556 switch (msg)
558 /* We do not want the focus unless we have been activated */
559 case WIDGET_FOCUS:
560 if (!menubar->is_active)
561 return MSG_NOT_HANDLED;
563 /* Trick to get all the mouse events */
564 menubar->widget.lines = LINES;
566 /* Trick to get all of the hotkeys */
567 widget_want_hotkey (menubar->widget, 1);
568 menubar_draw (menubar);
569 return MSG_HANDLED;
571 /* We don't want the buttonbar to activate while using the menubar */
572 case WIDGET_HOTKEY:
573 case WIDGET_KEY:
574 if (menubar->is_active)
576 menubar_handle_key (menubar, parm);
577 return MSG_HANDLED;
579 return MSG_NOT_HANDLED;
581 case WIDGET_CURSOR:
582 /* Put the cursor in a suitable place */
583 return MSG_NOT_HANDLED;
585 case WIDGET_UNFOCUS:
586 return menubar->is_active ? MSG_NOT_HANDLED : MSG_HANDLED;
588 case WIDGET_DRAW:
589 if (menubar->is_visible)
591 menubar_draw (menubar);
592 return MSG_HANDLED;
594 /* fall through */
596 case WIDGET_RESIZED:
597 /* try show menu after screen resize */
598 send_message (w, WIDGET_FOCUS, 0);
599 return MSG_HANDLED;
602 case WIDGET_DESTROY:
603 menubar_set_menu (menubar, NULL);
604 return MSG_HANDLED;
606 default:
607 return default_proc (msg, parm);
611 /* --------------------------------------------------------------------------------------------- */
613 static int
614 menubar_event (Gpm_Event * event, void *data)
616 WMenuBar *menubar = (WMenuBar *) data;
617 Widget *w = (Widget *) data;
618 gboolean was_active = TRUE;
619 int left_x, right_x, bottom_y;
620 Menu *menu;
621 Gpm_Event local;
623 if (!mouse_global_in_widget (event, w))
624 return MOU_UNHANDLED;
626 /* ignore unsupported events */
627 if ((event->type & (GPM_UP | GPM_DOWN | GPM_DRAG)) == 0)
628 return MOU_NORMAL;
630 /* ignore wheel events if menu is inactive */
631 if (!menubar->is_active && ((event->buttons & (GPM_B_MIDDLE | GPM_B_UP | GPM_B_DOWN)) != 0))
632 return MOU_NORMAL;
634 local = mouse_get_local (event, w);
636 if (local.y == 1 && (local.type & GPM_UP) != 0)
637 return MOU_NORMAL;
639 if (!menubar->is_dropped)
641 menubar->previous_widget = dlg_get_current_widget_id (w->owner);
642 menubar->is_active = TRUE;
643 menubar->is_dropped = TRUE;
644 was_active = FALSE;
647 /* Mouse operations on the menubar */
648 if (local.y == 1 || !was_active)
650 /* wheel events on menubar */
651 if ((local.buttons & GPM_B_UP) != 0)
652 menubar_left (menubar);
653 else if ((local.buttons & GPM_B_DOWN) != 0)
654 menubar_right (menubar);
655 else
657 const unsigned int len = g_list_length (menubar->menu);
658 unsigned int new_selection = 0;
660 while ((new_selection < len)
661 && (local.x > ((Menu *) g_list_nth_data (menubar->menu,
662 new_selection))->start_x))
663 new_selection++;
665 if (new_selection != 0) /* Don't set the invalid value -1 */
666 new_selection--;
668 if (!was_active)
670 menubar->selected = new_selection;
671 dlg_select_widget (menubar);
673 else
675 menubar_remove (menubar);
676 menubar->selected = new_selection;
678 menubar_draw (menubar);
680 return MOU_NORMAL;
683 if (!menubar->is_dropped || (local.y < 2))
684 return MOU_NORMAL;
686 /* middle click -- everywhere */
687 if (((local.buttons & GPM_B_MIDDLE) != 0) && ((local.type & GPM_DOWN) != 0))
689 menubar_execute (menubar);
690 return MOU_NORMAL;
693 /* the mouse operation is on the menus or it is not */
694 menu = (Menu *) g_list_nth_data (menubar->menu, menubar->selected);
695 left_x = menu->start_x;
696 right_x = left_x + menu->max_entry_len + 3;
697 if (right_x > menubar->widget.cols)
699 left_x = menubar->widget.cols - menu->max_entry_len - 3;
700 right_x = menubar->widget.cols;
703 bottom_y = g_list_length (menu->entries) + 3;
705 if ((local.x >= left_x) && (local.x <= right_x) && (local.y <= bottom_y))
707 int pos = local.y - 3;
708 const menu_entry_t *entry = g_list_nth_data (menu->entries, pos);
710 /* mouse wheel */
711 if ((local.buttons & GPM_B_UP) != 0 && (local.type & GPM_DOWN) != 0)
713 menubar_up (menubar);
714 return MOU_NORMAL;
716 if ((local.buttons & GPM_B_DOWN) != 0 && (local.type & GPM_DOWN) != 0)
718 menubar_down (menubar);
719 return MOU_NORMAL;
722 /* ignore events above and below dropped down menu */
723 if ((pos < 0) || (pos >= bottom_y - 3))
724 return MOU_NORMAL;
726 if ((entry != NULL) && (entry->command != CK_IgnoreKey))
728 menubar_paint_idx (menubar, menu->selected, MENU_ENTRY_COLOR);
729 menu->selected = pos;
730 menubar_paint_idx (menubar, menu->selected, MENU_SELECTED_COLOR);
732 if ((event->type & GPM_UP) != 0)
733 menubar_execute (menubar);
736 else if (((local.type & GPM_DOWN) != 0) && ((local.buttons & (GPM_B_UP | GPM_B_DOWN)) == 0))
738 /* use click not wheel to close menu */
739 menubar_finish (menubar);
742 return MOU_NORMAL;
745 /* --------------------------------------------------------------------------------------------- */
746 /*** public functions ****************************************************************************/
747 /* --------------------------------------------------------------------------------------------- */
749 menu_entry_t *
750 menu_entry_create (const char *name, unsigned long command)
752 menu_entry_t *entry;
754 entry = g_new (menu_entry_t, 1);
755 entry->first_letter = ' ';
756 entry->text = parse_hotkey (name);
757 entry->command = command;
758 entry->shortcut = NULL;
760 return entry;
763 /* --------------------------------------------------------------------------------------------- */
765 void
766 menu_entry_free (menu_entry_t * entry)
768 if (entry != NULL)
770 release_hotkey (entry->text);
771 g_free (entry->shortcut);
772 g_free (entry);
776 /* --------------------------------------------------------------------------------------------- */
778 Menu *
779 create_menu (const char *name, GList * entries, const char *help_node)
781 Menu *menu;
783 menu = g_new (Menu, 1);
784 menu->start_x = 0;
785 menu->text = parse_hotkey (name);
786 menu->entries = entries;
787 menu->max_entry_len = 1;
788 menu->max_hotkey_len = 0;
789 menu->selected = 0;
790 menu->help_node = g_strdup (help_node);
792 return menu;
795 /* --------------------------------------------------------------------------------------------- */
797 void
798 menu_set_name (Menu * menu, const char *name)
800 release_hotkey (menu->text);
801 menu->text = parse_hotkey (name);
804 /* --------------------------------------------------------------------------------------------- */
806 void
807 destroy_menu (Menu * menu)
809 release_hotkey (menu->text);
810 g_list_foreach (menu->entries, (GFunc) menu_entry_free, NULL);
811 g_list_free (menu->entries);
812 g_free (menu->help_node);
813 g_free (menu);
816 /* --------------------------------------------------------------------------------------------- */
818 WMenuBar *
819 menubar_new (int y, int x, int cols, GList * menu)
821 WMenuBar *menubar;
823 menubar = g_new0 (WMenuBar, 1);
824 init_widget (&menubar->widget, y, x, 1, cols, menubar_callback, menubar_event);
825 widget_want_cursor (menubar->widget, FALSE);
826 menubar->is_visible = TRUE; /* by default */
827 menubar_set_menu (menubar, menu);
829 return menubar;
832 /* --------------------------------------------------------------------------------------------- */
834 void
835 menubar_set_menu (WMenuBar * menubar, GList * menu)
837 /* delete previous menu */
838 if (menubar->menu != NULL)
840 g_list_foreach (menubar->menu, (GFunc) destroy_menu, NULL);
841 g_list_free (menubar->menu);
843 /* add new menu */
844 menubar->is_active = FALSE;
845 menubar->is_dropped = FALSE;
846 menubar->menu = menu;
847 menubar->selected = 0;
848 menubar_arrange (menubar);
851 /* --------------------------------------------------------------------------------------------- */
853 void
854 menubar_add_menu (WMenuBar * menubar, Menu * menu)
856 if (menu != NULL)
858 menu_arrange (menu, menubar->widget.owner->get_shortcut);
859 menubar->menu = g_list_append (menubar->menu, menu);
862 menubar_arrange (menubar);
865 /* --------------------------------------------------------------------------------------------- */
867 * Properly space menubar items. Should be called when menubar is created
868 * and also when widget width is changed (i.e. upon xterm resize).
871 void
872 menubar_arrange (WMenuBar * menubar)
874 int start_x = 1;
875 GList *i;
876 int gap;
878 if (menubar->menu == NULL)
879 return;
881 gap = menubar->widget.cols - 2;
883 /* First, calculate gap between items... */
884 for (i = menubar->menu; i != NULL; i = g_list_next (i))
886 Menu *menu = (Menu *) i->data;
887 /* preserve length here, to be used below */
888 menu->start_x = hotkey_width (menu->text) + 2;
889 gap -= menu->start_x;
892 if (g_list_next (menubar->menu) == NULL)
893 gap = 1;
894 else
895 gap /= (g_list_length (menubar->menu) - 1);
897 if (gap <= 0)
899 /* We are out of luck - window is too narrow... */
900 gap = 1;
902 else if (gap >= 3)
903 gap = 3;
905 /* ...and now fix start positions of menubar items */
906 for (i = menubar->menu; i != NULL; i = g_list_next (i))
908 Menu *menu = (Menu *) i->data;
909 int len = menu->start_x;
911 menu->start_x = start_x;
912 start_x += len + gap;
916 /* --------------------------------------------------------------------------------------------- */
917 /** Find MenuBar widget in the dialog */
919 WMenuBar *
920 find_menubar (const Dlg_head * h)
922 return (WMenuBar *) find_widget_type (h, menubar_callback);
925 /* --------------------------------------------------------------------------------------------- */