mirror of
https://github.com/vim/vim.git
synced 2025-09-24 03:44:06 -04:00
patch 8.1.1609: the user cannot easily close a popup window
Problem: The user cannot easily close a popup window. Solution: Add the "close" property. (mostly by Masato Nishihata, closes #4601)
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
*popup.txt* For Vim version 8.1. Last change: 2019 Jun 29
|
||||
*popup.txt* For Vim version 8.1. Last change: 2019 Jun 30
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
@@ -68,12 +68,12 @@ increase the width or use the "minwidth" property.
|
||||
|
||||
By default the 'wrap' option is set, so that no text disappears. Otherwise,
|
||||
if there is not enough space then the window is shifted left in order to
|
||||
display more text. This can be disabled with the "fixed" property. Also
|
||||
disabled when right-aligned.
|
||||
display more text. When right-aligned the window is shifted right to display
|
||||
more text. The shifting can be disabled with the "fixed" property.
|
||||
|
||||
Vim tries to show the popup in the location you specify. In some cases, e.g.
|
||||
when the popup would go outside of the Vim window, it will show it somewhere
|
||||
else. E.g. if you use `popup_atcursor()` the popup normally shows just above
|
||||
nearby. E.g. if you use `popup_atcursor()` the popup normally shows just above
|
||||
the current cursor position, but if the cursor is close to the top of the Vim
|
||||
window it will be placed below the cursor position.
|
||||
|
||||
@@ -85,6 +85,18 @@ That way you can still see where it is, even though you cannot see the text
|
||||
that it is in.
|
||||
|
||||
|
||||
CLOSING THE POPUP WINDOW *popup-close*
|
||||
|
||||
Normally the plugin that created the popup window is also in charge of closing
|
||||
it. If somehow a popup hangs around, you can close all of them with: >
|
||||
call popup_clear()
|
||||
Some popups, such as notifications, close after a specified time. This can be
|
||||
set with the "time" property on `popup_create()`.
|
||||
Otherwise, a popup can be closed by clicking on the X in the top-right corner
|
||||
or by clicking anywhere inside the popup. This must be enabled with the
|
||||
"close" property. It is set by default for notifications.
|
||||
|
||||
|
||||
TODO:
|
||||
- Currently 'buftype' is set to "popup", but all the specifics are on the
|
||||
window. Can we use a "normal" buffer and put the type on the window? (#4595)
|
||||
@@ -350,13 +362,14 @@ popup_notification({text}, {options}) *popup_notification()*
|
||||
\ 'drag': 1,
|
||||
\ 'highlight': 'WarningMsg',
|
||||
\ 'border': [],
|
||||
\ 'close': 'click',
|
||||
\ 'padding': [0,1,0,1],
|
||||
\ })
|
||||
< The PopupNotification highlight group is used instead of
|
||||
WarningMsg if it is defined.
|
||||
|
||||
This popup should only be used with the |+timers| feature,
|
||||
otherwise it will not disappear.
|
||||
Without the |+timers| feature the poup will not disappear
|
||||
automatically, the user has to click in it.
|
||||
|
||||
The position will be adjusted to avoid overlap with other
|
||||
notifications.
|
||||
@@ -371,25 +384,26 @@ popup_show({id}) *popup_show()*
|
||||
popup_setoptions({id}, {options}) *popup_setoptions()*
|
||||
Override options in popup {id} with entries in {options}.
|
||||
These options can be set:
|
||||
flip
|
||||
firstline
|
||||
title
|
||||
wrap
|
||||
drag
|
||||
highlight
|
||||
padding
|
||||
border
|
||||
borderhighlight
|
||||
borderchars
|
||||
borderhighlight
|
||||
callback
|
||||
close
|
||||
drag
|
||||
filter
|
||||
firstline
|
||||
flip
|
||||
highlight
|
||||
mask
|
||||
moved
|
||||
padding
|
||||
scrollbar
|
||||
scrollbarhighlight
|
||||
thumbhighlight
|
||||
zindex
|
||||
mask
|
||||
time
|
||||
moved
|
||||
filter
|
||||
callback
|
||||
title
|
||||
wrap
|
||||
zindex
|
||||
The options from |popup_move()| can also be used.
|
||||
For "hidden" use |popup_hide()| and |popup_show()|.
|
||||
"tabpage" cannot be changed.
|
||||
@@ -509,6 +523,14 @@ The second argument of |popup_create()| is a dictionary with options:
|
||||
popup does not have a border. As soon as dragging
|
||||
starts and "pos" is "center" it is changed to
|
||||
"topleft".
|
||||
close When "button" an X is displayed in the top-right, on
|
||||
top of any border, padding or text. When clicked on
|
||||
the X the popup will close. Any callback is invoked
|
||||
with the value -2.
|
||||
When "click" any mouse click in the popup will close
|
||||
it.
|
||||
When "none" (the default) mouse clicks do not close
|
||||
the popup window.
|
||||
highlight Highlight group name to use for the text, stored in
|
||||
the 'wincolor' option.
|
||||
padding List with numbers, defining the padding
|
||||
|
@@ -180,6 +180,17 @@ popup_on_border(win_T *wp, int row, int col)
|
||||
|| (col == popup_width(wp) - 1 && wp->w_popup_border[1] > 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return TRUE if "row"/"col" is on the "X" button of the popup.
|
||||
* The values are relative to the top-left corner.
|
||||
* Caller should check w_popup_close is POPCLOSE_BUTTON.
|
||||
*/
|
||||
int
|
||||
popup_on_X_button(win_T *wp, int row, int col)
|
||||
{
|
||||
return row == 0 && col == popup_width(wp) - 1;
|
||||
}
|
||||
|
||||
// Values set when dragging a popup window starts.
|
||||
static int drag_start_row;
|
||||
static int drag_start_col;
|
||||
@@ -384,6 +395,30 @@ apply_general_options(win_T *wp, dict_T *dict)
|
||||
if (di != NULL)
|
||||
wp->w_popup_drag = dict_get_number(dict, (char_u *)"drag");
|
||||
|
||||
di = dict_find(dict, (char_u *)"close", -1);
|
||||
if (di != NULL)
|
||||
{
|
||||
int ok = TRUE;
|
||||
|
||||
if (di->di_tv.v_type == VAR_STRING && di->di_tv.vval.v_string != NULL)
|
||||
{
|
||||
char_u *s = di->di_tv.vval.v_string;
|
||||
|
||||
if (STRCMP(s, "none") == 0)
|
||||
wp->w_popup_close = POPCLOSE_NONE;
|
||||
else if (STRCMP(s, "button") == 0)
|
||||
wp->w_popup_close = POPCLOSE_BUTTON;
|
||||
else if (STRCMP(s, "click") == 0)
|
||||
wp->w_popup_close = POPCLOSE_CLICK;
|
||||
else
|
||||
ok = FALSE;
|
||||
}
|
||||
else
|
||||
ok = FALSE;
|
||||
if (!ok)
|
||||
semsg(_(e_invargNval), "close", tv_get_string(&di->di_tv));
|
||||
}
|
||||
|
||||
str = dict_get_string(dict, (char_u *)"highlight", FALSE);
|
||||
if (str != NULL)
|
||||
set_string_option_direct_in_win(wp, (char_u *)"wincolor", -1,
|
||||
@@ -1072,6 +1107,7 @@ popup_create(typval_T *argvars, typval_T *rettv, create_type_T type)
|
||||
|
||||
// set default values
|
||||
wp->w_zindex = POPUPWIN_DEFAULT_ZINDEX;
|
||||
wp->w_popup_close = POPCLOSE_NONE;
|
||||
|
||||
if (type == TYPE_NOTIFICATION)
|
||||
{
|
||||
@@ -1106,6 +1142,7 @@ popup_create(typval_T *argvars, typval_T *rettv, create_type_T type)
|
||||
wp->w_zindex = POPUPWIN_NOTIFICATION_ZINDEX;
|
||||
wp->w_minwidth = 20;
|
||||
wp->w_popup_drag = 1;
|
||||
wp->w_popup_close = POPCLOSE_CLICK;
|
||||
for (i = 0; i < 4; ++i)
|
||||
wp->w_popup_border[i] = 1;
|
||||
wp->w_popup_padding[1] = 1;
|
||||
@@ -1241,6 +1278,19 @@ popup_close_and_callback(win_T *wp, typval_T *arg)
|
||||
popup_close(id);
|
||||
}
|
||||
|
||||
/*
|
||||
* Close popup "wp" because of a mouse click.
|
||||
*/
|
||||
void
|
||||
popup_close_for_mouse_click(win_T *wp)
|
||||
{
|
||||
typval_T res;
|
||||
|
||||
res.v_type = VAR_NUMBER;
|
||||
res.vval.v_number = -2;
|
||||
popup_close_and_callback(wp, &res);
|
||||
}
|
||||
|
||||
/*
|
||||
* In a filter: check if the typed key is a mouse event that is used for
|
||||
* dragging the popup.
|
||||
@@ -1816,6 +1866,10 @@ f_popup_getoptions(typval_T *argvars, typval_T *rettv)
|
||||
break;
|
||||
}
|
||||
|
||||
dict_add_string(dict, "close", (char_u *)(
|
||||
wp->w_popup_close == POPCLOSE_BUTTON ? "button"
|
||||
: wp->w_popup_close == POPCLOSE_CLICK ? "click" : "none"));
|
||||
|
||||
# if defined(FEAT_TIMERS)
|
||||
dict_add_number(dict, "time", wp->w_popup_timer != NULL
|
||||
? (long)wp->w_popup_timer->tr_interval : 0L);
|
||||
@@ -2434,6 +2488,14 @@ update_popups(void (*win_update)(win_T *wp))
|
||||
}
|
||||
}
|
||||
|
||||
if (wp->w_popup_close == POPCLOSE_BUTTON)
|
||||
{
|
||||
// close button goes on top of anything at the top-right corner
|
||||
buf[mb_char2bytes('X', buf)] = NUL;
|
||||
screen_puts(buf, wp->w_winrow, wp->w_wincol + total_width - 1,
|
||||
wp->w_popup_border[0] > 0 ? border_attr[0] : popup_attr);
|
||||
}
|
||||
|
||||
update_popup_transparent(wp, 0);
|
||||
|
||||
// Back to the normal zindex.
|
||||
|
@@ -1,5 +1,6 @@
|
||||
/* popupwin.c */
|
||||
int popup_on_border(win_T *wp, int row, int col);
|
||||
int popup_on_X_button(win_T *wp, int row, int col);
|
||||
void popup_start_drag(win_T *wp);
|
||||
void popup_drag(win_T *wp);
|
||||
void popup_set_firstline(win_T *wp);
|
||||
@@ -10,6 +11,7 @@ void popup_adjust_position(win_T *wp);
|
||||
void f_popup_clear(typval_T *argvars, typval_T *rettv);
|
||||
void f_popup_create(typval_T *argvars, typval_T *rettv);
|
||||
void f_popup_atcursor(typval_T *argvars, typval_T *rettv);
|
||||
void popup_close_for_mouse_click(win_T *wp);
|
||||
void f_popup_filter_menu(typval_T *argvars, typval_T *rettv);
|
||||
void f_popup_filter_yesno(typval_T *argvars, typval_T *rettv);
|
||||
void f_popup_dialog(typval_T *argvars, typval_T *rettv);
|
||||
|
@@ -1996,6 +1996,12 @@ typedef enum {
|
||||
POPPOS_CENTER
|
||||
} poppos_T;
|
||||
|
||||
typedef enum {
|
||||
POPCLOSE_NONE,
|
||||
POPCLOSE_BUTTON,
|
||||
POPCLOSE_CLICK
|
||||
} popclose_T;
|
||||
|
||||
# define POPUPWIN_DEFAULT_ZINDEX 50
|
||||
# define POPUPMENU_ZINDEX 100
|
||||
# define POPUPWIN_DIALOG_ZINDEX 200
|
||||
@@ -2920,6 +2926,7 @@ struct window_S
|
||||
colnr_T w_popup_mincol; // close popup if cursor before this col
|
||||
colnr_T w_popup_maxcol; // close popup if cursor after this col
|
||||
int w_popup_drag; // allow moving the popup with the mouse
|
||||
popclose_T w_popup_close; // allow closing the popup with the mouse
|
||||
list_T *w_popup_mask; // list of lists for "mask"
|
||||
|
||||
# if defined(FEAT_TIMERS)
|
||||
|
10
src/testdir/dumps/Test_popupwin_close_01.dump
Normal file
10
src/testdir/dumps/Test_popupwin_close_01.dump
Normal file
@@ -0,0 +1,10 @@
|
||||
>╔+0#0000001#ffd7ff255|═@5|X| +0#0000000#ffffff0@66
|
||||
|║+0#0000001#ffd7ff255|f|o@1|b|a|r|║| +0#0000000#ffffff0@66
|
||||
|╚+0#0000001#ffd7ff255|═@5|╝| +0#0000000#ffffff0@5|n+0#0000001#ffd7ff255|o|t|i|f|i|c|a|t|i|o|n| +0#0000000#ffffff0@48
|
||||
|4| @73
|
||||
|5| |n+0#0000001#ffd7ff255|o| |b|o|r|d|e|r| |h|e|r|X| +0#0000000#ffffff0@5| +0#0000001#ffd7ff255@12|X| +0#0000000#ffffff0@38
|
||||
|6| @20| +0#0000001#ffd7ff255|o|n|l|y| |p|a|d@1|i|n|g| | +0#0000000#ffffff0@38
|
||||
|7| @20| +0#0000001#ffd7ff255@13| +0#0000000#ffffff0@38
|
||||
|8| @73
|
||||
|9| @73
|
||||
@57|1|,|1| @10|T|o|p|
|
10
src/testdir/dumps/Test_popupwin_close_02.dump
Normal file
10
src/testdir/dumps/Test_popupwin_close_02.dump
Normal file
@@ -0,0 +1,10 @@
|
||||
>1+0&#ffffff0| @73
|
||||
|2| @73
|
||||
|3| @12|n+0#0000001#ffd7ff255|o|t|i|f|i|c|a|t|i|o|n| +0#0000000#ffffff0@48
|
||||
|4| @73
|
||||
|5| |n+0#0000001#ffd7ff255|o| |b|o|r|d|e|r| |h|e|r|X| +0#0000000#ffffff0@5| +0#0000001#ffd7ff255@12|X| +0#0000000#ffffff0@38
|
||||
|6| @20| +0#0000001#ffd7ff255|o|n|l|y| |p|a|d@1|i|n|g| | +0#0000000#ffffff0@38
|
||||
|7| @20| +0#0000001#ffd7ff255@13| +0#0000000#ffffff0@38
|
||||
|8| @73
|
||||
|9| @73
|
||||
|:|c|a|l@1| |C|l|o|s|e|W|i|t|h|X|(|)| @38|1|,|1| @10|T|o|p|
|
10
src/testdir/dumps/Test_popupwin_close_03.dump
Normal file
10
src/testdir/dumps/Test_popupwin_close_03.dump
Normal file
@@ -0,0 +1,10 @@
|
||||
>1+0&#ffffff0| @73
|
||||
|2| @73
|
||||
|3| @73
|
||||
|4| @73
|
||||
|5| |n+0#0000001#ffd7ff255|o| |b|o|r|d|e|r| |h|e|r|X| +0#0000000#ffffff0@5| +0#0000001#ffd7ff255@12|X| +0#0000000#ffffff0@38
|
||||
|6| @20| +0#0000001#ffd7ff255|o|n|l|y| |p|a|d@1|i|n|g| | +0#0000000#ffffff0@38
|
||||
|7| @20| +0#0000001#ffd7ff255@13| +0#0000000#ffffff0@38
|
||||
|8| @73
|
||||
|9| @73
|
||||
|P|o|p|u|p| |c|l|o|s|e|d| |w|i|t|h| |-|2| @36|1|,|1| @10|T|o|p|
|
@@ -365,6 +365,63 @@ func Test_popup_drag()
|
||||
call delete('XtestPopupDrag')
|
||||
endfunc
|
||||
|
||||
func Test_popup_close_with_mouse()
|
||||
if !CanRunVimInTerminal()
|
||||
throw 'Skipped: cannot make screendumps'
|
||||
endif
|
||||
let lines =<< trim END
|
||||
call setline(1, range(1, 20))
|
||||
" With border, can click on X
|
||||
let winid = popup_create('foobar', {
|
||||
\ 'close': 'button',
|
||||
\ 'border': [],
|
||||
\ 'line': 1,
|
||||
\ 'col': 1,
|
||||
\ })
|
||||
func CloseMsg(id, result)
|
||||
echomsg 'Popup closed with ' .. a:result
|
||||
endfunc
|
||||
let winid = popup_create('notification', {
|
||||
\ 'close': 'click',
|
||||
\ 'line': 3,
|
||||
\ 'col': 15,
|
||||
\ 'callback': 'CloseMsg',
|
||||
\ })
|
||||
let winid = popup_create('no border here', {
|
||||
\ 'close': 'button',
|
||||
\ 'line': 5,
|
||||
\ 'col': 3,
|
||||
\ })
|
||||
let winid = popup_create('only padding', {
|
||||
\ 'close': 'button',
|
||||
\ 'padding': [],
|
||||
\ 'line': 5,
|
||||
\ 'col': 23,
|
||||
\ })
|
||||
func CloseWithX()
|
||||
call feedkeys("\<F3>\<LeftMouse>\<LeftRelease>", "xt")
|
||||
endfunc
|
||||
map <silent> <F3> :call test_setmouse(1, len('foobar') + 2)<CR>
|
||||
func CloseWithClick()
|
||||
call feedkeys("\<F4>\<LeftMouse>\<LeftRelease>", "xt")
|
||||
endfunc
|
||||
map <silent> <F4> :call test_setmouse(3, 17)<CR>
|
||||
END
|
||||
call writefile(lines, 'XtestPopupClose')
|
||||
let buf = RunVimInTerminal('-S XtestPopupClose', {'rows': 10})
|
||||
call VerifyScreenDump(buf, 'Test_popupwin_close_01', {})
|
||||
|
||||
call term_sendkeys(buf, ":call CloseWithX()\<CR>")
|
||||
call VerifyScreenDump(buf, 'Test_popupwin_close_02', {})
|
||||
|
||||
call term_sendkeys(buf, ":call CloseWithClick()\<CR>")
|
||||
call VerifyScreenDump(buf, 'Test_popupwin_close_03', {})
|
||||
|
||||
" clean up
|
||||
call StopVimInTerminal(buf)
|
||||
call delete('XtestPopupClose')
|
||||
endfunction
|
||||
|
||||
func Test_popup_with_mask()
|
||||
if !CanRunVimInTerminal()
|
||||
throw 'Skipped: cannot make screendumps'
|
||||
|
25
src/ui.c
25
src/ui.c
@@ -2929,6 +2929,7 @@ jump_to_mouse(
|
||||
#endif
|
||||
#ifdef FEAT_TEXT_PROP
|
||||
static int in_popup_win = FALSE;
|
||||
static win_T *click_in_popup_win = NULL;
|
||||
#endif
|
||||
static int prev_row = -1;
|
||||
static int prev_col = -1;
|
||||
@@ -2957,7 +2958,11 @@ jump_to_mouse(
|
||||
dragwin = NULL;
|
||||
did_drag = FALSE;
|
||||
#ifdef FEAT_TEXT_PROP
|
||||
if (click_in_popup_win != NULL && popup_dragwin == NULL)
|
||||
popup_close_for_mouse_click(click_in_popup_win);
|
||||
|
||||
popup_dragwin = NULL;
|
||||
click_in_popup_win = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -3001,6 +3006,7 @@ retnomove:
|
||||
// Continue a modeless selection in a popup window or dragging it.
|
||||
if (in_popup_win)
|
||||
{
|
||||
click_in_popup_win = NULL; // don't close it on release
|
||||
if (popup_dragwin != NULL)
|
||||
{
|
||||
// dragging a popup window
|
||||
@@ -3050,13 +3056,27 @@ retnomove:
|
||||
{
|
||||
on_sep_line = 0;
|
||||
in_popup_win = TRUE;
|
||||
if (wp->w_popup_drag && popup_on_border(wp, row, col))
|
||||
if (wp->w_popup_close == POPCLOSE_BUTTON
|
||||
&& which_button == MOUSE_LEFT
|
||||
&& popup_on_X_button(wp, row, col))
|
||||
{
|
||||
popup_close_for_mouse_click(wp);
|
||||
return IN_UNKNOWN;
|
||||
}
|
||||
else if (wp->w_popup_drag && popup_on_border(wp, row, col))
|
||||
{
|
||||
popup_dragwin = wp;
|
||||
popup_start_drag(wp);
|
||||
return IN_UNKNOWN;
|
||||
}
|
||||
if (which_button == MOUSE_LEFT)
|
||||
// Only close on release, otherwise it's not possible to drag or do
|
||||
// modeless selection.
|
||||
else if (wp->w_popup_close == POPCLOSE_CLICK
|
||||
&& which_button == MOUSE_LEFT)
|
||||
{
|
||||
click_in_popup_win = wp;
|
||||
}
|
||||
else if (which_button == MOUSE_LEFT)
|
||||
// If the click is in the scrollbar, may scroll up/down.
|
||||
popup_handle_scrollbar_click(wp, row, col);
|
||||
# ifdef FEAT_CLIPBOARD
|
||||
@@ -3244,6 +3264,7 @@ retnomove:
|
||||
return IN_UNKNOWN;
|
||||
}
|
||||
// continue a modeless selection in a popup window
|
||||
click_in_popup_win = NULL;
|
||||
return IN_OTHER_WIN;
|
||||
}
|
||||
#endif
|
||||
|
@@ -777,6 +777,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
1609,
|
||||
/**/
|
||||
1608,
|
||||
/**/
|
||||
|
Reference in New Issue
Block a user