?? menu.c
字號:
scroll_menu(menu, 0, 1); display_menu(win->term, menu); select_menu(win->term, menu); } }}#endif#define DIST 5static voidmenu_page_up(struct menu *menu){ int current = int_max(0, int_min(menu->selected, menu->size - 1)); int step; int i; int next_sep = 0; for (i = current - 1; i > 0; i--) if (mi_is_horizontal_bar(&menu->items[i])) { next_sep = i; break; } step = current - next_sep + 1; int_bounds(&step, 0, int_min(current, DIST)); scroll_menu(menu, -step, 0);}static voidmenu_page_down(struct menu *menu){ int current = int_max(0, int_min(menu->selected, menu->size - 1)); int step; int i; int next_sep = menu->size - 1; for (i = current + 1; i < menu->size; i++) if (mi_is_horizontal_bar(&menu->items[i])) { next_sep = i; break; } step = next_sep - current + 1; int_bounds(&step, 0, int_min(menu->size - 1 - current, DIST)); scroll_menu(menu, step, 0);}#undef DISTstatic inline intsearch_menu_item(struct menu_item *item, unsigned char *buffer, struct terminal *term){ unsigned char *text, *match; if (!mi_has_left_text(item)) return 0; text = mi_text_translate(item) ? _(item->text, term) : item->text; /* Crap. We have to remove the hotkey markers '~' */ text = stracpy(text); if (!text) return 0; match = strchr(text, '~'); if (match) memmove(match, match + 1, strlen(match)); match = strcasestr(text, buffer); mem_free(text); return !!match;}static enum input_line_codemenu_search_handler(struct input_line *line, int action){ struct menu *menu = line->data; struct terminal *term = menu->win->term; unsigned char *buffer = line->buffer; struct window *win; int pos = menu->selected; int direction; switch (action) { case ACT_EDIT_REDRAW: return INPUT_LINE_PROCEED; case ACT_EDIT_ENTER: /* XXX: The input line dialog window is above the menu window. * Remove it from the top, so that select_menu() will correctly * remove all the windows it has to and then readd it. */ win = term->windows.next; del_from_list(win); select_menu(term, menu); add_to_list(term->windows, win); return INPUT_LINE_CANCEL; case ACT_EDIT_PREVIOUS_ITEM: pos--; direction = -1; break; case ACT_EDIT_NEXT_ITEM: pos++; default: direction = 1; } /* If there is nothing to match with don't start searching */ if (!*buffer) return INPUT_LINE_PROCEED; pos %= menu->size; do { struct menu_item *item = &menu->items[pos]; if (search_menu_item(item, buffer, term)) { scroll_menu(menu, pos - menu->selected, 0); display_menu(term, menu); return INPUT_LINE_PROCEED; } pos += direction; if (pos == menu->size) pos = 0; else if (pos < 0) pos = menu->size - 1; } while (pos != menu->selected); return INPUT_LINE_CANCEL;}static voidsearch_menu(struct menu *menu){ struct terminal *term = menu->win->term; struct window *tab = get_current_tab(term); struct session *ses = tab ? tab->data : NULL; unsigned char *prompt = _("Search menu/", term); if (menu->size < 1 || !ses) return; input_field_line(ses, prompt, menu, NULL, menu_search_handler);}static voidmenu_kbd_handler(struct menu *menu, struct term_event *ev){ struct window *win = menu->win; enum menu_action action = kbd_action(KEYMAP_MENU, ev, NULL); int s = 0; switch (action) { case ACT_MENU_LEFT: case ACT_MENU_RIGHT: if (list_has_next(win->term->windows, win) && win->next->handler == mainmenu_handler) { struct window *next_win = win->next; delete_window_ev(win, ev); select_menu(next_win->term, next_win->data); return; } if (action == ACT_MENU_RIGHT) goto enter; delete_window(win); return; case ACT_MENU_UP: scroll_menu(menu, -1, 1); break; case ACT_MENU_DOWN: scroll_menu(menu, 1, 1); break; case ACT_MENU_HOME: scroll_menu(menu, -menu->selected, 0); break; case ACT_MENU_END: scroll_menu(menu, menu->size - menu->selected - 1, 0); break; case ACT_MENU_PAGE_UP: menu_page_up(menu); break; case ACT_MENU_PAGE_DOWN: menu_page_down(menu); break; case ACT_MENU_ENTER: case ACT_MENU_SELECT: goto enter; case ACT_MENU_SEARCH: search_menu(menu); break; case ACT_MENU_CANCEL: if (list_has_next(win->term->windows, win) && win->next->handler == mainmenu_handler) delete_window_ev(win, ev); else delete_window_ev(win, NULL); return; default: { int key = get_kbd_key(ev); if ((key >= KBD_F1 && key <= KBD_F12) || check_kbd_modifier(ev, KBD_ALT)) { delete_window_ev(win, ev); return; } if (!check_kbd_label_key(ev)) break; s = check_hotkeys(menu, key, win->term); if (s || check_not_so_hot_keys(menu, key, win->term)) scroll_menu(menu, 0, 1); } } display_menu(win->term, menu); if (s) {enter: select_menu(win->term, menu); }}static voidmenu_handler(struct window *win, struct term_event *ev){ struct menu *menu = win->data; menu->win = win; switch (ev->ev) { case EVENT_INIT: case EVENT_RESIZE: case EVENT_REDRAW: get_parent_ptr(win, &menu->parent_x, &menu->parent_y); count_menu_size(win->term, menu); menu->selected--; scroll_menu(menu, 1, 1); display_menu(win->term, menu); break; case EVENT_MOUSE:#ifdef CONFIG_MOUSE menu_mouse_handler(menu, ev);#endif /* CONFIG_MOUSE */ break; case EVENT_KBD: menu_kbd_handler(menu, ev); break; case EVENT_ABORT: if (menu->items->flags & FREE_ANY) free_menu_items(menu->items); break; }}voiddo_mainmenu(struct terminal *term, struct menu_item *items, void *data, int sel){ struct menu *menu = mem_calloc(1, sizeof(*menu)); if (!menu) return; menu->selected = (sel == -1 ? 0 : sel); menu->items = items; menu->data = data; menu->size = count_items(items); menu->hotkeys = 1;#ifdef ENABLE_NLS clear_hotkeys_cache(menu);#endif init_hotkeys(term, menu); add_window(term, mainmenu_handler, menu); if (sel != -1) { select_menu(term, menu); }}static voiddisplay_mainmenu(struct terminal *term, struct menu *menu){ struct color_pair *normal_color = get_bfu_color(term, "menu.normal"); struct color_pair *selected_color = get_bfu_color(term, "menu.selected"); int p = 0; int i; struct box box; /* FIXME: menu horizontal scrolling do not work well yet, we need to cache * menu items width and recalculate them only when needed (ie. language change) * instead of looping and calculate them each time. --Zas */ /* Try to make current selected menu entry visible. */ if (menu->selected < menu->first) { int num_items_offscreen = menu->selected - menu->first; menu->first += num_items_offscreen; menu->last += num_items_offscreen; } else if (menu->selected > menu->last) { int num_items_offscreen = menu->last - menu->selected; menu->first -= num_items_offscreen; menu->last -= num_items_offscreen; } if (menu->last <= 0) menu->last = menu->size - 1; int_bounds(&menu->last, 0, menu->size - 1); int_bounds(&menu->first, 0, menu->last); set_box(&box, 0, 0, term->width, 1); draw_box(term, &box, ' ', 0, normal_color); if (menu->first != 0) { box.width = L_MAINMENU_SPACE; draw_box(term, &box, '<', 0, normal_color); } p += L_MAINMENU_SPACE; for (i = menu->first; i < menu->size; i++) { struct menu_item *mi = &menu->items[i]; struct color_pair *color = normal_color; unsigned char *text = mi->text; int l = mi->hotkey_pos; int textlen; int selected = (i == menu->selected); if (mi_text_translate(mi)) text = _(text, term); textlen = strlen(text) - !!l; if (selected) { color = selected_color; box.x = p; box.width = L_MAINTEXT_SPACE + L_TEXT_SPACE + textlen + R_TEXT_SPACE + R_MAINTEXT_SPACE; draw_box(term, &box, ' ', 0, color); set_cursor(term, p, 0, 1); set_window_ptr(menu->win, p, 1); } p += L_MAINTEXT_SPACE; if (l) { draw_menu_left_text_hk(term, text, l, p, 0, textlen + R_TEXT_SPACE + L_TEXT_SPACE, color, selected); } else { draw_menu_left_text(term, text, textlen, p, 0, textlen + R_TEXT_SPACE + L_TEXT_SPACE, color); } p += textlen; if (p >= term->width - R_MAINMENU_SPACE) break; p += R_MAINTEXT_SPACE + R_TEXT_SPACE + L_TEXT_SPACE; } menu->last = i - 1; int_lower_bound(&menu->last, menu->first); if (menu->last < menu->size - 1) { set_box(&box, term->width - R_MAINMENU_SPACE, 0, R_MAINMENU_SPACE, 1); draw_box(term, &box, '>', 0, normal_color); } redraw_from_window(menu->win);}#ifdef CONFIG_MOUSEstatic voidmainmenu_mouse_handler(struct menu *menu, struct term_event *ev){ struct window *win = menu->win; struct menu_item *item; int scroll = 0; if (check_mouse_wheel(ev)) return; /* Mouse was clicked outside the mainmenu bar */ if (ev->info.mouse.y) { if (check_mouse_action(ev, B_DOWN)) delete_window_ev(win, NULL); return; } /* First check if the mouse button was pressed in the side of the * terminal and simply scroll one step in that direction else iterate * through the menu items to see if it was pressed on a label. */ if (ev->info.mouse.x < L_MAINMENU_SPACE) { scroll = -1; } else if (ev->info.mouse.x >= win->term->width - R_MAINMENU_SPACE) { scroll = 1; } else { int p = L_MAINMENU_SPACE; /* We don't initialize to menu->first here, since it breaks * horizontal scrolling using mouse in some cases. --Zas */ foreach_menu_item (item, menu->items) { unsigned char *text = item->text; if (!mi_has_left_text(item)) continue; if (mi_text_translate(item)) text = _(item->text, win->term); /* The label width is made up of a little padding on * the sides followed by the text width substracting * one char if it has hotkeys (the '~' char) */ p += L_MAINTEXT_SPACE + L_TEXT_SPACE + strlen(text) - !!item->hotkey_pos + R_TEXT_SPACE + R_MAINTEXT_SPACE; if (ev->info.mouse.x < p) { scroll = (item - menu->items) - menu->selected; break; } } } if (scroll) { scroll_menu(menu, scroll, 1); display_mainmenu(win->term, menu); } /* We need to select the menu item even if we didn't scroll * apparently because we will delete any drop down menus * in the clicking process. */ select_menu(win->term, menu);}#endifstatic voidmainmenu_kbd_handler(struct menu *menu, struct term_event *ev){ struct window *win = menu->win; enum menu_action action = kbd_action(KEYMAP_MENU, ev, NULL); switch (action) { case ACT_MENU_ENTER: case ACT_MENU_DOWN: case ACT_MENU_UP: case ACT_MENU_PAGE_UP: case ACT_MENU_PAGE_DOWN: case ACT_MENU_SELECT: select_menu(win->term, menu); return; case ACT_MENU_HOME: scroll_menu(menu, -menu->selected, 0); break; case ACT_MENU_END: scroll_menu(menu, menu->size - menu->selected - 1, 0); break; case ACT_MENU_NEXT_ITEM: case ACT_MENU_PREVIOUS_ITEM: /* This is pretty western centric since `what is next'? * Anyway we cycle clockwise by resetting the action ... */ action = (action == ACT_MENU_NEXT_ITEM) ? ACT_MENU_RIGHT : ACT_MENU_LEFT; /* ... and then letting left/right handling take over. */ case ACT_MENU_LEFT: case ACT_MENU_RIGHT: scroll_menu(menu, action == ACT_MENU_LEFT ? -1 : 1, 1); break; case ACT_MENU_REDRAW: /* Just call display_mainmenu() */ break; default: /* Fallback to see if any hotkey matches the pressed key */ if (check_kbd_label_key(ev) && check_hotkeys(menu, get_kbd_key(ev), win->term)) { display_mainmenu(win->term, menu); select_menu(win->term, menu); return; } case ACT_MENU_CANCEL: delete_window_ev(win, action != ACT_MENU_CANCEL ? ev : NULL); return; } /* Redraw the menu */ display_mainmenu(win->term, menu);}static voidmainmenu_handler(struct window *win, struct term_event *ev){ struct menu *menu = win->data; menu->win = win; switch (ev->ev) { case EVENT_INIT: case EVENT_RESIZE: case EVENT_REDRAW: display_mainmenu(win->term, menu); break; case EVENT_MOUSE:#ifdef CONFIG_MOUSE mainmenu_mouse_handler(menu, ev);#endif /* CONFIG_MOUSE */ break; case EVENT_KBD: mainmenu_kbd_handler(menu, ev); break; case EVENT_ABORT: break; }}/* For dynamic menus the last (cleared) item is used to mark the end. */#define realloc_menu_items(mi_, size) \ mem_align_alloc(mi_, size, (size) + 2, struct menu_item, 0xF)struct menu_item *new_menu(enum menu_item_flags flags){ struct menu_item *mi = NULL; if (realloc_menu_items(&mi, 0)) mi->flags = flags; return mi;}voidadd_to_menu(struct menu_item **mi, unsigned char *text, unsigned char *rtext, enum main_action action, menu_func func, void *data, enum menu_item_flags flags){ int n = count_items(*mi); /* XXX: Don't clear the last and special item. */ struct menu_item *item = realloc_menu_items(mi, n + 1); if (!item) return; item += n; /* Shift current last item by one place. */ copy_struct(item + 1, item); /* Setup the new item. All menu items share the item_free value. */ SET_MENU_ITEM(item, text, rtext, action, func, data, item->flags | flags, HKS_SHOW, 0);}#undef L_MAINMENU_SPACE#undef R_MAINMENU_SPACE#undef L_MAINTEXT_SPACE#undef R_MAINTEXT_SPACE#undef L_RTEXT_SPACE#undef R_RTEXT_SPACE#undef L_TEXT_SPACE#undef R_TEXT_SPACE#undef MENU_BORDER_SIZE
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -