mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-23 00:39:44 +02:00
Gtk3: Fixed button sizing/autosizing by introducing LCLGtkButton class, fixed SetScrollInfo, fixed GetClientRect for all scrollable widgets.
This commit is contained in:
parent
b230dabbd3
commit
0c0b6882c0
150
lcl/interfaces/gtk3/gtk3lclbutton.inc
Normal file
150
lcl/interfaces/gtk3/gtk3lclbutton.inc
Normal file
@ -0,0 +1,150 @@
|
||||
{%MainUnit gtk3widgets.pas}
|
||||
const
|
||||
GTK_BUTTON_CLASS_SIZE = SizeOf(TGtkButtonClass);
|
||||
GTK_BUTTON_INSTANCE_SIZE = SizeOf(TGtkButton);
|
||||
|
||||
procedure LCLGtkButtonGetPreferredWidth(widget: PGtkWidget; min_width, nat_width: Pgint); cdecl;
|
||||
var
|
||||
AControl: TGtk3Widget;
|
||||
ParentClass: PGtkWidgetClass;
|
||||
begin
|
||||
if not Assigned(min_width) or not Assigned(nat_width) then
|
||||
begin
|
||||
DebugLn('Error: LCLGtkButtonGetPreferredWidth invalid params.');
|
||||
Exit;
|
||||
end;
|
||||
|
||||
if not Gtk3IsWidget(widget) then
|
||||
begin
|
||||
DebugLn('Error: LCLGtkButtonGetPreferredWidth widget param is not PGtkWidget.');
|
||||
Exit;
|
||||
end;
|
||||
|
||||
ParentClass := PGtkWidgetClass(g_type_class_peek_parent(widget^.g_type_instance.g_class));
|
||||
if not Assigned(ParentClass) then
|
||||
begin
|
||||
DebugLn('Error: cannot get ParentClass !');
|
||||
Exit;
|
||||
end;
|
||||
|
||||
// Call parent class implementation
|
||||
ParentClass^.get_preferred_width(widget, min_width, nat_width);
|
||||
|
||||
AControl := TGtk3Widget(HwndFromGtkWidget(widget));
|
||||
if not Assigned(AControl) then
|
||||
begin
|
||||
DebugLn('Error: cannot get TGtk3Widget for widget parameter.');
|
||||
Exit;
|
||||
end;
|
||||
|
||||
// we respect ws width of button if autosize is true.
|
||||
if AControl.LCLObject.AutoSize then
|
||||
exit;
|
||||
// Custom width handling
|
||||
if AControl.LCLWidth = 0 then
|
||||
begin
|
||||
min_width^ := Max(50, AControl.LCLObject.Width);
|
||||
nat_width^ := Max(50, AControl.LCLObject.Width);
|
||||
end else
|
||||
begin
|
||||
min_width^ := Max(50, AControl.LCLWidth);
|
||||
nat_width^ := Max(50, AControl.LCLWidth);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure LCLGtkButtonGetPreferredHeight(widget: PGtkWidget; min_height, nat_height: Pgint); cdecl;
|
||||
var
|
||||
AControl: TGtk3Widget;
|
||||
ParentClass: PGtkWidgetClass;
|
||||
begin
|
||||
if not Assigned(min_height) or not Assigned(nat_height) then
|
||||
begin
|
||||
DebugLn('Error: LCLGtkButtonGetPreferredHeight invalid params.');
|
||||
Exit;
|
||||
end;
|
||||
|
||||
if not Gtk3IsWidget(widget) then
|
||||
begin
|
||||
DebugLn('Error: LCLGtkButtonGetPreferredHeight widget param is not PGtkWidget.');
|
||||
Exit;
|
||||
end;
|
||||
|
||||
ParentClass := PGtkWidgetClass(g_type_class_peek_parent(widget^.g_type_instance.g_class));
|
||||
if not Assigned(ParentClass) then
|
||||
begin
|
||||
DebugLn('Error: cannot get ParentClass !');
|
||||
Exit;
|
||||
end;
|
||||
|
||||
// Call parent class implementation
|
||||
ParentClass^.get_preferred_height(widget, min_height, nat_height);
|
||||
|
||||
AControl := TGtk3Widget(HwndFromGtkWidget(widget));
|
||||
if not Assigned(AControl) then
|
||||
begin
|
||||
DebugLn('Error: cannot get TGtk3Widget for widget parameter.');
|
||||
Exit;
|
||||
end;
|
||||
|
||||
// we respect ws height if autosize is true.
|
||||
if AControl.LCLObject.AutoSize then
|
||||
exit;
|
||||
|
||||
// Custom height handling
|
||||
if AControl.LCLHeight = 0 then
|
||||
begin
|
||||
min_height^ := Max(20, AControl.LCLObject.Height);
|
||||
nat_height^ := Max(20, AControl.LCLObject.Height);
|
||||
end else
|
||||
begin
|
||||
min_height^ := Max(20, AControl.LCLHeight);
|
||||
nat_height^ := Max(20, AControl.LCLHeight);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure LCLGtkButtonClassInit(klass: PGTypeClass; {%H-}data: Pointer); cdecl;
|
||||
var
|
||||
AWidgetClass: PGtkWidgetClass;
|
||||
begin
|
||||
AWidgetClass := PGtkWidgetClass(klass);
|
||||
AWidgetClass^.get_preferred_width := @LCLGtkButtonGetPreferredWidth;
|
||||
AWidgetClass^.get_preferred_height := @LCLGtkButtonGetPreferredHeight;
|
||||
end;
|
||||
|
||||
procedure LCLGtkButtonInstanceInit(instance: PGTypeInstance; {%H-}klass: PGTypeClass); cdecl;
|
||||
var
|
||||
buttonWidget: PGtkButton;
|
||||
begin
|
||||
buttonWidget := PGtkButton(instance);
|
||||
// Custom initialization logic (if needed)
|
||||
end;
|
||||
|
||||
var
|
||||
LCLGtkButtonType: TGType = 0;
|
||||
|
||||
function LCLGtkButtonGetType: TGType; cdecl;
|
||||
const
|
||||
lcl_button_type_info: TGTypeInfo = (
|
||||
class_size: GTK_BUTTON_CLASS_SIZE;
|
||||
base_init: nil;
|
||||
base_finalize: nil;
|
||||
class_init: @LCLGtkButtonClassInit;
|
||||
class_finalize: nil;
|
||||
class_data: nil;
|
||||
instance_size: GTK_BUTTON_INSTANCE_SIZE;
|
||||
n_preallocs: 0;
|
||||
instance_init: @LCLGtkButtonInstanceInit;
|
||||
value_table: nil;
|
||||
);
|
||||
begin
|
||||
if LCLGtkButtonType = 0 then
|
||||
LCLGtkButtonType := g_type_register_static(gtk_button_get_type, 'LCLGtkButton', @lcl_button_type_info, G_TYPE_FLAG_NONE);
|
||||
Result := LCLGtkButtonType;
|
||||
end;
|
||||
|
||||
function LCLGtkButtonNew: PGtkButton;
|
||||
begin
|
||||
Result := PGtkButton(g_object_new(LCLGtkButtonGetType(),'label',['', nil]));
|
||||
end;
|
||||
|
||||
|
@ -392,6 +392,24 @@ begin
|
||||
Result := lpGtk3;
|
||||
end;
|
||||
|
||||
//This is the only way to fix missing corner widget in GtkScrolledWindow.
|
||||
procedure ApplyCustomScrollbarStyles(const APixels: integer);
|
||||
var
|
||||
CssProvider: PGtkCssProvider;
|
||||
begin
|
||||
CssProvider := gtk_css_provider_new();
|
||||
gtk_css_provider_load_from_data(CssProvider,
|
||||
PgChar(Format('scrollbar.horizontal { margin-right: %dpx; }' +
|
||||
'scrollbar.vertical { margin-bottom: %dpx; }',[APixels, APixels])),
|
||||
-1, nil);
|
||||
|
||||
gtk_style_context_add_provider_for_screen(
|
||||
gdk_screen_get_default(),
|
||||
PGtkStyleProvider(CssProvider),
|
||||
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION
|
||||
);
|
||||
end;
|
||||
|
||||
procedure TGtk3WidgetSet.AppInit(var ScreenInfo: TScreenInfo);
|
||||
var
|
||||
ScreenDC: HDC;
|
||||
@ -479,6 +497,11 @@ begin
|
||||
scrollBarV^.get_preferred_width(@MinH, @PrefH);
|
||||
FSystemMetricsList.Items[SM_CXVSCROLL] := Max(MinH, PrefH);
|
||||
|
||||
//loading distance between scrollbars in corner, since
|
||||
//gtk3 does not have corner widget, we set it via css.
|
||||
ApplyCustomScrollbarStyles(Max(0, Floor(PrefH / 2) - 1));
|
||||
|
||||
|
||||
header^.get_preferred_height(@MinH, @PrefH);
|
||||
FSystemMetricsList.Items[SM_CYCAPTION] := Max(MinH, PrefH);
|
||||
|
||||
|
@ -505,6 +505,7 @@ type
|
||||
procedure InitializeWidget;override;
|
||||
procedure SetScrollBarsSignalHandlers;
|
||||
function getClientBounds: TRect; override;
|
||||
function getViewport: PGtkViewport; virtual;
|
||||
function getHorizontalScrollbar: PGtkScrollbar; virtual; abstract;
|
||||
function getVerticalScrollbar: PGtkScrollbar; virtual; abstract;
|
||||
function getScrolledWindow: PGtkScrolledWindow; virtual; abstract;
|
||||
@ -778,6 +779,7 @@ type
|
||||
function EatArrowKeys(const {%H-}AKey: Word): Boolean; override;
|
||||
public
|
||||
procedure InitializeWidget; override;
|
||||
function getViewport: PGtkViewport; override;
|
||||
procedure preferredSize(var PreferredWidth, PreferredHeight: integer; {%H-}WithThemeSpace: Boolean); override;
|
||||
function getClientRect: TRect; override;
|
||||
function getHorizontalScrollbar: PGtkScrollbar; override;
|
||||
@ -821,6 +823,7 @@ type
|
||||
procedure setText(const AValue: String); override;
|
||||
public
|
||||
// function getClientBounds: TRect; override;
|
||||
function getViewport: PGtkViewport; override;
|
||||
function getClientRect: TRect; override;
|
||||
function getHorizontalScrollbar: PGtkScrollbar; override;
|
||||
function getVerticalScrollbar: PGtkScrollbar; override;
|
||||
@ -1039,6 +1042,7 @@ end;
|
||||
|
||||
{$i gtk3lclcombobox.inc}
|
||||
{$i gtk3lclentry.inc}
|
||||
{$i gtk3lclbutton.inc}
|
||||
|
||||
class function TGtk3Widget.WidgetEvent(widget: PGtkWidget; event: PGdkEvent; data: GPointer): gboolean; cdecl;
|
||||
begin
|
||||
@ -5422,17 +5426,139 @@ begin
|
||||
TGCallback(@Gtk3RangeScrollCB), Self, nil, G_CONNECT_DEFAULT);
|
||||
end;
|
||||
|
||||
{$IFDEF GTK3DEBUGSIZE}
|
||||
function GetViewportClientAreaWithScrollbars(ScrolledWindow: PGtkScrolledWindow): TRect;
|
||||
var
|
||||
Viewport: PGtkViewport;
|
||||
ViewportAllocation, HScrollbarAllocation, VScrollbarAllocation: TGtkAllocation;
|
||||
Padding, Border: TGtkBorder;
|
||||
HScrollbar, VScrollbar: PGtkWidget;
|
||||
HScrollbarHeight, VScrollbarWidth: Integer;
|
||||
ScrollPolicyH, ScrollPolicyV: TGtkPolicyType;
|
||||
StyleContext: PGtkStyleContext;
|
||||
begin
|
||||
|
||||
FillChar(Result, SizeOf(Result), 0);
|
||||
HScrollbarHeight := 0;
|
||||
VScrollbarWidth := 0;
|
||||
|
||||
Viewport := PGtkViewport(gtk_bin_get_child(PGtkBin(ScrolledWindow)));
|
||||
if Viewport = nil then
|
||||
begin
|
||||
writeln('Viewport not found.');
|
||||
Exit;
|
||||
end;
|
||||
|
||||
gtk_widget_get_allocation(PGtkWidget(Viewport), @ViewportAllocation);
|
||||
|
||||
//Get the style context for padding and border
|
||||
StyleContext := gtk_widget_get_style_context(PGtkWidget(Viewport));
|
||||
FillChar(Padding, SizeOf(Padding), 0);
|
||||
FillChar(Border, SizeOf(Border), 0);
|
||||
|
||||
|
||||
gtk_style_context_get_padding(StyleContext, GTK_STATE_FLAG_NORMAL, @Padding);
|
||||
gtk_style_context_get_border(StyleContext, GTK_STATE_FLAG_NORMAL, @Border);
|
||||
|
||||
// Check scrollbar visibility policies
|
||||
gtk_scrolled_window_get_policy(ScrolledWindow, @ScrollPolicyH, @ScrollPolicyV);
|
||||
|
||||
//Check if the horizontal scrollbar is visible
|
||||
HScrollbar := gtk_scrolled_window_get_hscrollbar(ScrolledWindow);
|
||||
if (HScrollbar <> nil) and gtk_widget_get_visible(HScrollbar) and (ScrollPolicyH <> GTK_POLICY_NEVER) then
|
||||
begin
|
||||
gtk_widget_get_allocation(HScrollbar, @HScrollbarAllocation);
|
||||
HScrollbarHeight := HScrollbarAllocation.height;
|
||||
end;
|
||||
|
||||
//Check if the vertical scrollbar is visible
|
||||
VScrollbar := gtk_scrolled_window_get_vscrollbar(ScrolledWindow);
|
||||
if (VScrollbar <> nil) and gtk_widget_get_visible(VScrollbar) and (ScrollPolicyV <> GTK_POLICY_NEVER) then
|
||||
begin
|
||||
gtk_widget_get_allocation(VScrollbar, @VScrollbarAllocation);
|
||||
VScrollbarWidth := VScrollbarAllocation.width;
|
||||
end;
|
||||
|
||||
//Now we calculate the client area.
|
||||
Result.Left := ViewportAllocation.x + Border.left + Padding.left;
|
||||
Result.Top := ViewportAllocation.y + Border.top + Padding.top;
|
||||
Result.Right := ViewportAllocation.x + ViewportAllocation.width - Border.right - Padding.right - VScrollbarWidth;
|
||||
Result.Bottom := ViewportAllocation.y + ViewportAllocation.height - Border.bottom - Padding.bottom - HScrollbarHeight;
|
||||
|
||||
writeln(Format('Client Area Calculation: Left=%d, Top=%d, Right=%d, Bottom=%d',
|
||||
[Result.Left, Result.Top, Result.Right, Result.Bottom]));
|
||||
end;
|
||||
{$ENDIF}
|
||||
|
||||
function TGtk3ScrollableWin.getClientBounds: TRect;
|
||||
var
|
||||
Allocation: TGtkAllocation;
|
||||
x:gint;
|
||||
y:gint;
|
||||
w:gint;
|
||||
h:gint;
|
||||
AViewport:PGtkViewport;
|
||||
AWindow:PGdkWindow;
|
||||
VOffset, HOffset:gint;
|
||||
Bar:PGtkScrollbar;
|
||||
begin
|
||||
Result := Rect(0, 0, 0, 0);
|
||||
if IsWidgetOK then
|
||||
begin
|
||||
getContainerWidget^.get_allocation(@Allocation);
|
||||
Result := RectFromGtkAllocation(Allocation);
|
||||
(*
|
||||
if (Self is TGtk3CustomControl) then
|
||||
begin
|
||||
if Self is TGtk3Window then
|
||||
Result := GetViewportClientAreaWithScrollbars(PGtkScrolledWindow(TGtk3Window(Self).FScrollWin))
|
||||
else
|
||||
Result := GetViewportClientAreaWithScrollbars(PGtkScrolledWindow(FWidget));
|
||||
//DebugLn('TGtk3ScrollableWin.getClientBounds result ',dbgs(Result),' from viewport ',dbgsName(LCLObject));
|
||||
exit;
|
||||
end else
|
||||
*)
|
||||
AViewport := getViewPort;
|
||||
if Assigned(AViewport) and Gtk3IsGdkWindow(AViewport^.get_view_window) then
|
||||
begin
|
||||
AWindow := AViewport^.get_view_window;
|
||||
if Assigned(AWindow) then
|
||||
begin
|
||||
Bar := getHorizontalScrollbar;
|
||||
if (Bar <> nil) and Gtk3IsWidget(Bar) and Bar^.get_visible then
|
||||
HOffset := Bar^.get_allocated_height
|
||||
else
|
||||
HOffset := 0;
|
||||
Bar := getVerticalScrollbar;
|
||||
if (Bar <> nil) and Gtk3IsWidget(Bar) and Bar^.get_visible then
|
||||
VOffset := Bar^.get_allocated_width
|
||||
else
|
||||
VOffset := 0;
|
||||
|
||||
AViewPort^.get_view_window^.get_geometry(@x, @y, @w, @h);
|
||||
Result := Bounds(x, y, w - VOffset, h - HOffset);
|
||||
end else
|
||||
begin
|
||||
AViewPort^.get_allocation(@Allocation);
|
||||
Result := RectFromGtkAllocation(Allocation);
|
||||
end;
|
||||
end else
|
||||
begin
|
||||
getContainerWidget^.get_allocation(@Allocation);
|
||||
Result := RectFromGtkAllocation(Allocation);
|
||||
end;
|
||||
end;
|
||||
// DebugLn('TGtk3ScrollableWin.getClientBounds result ',dbgs(Result));
|
||||
if (Self is TGtk3Window) then
|
||||
exit;
|
||||
{$IFDEF GTK3DEBUGSIZE}
|
||||
if Assigned(AViewPort) then
|
||||
DebugLn('TGtk3ScrollableWin.getClientBounds result ',dbgs(Result),' from viewport ',dbgsName(LCLObject))
|
||||
else
|
||||
;//DebugLn('TGtk3ScrollableWin.getClientBounds result ',dbgs(Result),' no viewport ',dbgsName(LCLObject));
|
||||
{$ENDIF}
|
||||
end;
|
||||
|
||||
function TGtk3ScrollableWin.getViewport:PGtkViewport;
|
||||
begin
|
||||
Result := nil;
|
||||
end;
|
||||
|
||||
{ TGtk3Memo }
|
||||
@ -7456,7 +7582,7 @@ function TGtk3Button.CreateWidget(const Params: TCreateParams): PGtkWidget;
|
||||
var
|
||||
btn:PGtkButton absolute Result;
|
||||
begin
|
||||
Result := PGtkWidget(TGtkButton.new);
|
||||
Result := LCLGtkButtonNew;
|
||||
|
||||
btn^.set_use_underline(true);
|
||||
if not IsDesigning then
|
||||
@ -7675,6 +7801,11 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
function TGtk3CustomControl.getViewport:PGtkViewport;
|
||||
begin
|
||||
Result := PGtkViewport(PGtkScrolledWindow(Widget)^.get_child);
|
||||
end;
|
||||
|
||||
procedure TGtk3CustomControl.preferredSize(var PreferredWidth,PreferredHeight:
|
||||
integer;WithThemeSpace:Boolean);
|
||||
begin
|
||||
@ -7695,14 +7826,41 @@ var
|
||||
x: gint;
|
||||
y: gint;
|
||||
AViewPort: PGtkViewport;
|
||||
VOffset, HOffset:gint;
|
||||
Bar:PGtkScrollbar;
|
||||
begin
|
||||
// Result := inherited getClientRect;
|
||||
AViewPort := PGtkViewPort(FCentralWidget^.get_parent);
|
||||
AViewPort := getViewport;
|
||||
if Gtk3IsViewPort(AViewPort) and Gtk3IsGdkWindow(AViewPort^.get_view_window) then
|
||||
begin
|
||||
// Result := GetViewportClientAreaWithScrollbars(PGtkScrolledWindow(FWidget));
|
||||
|
||||
AViewPort^.get_view_window^.get_geometry(@x, @y, @w, @h);
|
||||
Result := Rect(0, 0, AViewPort^.get_view_window^.get_width, AViewPort^.get_view_window^.get_height);
|
||||
// DebugLn('TGtk3CustomControl.GetClientRect via Viewport ',dbgsName(LCLObject),' Result ',dbgs(Result),' X=',dbgs(X),' Y=',dbgs(Y));
|
||||
|
||||
Bar := getHorizontalScrollbar;
|
||||
if (Bar <> nil) and Bar^.get_visible then
|
||||
HOffset := Bar^.get_allocated_height
|
||||
else
|
||||
HOffset := 0;
|
||||
|
||||
Bar := getVerticalScrollbar;
|
||||
if (Bar <> nil) and Gtk3IsWidget(Bar) and Bar^.get_visible then
|
||||
VOffset := Bar^.get_allocated_width
|
||||
else
|
||||
VOffset := 0;
|
||||
|
||||
// AViewPort^.get_view_window^.get_frame_extents(@AFrameRect);
|
||||
|
||||
Result := Rect(0, 0, AViewPort^.get_view_window^.get_width - VOffset, AViewPort^.get_view_window^.get_height - HOffset);
|
||||
|
||||
{$IFDEF GTK3DEBUGSIZE}
|
||||
DebugLn('TGtk3CustomControl.GetClientRect via Viewport ',dbgsName(LCLObject),' Result ',dbgs(Result),' X=',dbgs(X),' Y=',dbgs(Y),' AllocH=',dbgs(AViewPort^.get_allocated_height));
|
||||
getContainerWidget^.get_allocation(@Allocation);
|
||||
with ALlocation do
|
||||
begin
|
||||
DebugLn(Format(' GtkFixed alloc x %d y %d width %d height %d',[x, y, width, height]));
|
||||
end;
|
||||
{$ENDIF}
|
||||
exit;
|
||||
end else
|
||||
FCentralWidget^.get_allocation(@Allocation);
|
||||
@ -8065,6 +8223,11 @@ begin
|
||||
Title := AValue;
|
||||
end;
|
||||
|
||||
function TGtk3Window.getViewport:PGtkViewport;
|
||||
begin
|
||||
Result := PGtkViewPort(FScrollWin^.get_child);
|
||||
end;
|
||||
|
||||
function TGtk3Window.getClientRect: TRect;
|
||||
var
|
||||
Allocation: TGtkAllocation;
|
||||
|
@ -3597,7 +3597,7 @@ begin
|
||||
if IsRectEmpty(R) then
|
||||
R := ScrollRect;
|
||||
{$ENDIF}
|
||||
gtk_widget_queue_draw(Widget.Widget);
|
||||
Widget.Update(nil);
|
||||
end else
|
||||
if (Flags and SW_INVALIDATE) <> 0 then
|
||||
begin
|
||||
@ -3606,13 +3606,15 @@ begin
|
||||
cairo_region_get_extents(cairoRegion, @UpdateRect);
|
||||
R := Bounds(UpdateRect.x, UpdateRect.y, UpdateRect.Width, UpdateRect.Height);
|
||||
prcUpdate := @R;
|
||||
gtk_widget_queue_draw_area(Widget.GetContainerWidget, UpdateRect.x, UpdateRect.y, UpdateRect.width, UpdateRect.Height);
|
||||
Widget.Update(@R);
|
||||
// gtk_widget_queue_draw_area(Widget.GetContainerWidget, UpdateRect.x, UpdateRect.y, UpdateRect.width, UpdateRect.Height);
|
||||
end else
|
||||
if prcClip <> nil then
|
||||
begin
|
||||
prcUpdate := prcClip;
|
||||
with prcClip^ do
|
||||
gtk_widget_queue_draw_area(Widget.GetContainerWidget, Left, Top, Width, Height);
|
||||
Widget.Update(prcUpdate);
|
||||
// with prcClip^ do
|
||||
// gtk_widget_queue_draw_area(Widget.GetContainerWidget, Left, Top, Width, Height);
|
||||
end;
|
||||
end;
|
||||
{$IFDEF DEBUGSCROLLWINDOWEX}
|
||||
@ -3885,154 +3887,180 @@ end;
|
||||
function TGtk3WidgetSet.SetScrollInfo(Handle: HWND; SBStyle: Integer;
|
||||
ScrollInfo: TScrollInfo; bRedraw: Boolean): Integer;
|
||||
|
||||
(*
|
||||
|
||||
procedure SetRangeUpdatePolicy(Range: PGtkRange);
|
||||
var
|
||||
UpdPolicy: TGTKUpdateType;
|
||||
begin
|
||||
case ScrollInfo.nTrackPos of
|
||||
SB_POLICY_DISCONTINUOUS: UpdPolicy := GTK_UPDATE_DISCONTINUOUS;
|
||||
SB_POLICY_DELAYED: UpdPolicy := GTK_UPDATE_DELAYED;
|
||||
else
|
||||
UpdPolicy := GTK_UPDATE_CONTINUOUS;
|
||||
end;
|
||||
!!! update policy for gtkRange does not exist anymore in gtk3
|
||||
so we must mimic that by using events. !!!
|
||||
gtk_range_set_update_policy(Range, UpdPolicy);
|
||||
end;
|
||||
procedure SetScrolledWindowUpdatePolicy(ScrolledWindow:PGTKScrolledWindow);
|
||||
var
|
||||
Range: PGtkRange;
|
||||
begin
|
||||
case SBStyle of
|
||||
SB_VERT: Range := PGtkRange(ScrolledWindow^.vscrollbar);
|
||||
SB_HORZ: Range := PGtkRange(ScrolledWindow^.hscrollbar);
|
||||
else exit;
|
||||
end;
|
||||
SetRangeUpdatePolicy(Range);
|
||||
end;
|
||||
*)
|
||||
|
||||
const
|
||||
POLICY: array[BOOLEAN] of TGTKPolicyType = (GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
|
||||
POLICY: array[Boolean] of TGTKPolicyType = (GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
|
||||
|
||||
procedure SetGDouble(var ATarget: Double; ANewValue: Double; var AHasChanged: Boolean);
|
||||
begin
|
||||
if ATarget = ANewValue then
|
||||
Exit;
|
||||
ATarget := ANewValue;
|
||||
AHasChanged := True;
|
||||
end;
|
||||
|
||||
var
|
||||
Adjustment,hadj,vadj: PGtkAdjustment;
|
||||
AWidget: TGtk3Widget;
|
||||
ACenter:PGtkWidget;
|
||||
ARange: PGtkRange;
|
||||
AScrollWin: PGtkScrolledWindow;
|
||||
IsScrollbarVis: Boolean;
|
||||
w,h:gint;
|
||||
IsScrollbarVis:Boolean;
|
||||
ScrollWin: PGtkScrolledWindow;
|
||||
Adjustment: PGtkAdjustment;
|
||||
IsScrollWindow: Boolean;
|
||||
HasChanged: Boolean;
|
||||
ScrollBar: PGtkScrollbar;
|
||||
W, H: double;
|
||||
|
||||
procedure UpdateAdjustment;
|
||||
var
|
||||
ATarget: gdouble;
|
||||
begin
|
||||
if (ScrollInfo.FMask and SIF_RANGE) <> 0 then
|
||||
begin
|
||||
ATarget := Adjustment^.lower;
|
||||
SetGDouble(ATarget, ScrollInfo.nMin, HasChanged);
|
||||
Adjustment^.lower := ATarget;
|
||||
|
||||
ATarget := Adjustment^.upper;
|
||||
SetGDouble(ATarget, ScrollInfo.nMax, HasChanged);
|
||||
Adjustment^.upper := ATarget;
|
||||
end;
|
||||
|
||||
if (ScrollInfo.FMask and SIF_PAGE) <> 0 then
|
||||
begin
|
||||
ATarget := Adjustment^.page_size;
|
||||
SetGDouble(ATarget, ScrollInfo.nPage, HasChanged);
|
||||
|
||||
ATarget := Min(Max(ATarget, 0), Adjustment^.upper - Adjustment^.lower + 1);
|
||||
Adjustment^.page_size := ATarget;
|
||||
|
||||
ATarget := Adjustment^.page_increment;
|
||||
SetGDouble(ATarget, Max(1, (Adjustment^.page_size / 6) + 1), HasChanged);
|
||||
Adjustment^.page_increment := ATarget;
|
||||
end;
|
||||
|
||||
if (ScrollInfo.FMask and SIF_POS) <> 0 then
|
||||
begin
|
||||
ATarget := Adjustment^.value;
|
||||
SetGDouble(ATarget, ScrollInfo.nPos, HasChanged);
|
||||
ATarget := Max(ATarget, Adjustment^.lower);
|
||||
ATarget := Min(ATarget, Adjustment^.upper - Max(Adjustment^.page_size - 1, 0));
|
||||
Adjustment^.value := ATarget;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure HandleRedraw;
|
||||
var
|
||||
AHorzPolicy:TGtkPolicyType;
|
||||
AVertPolicy:TGtkPolicyType;
|
||||
begin
|
||||
if bRedraw then
|
||||
begin
|
||||
gtk_adjustment_changed(Adjustment);
|
||||
if IsScrollWindow then // seem that gtk3 does not like this
|
||||
begin
|
||||
ScrollWin^.get_policy(@AHorzPolicy, @AVertPolicy);
|
||||
case SBStyle of
|
||||
SB_HORZ:
|
||||
ScrollWin^.set_policy(POLICY[IsScrollbarVis], AVertPolicy);
|
||||
SB_VERT:
|
||||
ScrollWin^.set_policy(AHorzPolicy, POLICY[IsScrollbarVis]);
|
||||
end;
|
||||
end;
|
||||
TGtk3Widget(Handle).Update(nil);
|
||||
end;
|
||||
end;
|
||||
|
||||
begin
|
||||
Result := 0;
|
||||
if not IsValidHandle(Handle) then
|
||||
if not IsValidHandle(Handle) then Exit;
|
||||
|
||||
HasChanged := False;
|
||||
|
||||
// must implement first
|
||||
if TGtk3Widget(Handle) is TGtk3Window then
|
||||
exit;
|
||||
|
||||
AWidget := TGtk3Widget(Handle);
|
||||
|
||||
Adjustment := nil;
|
||||
ARange := nil;
|
||||
AScrollWin := nil;
|
||||
|
||||
if wtScrollBar in AWidget.WidgetType then
|
||||
ScrollWin := nil;
|
||||
ScrollBar := niL;
|
||||
if TGtk3Widget(Handle) is TGtk3ScrollBar then
|
||||
ScrollBar := PGtkScrollBar(TGtk3Widget(Handle).Widget)
|
||||
else
|
||||
begin
|
||||
ARange := PGtkRange(AWidget.Widget);
|
||||
Adjustment := ARange^.adjustment;
|
||||
end else
|
||||
if wtScrollingWin in AWidget.WidgetType then
|
||||
begin
|
||||
AScrollWin := TGtk3ScrollableWin(Handle).GetScrolledWindow;
|
||||
if AScrollWin = nil then
|
||||
exit;
|
||||
if not Gtk3IsScrolledWindow(AScrollWin) then
|
||||
begin
|
||||
DebugLn('ERROR: TGtk3WidgetSet.SetScrollInfo: Wrong class extracted for scrollwin ',dbgsName(TGtk3Widget(Handle).LCLObject));
|
||||
AScrollWin := nil;
|
||||
end;
|
||||
if Assigned(AScrollWin) then
|
||||
begin
|
||||
hadj := AScrollWin^.get_hadjustment;
|
||||
vadj := AScrollWin^.get_vadjustment;
|
||||
end else
|
||||
begin
|
||||
hadj:=nil;
|
||||
vadj:=nil;
|
||||
end;
|
||||
// TODO: Convert Handle to GtkScrolledWindow, this is not the case with
|
||||
// TGtk3Window, so we must introduce new function for scrollables
|
||||
// to return GtkScrollingWindow, like we have with getViewport.
|
||||
ScrollWin := PGtkScrolledWindow(TGtk3ScrollableWin(Handle).Widget);
|
||||
if not Assigned(ScrollWin) then Exit;
|
||||
IsScrollWindow := True;
|
||||
end;
|
||||
|
||||
case SBStyle of
|
||||
SB_Horz:
|
||||
SB_HORZ:
|
||||
begin
|
||||
if not Assigned(Adjustment) and Assigned(AScrollWin) then
|
||||
if Assigned(ScrollWin) then
|
||||
begin
|
||||
Adjustment := hadj;
|
||||
if (ScrollInfo.fMask and SIF_RANGE) <> 0 then
|
||||
Adjustment := gtk_scrolled_window_get_hadjustment(ScrollWin);
|
||||
ScrollBar := TGtk3ScrollableWin(Handle).getHorizontalScrollbar;
|
||||
if ((ScrollInfo.fMask and SIF_RANGE) <> 0) and Gtk3IsScrolledWindow(ScrollWin) then
|
||||
begin
|
||||
ACenter:=AWidget.GetContainerWidget;
|
||||
Acenter^.set_size_request(ScrollInfo.nMax - ScrollInfo.nMin,round(vadj^.upper));
|
||||
H := gtk_scrolled_window_get_vadjustment(ScrollWin)^.upper;
|
||||
W := (ScrollInfo.nMax - ScrollInfo.nMin) + (gtk_scrolled_window_get_vscrollbar(ScrollWin)^.get_allocated_width * 2{scrollbars overlaps each other, so x2});
|
||||
W := Max(W, TGtk3ScrollableWin(Handle).getClientRect.Width);
|
||||
TGtk3ScrollableWin(Handle).GetContainerWidget^.set_size_request(Round(W), Round(H));
|
||||
end;
|
||||
end;
|
||||
end else
|
||||
Adjustment := ScrollBar^.adjustment;
|
||||
end;
|
||||
SB_Vert:
|
||||
SB_VERT:
|
||||
begin
|
||||
if not Assigned(Adjustment) and Assigned(AScrollWin) then
|
||||
if Assigned(ScrollWin) then
|
||||
begin
|
||||
Adjustment := vadj;
|
||||
if (ScrollInfo.fMask and SIF_RANGE) <> 0 then
|
||||
Adjustment := gtk_scrolled_window_get_vadjustment(ScrollWin);
|
||||
ScrollBar := TGtk3ScrollableWin(Handle).getVerticalScrollbar;
|
||||
if ((ScrollInfo.fMask and SIF_RANGE) <> 0) and Gtk3IsScrolledWindow(ScrollWin) then
|
||||
begin
|
||||
ACenter:=AWidget.GetContainerWidget;
|
||||
Acenter^.set_size_request(round(hadj^.upper),ScrollInfo.nMax - ScrollInfo.nMin);
|
||||
W := gtk_scrolled_window_get_hadjustment(ScrollWin)^.upper;
|
||||
H := (ScrollInfo.nMax - ScrollInfo.nMin) + (gtk_scrolled_window_get_hscrollbar(ScrollWin)^.get_allocated_height * 2{scrollbars overlaps each other, so x2});
|
||||
H := Max(H, TGtk3ScrollAbleWin(Handle).getClientRect.Height);
|
||||
//writeln(Format('VerticalScrollBar: set new size for Container W=%f H=%f viewport W=%d H=%d HScrollHeight=%d nMax=%f',[W, H, TGtk3ScrollableWin(Handle).getViewport^.get_allocated_width, TGtk3ScrollableWin(Handle).getViewport^.get_allocated_height, gtk_scrolled_window_get_hscrollbar(ScrollWin)^.get_allocated_height, adjustment^.get_upper]));
|
||||
//writeln(Format('VBAR min %d max %d Scale %d',[ScrollInfo.nMin, ScrollInfo.nMax, ScrollWin^.scale_factor]));
|
||||
TGtk3ScrollableWin(Handle).GetContainerWidget^.set_size_request(Round(W), Round(H));
|
||||
end;
|
||||
end;
|
||||
end else
|
||||
Adjustment := ScrollBar^.adjustment;
|
||||
end;
|
||||
SB_CTL:
|
||||
begin
|
||||
DebugLn('TGtk3WidgetSet.SetScrollInfo SB_CTL error: not implemented ',
|
||||
dbgsName(AWidget.LCLObject));
|
||||
if Assigned(ScrollBar) then
|
||||
Adjustment := ScrollBar^.adjustment
|
||||
else
|
||||
if Assigned(ScrollWin) then
|
||||
begin
|
||||
//
|
||||
end else
|
||||
exit;
|
||||
|
||||
end;
|
||||
SB_BOTH:
|
||||
begin
|
||||
DebugLn('TGtk3WidgetSet.SetScrollInfo SB_BOTH error: not implemented ',
|
||||
dbgsName(AWidget.LCLObject));
|
||||
DebugLn('[SetScrollInfo] SB_BOTH not implemented yet with gtk3.');
|
||||
exit;
|
||||
end;
|
||||
else
|
||||
Exit; // Unsupported SBStyle
|
||||
end;
|
||||
|
||||
if Adjustment = nil then
|
||||
if not Assigned(Adjustment) then
|
||||
begin
|
||||
DebugLn('TGtk3WidgetSet.SetScrollInfo error: cannot get PGtkAdjustment from ',
|
||||
dbgsName(AWidget.LCLObject));
|
||||
exit;
|
||||
DebugLn('SetScrollinfo: error adjustment is not assigned !');
|
||||
Exit;
|
||||
end;
|
||||
|
||||
if (ScrollInfo.fMask and SIF_RANGE) <> 0 then
|
||||
begin
|
||||
Adjustment^.lower := ScrollInfo.nMin;
|
||||
Adjustment^.upper := ScrollInfo.nMax;
|
||||
end;
|
||||
if (ScrollInfo.fMask and SIF_PAGE) <> 0 then
|
||||
begin
|
||||
// 0 <= nPage <= nMax-nMin+1
|
||||
Adjustment^.page_size := ScrollInfo.nPage;
|
||||
Adjustment^.page_size := Min(Max(Adjustment^.page_size,0),
|
||||
Adjustment^.upper-Adjustment^.lower+1);
|
||||
Adjustment^.page_increment := (Adjustment^.page_size/6)+1;
|
||||
end;
|
||||
if (ScrollInfo.fMask and SIF_POS) <> 0 then
|
||||
begin
|
||||
// nMin <= nPos <= nMax - Max(nPage-1,0)
|
||||
Adjustment^.value := ScrollInfo.nPos;
|
||||
Adjustment^.value := Max(Adjustment^.value,Adjustment^.lower);
|
||||
Adjustment^.value := Min(Adjustment^.value,
|
||||
Adjustment^.upper-Max(Adjustment^.page_size-1,0));
|
||||
end;
|
||||
|
||||
UpdateAdjustment;
|
||||
|
||||
// check if scrollbar should be hidden
|
||||
IsScrollbarVis := True;
|
||||
if ((ScrollInfo.fMask and (SIF_RANGE or SIF_PAGE)) <> 0) and
|
||||
((SBStyle=SB_HORZ) or (SBStyle=SB_VERT)) then
|
||||
begin
|
||||
((SBStyle=SB_HORZ) or (SBStyle=SB_VERT))
|
||||
then begin
|
||||
if (Adjustment^.lower >= (Adjustment^.upper-Max(adjustment^.page_size-1,0)))
|
||||
then begin
|
||||
if (ScrollInfo.fMask and SIF_DISABLENOSCROLL) = 0 then
|
||||
@ -4042,21 +4070,17 @@ begin
|
||||
// maybe not possible in gtk
|
||||
end;
|
||||
end;
|
||||
if bRedraw then
|
||||
begin
|
||||
if (AScrollWin <> nil) then
|
||||
begin
|
||||
// DebugLn('Setting scrollstyle of ',dbgsName(AWidget.LCLObject));
|
||||
if SBStyle = SB_HORZ then
|
||||
TGtk3ScrollableWin(AWidget).HScrollBarPolicy := POLICY[IsScrollbarVis]
|
||||
else
|
||||
if SBStyle = SB_VERT then
|
||||
TGtk3ScrollableWin(AWidget).VScrollBarPolicy := POLICY[IsScrollbarVis];
|
||||
end;
|
||||
AWidget.Update(nil);
|
||||
Adjustment^.changed;
|
||||
end;
|
||||
|
||||
|
||||
Result := Round(Adjustment^.value);
|
||||
if Result < 0 then
|
||||
begin
|
||||
DebugLn(Format('WARNING: TGtk3WidgetSet.SetScrollInfo: Result < 0 control %s',[Result, dbgsName(TGtk3Widget(Handle).LCLObject)]));
|
||||
Result := 0;
|
||||
end;
|
||||
|
||||
HandleRedraw;
|
||||
|
||||
end;
|
||||
|
||||
function TGtk3WidgetSet.SetSysColors(cElements: Integer; const lpaElements;
|
||||
|
Loading…
Reference in New Issue
Block a user