diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/popupwin.c | 62 | ||||
-rw-r--r-- | src/proto/popupwin.pro | 2 | ||||
-rw-r--r-- | src/structs.h | 7 | ||||
-rw-r--r-- | src/testdir/dumps/Test_popupwin_close_01.dump | 10 | ||||
-rw-r--r-- | src/testdir/dumps/Test_popupwin_close_02.dump | 10 | ||||
-rw-r--r-- | src/testdir/dumps/Test_popupwin_close_03.dump | 10 | ||||
-rw-r--r-- | src/testdir/test_popupwin.vim | 57 | ||||
-rw-r--r-- | src/ui.c | 25 | ||||
-rw-r--r-- | src/version.c | 2 |
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' @@ -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, |