aboutsummaryrefslogtreecommitdiffstats
path: root/src/term.c
diff options
context:
space:
mode:
authorEli Zaretskii2013-10-14 18:37:12 +0300
committerEli Zaretskii2013-10-14 18:37:12 +0300
commitccd4a7833f341e2c22d6933357282954af6a57b2 (patch)
treee28e73f9b0e1b85ee9d81adb79d7389c04e4473f /src/term.c
parent77e3b1b7095b3376dbddd22cbca4827b797767c0 (diff)
downloademacs-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.c114
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
2916static void 2917static void
2917tty_menu_display (tty_menu *menu, int x, int y, int pn, int *faces, 2918tty_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 3129typedef 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. */
3134static int 3142static mi_result
3135read_menu_input (struct frame *sf, int *x, int *y, int min_y, int max_y, 3143read_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 }