mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-19 09:59:10 +02:00
Gtk3: fixed mess with mouse wheel events.
This commit is contained in:
parent
46def57926
commit
5b22d571b2
@ -27,7 +27,7 @@ uses
|
|||||||
Controls, StdCtrls, ExtCtrls, Buttons, ComCtrls, Graphics, Dialogs, Forms, Menus, ExtDlgs,
|
Controls, StdCtrls, ExtCtrls, Buttons, ComCtrls, Graphics, Dialogs, Forms, Menus, ExtDlgs,
|
||||||
Spin, CheckLst, PairSplitter, LCLType, LMessages, LCLMessageGlue, LCLIntf,
|
Spin, CheckLst, PairSplitter, LCLType, LMessages, LCLMessageGlue, LCLIntf,
|
||||||
// LazUtils
|
// LazUtils
|
||||||
GraphType, LazUtilities,
|
GraphType,
|
||||||
// GTK3
|
// GTK3
|
||||||
LazGtk3, LazGdk3, LazGObject2, LazGLib2, LazCairo1, LazPango1, LazGdkPixbuf2,
|
LazGtk3, LazGdk3, LazGObject2, LazGLib2, LazCairo1, LazPango1, LazGdkPixbuf2,
|
||||||
gtk3objects, gtk3procs, gtk3private, Gtk3CellRenderer;
|
gtk3objects, gtk3procs, gtk3private, Gtk3CellRenderer;
|
||||||
@ -168,7 +168,6 @@ type
|
|||||||
function GtkEventResize(Sender: PGtkWidget; Event: PGdkEvent): Boolean; virtual; cdecl;
|
function GtkEventResize(Sender: PGtkWidget; Event: PGdkEvent): Boolean; virtual; cdecl;
|
||||||
procedure GtkEventFocus(Sender: PGtkWidget; Event: PGdkEvent); cdecl;
|
procedure GtkEventFocus(Sender: PGtkWidget; Event: PGdkEvent); cdecl;
|
||||||
procedure GtkEventDestroy; cdecl;
|
procedure GtkEventDestroy; cdecl;
|
||||||
function GtkEventMouseWheel(Sender: PGtkWidget; Event: PGdkEvent): Boolean; virtual; cdecl;
|
|
||||||
|
|
||||||
function IsValidHandle: Boolean;
|
function IsValidHandle: Boolean;
|
||||||
function IsWidgetOk: Boolean; virtual;
|
function IsWidgetOk: Boolean; virtual;
|
||||||
@ -1322,7 +1321,7 @@ begin
|
|||||||
GDK_SCROLL:
|
GDK_SCROLL:
|
||||||
begin
|
begin
|
||||||
// DebugLn('****** GDK_SCROLL ' + dbgsName(TGtk3Widget(Data).LCLObject));
|
// DebugLn('****** GDK_SCROLL ' + dbgsName(TGtk3Widget(Data).LCLObject));
|
||||||
Result := TGtk3Widget(Data).GtkEventMouseWheel(Widget, Event);
|
// Result := TGtk3Widget(Data).GtkEventMouseWheel(Widget, Event);
|
||||||
end;
|
end;
|
||||||
GDK_WINDOW_STATE:
|
GDK_WINDOW_STATE:
|
||||||
begin
|
begin
|
||||||
@ -1425,7 +1424,6 @@ end;
|
|||||||
class function TGtk3Widget.ScrollEvent(AWidget: PGtkWidget; AEvent: PGdkEvent; AData: GPointer): GBoolean; cdecl;
|
class function TGtk3Widget.ScrollEvent(AWidget: PGtkWidget; AEvent: PGdkEvent; AData: GPointer): GBoolean; cdecl;
|
||||||
var
|
var
|
||||||
AWinControl: TWinControl;
|
AWinControl: TWinControl;
|
||||||
EventXY: TPoint;
|
|
||||||
AState: Cardinal;
|
AState: Cardinal;
|
||||||
ShiftState: TShiftState;
|
ShiftState: TShiftState;
|
||||||
MappedXY: TPoint;
|
MappedXY: TPoint;
|
||||||
@ -1433,12 +1431,13 @@ var
|
|||||||
begin
|
begin
|
||||||
Result := False;
|
Result := False;
|
||||||
if AWidget=nil then ;
|
if AWidget=nil then ;
|
||||||
|
|
||||||
AWinControl := TGtk3Widget(AData).LCLObject;
|
AWinControl := TGtk3Widget(AData).LCLObject;
|
||||||
|
|
||||||
if AEvent^.scroll.send_event = NO_PROPAGATION_TO_PARENT then
|
if AEvent^.scroll.send_event = NO_PROPAGATION_TO_PARENT then
|
||||||
exit;
|
exit;
|
||||||
|
|
||||||
EventXY := Point(LazUtilities.TruncToInt(AEvent^.Scroll.X),LazUtilities.TruncToInt(AEvent^.scroll.Y));
|
MappedXY := Point(Round(AEvent^.Scroll.X),Round(AEvent^.scroll.Y));
|
||||||
AState := GtkModifierStateToShiftState(AEvent^.scroll.state, False);
|
AState := GtkModifierStateToShiftState(AEvent^.scroll.state, False);
|
||||||
ShiftState := [];
|
ShiftState := [];
|
||||||
if AState and MK_SHIFT <> 0 then
|
if AState and MK_SHIFT <> 0 then
|
||||||
@ -1447,38 +1446,51 @@ begin
|
|||||||
ShiftState := ShiftState + [ssCtrl];
|
ShiftState := ShiftState + [ssCtrl];
|
||||||
if AState and MK_ALT <> 0 then
|
if AState and MK_ALT <> 0 then
|
||||||
ShiftState := ShiftState + [ssAlt];
|
ShiftState := ShiftState + [ssAlt];
|
||||||
// MappedXY := TranslateGdkPointToClientArea(AEvent^.scroll.window, EventXY,
|
|
||||||
// {%H-}TGtk3Widget(AWinControl.Handle).GetContainerWidget);
|
|
||||||
MappedXY := EventXY;
|
|
||||||
if TGtk3Widget(AWinControl.Handle) is TGtk3ScrollableWin then
|
|
||||||
MappedXY := SubtractScroll(TGtk3Widget(AWinControl.Handle).Widget, MappedXY)
|
|
||||||
else
|
|
||||||
MappedXY := SubtractScroll(TGtk3Widget(AWinControl.Handle).GetContainerWidget, MappedXY);
|
|
||||||
//DebugLn('gtkMouseWheelCB ',DbgSName(AWinControl),' Mapped=',dbgs(MappedXY.X),',',dbgs(MappedXY.Y),' Event=',dbgs(EventXY.X),',',dbgs(EventXY.Y));
|
|
||||||
TGtk3Widget(AData).OffsetMousePos(@MappedXY);
|
TGtk3Widget(AData).OffsetMousePos(@MappedXY);
|
||||||
// this is a mouse wheel event
|
|
||||||
FillChar(MessE{%H-},SizeOf(MessE),0);
|
FillChar(MessE{%H-},SizeOf(MessE),0);
|
||||||
MessE.Msg := LM_MOUSEWHEEL;
|
MessE.Msg := LM_MOUSEWHEEL;
|
||||||
case AEvent^.scroll.direction of
|
case AEvent^.scroll.direction of
|
||||||
GDK_SCROLL_UP {0}: MessE.WheelDelta := 120;
|
GDK_SCROLL_UP, GDK_SCROLL_RIGHT {0}: MessE.WheelDelta := 120;
|
||||||
GDK_SCROLL_DOWN {1}: MessE.WheelDelta := -120;
|
GDK_SCROLL_DOWN, GDK_SCROLL_LEFT {1}: MessE.WheelDelta := -120;
|
||||||
|
GDK_SCROLL_SMOOTH:
|
||||||
|
begin
|
||||||
|
if AEvent^.scroll.delta_y <> 0 then
|
||||||
|
begin
|
||||||
|
if AEvent^.scroll.delta_y > 0 then
|
||||||
|
MessE.WheelDelta := -120
|
||||||
|
else
|
||||||
|
MessE.WheelDelta := 120;
|
||||||
|
//TODO: find in settings default wheel scroll distance
|
||||||
|
//MessE.WheelDelta := -Round((120 * AEvent^.scroll.delta_y) / 10);
|
||||||
|
end else
|
||||||
|
if AEvent^.scroll.delta_x <> 0 then
|
||||||
|
begin
|
||||||
|
if AEvent^.scroll.delta_x > 0 then
|
||||||
|
MessE.WheelDelta := -120
|
||||||
|
else
|
||||||
|
MessE.WheelDelta := 120;
|
||||||
|
end else
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
else
|
else
|
||||||
|
begin
|
||||||
|
DebugLn('WARNING: ',dbgsName(aWinControl),' unhandled scrollDirection event ',dbgs(Ord(AEvent^.scroll.direction)));
|
||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
MessE.X := MappedXY.X;
|
end;
|
||||||
MessE.Y := MappedXY.Y;
|
MessE.X := SmallInt(MappedXY.X);
|
||||||
|
MessE.Y := SmallInt(MappedXY.Y);
|
||||||
MessE.State := ShiftState;
|
MessE.State := ShiftState;
|
||||||
MessE.UserData := AWinControl;
|
MessE.UserData := AWinControl;
|
||||||
MessE.Button := 0;
|
MessE.Button := 0;
|
||||||
|
|
||||||
// send the message directly to the LCL
|
|
||||||
NotifyApplicationUserInput(AWinControl, MessE.Msg);
|
NotifyApplicationUserInput(AWinControl, MessE.Msg);
|
||||||
if TGtk3Widget(AData).DeliverMessage(MessE) <> 0 then
|
Result := TGtk3Widget(AData).DeliverMessage(MessE) <> 0;
|
||||||
Result := True // message handled by LCL, stop processing
|
AEvent^.scroll.send_event := NO_PROPAGATION_TO_PARENT;
|
||||||
else
|
|
||||||
AEvent^.scroll.send_event := NO_PROPAGATION_TO_PARENT;
|
|
||||||
|
|
||||||
// DebugLn('Gtk3ScrollEvent for ', dbgsName(TGtk3Widget(AData).LCLObject),' Result ',dbgs(Result));
|
//DebugLn('Gtk3ScrollEvent for ', dbgsName(TGtk3Widget(AData).LCLObject),' Result ',dbgs(Result));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
class procedure TGtk3Widget.SizeAllocate(AWidget: PGtkWidget; AGdkRect: PGdkRectangle; Data: gpointer); cdecl;
|
class procedure TGtk3Widget.SizeAllocate(AWidget: PGtkWidget; AGdkRect: PGdkRectangle; Data: gpointer); cdecl;
|
||||||
@ -1615,110 +1627,6 @@ begin
|
|||||||
Gtk3Widget.DeliverMessage(Msg);
|
Gtk3Widget.DeliverMessage(Msg);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function Gtk3ScrolledWindowScrollEvent(AScrollWindow: PGtkScrolledWindow; AEvent: PGdkEvent; AData: gPointer): gboolean; cdecl;
|
|
||||||
var
|
|
||||||
Msg: TLMVScroll;
|
|
||||||
ScrollStep, AValue: Double;
|
|
||||||
Adjustment: PGtkAdjustment;
|
|
||||||
Range: PGtkRange;
|
|
||||||
ACtl: TGtk3Widget absolute AData;
|
|
||||||
IsVerticalScroll: Boolean;
|
|
||||||
begin
|
|
||||||
Result := False;
|
|
||||||
|
|
||||||
if ACtl = nil then
|
|
||||||
Exit;
|
|
||||||
|
|
||||||
{$IFDEF GTK3DEBUGSCROLL}
|
|
||||||
DebugLn(['>Gtk3ScrolledWindowScrollEvent triggered InUpdate lock=',dbgs(ACtl.InUpdate)]);
|
|
||||||
{$ENDIF}
|
|
||||||
|
|
||||||
Msg := Default(TLMVScroll);
|
|
||||||
|
|
||||||
case AEvent^.scroll.direction of
|
|
||||||
GDK_SCROLL_UP, GDK_SCROLL_DOWN:
|
|
||||||
begin
|
|
||||||
Msg.Msg := LM_VSCROLL;
|
|
||||||
Range := PGtkRange(gtk_scrolled_window_get_vscrollbar(AScrollWindow));
|
|
||||||
Adjustment := gtk_range_get_adjustment(Range);
|
|
||||||
ScrollStep := power(Adjustment^.page_size, 2 / 3);
|
|
||||||
if AEvent^.scroll.direction = GDK_SCROLL_DOWN then
|
|
||||||
ScrollStep := -ScrollStep;
|
|
||||||
end;
|
|
||||||
GDK_SCROLL_LEFT, GDK_SCROLL_RIGHT:
|
|
||||||
begin
|
|
||||||
Msg.Msg := LM_HSCROLL;
|
|
||||||
Range := PGtkRange(gtk_scrolled_window_get_hscrollbar(AScrollWindow));
|
|
||||||
Adjustment := gtk_range_get_adjustment(Range);
|
|
||||||
ScrollStep := power(Adjustment^.page_size, 2 / 3);
|
|
||||||
if AEvent^.scroll.direction = GDK_SCROLL_RIGHT then
|
|
||||||
ScrollStep := -ScrollStep;
|
|
||||||
end;
|
|
||||||
GDK_SCROLL_SMOOTH:
|
|
||||||
begin
|
|
||||||
IsVerticalScroll := Abs(AEvent^.scroll.delta_y) > Abs(AEvent^.scroll.delta_x);
|
|
||||||
if IsVerticalScroll then
|
|
||||||
begin
|
|
||||||
Msg.Msg := LM_VSCROLL;
|
|
||||||
Range := PGtkRange(gtk_scrolled_window_get_vscrollbar(AScrollWindow));
|
|
||||||
Adjustment := gtk_range_get_adjustment(Range);
|
|
||||||
ScrollStep := -(-AEvent^.scroll.delta_y * Adjustment^.page_size * 0.1);
|
|
||||||
end
|
|
||||||
else
|
|
||||||
begin
|
|
||||||
Msg.Msg := LM_HSCROLL;
|
|
||||||
Range := PGtkRange(gtk_scrolled_window_get_hscrollbar(AScrollWindow));
|
|
||||||
Adjustment := gtk_range_get_adjustment(Range);
|
|
||||||
ScrollStep := -AEvent^.scroll.delta_x * Adjustment^.page_size * 0.1;
|
|
||||||
end;
|
|
||||||
|
|
||||||
if Abs(ScrollStep) < 1.0 then
|
|
||||||
begin
|
|
||||||
if ScrollStep > 0 then
|
|
||||||
ScrollStep := 1.0
|
|
||||||
else
|
|
||||||
ScrollStep := -1.0;
|
|
||||||
end;
|
|
||||||
{$IFDEF GTK3DEBUGSCROLL}
|
|
||||||
DebugLn(Format('Smooth Scroll: delta_x=%.2f, delta_y=%.2f, ScrollStep=%.2f',
|
|
||||||
[AEvent^.scroll.delta_x, AEvent^.scroll.delta_y, ScrollStep]));
|
|
||||||
{$ENDIF}
|
|
||||||
end;
|
|
||||||
else
|
|
||||||
begin
|
|
||||||
{$IFDEF GTK3DEBUGSCROLL}
|
|
||||||
DebugLn('Gtk3ScrolledWindowScrollEvent: Unknown scroll direction: ', dbgs(AEvent^.scroll.direction));
|
|
||||||
{$ENDIF}
|
|
||||||
Exit;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
with Adjustment^ do
|
|
||||||
begin
|
|
||||||
AValue := value + ScrollStep;
|
|
||||||
AValue := Max(AValue, lower);
|
|
||||||
AValue := Min(AValue, upper - page_size);
|
|
||||||
end;
|
|
||||||
|
|
||||||
with Msg do
|
|
||||||
begin
|
|
||||||
Pos := Round(AValue);
|
|
||||||
ScrollBar := HWND({%H-}TGtk3Widget(AData)); //TODO: Implement TGtk3Scrollbar.CreateFrom
|
|
||||||
ScrollCode := SB_THUMBPOSITION;
|
|
||||||
end;
|
|
||||||
|
|
||||||
{$IFDEF GTK3DEBUGSCROLL}
|
|
||||||
DebugLn(Format('Scroll Event: Pos=%d, ScrollStep=%.2f, Value=%.2f', [Msg.Pos, ScrollStep, AValue]));
|
|
||||||
{$ENDIF}
|
|
||||||
|
|
||||||
|
|
||||||
Result := ACtl.DeliverMessage(Msg) <> 0;
|
|
||||||
//Result := gtk_true;
|
|
||||||
{$IFDEF GTK3DEBUGSCROLL}
|
|
||||||
DebugLn(['<Gtk3ScrolledWindowScrollEvent completed: Pos=', Msg.Pos, ', ScrollStep=', ScrollStep.ToString,' InUpdate=',dbgs(ACtl.InUpdate),' Result=',dbgs(Result)]);
|
|
||||||
{$ENDIF}
|
|
||||||
end;
|
|
||||||
|
|
||||||
{ TGtk3SplitterSide }
|
{ TGtk3SplitterSide }
|
||||||
|
|
||||||
function TGtk3SplitterSide.CreateWidget(const Params: TCreateParams): PGtkWidget;
|
function TGtk3SplitterSide.CreateWidget(const Params: TCreateParams): PGtkWidget;
|
||||||
@ -1945,47 +1853,6 @@ begin
|
|||||||
Release;
|
Release;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TGtk3Widget.GtkEventMouseWheel(Sender: PGtkWidget; Event: PGdkEvent
|
|
||||||
): Boolean; cdecl;
|
|
||||||
var
|
|
||||||
Msg: TLMMouseEvent;
|
|
||||||
MousePos: TPoint;
|
|
||||||
begin
|
|
||||||
// gtk3 have ugly bug with scroll-event
|
|
||||||
// https://bugzilla.gnome.org/show_bug.cgi?id=675959
|
|
||||||
Result := False;
|
|
||||||
FillChar(Msg{%H-},SizeOf(Msg),0);
|
|
||||||
Msg.Msg := LM_MOUSEWHEEL;
|
|
||||||
//DebugLn('Scroll ',Format('deltaX %2.2n deltaY %2.2n x %2.2n y %2.2n rootx %2.2n rooty %2.2n',
|
|
||||||
// [Event^.scroll.delta_x, Event^.scroll.delta_y, Event^.scroll.x, Event^.scroll.y,
|
|
||||||
// Event^.scroll.x_root, Event^.scroll.y_root]));
|
|
||||||
if Event^.scroll.direction = GDK_SCROLL_UP then
|
|
||||||
Msg.WheelDelta := 120
|
|
||||||
else
|
|
||||||
if Event^.scroll.direction = GDK_SCROLL_DOWN then
|
|
||||||
Msg.WheelDelta := -120
|
|
||||||
else
|
|
||||||
exit;
|
|
||||||
|
|
||||||
MousePos.x := Round(Event^.scroll.x);
|
|
||||||
MousePos.y := Round(Event^.scroll.y);
|
|
||||||
|
|
||||||
OffsetMousePos(@MousePos);
|
|
||||||
|
|
||||||
Msg.X := SmallInt(MousePos.X);
|
|
||||||
Msg.Y := SmallInt(MousePos.Y);
|
|
||||||
|
|
||||||
Msg.State := GdkModifierStateToShiftState(Event^.scroll.state);
|
|
||||||
Msg.UserData := LCLObject;
|
|
||||||
Msg.Button := 0;
|
|
||||||
|
|
||||||
NotifyApplicationUserInput(LCLObject, Msg.Msg);
|
|
||||||
if Widget^.get_parent <> nil then
|
|
||||||
Event^.motion.send_event := NO_PROPAGATION_TO_PARENT;
|
|
||||||
if DeliverMessage(Msg, True) <> 0 then
|
|
||||||
Result := True;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TGtk3Widget.IsValidHandle: Boolean;
|
function TGtk3Widget.IsValidHandle: Boolean;
|
||||||
begin
|
begin
|
||||||
Result := Assigned(FWidget) and Gtk3IsWidget(FWidget) and not FWidget^.in_destruction;
|
Result := Assigned(FWidget) and Gtk3IsWidget(FWidget) and not FWidget^.in_destruction;
|
||||||
@ -8973,8 +8840,6 @@ begin
|
|||||||
inherited InitializeWidget;
|
inherited InitializeWidget;
|
||||||
if not IsDesigning then
|
if not IsDesigning then
|
||||||
begin
|
begin
|
||||||
g_signal_connect_data(GetScrolledWindow,'scroll-event', TGCallback(@Gtk3ScrolledWindowScrollEvent), Self, nil, G_CONNECT_DEFAULT);
|
|
||||||
|
|
||||||
g_signal_connect_data(gtk_scrolled_window_get_hscrollbar(GetScrolledWindow), 'change-value',
|
g_signal_connect_data(gtk_scrolled_window_get_hscrollbar(GetScrolledWindow), 'change-value',
|
||||||
TGCallback(@RangeChangeValue), Self, nil, G_CONNECT_DEFAULT);
|
TGCallback(@RangeChangeValue), Self, nil, G_CONNECT_DEFAULT);
|
||||||
g_signal_connect_data(gtk_scrolled_window_get_vscrollbar(GetScrolledWindow), 'change-value',
|
g_signal_connect_data(gtk_scrolled_window_get_vscrollbar(GetScrolledWindow), 'change-value',
|
||||||
|
Loading…
Reference in New Issue
Block a user