]> granicus.if.org Git - vim/commitdiff
patch 8.1.1589: popup window does not indicate scroll position v8.1.1589
authorBram Moolenaar <Bram@vim.org>
Tue, 25 Jun 2019 03:15:58 +0000 (05:15 +0200)
committerBram Moolenaar <Bram@vim.org>
Tue, 25 Jun 2019 03:15:58 +0000 (05:15 +0200)
Problem:    Popup window does not indicate scroll position.
Solution:   Add a scrollbar.

runtime/doc/popup.txt
src/popupwin.c
src/structs.h
src/testdir/dumps/Test_popupwin_firstline.dump
src/testdir/dumps/Test_popupwin_scroll_1.dump [new file with mode: 0644]
src/testdir/dumps/Test_popupwin_scroll_2.dump [new file with mode: 0644]
src/testdir/dumps/Test_popupwin_scroll_3.dump [new file with mode: 0644]
src/testdir/dumps/Test_popupwin_scroll_4.dump [new file with mode: 0644]
src/testdir/test_popupwin.vim
src/version.c

index d04a6b44ec72ae1a11ac7d50d19eda961d168b50..21af8f9e2e240bfb14af8a7f62de85be6982be1b 100644 (file)
@@ -87,9 +87,10 @@ that it is in.
 
 
 TODO:
-- Why does 'nrformats' leak from the popup window buffer???
 - When the lines do not fit show a scrollbar (like in the popup menu).
-  Use the mouse wheel for scrolling.
+- Use the mouse wheel for scrolling.
+- Have a way to scroll to the botton. (#4577)
+- Why does 'nrformats' leak from the popup window buffer???
 - Disable commands, feedkeys(), CTRL-W, etc. in a popup window.
   Use ERROR_IF_POPUP_WINDOW for more commands.
 - Add 'balloonpopup': instead of showing text, let the callback open a popup
@@ -347,6 +348,9 @@ popup_notification({text}, {options})                        *popup_notification()*
 <              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.
+
                The position will be adjusted to avoid overlap with other
                notifications.
                Use {options} to change the properties.
@@ -370,6 +374,7 @@ popup_setoptions({id}, {options})                   *popup_setoptions()*
                        border
                        borderhighlight
                        borderchars
+                       scrollbar
                        zindex
                        mask
                        time
@@ -475,6 +480,7 @@ The second argument of |popup_create()| is a dictionary with options:
        firstline       First buffer line to display.  When larger than one it
                        looks like the text scrolled up.  When out of range
                        the last buffer line will at the top of the window.
+                       Also see "scrollbar".
        hidden          When TRUE the popup exists but is not displayed; use
                        `popup_show()` to unhide it.
                        {not implemented yet}
@@ -525,6 +531,8 @@ The second argument of |popup_create()| is a dictionary with options:
                        By default a double line is used all around when
                        'encoding' is "utf-8" and 'ambiwidth' is "single",
                        otherwise ASCII characters are used.
+       scrollbar       non-zero: show a scrollbar when the text doesn't fit.
+                       zero: do not show a scrollbar.  Default is non-zero.
        zindex          Priority for the popup, default 50.  Minimum value is
                        1, maximum value is 32000.
        mask            A list of lists with coordinates, defining parts of
index 16ec1a2830eabfe30df979434d924df320846114..aa8bba088f6aa70d7cae8e7500cf91ccda11c07d 100644 (file)
@@ -287,6 +287,10 @@ apply_general_options(win_T *wp, dict_T *dict)
     if (wp->w_firstline < 1)
        wp->w_firstline = 1;
 
+    di = dict_find(dict, (char_u *)"scrollbar", -1);
+    if (di != NULL)
+       wp->w_want_scrollbar = dict_get_number(dict, (char_u *)"scrollbar");
+
     str = dict_get_string(dict, (char_u *)"title", FALSE);
     if (str != NULL)
     {
@@ -733,6 +737,9 @@ popup_adjust_position(win_T *wp)
            break;
     }
 
+    wp->w_has_scrollbar = wp->w_want_scrollbar
+          && (wp->w_topline > 1 || lnum <= wp->w_buffer->b_ml.ml_line_count);
+
     minwidth = wp->w_minwidth;
     if (wp->w_popup_title != NULL && *wp->w_popup_title != NUL)
     {
@@ -1047,6 +1054,7 @@ popup_create(typval_T *argvars, typval_T *rettv, create_type_T type)
        VIM_CLEAR(wp->w_border_highlight[i]);
     for (i = 0; i < 8; ++i)
        wp->w_border_char[i] = 0;
+    wp->w_want_scrollbar = 1;
 
     // Deal with options.
     apply_options(wp, argvars[1].vval.v_dict);
@@ -1483,6 +1491,7 @@ f_popup_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
     dict_T     *dict;
     int                id = (int)tv_get_number(argvars);
     win_T      *wp = find_popup_win(id);
+    linenr_T   old_firstline;
 
     if (wp == NULL)
        return;  // invalid {id}
@@ -1493,10 +1502,13 @@ f_popup_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
        return;
     }
     dict = argvars[1].vval.v_dict;
+    old_firstline = wp->w_firstline;
 
     apply_move_options(wp, dict);
     apply_general_options(wp, dict);
 
+    if (old_firstline != wp->w_firstline)
+       redraw_win_later(wp, NOT_VALID);
     popup_mask_refresh = TRUE;
     popup_adjust_position(wp);
 }
