summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/popupwin.c62
-rw-r--r--src/proto/popupwin.pro2
-rw-r--r--src/structs.h7
-rw-r--r--src/testdir/dumps/Test_popupwin_close_01.dump10
-rw-r--r--src/testdir/dumps/Test_popupwin_close_02.dump10
-rw-r--r--src/testdir/dumps/Test_popupwin_close_03.dump10
-rw-r--r--src/testdir/test_popupwin.vim57
-rw-r--r--src/ui.c25
-rw-r--r--src/version.c2
9 files changed, 183 insertions, 2 deletions
diff --git a/src/popupwin.c b/src/popupwin.c
index 96263bca4f..a10d4e0a2f 100644
--- a/src/popupwin.c
+++ b/src/popupwin.c
@@ -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;
@@ -1242,6 +1279,19 @@ popup_close_and_callback(win_T *wp, typval_T *arg)
}
/*
+ * 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.
diff --git a/src/proto/popupwin.pro b/src/proto/popupwin.pro
index 7ac8612cd7..a251f9ad56 100644
--- a/src/proto/popupwin.pro
+++ b/src/proto/popupwin.pro
@@ -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);
diff --git a/src/structs.h b/src/structs.h
index 208a11ece6..b579de3f5c 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -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)
diff --git a/src/testdir/dumps/Test_popupwin_close_01.dump b/src/testdir/dumps/Test_popupwin_close_01.dump
new file mode 100644
index 0000000000..e11ae83dd8
--- /dev/null
+++ b/src/testdir/dumps/Test_popupwin_close_01.dump
@@ -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|
diff --git a/src/testdir/dumps/Test_popupwin_close_02.dump b/src/testdir/dumps/Test_popupwin_close_02.dump
new file mode 100644
index 0000000000..75342ef258
--- /dev/null
+++ b/src/testdir/dumps/Test_popupwin_close_02.dump
@@ -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|
diff --git a/src/testdir/dumps/Test_popupwin_close_03.dump b/src/testdir/dumps/Test_popupwin_close_03.dump
new file mode 100644
index 0000000000..82438c8eea
--- /dev/null
+++ b/src/testdir/dumps/Test_popupwin_close_03.dump
@@ -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|
diff --git a/src/testdir/test_popupwin.vim b/src/testdir/test_popupwin.vim
index f4bc33cb11..a3e6acc5c3 100644
--- a/src/testdir/test_popupwin.vim
+++ b/src/testdir/test_popupwin.vim
@@ -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'
diff --git a/src/ui.c b/src/ui.c
index d09e0ab90d..1732fe8ff7 100644
--- a/src/ui.c
+++ b/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
diff --git a/src/version.c b/src/version.c
index 656cb05101..89b7f4f429 100644
--- a/src/version.c
+++ b/src/version.c
@@ -778,6 +778,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1609,
+/**/
1608,
/**/
1607,