mirror of
https://github.com/vim/vim.git
synced 2026-05-28 00:21:37 +02:00
patch 9.2.0492: popup: decoration wrongly drawn with clipping on border
Problem: popup: clipwindow popups with border and padding could still
spill into the surrounding chrome of the host window
Solution: Consume the border first, then the padding, per edge; spill
any leftover clip into the opposite edge's decoration; derive
the bottom padding row from total_height; skip the scrollbar
branch for clipwindow popups (Yasuhiro Matsumoto).
closes: #20227
Signed-off-by: Yasuhiro Matsumoto <mattn.jp@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
committed by
Christian Brabandt
parent
ab24858cf5
commit
3db4c3a20b
+108
-24
@@ -1356,15 +1356,15 @@ popup_get_clipwin(win_T *wp)
|
||||
// clip_*_content : how many *content* rows/cols are clipped at each edge
|
||||
// (border/padding is consumed first; the rest comes off
|
||||
// w_height/w_width). >= 0.
|
||||
// eff_*_extra : 0 when that edge is clipped (border+padding gone),
|
||||
// otherwise the original *_extra.
|
||||
// eff_border[],
|
||||
// eff_padding[] : per-edge border/padding sizes (indexed [top,right,bot,left]
|
||||
// matching wp->w_popup_border / wp->w_popup_padding). At a
|
||||
// clipped edge they collapse to 0; elsewhere they keep the
|
||||
// original size. Drawing code can replace
|
||||
// matching wp->w_popup_border / wp->w_popup_padding). The
|
||||
// clip consumes the border first, then the padding, so when
|
||||
// only the border is clipped the padding still survives.
|
||||
// Drawing code can replace
|
||||
// `wp->w_popup_border[N] > 0 && wp->w_popup_*clip == 0`
|
||||
// with a single `cl.eff_border[N] > 0` test.
|
||||
// eff_*_extra : eff_border + eff_padding at that edge (visible decoration).
|
||||
// eff_height : drawn extent = eff_top_extra + visible content + eff_bot_extra.
|
||||
// eff_width : drawn extent = eff_left_extra + visible content + eff_right_extra
|
||||
// (does NOT include w_leftcol or scrollbar; see callers).
|
||||
@@ -1414,21 +1414,95 @@ popup_compute_clip(win_T *wp, popup_clip_T *cl)
|
||||
if (cl->clip_right_content < 0)
|
||||
cl->clip_right_content = 0;
|
||||
|
||||
cl->eff_top_extra = wp->w_popup_topoff > 0 ? 0 : cl->top_extra;
|
||||
cl->eff_bot_extra = wp->w_popup_bottomoff > 0 ? 0 : cl->bot_extra;
|
||||
// Border is consumed before padding: when only the border row/column is
|
||||
// clipped, the adjacent padding row/column is still visible. Horizontal
|
||||
// edges keep the previous all-or-nothing behaviour for now; the drawing
|
||||
// code there still uses original w_popup_border / w_popup_padding offsets.
|
||||
{
|
||||
int clip = wp->w_popup_topoff;
|
||||
int b = wp->w_popup_border[0];
|
||||
int p = wp->w_popup_padding[0];
|
||||
int rem;
|
||||
|
||||
if (clip >= b)
|
||||
{
|
||||
cl->eff_border[0] = 0;
|
||||
rem = clip - b;
|
||||
cl->eff_padding[0] = (rem >= p) ? 0 : p - rem;
|
||||
}
|
||||
else
|
||||
{
|
||||
cl->eff_border[0] = b;
|
||||
cl->eff_padding[0] = p;
|
||||
}
|
||||
}
|
||||
{
|
||||
int clip = wp->w_popup_bottomoff;
|
||||
int b = wp->w_popup_border[2];
|
||||
int p = wp->w_popup_padding[2];
|
||||
int rem;
|
||||
|
||||
if (clip >= b)
|
||||
{
|
||||
cl->eff_border[2] = 0;
|
||||
rem = clip - b;
|
||||
cl->eff_padding[2] = (rem >= p) ? 0 : p - rem;
|
||||
}
|
||||
else
|
||||
{
|
||||
cl->eff_border[2] = b;
|
||||
cl->eff_padding[2] = p;
|
||||
}
|
||||
}
|
||||
cl->eff_border[1] = wp->w_popup_rightclip > 0 ? 0 : wp->w_popup_border[1];
|
||||
cl->eff_border[3] = wp->w_popup_leftclip > 0 ? 0 : wp->w_popup_border[3];
|
||||
cl->eff_padding[1] = wp->w_popup_rightclip > 0 ? 0 : wp->w_popup_padding[1];
|
||||
cl->eff_padding[3] = wp->w_popup_leftclip > 0 ? 0 : wp->w_popup_padding[3];
|
||||
|
||||
// When a clip on one edge runs past the content rows, the excess must
|
||||
// eat into the OPPOSITE edge's decorations. Otherwise the surviving
|
||||
// padding/border can land outside the host (e.g. a popup whose body is
|
||||
// wholly below the host still drew its top padding onto the status row).
|
||||
{
|
||||
int excess = wp->w_popup_bottomoff - cl->bot_extra - wp->w_height;
|
||||
if (excess > 0)
|
||||
{
|
||||
if (excess >= cl->eff_padding[0])
|
||||
{
|
||||
excess -= cl->eff_padding[0];
|
||||
cl->eff_padding[0] = 0;
|
||||
if (excess >= cl->eff_border[0])
|
||||
cl->eff_border[0] = 0;
|
||||
else
|
||||
cl->eff_border[0] -= excess;
|
||||
}
|
||||
else
|
||||
cl->eff_padding[0] -= excess;
|
||||
}
|
||||
}
|
||||
{
|
||||
int excess = wp->w_popup_topoff - cl->top_extra - wp->w_height;
|
||||
if (excess > 0)
|
||||
{
|
||||
if (excess >= cl->eff_padding[2])
|
||||
{
|
||||
excess -= cl->eff_padding[2];
|
||||
cl->eff_padding[2] = 0;
|
||||
if (excess >= cl->eff_border[2])
|
||||
cl->eff_border[2] = 0;
|
||||
else
|
||||
cl->eff_border[2] -= excess;
|
||||
}
|
||||
else
|
||||
cl->eff_padding[2] -= excess;
|
||||
}
|
||||
}
|
||||
|
||||
cl->eff_top_extra = cl->eff_border[0] + cl->eff_padding[0];
|
||||
cl->eff_bot_extra = cl->eff_border[2] + cl->eff_padding[2];
|
||||
cl->eff_left_extra = wp->w_popup_leftclip > 0 ? 0 : cl->left_extra;
|
||||
cl->eff_right_extra = wp->w_popup_rightclip > 0 ? 0 : cl->right_extra;
|
||||
|
||||
cl->eff_border[0] = wp->w_popup_topoff > 0 ? 0 : wp->w_popup_border[0];
|
||||
cl->eff_border[1] = wp->w_popup_rightclip > 0 ? 0 : wp->w_popup_border[1];
|
||||
cl->eff_border[2] = wp->w_popup_bottomoff > 0 ? 0 : wp->w_popup_border[2];
|
||||
cl->eff_border[3] = wp->w_popup_leftclip > 0 ? 0 : wp->w_popup_border[3];
|
||||
|
||||
cl->eff_padding[0] = wp->w_popup_topoff > 0 ? 0 : wp->w_popup_padding[0];
|
||||
cl->eff_padding[1] = wp->w_popup_rightclip > 0 ? 0 : wp->w_popup_padding[1];
|
||||
cl->eff_padding[2] = wp->w_popup_bottomoff > 0 ? 0 : wp->w_popup_padding[2];
|
||||
cl->eff_padding[3] = wp->w_popup_leftclip > 0 ? 0 : wp->w_popup_padding[3];
|
||||
|
||||
h = wp->w_height - cl->clip_top_content - cl->clip_bot_content;
|
||||
if (h < 0)
|
||||
h = 0;
|
||||
@@ -2172,10 +2246,14 @@ popup_adjust_position(win_T *wp)
|
||||
}
|
||||
|
||||
if (adjust_height_for_top_aligned && wp->w_want_scrollbar
|
||||
&& !(wp->w_popup_flags & POPF_CLIPWINDOW)
|
||||
&& wp->w_winrow + wp->w_height + extra_height > Rows)
|
||||
{
|
||||
// Bottom of the popup goes below the last line, reduce the height and
|
||||
// add a scrollbar.
|
||||
// add a scrollbar. For "clipwindow" popups the host-window clip
|
||||
// already truncates the popup to fit inside the host, so we must not
|
||||
// also force a scrollbar here -- that would widen the popup by one
|
||||
// column the moment its decoration crossed the screen edge.
|
||||
wp->w_height = Rows - wp->w_winrow - extra_height;
|
||||
#ifdef FEAT_TERMINAL
|
||||
if (wp->w_buffer->b_term == NULL || term_is_finished(wp->w_buffer))
|
||||
@@ -6267,7 +6345,7 @@ update_popups(void (*win_update)(win_T *wp))
|
||||
}
|
||||
if (top_padding > 0)
|
||||
{
|
||||
row = wp->w_winrow + wp->w_popup_border[0];
|
||||
row = wp->w_winrow + cl.eff_border[0];
|
||||
if (title_len > 0 && row == wp->w_winrow)
|
||||
{
|
||||
// top padding and no border; do not draw over the title
|
||||
@@ -6432,14 +6510,20 @@ update_popups(void (*win_update)(win_T *wp))
|
||||
|
||||
if (cl.eff_padding[2] > 0)
|
||||
{
|
||||
// bottom padding
|
||||
row = wp->w_winrow + wp->w_popup_border[0]
|
||||
+ wp->w_popup_padding[0] + wp->w_height;
|
||||
// bottom padding -- sits right after the visible content rows.
|
||||
// Derive the row from total_height so it always lands inside the
|
||||
// popup's drawn extent, including the corner case where the top
|
||||
// clip consumes more rows than the content itself (so the visible
|
||||
// content height is zero). A formula based on
|
||||
// w_height - clip_top_content - clip_bot_content can go negative
|
||||
// there and would draw the padding above w_winrow.
|
||||
row = wp->w_winrow + total_height
|
||||
- cl.eff_padding[2] - cl.eff_border[2];
|
||||
if (screen_opacity_popup != NULL && saved_screen.lines != NULL)
|
||||
fill_opacity_padding(row, row + wp->w_popup_padding[2],
|
||||
fill_opacity_padding(row, row + cl.eff_padding[2],
|
||||
padcol, padendcol, &saved_screen);
|
||||
else
|
||||
screen_fill(row, row + wp->w_popup_padding[2],
|
||||
screen_fill(row, row + cl.eff_padding[2],
|
||||
padcol, padendcol, ' ', ' ', popup_attr);
|
||||
}
|
||||
|
||||
|
||||
@@ -729,6 +729,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
492,
|
||||
/**/
|
||||
491,
|
||||
/**/
|
||||
|
||||
Reference in New Issue
Block a user