@@ -1534,6 +1546,7 @@ f_popup_getpos(typval_T *argvars, typval_T *rettv)
        dict_add_number(dict, "core_width", wp->w_width);
        dict_add_number(dict, "core_height", wp->w_height);
 
+       dict_add_number(dict, "scrollbar", wp->w_has_scrollbar);
        dict_add_number(dict, "visible",
                      win_valid(wp) && (wp->w_popup_flags & POPF_HIDDEN) == 0);
     }
@@ -1656,6 +1669,7 @@ f_popup_getoptions(typval_T *argvars, typval_T *rettv)
        dict_add_number(dict, "maxheight", wp->w_maxheight);
        dict_add_number(dict, "maxwidth", wp->w_maxwidth);
        dict_add_number(dict, "firstline", wp->w_firstline);
+       dict_add_number(dict, "scrollbar", wp->w_want_scrollbar);
        dict_add_number(dict, "zindex", wp->w_zindex);
        dict_add_number(dict, "fixed", wp->w_popup_fixed);
        dict_add_string(dict, "title", wp->w_popup_title);
@@ -2114,6 +2128,10 @@ update_popups(void (*win_update)(win_T *wp))
     char_u  buf[MB_MAXBYTES];
     int            row;
     int            i;
+    int            sb_thumb_top;
+    int            sb_thumb_height;
+    int            attr_scroll = highlight_attr[HLF_PSB];
+    int            attr_thumb = highlight_attr[HLF_PST];
 
     // Find the window with the lowest zindex that hasn't been updated yet,
     // so that the window with a higher zindex is drawn later, thus goes on
@@ -2143,7 +2161,8 @@ update_popups(void (*win_update)(win_T *wp))
        wp->w_wincol -= left_off;
 
        total_width = wp->w_popup_border[3] + wp->w_popup_padding[3]
-               + wp->w_width + wp->w_popup_padding[1] + wp->w_popup_border[1];
+               + wp->w_width + wp->w_popup_padding[1] + wp->w_popup_border[1]
+               + wp->w_has_scrollbar;
        total_height = popup_top_extra(wp)
                + wp->w_height + wp->w_popup_padding[2] + wp->w_popup_border[2];
        popup_attr = get_wcr_attr(wp);
@@ -2203,7 +2222,8 @@ update_popups(void (*win_update)(win_T *wp))
            row = wp->w_winrow + wp->w_popup_border[0];
            screen_fill(row, row + top_padding,
                    wp->w_wincol + wp->w_popup_border[3],
-                   wp->w_wincol + total_width - wp->w_popup_border[1],
+                   wp->w_wincol + total_width - wp->w_popup_border[1]
+                                                       - wp->w_has_scrollbar,
                                                         ' ', ' ', popup_attr);
        }
 
@@ -2212,10 +2232,24 @@ update_popups(void (*win_update)(win_T *wp))
            screen_puts(wp->w_popup_title, wp->w_winrow, wp->w_wincol + 1,
                    wp->w_popup_border[0] > 0 ? border_attr[0] : popup_attr);
 
