From 8adaca3cb46f200a58e3bba84e061fdce015358f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Caol=C3=A1n=20McNamara?= Date: Wed, 22 Mar 2017 11:21:33 +0000 Subject: [PATCH] Resolves: tdf#106645 gtk3 scrollbar is too wide Change-Id: I4041dff0945c4bd34e085078a7130b637124c6cd (cherry picked from commit aa5d6f5acbab12b1ba76365f776ba228ba5e7e0e) Related: tdf#106645 make gtk3 scrollbar themes with arrows work properly, e.g. breeze-dark has arrows Change-Id: Ic59c0de3fb385adc2f8fddc605edd7498230d5fb (cherry picked from commit 9b7c35b4b7fd5a5347a3602f110d78e1019a54e9) --- vcl/unx/gtk3/gtk3salnativewidgets-gtk.cxx | 453 ++++++++++++++++++++++++++++-- 1 file changed, 429 insertions(+), 24 deletions(-) diff --git a/vcl/unx/gtk3/gtk3salnativewidgets-gtk.cxx b/vcl/unx/gtk3/gtk3salnativewidgets-gtk.cxx index 729b6f5..c8be891 100644 --- a/vcl/unx/gtk3/gtk3salnativewidgets-gtk.cxx +++ b/vcl/unx/gtk3/gtk3salnativewidgets-gtk.cxx @@ -216,31 +216,42 @@ Rectangle GtkSalGraphics::NWGetSpinButtonRect( ControlPart nPart, Rectangle aAre return partRect; } -Rectangle GtkSalGraphics::NWGetScrollButtonRect( ControlPart nPart, Rectangle aAreaRect ) +namespace { - GtkStyleContext* pScrollbarStyle = nullptr; - if ((nPart == ControlPart::ButtonLeft) || (nPart == ControlPart::ButtonRight)) - pScrollbarStyle = mpHScrollbarStyle; - else // (nPart == ControlPart::ButtonUp) || (nPart == ControlPart::ButtonDown) - pScrollbarStyle = mpVScrollbarStyle; + void QuerySize(GtkStyleContext *pContext, Size &rSize) + { + GtkBorder margin, border, padding; - gint slider_width; - gint stepper_size; - gint stepper_spacing; - gint trough_border; + gtk_style_context_get_margin(pContext, gtk_style_context_get_state(pContext), &margin); + gtk_style_context_get_border(pContext, gtk_style_context_get_state(pContext), &border); + gtk_style_context_get_padding(pContext, gtk_style_context_get_state(pContext), &padding); - // Grab some button style attributes - gtk_style_context_get_style( pScrollbarStyle, - "slider-width", &slider_width, - "stepper-size", &stepper_size, - "trough-border", &trough_border, - "stepper-spacing", &stepper_spacing, nullptr ); + int nMinWidth, nMinHeight; + gtk_style_context_get(pContext, gtk_style_context_get_state(pContext), + "min-width", &nMinWidth, "min-height", &nMinHeight, nullptr); + + nMinWidth += margin.left + margin.right + border.left + border.right + padding.left + padding.right; + nMinHeight += margin.top + margin.bottom + border.top + border.bottom + padding.top + padding.bottom; + + rSize = Size(std::max(rSize.Width(), nMinWidth), std::max(rSize.Height(), nMinHeight)); + } +} + +Rectangle GtkSalGraphics::NWGetScrollButtonRect( ControlPart nPart, Rectangle aAreaRect ) +{ + Rectangle buttonRect; gboolean has_forward; gboolean has_forward2; gboolean has_backward; gboolean has_backward2; + GtkStyleContext* pScrollbarStyle = nullptr; + if ((nPart == ControlPart::ButtonLeft) || (nPart == ControlPart::ButtonRight)) + pScrollbarStyle = mpHScrollbarStyle; + else // (nPart == ControlPart::ButtonUp) || (nPart == ControlPart::ButtonDown) + pScrollbarStyle = mpVScrollbarStyle; + gtk_style_context_get_style( pScrollbarStyle, "has-forward-stepper", &has_forward, "has-secondary-forward-stepper", &has_forward2, @@ -248,7 +259,6 @@ Rectangle GtkSalGraphics::NWGetScrollButtonRect( ControlPart nPart, Rectangle aA "has-secondary-backward-stepper", &has_backward2, nullptr ); gint buttonWidth; gint buttonHeight; - Rectangle buttonRect; gint nFirst = 0; gint nSecond = 0; @@ -258,6 +268,64 @@ Rectangle GtkSalGraphics::NWGetScrollButtonRect( ControlPart nPart, Rectangle aA if ( has_backward ) nFirst += 1; if ( has_backward2 ) nSecond += 1; + if (gtk_check_version(3, 20, 0) == nullptr) + { + Size aSize; + if (nPart == ControlPart::ButtonLeft || nPart == ControlPart::ButtonRight) + { + QuerySize(mpHScrollbarStyle, aSize); + QuerySize(mpHScrollbarContentsStyle, aSize); + QuerySize(mpHScrollbarButtonStyle, aSize); + } + else + { + QuerySize(mpVScrollbarStyle, aSize); + QuerySize(mpVScrollbarContentsStyle, aSize); + QuerySize(mpVScrollbarButtonStyle, aSize); + } + + if (nPart == ControlPart::ButtonUp) + { + aSize.Height() *= nFirst; + buttonRect.setX(aAreaRect.Left()); + buttonRect.setY(aAreaRect.Top()); + } + else if (nPart == ControlPart::ButtonLeft) + { + aSize.Width() *= nFirst; + buttonRect.setX(aAreaRect.Left()); + buttonRect.setY(aAreaRect.Top()); + } + else if (nPart == ControlPart::ButtonDown) + { + aSize.Height() *= nSecond; + buttonRect.setX(aAreaRect.Left()); + buttonRect.setY(aAreaRect.Top() + aAreaRect.GetHeight() - aSize.Height()); + } + else if (nPart == ControlPart::ButtonRight) + { + aSize.Width() *= nSecond; + buttonRect.setX(aAreaRect.Left() + aAreaRect.GetWidth() - aSize.Width()); + buttonRect.setY(aAreaRect.Top()); + } + + buttonRect.SetSize(aSize); + + return buttonRect; + } + + gint slider_width; + gint stepper_size; + gint stepper_spacing; + gint trough_border; + + // Grab some button style attributes + gtk_style_context_get_style( pScrollbarStyle, + "slider-width", &slider_width, + "stepper-size", &stepper_size, + "trough-border", &trough_border, + "stepper-spacing", &stepper_spacing, nullptr ); + if ( ( nPart == ControlPart::ButtonUp ) || ( nPart == ControlPart::ButtonDown ) ) { buttonWidth = slider_width + 2 * trough_border; @@ -369,6 +437,327 @@ void GtkSalGraphics::PaintScrollbar(GtkStyleContext *context, ControlPart nPart, const ImplControlValue& rValue ) { + if (gtk_check_version(3, 20, 0) == nullptr) + { + assert(rValue.getType() == ControlType::Scrollbar); + const ScrollbarValue& rScrollbarVal = static_cast(rValue); + Rectangle scrollbarRect; + GtkStateFlags stateFlags; + GtkOrientation scrollbarOrientation; + Rectangle thumbRect = rScrollbarVal.maThumbRect; + Rectangle button11BoundRect = rScrollbarVal.maButton1Rect; // backward + Rectangle button22BoundRect = rScrollbarVal.maButton2Rect; // forward + Rectangle button12BoundRect = rScrollbarVal.maButton1Rect; // secondary forward + Rectangle button21BoundRect = rScrollbarVal.maButton2Rect; // secondary backward + gdouble arrow1Angle; // backward + gdouble arrow2Angle; // forward + Rectangle arrowRect; + gint slider_width = 0; + gint stepper_size = 0; + + // make controlvalue rectangles relative to area + thumbRect.Move( -rControlRectangle.Left(), -rControlRectangle.Top() ); + button11BoundRect.Move( -rControlRectangle.Left(), -rControlRectangle.Top() ); + button22BoundRect.Move( -rControlRectangle.Left(), -rControlRectangle.Top() ); + button12BoundRect.Move( -rControlRectangle.Left(), -rControlRectangle.Top() ); + button21BoundRect.Move( -rControlRectangle.Left(), -rControlRectangle.Top() ); + + // Find the overall bounding rect of the control + scrollbarRect = rControlRectangle; + if (scrollbarRect.GetWidth() <= 0 || scrollbarRect.GetHeight() <= 0) + return; + + gint slider_side; + Size aSize; + if (nPart == ControlPart::DrawBackgroundHorz) + { + QuerySize(mpHScrollbarStyle, aSize); + QuerySize(mpHScrollbarContentsStyle, aSize); + QuerySize(mpHScrollbarTroughStyle, aSize); + QuerySize(mpHScrollbarSliderStyle, aSize); + slider_side = aSize.Height(); + gtk_style_context_get(mpHScrollbarButtonStyle, + gtk_style_context_get_state(mpHScrollbarButtonStyle), + "min-height", &slider_width, + "min-width", &stepper_size, nullptr); + } + else + { + QuerySize(mpVScrollbarStyle, aSize); + QuerySize(mpVScrollbarContentsStyle, aSize); + QuerySize(mpVScrollbarTroughStyle, aSize); + QuerySize(mpVScrollbarSliderStyle, aSize); + slider_side = aSize.Width(); + gtk_style_context_get(mpVScrollbarButtonStyle, + gtk_style_context_get_state(mpVScrollbarButtonStyle), + "min-width", &slider_width, + "min-height", &stepper_size, nullptr); + } + + gboolean has_forward; + gboolean has_forward2; + gboolean has_backward; + gboolean has_backward2; + + gtk_style_context_get_style( context, + "has-forward-stepper", &has_forward, + "has-secondary-forward-stepper", &has_forward2, + "has-backward-stepper", &has_backward, + "has-secondary-backward-stepper", &has_backward2, nullptr ); + + if ( nPart == ControlPart::DrawBackgroundHorz ) + { + // Center vertically in the track + scrollbarRect.Move( 0, (scrollbarRect.GetHeight() - slider_side) / 2 ); + scrollbarRect.SetSize( Size( scrollbarRect.GetWidth(), slider_side ) ); + thumbRect.Move( 0, (scrollbarRect.GetHeight() - slider_side) / 2 ); + thumbRect.SetSize( Size( thumbRect.GetWidth(), slider_side ) ); + + scrollbarOrientation = GTK_ORIENTATION_HORIZONTAL; + arrow1Angle = G_PI * 3 / 2; + arrow2Angle = G_PI / 2; + + if ( has_backward ) + { + button12BoundRect.Move( stepper_size, + (scrollbarRect.GetHeight() - slider_width) / 2 ); + } + + button11BoundRect.Move( 0, (scrollbarRect.GetHeight() - slider_width) / 2 ); + button11BoundRect.SetSize( Size( stepper_size, slider_width ) ); + button12BoundRect.SetSize( Size( stepper_size, slider_width ) ); + + if ( has_backward2 ) + { + button22BoundRect.Move( stepper_size, (scrollbarRect.GetHeight() - slider_width) / 2 ); + button21BoundRect.Move( 0, (scrollbarRect.GetHeight() - slider_width) / 2 ); + } + else + { + button22BoundRect.Move( 0, (scrollbarRect.GetHeight() - slider_width) / 2 ); + } + + button21BoundRect.SetSize( Size( stepper_size, slider_width ) ); + button22BoundRect.SetSize( Size( stepper_size, slider_width ) ); + } + else + { + // Center horizontally in the track + scrollbarRect.Move( (scrollbarRect.GetWidth() - slider_side) / 2, 0 ); + scrollbarRect.SetSize( Size( slider_side, scrollbarRect.GetHeight() ) ); + thumbRect.Move( (scrollbarRect.GetWidth() - slider_side) / 2, 0 ); + thumbRect.SetSize( Size( slider_side, thumbRect.GetHeight() ) ); + + scrollbarOrientation = GTK_ORIENTATION_VERTICAL; + arrow1Angle = 0; + arrow2Angle = G_PI; + + if ( has_backward ) + { + button12BoundRect.Move( (scrollbarRect.GetWidth() - slider_width) / 2, + stepper_size ); + } + button11BoundRect.Move( (scrollbarRect.GetWidth() - slider_width) / 2, 0 ); + button11BoundRect.SetSize( Size( slider_width, stepper_size ) ); + button12BoundRect.SetSize( Size( slider_width, stepper_size ) ); + + if ( has_backward2 ) + { + button22BoundRect.Move( (scrollbarRect.GetWidth() - slider_width) / 2, stepper_size ); + button21BoundRect.Move( (scrollbarRect.GetWidth() - slider_width) / 2, 0 ); + } + else + { + button22BoundRect.Move( (scrollbarRect.GetWidth() - slider_width) / 2, 0 ); + } + + button21BoundRect.SetSize( Size( slider_width, stepper_size ) ); + button22BoundRect.SetSize( Size( slider_width, stepper_size ) ); + } + + bool has_slider = ( thumbRect.GetWidth() > 0 && thumbRect.GetHeight() > 0 ); + + // ----------------- CONTENTS + GtkStyleContext* pScrollbarContentsStyle = scrollbarOrientation == GTK_ORIENTATION_VERTICAL ? + mpVScrollbarContentsStyle : mpHScrollbarContentsStyle; + + gtk_render_background(gtk_widget_get_style_context(gCacheWindow), cr, 0, 0, + scrollbarRect.GetWidth(), scrollbarRect.GetHeight() ); + + gtk_render_background(context, cr, 0, 0, + scrollbarRect.GetWidth(), scrollbarRect.GetHeight() ); + gtk_render_frame(context, cr, 0, 0, + scrollbarRect.GetWidth(), scrollbarRect.GetHeight() ); + + gtk_render_background(pScrollbarContentsStyle, cr, 0, 0, + scrollbarRect.GetWidth(), scrollbarRect.GetHeight() ); + gtk_render_frame(pScrollbarContentsStyle, cr, 0, 0, + scrollbarRect.GetWidth(), scrollbarRect.GetHeight() ); + + bool backwardButtonInsensitive = + rScrollbarVal.mnCur == rScrollbarVal.mnMin; + bool forwardButtonInsensitive = rScrollbarVal.mnMax == 0 || + rScrollbarVal.mnCur + rScrollbarVal.mnVisibleSize >= rScrollbarVal.mnMax; + + // ----------------- BUTTON 1 + if ( has_backward ) + { + stateFlags = NWConvertVCLStateToGTKState(rScrollbarVal.mnButton1State); + if ( backwardButtonInsensitive ) + stateFlags = GTK_STATE_FLAG_INSENSITIVE; + + GtkStyleContext* pScrollbarButtonStyle = scrollbarOrientation == GTK_ORIENTATION_VERTICAL ? + mpVScrollbarButtonStyle : mpHScrollbarButtonStyle; + + gtk_style_context_set_state(pScrollbarButtonStyle, stateFlags); + + gtk_render_background(pScrollbarButtonStyle, cr, + button11BoundRect.Left(), button11BoundRect.Top(), + button11BoundRect.GetWidth(), button11BoundRect.GetHeight() ); + gtk_render_frame(pScrollbarButtonStyle, cr, + button11BoundRect.Left(), button11BoundRect.Top(), + button11BoundRect.GetWidth(), button11BoundRect.GetHeight() ); + + // ----------------- ARROW 1 + NWCalcArrowRect( button11BoundRect, arrowRect ); + gtk_render_arrow(pScrollbarButtonStyle, cr, + arrow1Angle, + arrowRect.Left(), arrowRect.Top(), + MIN(arrowRect.GetWidth(), arrowRect.GetHeight()) ); + } + if ( has_forward2 ) + { + stateFlags = NWConvertVCLStateToGTKState(rScrollbarVal.mnButton2State); + if ( forwardButtonInsensitive ) + stateFlags = GTK_STATE_FLAG_INSENSITIVE; + + GtkStyleContext* pScrollbarButtonStyle = scrollbarOrientation == GTK_ORIENTATION_VERTICAL ? + mpVScrollbarButtonStyle : mpHScrollbarButtonStyle; + + gtk_style_context_set_state(pScrollbarButtonStyle, stateFlags); + + gtk_render_background(pScrollbarButtonStyle, cr, + button12BoundRect.Left(), button12BoundRect.Top(), + button12BoundRect.GetWidth(), button12BoundRect.GetHeight() ); + gtk_render_frame(pScrollbarButtonStyle, cr, + button12BoundRect.Left(), button12BoundRect.Top(), + button12BoundRect.GetWidth(), button12BoundRect.GetHeight() ); + + // ----------------- ARROW 1 + NWCalcArrowRect( button12BoundRect, arrowRect ); + gtk_render_arrow(pScrollbarButtonStyle, cr, + arrow2Angle, + arrowRect.Left(), arrowRect.Top(), + MIN(arrowRect.GetWidth(), arrowRect.GetHeight()) ); + } + // ----------------- BUTTON 2 + + if ( has_forward ) + { + stateFlags = NWConvertVCLStateToGTKState(rScrollbarVal.mnButton2State); + if ( forwardButtonInsensitive ) + stateFlags = GTK_STATE_FLAG_INSENSITIVE; + + GtkStyleContext* pScrollbarButtonStyle = scrollbarOrientation == GTK_ORIENTATION_VERTICAL ? + mpVScrollbarButtonStyle : mpHScrollbarButtonStyle; + + gtk_style_context_set_state(pScrollbarButtonStyle, stateFlags); + + gtk_render_background(pScrollbarButtonStyle, cr, + button22BoundRect.Left(), button22BoundRect.Top(), + button22BoundRect.GetWidth(), button22BoundRect.GetHeight() ); + gtk_render_frame(pScrollbarButtonStyle, cr, + button22BoundRect.Left(), button22BoundRect.Top(), + button22BoundRect.GetWidth(), button22BoundRect.GetHeight() ); + + // ----------------- ARROW 2 + NWCalcArrowRect( button22BoundRect, arrowRect ); + gtk_render_arrow(pScrollbarButtonStyle, cr, + arrow2Angle, + arrowRect.Left(), arrowRect.Top(), + MIN(arrowRect.GetWidth(), arrowRect.GetHeight()) ); + } + + if ( has_backward2 ) + { + stateFlags = NWConvertVCLStateToGTKState(rScrollbarVal.mnButton1State); + if ( backwardButtonInsensitive ) + stateFlags = GTK_STATE_FLAG_INSENSITIVE; + + GtkStyleContext* pScrollbarButtonStyle = scrollbarOrientation == GTK_ORIENTATION_VERTICAL ? + mpVScrollbarButtonStyle : mpHScrollbarButtonStyle; + + gtk_style_context_set_state(pScrollbarButtonStyle, stateFlags); + + gtk_render_background(pScrollbarButtonStyle, cr, + button21BoundRect.Left(), button21BoundRect.Top(), + button21BoundRect.GetWidth(), button21BoundRect.GetHeight() ); + gtk_render_frame(pScrollbarButtonStyle, cr, + button21BoundRect.Left(), button21BoundRect.Top(), + button21BoundRect.GetWidth(), button21BoundRect.GetHeight() ); + + // ----------------- ARROW 2 + NWCalcArrowRect( button21BoundRect, arrowRect ); + gtk_render_arrow(pScrollbarButtonStyle, cr, + arrow1Angle, + arrowRect.Left(), arrowRect.Top(), + MIN(arrowRect.GetWidth(), arrowRect.GetHeight()) ); + } + + // ----------------- TROUGH + // trackrect matches that of ScrollBar::ImplCalc + Rectangle aTrackRect(Point(0, 0), scrollbarRect.GetSize()); + if (nPart == ControlPart::DrawBackgroundHorz) + { + Rectangle aBtn1Rect = NWGetScrollButtonRect(ControlPart::ButtonLeft, aTrackRect); + Rectangle aBtn2Rect = NWGetScrollButtonRect(ControlPart::ButtonRight, aTrackRect); + aTrackRect.Left() = aBtn1Rect.Right(); + aTrackRect.Right() = aBtn2Rect.Left(); + } + else + { + Rectangle aBtn1Rect = NWGetScrollButtonRect(ControlPart::ButtonUp, aTrackRect); + Rectangle aBtn2Rect = NWGetScrollButtonRect(ControlPart::ButtonDown, aTrackRect); + aTrackRect.Top() = aBtn1Rect.Bottom() + 1; + aTrackRect.Bottom() = aBtn2Rect.Top(); + } + + GtkStyleContext* pScrollbarTroughStyle = scrollbarOrientation == GTK_ORIENTATION_VERTICAL ? + mpVScrollbarTroughStyle : mpHScrollbarTroughStyle; + gtk_render_background(pScrollbarTroughStyle, cr, aTrackRect.Left(), aTrackRect.Top(), + aTrackRect.GetWidth(), aTrackRect.GetHeight() ); + gtk_render_frame(pScrollbarTroughStyle, cr, aTrackRect.Left(), aTrackRect.Top(), + aTrackRect.GetWidth(), aTrackRect.GetHeight() ); + + // ----------------- THUMB + if ( has_slider ) + { + stateFlags = NWConvertVCLStateToGTKState(rScrollbarVal.mnThumbState); + if ( rScrollbarVal.mnThumbState & ControlState::PRESSED ) + stateFlags = (GtkStateFlags) (stateFlags | GTK_STATE_PRELIGHT); + + GtkStyleContext* pScrollbarSliderStyle = scrollbarOrientation == GTK_ORIENTATION_VERTICAL ? + mpVScrollbarSliderStyle : mpHScrollbarSliderStyle; + + gtk_style_context_set_state(pScrollbarSliderStyle, stateFlags); + + GtkBorder margin; + gtk_style_context_get_margin(pScrollbarSliderStyle, stateFlags, &margin); + + gtk_render_background(pScrollbarSliderStyle, cr, + thumbRect.Left() + margin.left, thumbRect.Top() + margin.top, + thumbRect.GetWidth() - margin.left - margin.right, + thumbRect.GetHeight() - margin.top - margin.bottom); + + gtk_render_frame(pScrollbarSliderStyle, cr, + thumbRect.Left() + margin.left, thumbRect.Top() + margin.top, + thumbRect.GetWidth() - margin.left - margin.right, + thumbRect.GetHeight() - margin.top - margin.bottom); + } + + return; + } + (void)nType; OSL_ASSERT( rValue.getType() == ControlType::Scrollbar ); const ScrollbarValue& rScrollbarVal = static_cast(rValue); @@ -2725,18 +3114,28 @@ void GtkSalGraphics::updateSettings( AllSettings& rSettings ) aStyleSet.SetPrimaryButtonWarpsSlider(primarybuttonwarps); // set scrollbar settings - gint slider_width = 14; - gint trough_border = 1; gint min_slider_length = 21; // Grab some button style attributes - gtk_style_context_get_style(mpVScrollbarStyle, - "slider-width", &slider_width, - "trough-border", &trough_border, - nullptr); - aStyleSet.SetScrollBarSize(slider_width + 2*trough_border); if (gtk_check_version(3, 20, 0) == nullptr) { + Size aSize; + QuerySize(mpHScrollbarStyle, aSize); + QuerySize(mpHScrollbarContentsStyle, aSize); + QuerySize(mpHScrollbarTroughStyle, aSize); + QuerySize(mpHScrollbarSliderStyle, aSize); + + gboolean has_forward, has_forward2, has_backward, has_backward2; + gtk_style_context_get_style(mpHScrollbarStyle, + "has-forward-stepper", &has_forward, + "has-secondary-forward-stepper", &has_forward2, + "has-backward-stepper", &has_backward, + "has-secondary-backward-stepper", &has_backward2, nullptr); + if (has_forward || has_backward || has_forward2 || has_backward2) + QuerySize(mpHScrollbarButtonStyle, aSize); + + aStyleSet.SetScrollBarSize(aSize.Height()); + gtk_style_context_get(mpVScrollbarSliderStyle, gtk_style_context_get_state(mpVScrollbarSliderStyle), "min-height", &min_slider_length, nullptr); @@ -2744,9 +3143,15 @@ void GtkSalGraphics::updateSettings( AllSettings& rSettings ) } else { + gint slider_width = 14; + gint trough_border = 1; + gtk_style_context_get_style(mpVScrollbarStyle, + "slider-width", &slider_width, + "trough-border", &trough_border, "min-slider-length", &min_slider_length, nullptr); + aStyleSet.SetScrollBarSize(slider_width + 2*trough_border); gint magic = trough_border ? 1 : 0; aStyleSet.SetMinThumbSize(min_slider_length - magic); } -- 2.9.3