diff --git a/lib/widget/menu.c b/lib/widget/menu.c index a64717331..bfcce2a3b 100644 --- a/lib/widget/menu.c +++ b/lib/widget/menu.c @@ -70,6 +70,7 @@ struct menu_t size_t max_entry_len; // cached max length of entry texts (text + shortcut) size_t max_hotkey_len; // cached max length of shortcuts unsigned int current; // pointer to current menu entry + unsigned int top; // menu entry currently at the top of the scroll area char *help_node; }; @@ -128,7 +129,7 @@ menubar_paint_idx (const WMenuBar *menubar, unsigned int idx, int color) const WRect *w = &CONST_WIDGET (menubar)->rect; const menu_t *menu = MENU (g_list_nth_data (menubar->menu, menubar->current)); const menu_entry_t *entry = MENUENTRY (g_list_nth_data (menu->entries, idx)); - const int y = 2 + idx; + const int y = 2 + idx - menu->top; int x = menu->start_x; if (x + menu->max_entry_len + 3 > (gsize) w->cols) @@ -150,6 +151,12 @@ menubar_paint_idx (const WMenuBar *menubar, unsigned int idx, int color) int yt, xt; // menu text + + // left non-connecting border + widget_gotoyx (menubar, y, x - 1); + tty_setcolor (MENU_FRAME_COLOR); + tty_print_char (mc_tty_frm[MC_TTY_FRM_DVERT]); + tty_setcolor (color); widget_gotoyx (menubar, y, x); tty_print_char ((unsigned char) entry->first_letter); @@ -173,6 +180,11 @@ menubar_paint_idx (const WMenuBar *menubar, unsigned int idx, int color) tty_print_string (entry->shortcut); } + // right non-connecting border + widget_gotoyx (menubar, y, x + menu->max_entry_len + 2); + tty_setcolor (MENU_FRAME_COLOR); + tty_print_char (mc_tty_frm[MC_TTY_FRM_DVERT]); + // move cursor to the start of entry text widget_gotoyx (menubar, y, x + 1); } @@ -180,14 +192,36 @@ menubar_paint_idx (const WMenuBar *menubar, unsigned int idx, int color) /* --------------------------------------------------------------------------------------------- */ +static void +menubar_draw_drop_entries (const WMenuBar *menubar, menu_t *menu) +{ + const unsigned int lines = WIDGET (menubar)->rect.lines - 2; + const unsigned int count = g_list_length (menu->entries); + + if (menu->top > 0 && count - menu->top < lines) + // Screen size has grown, don't leave the new space empty + menu->top = count % lines; + + const unsigned int stop = MIN (count, menu->top + lines); + + for (unsigned int i = menu->top; i < stop; i++) + menubar_paint_idx (menubar, i, i == menu->current ? MENU_SELECTED_COLOR : MENU_ENTRY_COLOR); +} + +/* --------------------------------------------------------------------------------------------- */ + static void menubar_draw_drop (const WMenuBar *menubar) { + menu_t *menu; + int column; + + menu = MENU (g_list_nth_data (menubar->menu, menubar->current)); + const WRect *w = &CONST_WIDGET (menubar)->rect; - const menu_t *menu = MENU (g_list_nth_data (menubar->menu, menubar->current)); const unsigned int count = g_list_length (menu->entries); - int column = menu->start_x - 1; - unsigned int i; + + column = menu->start_x - 1; if (column + menu->max_entry_len + 4 > (gsize) w->cols) column = w->cols - menu->max_entry_len - 4; @@ -199,8 +233,7 @@ menubar_draw_drop (const WMenuBar *menubar) tty_setcolor (MENU_FRAME_COLOR); tty_draw_box (w->y + 1, w->x + column, count + 2, menu->max_entry_len + 4, FALSE); - for (i = 0; i < count; i++) - menubar_paint_idx (menubar, i, i == menu->current ? MENU_SELECTED_COLOR : MENU_ENTRY_COLOR); + menubar_draw_drop_entries (menubar, menu); } /* --------------------------------------------------------------------------------------------- */ @@ -369,6 +402,26 @@ menubar_execute (WMenuBar *menubar) /* --------------------------------------------------------------------------------------------- */ +static void +menubar_scroll_to_view (WMenuBar *menubar, menu_t *menu, unsigned int idx) +{ + const Widget *w = WIDGET (menubar); + const int lines = w->rect.lines - 3; + + g_return_if_fail (lines > 0); + + if (idx < menu->top) + menu->top = idx; + else if (idx > menu->top + lines) + menu->top = idx - lines; + else + return; + + menubar_draw_drop_entries (menubar, menu); +} + +/* --------------------------------------------------------------------------------------------- */ + static void menubar_down (WMenuBar *menubar) { @@ -385,6 +438,7 @@ menubar_down (WMenuBar *menubar) } while ((entry == NULL) || (entry->command == CK_IgnoreKey)); + menubar_scroll_to_view (menubar, menu, menu->current); menubar_paint_idx (menubar, menu->current, MENU_SELECTED_COLOR); } @@ -409,6 +463,7 @@ menubar_up (WMenuBar *menubar) } while ((entry == NULL) || (entry->command == CK_IgnoreKey)); + menubar_scroll_to_view (menubar, menu, menu->current); menubar_paint_idx (menubar, menu->current, MENU_SELECTED_COLOR); } @@ -440,6 +495,7 @@ menubar_first (WMenuBar *menubar) break; } + menubar_scroll_to_view (menubar, menu, menu->current); menubar_paint_idx (menubar, menu->current, MENU_SELECTED_COLOR); } else @@ -474,6 +530,7 @@ menubar_last (WMenuBar *menubar) } while ((entry == NULL) || (entry->command == CK_IgnoreKey)); + menubar_scroll_to_view (menubar, menu, menu->current); menubar_paint_idx (menubar, menu->current, MENU_SELECTED_COLOR); } else @@ -743,7 +800,7 @@ menubar_mouse_on_menu_entry (const WMenuBar *menubar, int y, int x) return FALSE; menu = MENU (g_list_nth_data (menubar->menu, menubar->current)); - entry = MENUENTRY (g_list_nth_data (menu->entries, y - 2)); + entry = MENUENTRY (g_list_nth_data (menu->entries, menu->top + y - 2)); if (entry == NULL) return FALSE; // separator line @@ -755,7 +812,7 @@ menubar_mouse_on_menu_entry (const WMenuBar *menubar, int y, int x) right_x = w->cols - 1; } - bottom_y = g_list_length (menu->entries) + 2; // skip bar and top frame + bottom_y = g_list_length (menu->entries) + 2 - menu->top; // skip bar and top frame return (x >= left_x && x < right_x && y > 1 && y < bottom_y); } @@ -766,16 +823,16 @@ static void menubar_change_selected_item (WMenuBar *menubar, int y) { menu_t *menu; - menu_entry_t *entry; - y -= 2; // skip bar and top frame menu = MENU (g_list_nth_data (menubar->menu, menubar->current)); - entry = MENUENTRY (g_list_nth_data (menu->entries, y)); + + const int idx = menu->top + y - 2; // skip bar and top frame + const menu_entry_t *entry = MENUENTRY (g_list_nth_data (menu->entries, idx)); if (entry != NULL && entry->command != CK_IgnoreKey) { menubar_paint_idx (menubar, menu->current, MENU_ENTRY_COLOR); - menu->current = y; + menu->current = idx; menubar_paint_idx (menubar, menu->current, MENU_SELECTED_COLOR); } } @@ -939,6 +996,7 @@ menu_new (const char *name, GList *entries, const char *help_node) menu->max_entry_len = 1; menu->max_hotkey_len = 0; menu->current = 0; + menu->top = 0; menu->help_node = g_strdup (help_node); return menu;