-       for (row = wp->w_winrow + wp->w_popup_border[0];
-               row < wp->w_winrow + total_height - wp->w_popup_border[2];
-                   ++row)
+       // Compute scrollbar thumb position and size.
+       if (wp->w_has_scrollbar)
+       {
+           linenr_T linecount = wp->w_buffer->b_ml.ml_line_count;
+
+           sb_thumb_height = wp->w_height * wp->w_height / linecount;
+           if (sb_thumb_height == 0)
+               sb_thumb_height = 1;
+           sb_thumb_top = ((wp->w_topline * (wp->w_height - sb_thumb_height)
+                           + (linecount - wp->w_height) / 2))
+                             / (linecount - (wp->w_height - sb_thumb_height));
+       }
+
+       for (i = wp->w_popup_border[0];
+                                i < total_height - wp->w_popup_border[2]; ++i)
        {
+           row = wp->w_winrow + i;
+
            // left border
            if (wp->w_popup_border[3] > 0)
            {
@@ -2226,6 +2260,21 @@ update_popups(void (*win_update)(win_T *wp))
            if (wp->w_popup_padding[3] > 0)
                screen_puts(get_spaces(wp->w_popup_padding[3]), row,
                        wp->w_wincol + wp->w_popup_border[3], popup_attr);
+           // scrollbar
+           if (wp->w_has_scrollbar)
+           {
+               int line = i - top_off;
+               int scroll_col = wp->w_wincol + total_width - 1
+                                                      - wp->w_popup_border[1];
+
+               if (line >= 0 && line < wp->w_height)
+                   screen_putchar(' ', row, scroll_col,
+                           line >= sb_thumb_top
+                                      && line < sb_thumb_top + sb_thumb_height
+                                                 ? attr_thumb : attr_scroll);
+               else
+                   screen_putchar(' ', row, scroll_col, popup_attr);
+           }
            // right border
            if (wp->w_popup_border[1] > 0)
            {
index c664f0eb29b6d67d4fb054f2b64c4fc27db6ae95..9992e99fd5bc4a19575a9fccbd41bba54f098b35 100644 (file)
@@ -2902,6 +2902,8 @@ struct window_S
     int                w_wantline;         // "line" for popup window
     int                w_wantcol;          // "col" for popup window
     int                w_firstline;        // "firstline" for popup window
+    int                w_want_scrollbar;   // when zero don't use a scrollbar
+    int                w_has_scrollbar;    // scrollbar displayed
     int                w_popup_padding[4]; // popup padding top/right/bot/left
     int                w_popup_border[4];  // popup border top/right/bot/left
     char_u     *w_border_highlight[4];  // popup border highlight
index 276f4e5190c533c9e508228058ecea73d2b7c823..7efcf3ef4e43ce9388ef27c86fea145fd14ef4e1 100644 (file)
@@ -1,10 +1,10 @@
 >1+0&#ffffff0| @73
 |2| @73
 |3| @73
-|4| @33|3+0#0000001#ffd7ff255@4| +0#0000000#ffffff0@34
-|5| @33|4+0#0000001#ffd7ff255@1| @2| +0#0000000#ffffff0@34
-|6| @33|5+0#0000001#ffd7ff255| @3| +0#0000000#ffffff0@34
-|7| @33|6+0#0000001#ffd7ff255@4| +0#0000000#ffffff0@34
+|4| @33|3+0#0000001#ffd7ff255@4| +0#0000000#a8a8a8255| +0&#ffffff0@33
+|5| @33|4+0#0000001#ffd7ff255@1| @2| +0#0000000#0000001| +0&#ffffff0@33
+|6| @33|5+0#0000001#ffd7ff255| @3| +0#0000000#a8a8a8255| +0&#ffffff0@33
+|7| @33|6+0#0000001#ffd7ff255@4| +0#0000000#a8a8a8255| +0&#ffffff0@33
 |8| @73
 |9| @73
 @57|1|,|1| @10|T|o|p| 
diff --git a/src/testdir/dumps/Test_popupwin_scroll_1.dump b/src/testdir/dumps/Test_popupwin_scroll_1.dump
new file mode 100644 (file)
index 0000000..dd0e0b3
--- /dev/null
@@ -0,0 +1,10 @@
+>1+0&#ffffff0| @73
+|2| @73
+|3| @73
+|4| @31|o+0#0000001#ffd7ff255|n|e| @4| +0#0000000#0000001| +0&#ffffff0@32
+|5| @31|t+0#0000001#ffd7ff255|w|o| @4| +0#0000000#a8a8a8255| +0&#ffffff0@32
+|6| @31|t+0#0000001#ffd7ff255|h|r|e@1| @2| +0#0000000#a8a8a8255| +0&#ffffff0@32
+|7| @31|f+0#0000001#ffd7ff255|o|u|r| @3| +0#0000000#a8a8a8255| +0&#ffffff0@32
+|8| @73
+|9| @73
+@57|1|,|1| @10|T|o|p| 
diff --git a/src/testdir/dumps/Test_popupwin_scroll_2.dump b/src/testdir/dumps/Test_popupwin_scroll_2.dump
new file mode 100644 (file)
index 0000000..21d33da
--- /dev/null
@@ -0,0 +1,10 @@
+>1+0&#ffffff0| @73
+|2| @73
+|3| @73
+|4| @31|t+0#0000001#ffd7ff255|w|o| @4| +0#0000000#a8a8a8255| +0&#ffffff0@32
+|5| @31|t+0#0000001#ffd7ff255|h|r|e@1| @2| +0#0000000#0000001| +0&#ffffff0@32
+|6| @31|f+0#0000001#ffd7ff255|o|u|r| @3| +0#0000000#a8a8a8255| +0&#ffffff0@32
+|7| @31|f+0#0000001#ffd7ff255|i|v|e| @3| +0#0000000#a8a8a8255| +0&#ffffff0@32
+|8| @73
+|9| @73
+|:|c|a|l@1| |p|o|p|u|p|_|s|e|t|o|p|t|i|o|n|s|(|w|i|n|i|d|,| |{|'|f|i|r|s|t|l|i|n|e|'|:| |2|}|)| @9|1|,|1| @10|T|o|p| 
diff --git a/src/testdir/dumps/Test_popupwin_scroll_3.dump b/src/testdir/dumps/Test_popupwin_scroll_3.dump
new file mode 100644 (file)
index 0000000..656e058
--- /dev/null
@@ -0,0 +1,10 @@
+>1+0&#ffffff0| @73
+|2| @73
+|3| @73
+|4| @31|s+0#0000001#ffd7ff255|i|x| @4| +0#0000000#a8a8a8255| +0&#ffffff0@32
+|5| @31|s+0#0000001#ffd7ff255|e|v|e|n| @2| +0#0000000#a8a8a8255| +0&#ffffff0@32
+|6| @31|e+0#0000001#ffd7ff255|i|g|h|t| @2| +0#0000000#a8a8a8255| +0&#ffffff0@32
+|7| @31|n+0#0000001#ffd7ff255|i|n|e| @3| +0#0000000#0000001| +0&#ffffff0@32
+|8| @73
+|9| @73
+|:|c|a|l@1| |p|o|p|u|p|_|s|e|t|o|p|t|i|o|n|s|(|w|i|n|i|d|,| |{|'|f|i|r|s|t|l|i|n|e|'|:| |6|}|)| @9|1|,|1| @10|T|o|p| 
diff --git a/src/testdir/dumps/Test_popupwin_scroll_4.dump b/src/testdir/dumps/Test_popupwin_scroll_4.dump
new file mode 100644 (file)
index 0000000..5f35a1f
--- /dev/null
@@ -0,0 +1,10 @@
+>1+0&#ffffff0| @73
+|2| @73
+|3| @73
+|4| @73
+|5| @31|n+0#0000001#ffd7ff255|i|n|e| @3| +0#0000000#0000001| +0&#ffffff0@32
+|6| @73
+|7| @73
+|8| @73
+|9| @73
+|:|c|a|l@1| |p|o|p|u|p|_|s|e|t|o|p|t|i|o|n|s|(|w|i|n|i|d|,| |{|'|f|i|r|s|t|l|i|n|e|'|:| |9|}|)| @9|1|,|1| @10|T|o|p| 
index b4bfcef415e4944f4f3e3adeb881c6c6c384185c..1e8f522c91b7506b3707ce0316512d10e77b11d5 100644 (file)
@@ -1407,12 +1407,42 @@ func Test_notifications()
   call term_sendkeys(buf, ":call popup_notification('another important notification', {})\<CR>")
   call VerifyScreenDump(buf, 'Test_popupwin_notify_02', {})
 
-
   " clean up
   call StopVimInTerminal(buf)
   call delete('XtestNotifications')
 endfunc
 
+func Test_popup_scrollbar()
+  if !CanRunVimInTerminal()
+    throw 'Skipped: cannot make screendumps'
+  endif
+
+  let lines =<< trim END
+    call setline(1, range(1, 20))
+    let winid = popup_create(['one', 'two', 'three', 'four', 'five',
+         \ 'six', 'seven', 'eight', 'nine'], {
+         \ 'minwidth': 8,
+         \ 'maxheight': 4,
+         \ })
+  END
+  call writefile(lines, 'XtestPopupScroll')
+  let buf = RunVimInTerminal('-S XtestPopupScroll', {'rows': 10})
+  call VerifyScreenDump(buf, 'Test_popupwin_scroll_1', {})
+
+  call term_sendkeys(buf, ":call popup_setoptions(winid, {'firstline': 2})\<CR>")
+  call VerifyScreenDump(buf, 'Test_popupwin_scroll_2', {})
+
+  call term_sendkeys(buf, ":call popup_setoptions(winid, {'firstline': 6})\<CR>")
+  call VerifyScreenDump(buf, 'Test_popupwin_scroll_3', {})
+
+  call term_sendkeys(buf, ":call popup_setoptions(winid, {'firstline': 9})\<CR>")
+  call VerifyScreenDump(buf, 'Test_popupwin_scroll_4', {})
+
+  " clean up
+  call StopVimInTerminal(buf)
+  call delete('XtestPopupScroll')
+endfunc
+
 func Test_popup_settext()
   if !CanRunVimInTerminal()
     throw 'Skipped: cannot make screendumps'
index 3f3d77fd238e9bfc6d240bf97b1c75cde52e5394..34af0de9b1c18bc3a443b15fb91b9eac9e82d6c6 100644 (file)
@@ -777,6 +777,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1589,
 /**/
     1588,
 /**/