diff options
| author | Eli Zaretskii | 2013-10-14 18:37:12 +0300 |
|---|---|---|
| committer | Eli Zaretskii | 2013-10-14 18:37:12 +0300 |
| commit | ccd4a7833f341e2c22d6933357282954af6a57b2 (patch) | |
| tree | e28e73f9b0e1b85ee9d81adb79d7389c04e4473f /src/term.c | |
| parent | 77e3b1b7095b3376dbddd22cbca4827b797767c0 (diff) | |
| download | emacs-ccd4a7833f341e2c22d6933357282954af6a57b2.tar.gz emacs-ccd4a7833f341e2c22d6933357282954af6a57b2.zip | |
Implement scrolling of TTY menus when the screen is too short.
src/term.c (tty_menu_display): Accept an additional argument, the
menu item from which to start displaying the menu. Account for
the value of Y when limiting the menu to the number of available
screen lines.
(mi_result): New enumeration.
(read_menu_input): Return enumerated value. When the y coordinate
hits min_y or max_y, return scroll indication instead of wrapping
around the menu.
(tty_menu_activate): Handle the scrolling indications from
read_menu_input. Compute the first menu item to display and pass
it to tty_menu_display.
lisp/menu-bar.el (tty-menu-navigation-map): Bind shifted mouse clicks
to commands that scroll the menu.
Diffstat (limited to 'src/term.c')
| -rw-r--r-- | src/term.c | 114 |
1 files changed, 73 insertions, 41 deletions
diff --git a/src/term.c b/src/term.c index 58e0f2abd45..ee81c59dcd4 100644 --- a/src/term.c +++ b/src/term.c | |||
| @@ -2781,10 +2781,10 @@ DEFUN ("gpm-mouse-stop", Fgpm_mouse_stop, Sgpm_mouse_stop, | |||
| 2781 | However, unlike on MSDOS, where the menu text is drawn directly to | 2781 | However, unlike on MSDOS, where the menu text is drawn directly to |
| 2782 | the display video memory, on a TTY we use display_string (see | 2782 | the display video memory, on a TTY we use display_string (see |
| 2783 | display_tty_menu_item in xdisp.c) to put the glyphs produced from | 2783 | display_tty_menu_item in xdisp.c) to put the glyphs produced from |
| 2784 | the menu items directly into the frame's 'desired_matrix' glyph | 2784 | the menu items into the frame's 'desired_matrix' glyph matrix, and |
| 2785 | matrix, and then call update_frame_with_menu to deliver the results | 2785 | then call update_frame_with_menu to deliver the results to the |
| 2786 | to the glass. The previous contents of the screen, in the form of | 2786 | glass. The previous contents of the screen, in the form of the |
| 2787 | the current_matrix, is stashed away, and used to restore screen | 2787 | current_matrix, is stashed away, and used to restore screen |
| 2788 | contents when the menu selection changes or when the final | 2788 | contents when the menu selection changes or when the final |
| 2789 | selection is made and the menu should be popped down. | 2789 | selection is made and the menu should be popped down. |
| 2790 | 2790 | ||
| @@ -2911,11 +2911,12 @@ mouse_get_xy (int *x, int *y) | |||
| 2911 | } | 2911 | } |
| 2912 | } | 2912 | } |
| 2913 | 2913 | ||
| 2914 | /* Display MENU at (X,Y) using FACES. */ | 2914 | /* Display MENU at (X,Y) using FACES, starting with FIRST_ITEM |
| 2915 | (zero-based). */ | ||
| 2915 | 2916 | ||
| 2916 | static void | 2917 | static void |
| 2917 | tty_menu_display (tty_menu *menu, int x, int y, int pn, int *faces, | 2918 | tty_menu_display (tty_menu *menu, int x, int y, int pn, int *faces, |
| 2918 | int mx, int my, int disp_help) | 2919 | int mx, int my, int first_item, int disp_help) |
| 2919 | { | 2920 | { |
| 2920 | int i, face, width, enabled, mousehere, row, col; | 2921 | int i, face, width, enabled, mousehere, row, col; |
| 2921 | struct frame *sf = SELECTED_FRAME (); | 2922 | struct frame *sf = SELECTED_FRAME (); |
| @@ -2923,7 +2924,7 @@ tty_menu_display (tty_menu *menu, int x, int y, int pn, int *faces, | |||
| 2923 | /* Don't try to display more menu items than the console can display | 2924 | /* Don't try to display more menu items than the console can display |
| 2924 | using the available screen lines. Exclude the echo area line, as | 2925 | using the available screen lines. Exclude the echo area line, as |
| 2925 | it will be overwritten by the help-echo anyway. */ | 2926 | it will be overwritten by the help-echo anyway. */ |
| 2926 | int max_items = min (menu->count, FRAME_LINES (sf) - 1); | 2927 | int max_items = min (menu->count - first_item, FRAME_LINES (sf) - 1 - y); |
| 2927 | 2928 | ||
| 2928 | menu_help_message = NULL; | 2929 | menu_help_message = NULL; |
| 2929 | 2930 | ||
| @@ -2933,11 +2934,12 @@ tty_menu_display (tty_menu *menu, int x, int y, int pn, int *faces, | |||
| 2933 | for (i = 0; i < max_items; i++) | 2934 | for (i = 0; i < max_items; i++) |
| 2934 | { | 2935 | { |
| 2935 | int max_width = width + 2; /* +2 for padding blanks on each side */ | 2936 | int max_width = width + 2; /* +2 for padding blanks on each side */ |
| 2937 | int j = i + first_item; | ||
| 2936 | 2938 | ||
| 2937 | if (menu->submenu[i]) | 2939 | if (menu->submenu[j]) |
| 2938 | max_width += 2; /* for displaying " >" after the item */ | 2940 | max_width += 2; /* for displaying " >" after the item */ |
| 2939 | enabled | 2941 | enabled |
| 2940 | = (!menu->submenu[i] && menu->panenumber[i]) || (menu->submenu[i]); | 2942 | = (!menu->submenu[j] && menu->panenumber[j]) || (menu->submenu[j]); |
| 2941 | mousehere = (y + i == my && x <= mx && mx < x + max_width); | 2943 | mousehere = (y + i == my && x <= mx && mx < x + max_width); |
| 2942 | face = faces[enabled + mousehere * 2]; | 2944 | face = faces[enabled + mousehere * 2]; |
| 2943 | /* Display the menu help string for the i-th menu item even if | 2945 | /* Display the menu help string for the i-th menu item even if |
| @@ -2945,12 +2947,12 @@ tty_menu_display (tty_menu *menu, int x, int y, int pn, int *faces, | |||
| 2945 | code does. */ | 2947 | code does. */ |
| 2946 | if (disp_help && enabled + mousehere * 2 >= 2) | 2948 | if (disp_help && enabled + mousehere * 2 >= 2) |
| 2947 | { | 2949 | { |
| 2948 | menu_help_message = menu->help_text[i]; | 2950 | menu_help_message = menu->help_text[j]; |
| 2949 | menu_help_paneno = pn - 1; | 2951 | menu_help_paneno = pn - 1; |
| 2950 | menu_help_itemno = i; | 2952 | menu_help_itemno = j; |
| 2951 | } | 2953 | } |
| 2952 | display_tty_menu_item (menu->text[i], max_width, face, x, y + i, | 2954 | display_tty_menu_item (menu->text[j], max_width, face, x, y + i, |
| 2953 | menu->submenu[i] != NULL); | 2955 | menu->submenu[j] != NULL); |
| 2954 | } | 2956 | } |
| 2955 | update_frame_with_menu (sf); | 2957 | update_frame_with_menu (sf); |
| 2956 | cursor_to (sf, row, col); | 2958 | cursor_to (sf, row, col); |
| @@ -3124,14 +3126,20 @@ screen_update (struct frame *f, struct glyph_matrix *mtx) | |||
| 3124 | update_frame_with_menu (f); | 3126 | update_frame_with_menu (f); |
| 3125 | } | 3127 | } |
| 3126 | 3128 | ||
| 3127 | /* Read user input and return X and Y coordinates where that input | 3129 | typedef enum { |
| 3128 | puts us. We only consider mouse movement and click events and | 3130 | MI_QUIT_MENU = -1, |
| 3129 | keyboard movement commands; the rest are ignored. | 3131 | MI_CONTINUE = 0, |
| 3132 | MI_ITEM_SELECTED = 1, | ||
| 3133 | MI_NEXT_ITEM = 2, | ||
| 3134 | MI_PREV_ITEM = 3, | ||
| 3135 | MI_SCROLL_FORWARD = 4, | ||
| 3136 | MI_SCROLL_BACK = 5 | ||
| 3137 | } mi_result; | ||
| 3130 | 3138 | ||
| 3131 | Value is -1 if C-g was pressed, 1 if an item was selected, 2 or 3 | 3139 | /* Read user input and return X and Y coordinates where that input |
| 3132 | if we need to move to the next or previous menu-bar menu, zero | 3140 | puts us. We only consider mouse movement and click events, and |
| 3133 | otherwise. */ | 3141 | keyboard movement commands; the rest are ignored. */ |
| 3134 | static int | 3142 | static mi_result |
| 3135 | read_menu_input (struct frame *sf, int *x, int *y, int min_y, int max_y, | 3143 | read_menu_input (struct frame *sf, int *x, int *y, int min_y, int max_y, |
| 3136 | bool *first_time) | 3144 | bool *first_time) |
| 3137 | { | 3145 | { |
| @@ -3144,7 +3152,7 @@ read_menu_input (struct frame *sf, int *x, int *y, int min_y, int max_y, | |||
| 3144 | { | 3152 | { |
| 3145 | Lisp_Object cmd; | 3153 | Lisp_Object cmd; |
| 3146 | int usable_input = 1; | 3154 | int usable_input = 1; |
| 3147 | int st = 0; | 3155 | mi_result st = MI_CONTINUE; |
| 3148 | struct tty_display_info *tty = FRAME_TTY (sf); | 3156 | struct tty_display_info *tty = FRAME_TTY (sf); |
| 3149 | Lisp_Object saved_mouse_tracking = do_mouse_tracking; | 3157 | Lisp_Object saved_mouse_tracking = do_mouse_tracking; |
| 3150 | 3158 | ||
| @@ -3160,42 +3168,42 @@ read_menu_input (struct frame *sf, int *x, int *y, int min_y, int max_y, | |||
| 3160 | do_mouse_tracking = saved_mouse_tracking; | 3168 | do_mouse_tracking = saved_mouse_tracking; |
| 3161 | 3169 | ||
| 3162 | if (EQ (cmd, Qt) || EQ (cmd, Qtty_menu_exit)) | 3170 | if (EQ (cmd, Qt) || EQ (cmd, Qtty_menu_exit)) |
| 3163 | return -1; | 3171 | return MI_QUIT_MENU; |
| 3164 | if (EQ (cmd, Qtty_menu_mouse_movement)) | 3172 | if (EQ (cmd, Qtty_menu_mouse_movement)) |
| 3165 | mouse_get_xy (x, y); | 3173 | mouse_get_xy (x, y); |
| 3166 | else if (EQ (cmd, Qtty_menu_next_menu)) | 3174 | else if (EQ (cmd, Qtty_menu_next_menu)) |
| 3167 | { | 3175 | { |
| 3168 | usable_input = 0; | 3176 | usable_input = 0; |
| 3169 | st = 2; | 3177 | st = MI_NEXT_ITEM; |
| 3170 | } | 3178 | } |
| 3171 | else if (EQ (cmd, Qtty_menu_prev_menu)) | 3179 | else if (EQ (cmd, Qtty_menu_prev_menu)) |
| 3172 | { | 3180 | { |
| 3173 | usable_input = 0; | 3181 | usable_input = 0; |
| 3174 | st = 3; | 3182 | st = MI_PREV_ITEM; |
| 3175 | } | 3183 | } |
| 3176 | else if (EQ (cmd, Qtty_menu_next_item)) | 3184 | else if (EQ (cmd, Qtty_menu_next_item)) |
| 3177 | { | 3185 | { |
| 3178 | if (*y < max_y) | 3186 | if (*y < max_y) |
| 3179 | *y += 1; | 3187 | *y += 1; |
| 3180 | else | 3188 | else |
| 3181 | *y = min_y; | 3189 | st = MI_SCROLL_FORWARD; |
| 3182 | } | 3190 | } |
| 3183 | else if (EQ (cmd, Qtty_menu_prev_item)) | 3191 | else if (EQ (cmd, Qtty_menu_prev_item)) |
| 3184 | { | 3192 | { |
| 3185 | if (*y > min_y) | 3193 | if (*y > min_y) |
| 3186 | *y -= 1; | 3194 | *y -= 1; |
| 3187 | else | 3195 | else |
| 3188 | *y = max_y; | 3196 | st = MI_SCROLL_BACK; |
| 3189 | } | 3197 | } |
| 3190 | else if (EQ (cmd, Qtty_menu_select)) | 3198 | else if (EQ (cmd, Qtty_menu_select)) |
| 3191 | st = 1; | 3199 | st = MI_ITEM_SELECTED; |
| 3192 | else if (!EQ (cmd, Qtty_menu_ignore)) | 3200 | else if (!EQ (cmd, Qtty_menu_ignore)) |
| 3193 | usable_input = 0; | 3201 | usable_input = 0; |
| 3194 | if (usable_input) | 3202 | if (usable_input) |
| 3195 | sf->mouse_moved = 1; | 3203 | sf->mouse_moved = 1; |
| 3196 | return st; | 3204 | return st; |
| 3197 | } | 3205 | } |
| 3198 | return 0; | 3206 | return MI_CONTINUE; |
| 3199 | } | 3207 | } |
| 3200 | 3208 | ||
| 3201 | /* Display menu, wait for user's response, and return that response. */ | 3209 | /* Display menu, wait for user's response, and return that response. */ |
| @@ -3214,6 +3222,7 @@ tty_menu_activate (tty_menu *menu, int *pane, int *selidx, | |||
| 3214 | struct tty_display_info *tty = FRAME_TTY (sf); | 3222 | struct tty_display_info *tty = FRAME_TTY (sf); |
| 3215 | bool first_time; | 3223 | bool first_time; |
| 3216 | Lisp_Object selectface; | 3224 | Lisp_Object selectface; |
| 3225 | int first_item = 0; | ||
| 3217 | 3226 | ||
| 3218 | /* Don't allow non-positive x0 and y0, lest the menu will wrap | 3227 | /* Don't allow non-positive x0 and y0, lest the menu will wrap |
| 3219 | around the display. */ | 3228 | around the display. */ |
| @@ -3265,7 +3274,7 @@ tty_menu_activate (tty_menu *menu, int *pane, int *selidx, | |||
| 3265 | want to interpret them as zero-based column and row coordinates, | 3274 | want to interpret them as zero-based column and row coordinates, |
| 3266 | and also because we want the first item of the menu, not its | 3275 | and also because we want the first item of the menu, not its |
| 3267 | title, to appear at x0,y0. */ | 3276 | title, to appear at x0,y0. */ |
| 3268 | tty_menu_display (menu, x0 - 1, y0 - 1, 1, title_faces, x0 - 1, y0 - 1, 0); | 3277 | tty_menu_display (menu, x0 - 1, y0 - 1, 1, title_faces, x0 - 1, y0 - 1, 0, 0); |
| 3269 | 3278 | ||
| 3270 | /* Turn off the cursor. Otherwise it shows through the menu | 3279 | /* Turn off the cursor. Otherwise it shows through the menu |
| 3271 | panes, which is ugly. */ | 3280 | panes, which is ugly. */ |
| @@ -3292,7 +3301,7 @@ tty_menu_activate (tty_menu *menu, int *pane, int *selidx, | |||
| 3292 | leave = 0; | 3301 | leave = 0; |
| 3293 | while (!leave) | 3302 | while (!leave) |
| 3294 | { | 3303 | { |
| 3295 | int input_status; | 3304 | mi_result input_status; |
| 3296 | int min_y = state[0].y; | 3305 | int min_y = state[0].y; |
| 3297 | int max_y = min (min_y + state[0].menu->count, FRAME_LINES (sf) - 1) - 1; | 3306 | int max_y = min (min_y + state[0].menu->count, FRAME_LINES (sf) - 1) - 1; |
| 3298 | 3307 | ||
| @@ -3300,36 +3309,59 @@ tty_menu_activate (tty_menu *menu, int *pane, int *selidx, | |||
| 3300 | if (input_status) | 3309 | if (input_status) |
| 3301 | { | 3310 | { |
| 3302 | leave = 1; | 3311 | leave = 1; |
| 3303 | if (input_status == -1) | 3312 | switch (input_status) |
| 3304 | { | 3313 | { |
| 3314 | case MI_QUIT_MENU: | ||
| 3305 | /* Remove the last help-echo, so that it doesn't | 3315 | /* Remove the last help-echo, so that it doesn't |
| 3306 | re-appear after "Quit". */ | 3316 | re-appear after "Quit". */ |
| 3307 | show_help_echo (Qnil, Qnil, Qnil, Qnil); | 3317 | show_help_echo (Qnil, Qnil, Qnil, Qnil); |
| 3308 | result = TTYM_NO_SELECT; | 3318 | result = TTYM_NO_SELECT; |
| 3309 | } | 3319 | break; |
| 3310 | else if (input_status == 2) | 3320 | case MI_NEXT_ITEM: |
| 3311 | { | ||
| 3312 | if (kbd_navigation) | 3321 | if (kbd_navigation) |
| 3313 | result = TTYM_NEXT; | 3322 | result = TTYM_NEXT; |
| 3314 | else | 3323 | else |
| 3315 | leave = 0; | 3324 | leave = 0; |
| 3316 | } | 3325 | break; |
| 3317 | else if (input_status == 3) | 3326 | case MI_PREV_ITEM: |
| 3318 | { | ||
| 3319 | if (kbd_navigation) | 3327 | if (kbd_navigation) |
| 3320 | result = TTYM_PREV; | 3328 | result = TTYM_PREV; |
| 3321 | else | 3329 | else |
| 3322 | leave = 0; | 3330 | leave = 0; |
| 3331 | break; | ||
| 3332 | case MI_SCROLL_FORWARD: | ||
| 3333 | if (y - min_y == state[0].menu->count - 1 - first_item) | ||
| 3334 | { | ||
| 3335 | y = min_y; | ||
| 3336 | first_item = 0; | ||
| 3337 | } | ||
| 3338 | else | ||
| 3339 | first_item++; | ||
| 3340 | leave = 0; | ||
| 3341 | break; | ||
| 3342 | case MI_SCROLL_BACK: | ||
| 3343 | if (first_item == 0) | ||
| 3344 | { | ||
| 3345 | y = max_y; | ||
| 3346 | first_item = state[0].menu->count - 1 - (y - min_y); | ||
| 3347 | } | ||
| 3348 | else | ||
| 3349 | first_item--; | ||
| 3350 | leave = 0; | ||
| 3351 | break; | ||
| 3352 | default: | ||
| 3353 | /* MI_ITEM_SELECTED is handled below, so nothing to do. */ | ||
| 3354 | break; | ||
| 3323 | } | 3355 | } |
| 3324 | } | 3356 | } |
| 3325 | if (sf->mouse_moved && input_status != -1) | 3357 | if (sf->mouse_moved && input_status != MI_QUIT_MENU) |
| 3326 | { | 3358 | { |
| 3327 | sf->mouse_moved = 0; | 3359 | sf->mouse_moved = 0; |
| 3328 | result = TTYM_IA_SELECT; | 3360 | result = TTYM_IA_SELECT; |
| 3329 | for (i = 0; i < statecount; i++) | 3361 | for (i = 0; i < statecount; i++) |
| 3330 | if (state[i].x <= x && x < state[i].x + state[i].menu->width + 2) | 3362 | if (state[i].x <= x && x < state[i].x + state[i].menu->width + 2) |
| 3331 | { | 3363 | { |
| 3332 | int dy = y - state[i].y; | 3364 | int dy = y - state[i].y + first_item; |
| 3333 | if (0 <= dy && dy < state[i].menu->count) | 3365 | if (0 <= dy && dy < state[i].menu->count) |
| 3334 | { | 3366 | { |
| 3335 | if (!state[i].menu->submenu[dy]) | 3367 | if (!state[i].menu->submenu[dy]) |
| @@ -3358,7 +3390,7 @@ tty_menu_activate (tty_menu *menu, int *pane, int *selidx, | |||
| 3358 | state[i].x, | 3390 | state[i].x, |
| 3359 | state[i].y, | 3391 | state[i].y, |
| 3360 | state[i].pane, | 3392 | state[i].pane, |
| 3361 | faces, x, y, 1); | 3393 | faces, x, y, first_item, 1); |
| 3362 | state[statecount].menu = state[i].menu->submenu[dy]; | 3394 | state[statecount].menu = state[i].menu->submenu[dy]; |
| 3363 | state[statecount].pane = state[i].menu->panenumber[dy]; | 3395 | state[statecount].pane = state[i].menu->panenumber[dy]; |
| 3364 | state[statecount].screen_behind | 3396 | state[statecount].screen_behind |
| @@ -3374,7 +3406,7 @@ tty_menu_activate (tty_menu *menu, int *pane, int *selidx, | |||
| 3374 | state[statecount - 1].x, | 3406 | state[statecount - 1].x, |
| 3375 | state[statecount - 1].y, | 3407 | state[statecount - 1].y, |
| 3376 | state[statecount - 1].pane, | 3408 | state[statecount - 1].pane, |
| 3377 | faces, x, y, 1); | 3409 | faces, x, y, first_item, 1); |
| 3378 | tty_hide_cursor (tty); | 3410 | tty_hide_cursor (tty); |
| 3379 | fflush (tty->output); | 3411 | fflush (tty->output); |
| 3380 | } | 3412 | } |