mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-18 15:19:19 +02:00
SynEdit: Scrolling for dragging needs to happen while the mouse is inside the editor (near the edge). Otherwise the source edit, keeps scrolling while over a drop target outside it. Issue #40177
This commit is contained in:
parent
aba8a43de8
commit
29f079e7c1
@ -210,7 +210,9 @@ type
|
|||||||
// Mouse-states
|
// Mouse-states
|
||||||
sfLeftGutterClick, sfRightGutterClick,
|
sfLeftGutterClick, sfRightGutterClick,
|
||||||
sfInClick, sfDblClicked, sfTripleClicked, sfQuadClicked,
|
sfInClick, sfDblClicked, sfTripleClicked, sfQuadClicked,
|
||||||
sfWaitForDragging, sfWaitForDraggingNoCaret, sfIsDragging, sfWaitForMouseSelecting, sfMouseSelecting, sfMouseDoneSelecting,
|
sfWaitForDragging, sfWaitForDraggingNoCaret, sfIsDragging, // SynEdit is drag-source
|
||||||
|
sfDraggingOver, // SynEdit is drag target
|
||||||
|
sfWaitForMouseSelecting, sfMouseSelecting, sfMouseDoneSelecting,
|
||||||
sfIgnoreUpClick,
|
sfIgnoreUpClick,
|
||||||
sfSelChanged
|
sfSelChanged
|
||||||
); //mh 2000-10-30
|
); //mh 2000-10-30
|
||||||
@ -772,6 +774,7 @@ type
|
|||||||
procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
|
procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
|
||||||
procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
|
procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
|
||||||
override;
|
override;
|
||||||
|
procedure DragTimerHandler;
|
||||||
procedure ScrollTimerHandler(Sender: TObject);
|
procedure ScrollTimerHandler(Sender: TObject);
|
||||||
procedure DoContextPopup(MousePos: TPoint; var Handled: Boolean); override;
|
procedure DoContextPopup(MousePos: TPoint; var Handled: Boolean); override;
|
||||||
procedure FindAndHandleMouseAction(AButton: TSynMouseButton; AShift: TShiftState;
|
procedure FindAndHandleMouseAction(AButton: TSynMouseButton; AShift: TShiftState;
|
||||||
@ -820,6 +823,8 @@ type
|
|||||||
procedure SetHighlighter(const Value: TSynCustomHighlighter); virtual;
|
procedure SetHighlighter(const Value: TSynCustomHighlighter); virtual;
|
||||||
procedure UpdateShowing; override;
|
procedure UpdateShowing; override;
|
||||||
procedure SetColor(Value: TColor); override;
|
procedure SetColor(Value: TColor); override;
|
||||||
|
(* Fractions go +/- 1..256 // Fraction bigger 256 mean on opposite side outside hot zone *)
|
||||||
|
function GetDragHotZoneInfo(x,y: Integer; out HorizFraction, VertFraction: Integer): boolean;
|
||||||
procedure DragOver(Source: TObject; X, Y: Integer;
|
procedure DragOver(Source: TObject; X, Y: Integer;
|
||||||
State: TDragState; var Accept: Boolean); override;
|
State: TDragState; var Accept: Boolean); override;
|
||||||
procedure DoOnResize; override;
|
procedure DoOnResize; override;
|
||||||
@ -3666,6 +3671,36 @@ begin
|
|||||||
FPaintArea.BackgroundColor := Color;
|
FPaintArea.BackgroundColor := Color;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TCustomSynEdit.GetDragHotZoneInfo(x, y: Integer; out HorizFraction,
|
||||||
|
VertFraction: Integer): boolean;
|
||||||
|
var
|
||||||
|
b: TRect;
|
||||||
|
HotWidth, HotHeight: Integer;
|
||||||
|
begin
|
||||||
|
HorizFraction := 0;
|
||||||
|
VertFraction := 0;
|
||||||
|
|
||||||
|
b := FTextArea.Bounds;
|
||||||
|
HotWidth := Min(LineHeight * 11 div 4, (b.Right - b.Left) div 4);
|
||||||
|
HotHeight := Min(LineHeight * 9 div 4, (b.Bottom - b.Top) div 4);
|
||||||
|
|
||||||
|
if x < b.Left + HotWidth then
|
||||||
|
HorizFraction := (x - (b.Left + HotWidth)) * 256 div HotWidth
|
||||||
|
else
|
||||||
|
if x >= b.Right - HotWidth then
|
||||||
|
HorizFraction := (x - (b.Right - 1 - HotWidth)) * 256 div HotWidth;
|
||||||
|
|
||||||
|
if y < b.Top + HotWidth then
|
||||||
|
VertFraction := (y - (b.Top + HotWidth)) * 256 div HotWidth
|
||||||
|
else
|
||||||
|
if y >= b.Bottom - HotWidth then
|
||||||
|
VertFraction := (y - (b.Bottom - 1 - HotWidth)) * 256 div HotWidth;
|
||||||
|
|
||||||
|
Result := ( (HorizFraction <> 0) or (VertFraction <> 0) ) and
|
||||||
|
(abs(HorizFraction) <= 256) and
|
||||||
|
(abs(VertFraction) <= 256);
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TCustomSynEdit.FindAndHandleMouseAction(AButton: TSynMouseButton;
|
procedure TCustomSynEdit.FindAndHandleMouseAction(AButton: TSynMouseButton;
|
||||||
AShift: TShiftState; X, Y: Integer; ACCount: TSynMAClickCount; ADir: TSynMAClickDir; out
|
AShift: TShiftState; X, Y: Integer; ACCount: TSynMAClickCount; ADir: TSynMAClickDir; out
|
||||||
AnActionResult: TSynEditMouseActionResult; AWheelDelta: Integer);
|
AnActionResult: TSynEditMouseActionResult; AWheelDelta: Integer);
|
||||||
@ -3850,11 +3885,9 @@ begin
|
|||||||
end;
|
end;
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
if (fStateFlags * [sfMouseSelecting, sfIsDragging] <> []) and MouseCapture
|
if (fStateFlags * [sfMouseSelecting, sfIsDragging] = [sfMouseSelecting]) and MouseCapture
|
||||||
then begin
|
then begin
|
||||||
//DebugLn(' TCustomSynEdit.MouseMove CAPTURE Mouse=',dbgs(X),',',dbgs(Y),' Caret=',dbgs(CaretXY),', BlockBegin=',dbgs(BlockBegin),' BlockEnd=',dbgs(BlockEnd));
|
//DebugLn(' TCustomSynEdit.MouseMove CAPTURE Mouse=',dbgs(X),',',dbgs(Y),' Caret=',dbgs(CaretXY),', BlockBegin=',dbgs(BlockBegin),' BlockEnd=',dbgs(BlockEnd));
|
||||||
if sfIsDragging in fStateFlags then
|
|
||||||
FBlockSelection.IncPersistentLock;
|
|
||||||
|
|
||||||
// compare to Bounds => Padding area does not scroll
|
// compare to Bounds => Padding area does not scroll
|
||||||
if (X >= FTextArea.Bounds.Left) and
|
if (X >= FTextArea.Bounds.Left) and
|
||||||
@ -3865,8 +3898,7 @@ begin
|
|||||||
FInternalCaret.AssignFrom(FCaret);
|
FInternalCaret.AssignFrom(FCaret);
|
||||||
FInternalCaret.LineCharPos := PixelsToRowColumn(Point(X,Y));
|
FInternalCaret.LineCharPos := PixelsToRowColumn(Point(X,Y));
|
||||||
|
|
||||||
if (fStateFlags * [sfMouseSelecting, sfIsDragging] = [sfMouseSelecting]) and
|
if (FMouseSelectionCmd in [emcStartSelectTokens, emcStartSelectWords, emcStartSelectLines])
|
||||||
(FMouseSelectionCmd in [emcStartSelectTokens, emcStartSelectWords, emcStartSelectLines])
|
|
||||||
then begin
|
then begin
|
||||||
FInternalCaret.LineCharPos := PixelsToRowColumn(Point(X,Y), [scmForceLeftSidePos]);
|
FInternalCaret.LineCharPos := PixelsToRowColumn(Point(X,Y), [scmForceLeftSidePos]);
|
||||||
forw := ComparePoints(FInternalCaret.LineBytePos, FBlockSelection.StartLineBytePos) >= 0;
|
forw := ComparePoints(FInternalCaret.LineBytePos, FBlockSelection.StartLineBytePos) >= 0;
|
||||||
@ -3907,7 +3939,9 @@ begin
|
|||||||
Include(fStateFlags, sfMouseDoneSelecting);
|
Include(fStateFlags, sfMouseDoneSelecting);
|
||||||
FBlockSelection.StickyAutoExtend := False;
|
FBlockSelection.StickyAutoExtend := False;
|
||||||
FBlockSelection.AutoExtend := sfMouseSelecting in fStateFlags;
|
FBlockSelection.AutoExtend := sfMouseSelecting in fStateFlags;
|
||||||
|
Include(fStateFlags, sfPreventScrollAfterSelect); // not PaintLocked => setting caret will directly call EnsureCursorPos
|
||||||
FCaret.LineBytePos := FInternalCaret.LineBytePos;
|
FCaret.LineBytePos := FInternalCaret.LineBytePos;
|
||||||
|
exclude(fStateFlags, sfPreventScrollAfterSelect);
|
||||||
FBlockSelection.AutoExtend := False;
|
FBlockSelection.AutoExtend := False;
|
||||||
end
|
end
|
||||||
else begin
|
else begin
|
||||||
@ -3926,6 +3960,7 @@ begin
|
|||||||
else
|
else
|
||||||
FScrollDeltaY := 0;
|
FScrollDeltaY := 0;
|
||||||
|
|
||||||
|
fScrollTimer.Interval := 100;
|
||||||
fScrollTimer.Enabled := (fScrollDeltaX <> 0) or (fScrollDeltaY <> 0);
|
fScrollTimer.Enabled := (fScrollDeltaX <> 0) or (fScrollDeltaY <> 0);
|
||||||
if (sfMouseSelecting in fStateFlags) and ((fScrollDeltaX <> 0) or (fScrollDeltaY <> 0)) then
|
if (sfMouseSelecting in fStateFlags) and ((fScrollDeltaX <> 0) or (fScrollDeltaY <> 0)) then
|
||||||
Include(fStateFlags, sfMouseDoneSelecting);
|
Include(fStateFlags, sfMouseDoneSelecting);
|
||||||
@ -3933,8 +3968,6 @@ begin
|
|||||||
if sfMouseDoneSelecting in fStateFlags then begin
|
if sfMouseDoneSelecting in fStateFlags then begin
|
||||||
FBlockSelection.ActiveSelectionMode := FMouseSelectionMode;
|
FBlockSelection.ActiveSelectionMode := FMouseSelectionMode;
|
||||||
end;
|
end;
|
||||||
if sfIsDragging in fStateFlags then
|
|
||||||
FBlockSelection.DecPersistentLock;
|
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
if MouseCapture and (fStateFlags * [sfIsDragging, sfWaitForMouseSelecting] = [])
|
if MouseCapture and (fStateFlags * [sfIsDragging, sfWaitForMouseSelecting] = [])
|
||||||
@ -3950,9 +3983,14 @@ var
|
|||||||
CurMousePos: TPoint;
|
CurMousePos: TPoint;
|
||||||
X, Y: Integer;
|
X, Y: Integer;
|
||||||
begin
|
begin
|
||||||
|
fScrollTimer.Interval := 100;
|
||||||
|
|
||||||
|
if sfDraggingOver in fStateFlags then begin
|
||||||
|
DragTimerHandler;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
// changes to line / column in one go
|
// changes to line / column in one go
|
||||||
if sfIsDragging in fStateFlags then
|
|
||||||
FBlockSelection.IncPersistentLock;
|
|
||||||
DoIncPaintLock(Self); // No editing is taking place
|
DoIncPaintLock(Self); // No editing is taking place
|
||||||
try
|
try
|
||||||
CurMousePos:=Point(0,0);
|
CurMousePos:=Point(0,0);
|
||||||
@ -4003,9 +4041,9 @@ begin
|
|||||||
SetBlockEnd(LogicalCaretXY);
|
SetBlockEnd(LogicalCaretXY);
|
||||||
end;
|
end;
|
||||||
finally
|
finally
|
||||||
|
if sfEnsureCursorPos in fStateFlags then
|
||||||
|
Include(fStateFlags, sfPreventScrollAfterSelect);
|
||||||
DoDecPaintLock(Self);
|
DoDecPaintLock(Self);
|
||||||
if sfIsDragging in fStateFlags then
|
|
||||||
FBlockSelection.DecPersistentLock;
|
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -4087,6 +4125,43 @@ begin
|
|||||||
//DebugLn('TCustomSynEdit.MouseUp END Mouse=',X,',',Y,' Caret=',CaretX,',',CaretY,', BlockBegin=',BlockBegin.X,',',BlockBegin.Y,' BlockEnd=',BlockEnd.X,',',BlockEnd.Y);
|
//DebugLn('TCustomSynEdit.MouseUp END Mouse=',X,',',Y,' Caret=',CaretX,',',CaretY,', BlockBegin=',BlockBegin.X,',',BlockBegin.Y,' BlockEnd=',BlockEnd.X,',',BlockEnd.Y);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TCustomSynEdit.DragTimerHandler;
|
||||||
|
var
|
||||||
|
hf, vf: Integer;
|
||||||
|
CurMousePos: TPoint;
|
||||||
|
begin
|
||||||
|
CurMousePos:=Point(0,0);
|
||||||
|
GetCursorPos(CurMousePos);
|
||||||
|
CurMousePos:=ScreenToClient(CurMousePos);
|
||||||
|
|
||||||
|
GetDragHotZoneInfo(CurMousePos.x, CurMousePos.y, hf, vf);
|
||||||
|
if ( (hf = 0) and (vf = 0) ) or (abs(hf) >= 384) or (abs(vf) >= 384) then begin
|
||||||
|
fScrollTimer.Enabled := False;
|
||||||
|
Exclude(fStateFlags, sfDraggingOver);
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if sfIsDragging in fStateFlags then
|
||||||
|
FBlockSelection.IncPersistentLock;
|
||||||
|
DoIncPaintLock(Self);
|
||||||
|
try
|
||||||
|
if hf <> 0 then
|
||||||
|
LeftChar := LeftChar + hf div 32;
|
||||||
|
if vf <> 0 then
|
||||||
|
TopView := TopView + vf div 32;
|
||||||
|
|
||||||
|
FCaret.ViewedLineCharPos := PixelsToRowColumn(CurMousePos);
|
||||||
|
|
||||||
|
finally
|
||||||
|
if sfEnsureCursorPos in fStateFlags then
|
||||||
|
Include(fStateFlags, sfPreventScrollAfterSelect);
|
||||||
|
|
||||||
|
DoDecPaintLock(Self);
|
||||||
|
if sfIsDragging in fStateFlags then
|
||||||
|
FBlockSelection.DecPersistentLock;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TCustomSynEdit.Paint;
|
procedure TCustomSynEdit.Paint;
|
||||||
var
|
var
|
||||||
rcClip: TRect;
|
rcClip: TRect;
|
||||||
@ -6332,16 +6407,31 @@ end;
|
|||||||
procedure TCustomSynEdit.DragOver(Source: TObject; X, Y: Integer;
|
procedure TCustomSynEdit.DragOver(Source: TObject; X, Y: Integer;
|
||||||
State: TDragState; var Accept: Boolean);
|
State: TDragState; var Accept: Boolean);
|
||||||
var
|
var
|
||||||
DropMove: boolean;
|
DropMove, InHotZone: boolean;
|
||||||
|
hf, vf: Integer;
|
||||||
begin
|
begin
|
||||||
inherited;
|
inherited;
|
||||||
LastMouseCaret:=Point(-1,-1);
|
LastMouseCaret:=Point(-1,-1);
|
||||||
|
Exclude(fStateFlags, sfDraggingOver);
|
||||||
|
|
||||||
if (eoAcceptDragDropEditing in FOptions2) and (Source is TCustomSynEdit) then begin
|
if (eoAcceptDragDropEditing in FOptions2) and (Source is TCustomSynEdit) then begin
|
||||||
Accept := (X >= FTextArea.Bounds.Left) and
|
Accept := (X >= FTextArea.Bounds.Left) and
|
||||||
(X < FTextArea.Bounds.Right) and
|
(X < FTextArea.Bounds.Right) and
|
||||||
(Y >= FTextArea.Bounds.Top) and
|
(Y >= FTextArea.Bounds.Top) and
|
||||||
(Y < FTextArea.Bounds.Bottom);
|
(Y < FTextArea.Bounds.Bottom);
|
||||||
|
|
||||||
|
InHotZone := GetDragHotZoneInfo(x, y, hf, vf);
|
||||||
|
if InHotZone then begin
|
||||||
|
if not (sfDraggingOver in fStateFlags) then begin
|
||||||
|
fScrollTimer.Interval := 500;
|
||||||
|
end;
|
||||||
|
fScrollTimer.Enabled := True;
|
||||||
|
Include(fStateFlags, sfDraggingOver);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if ( (hf <> 0) or (vf <> 0) ) and (abs(hf) < 384) and (abs(vf) < 384) then
|
||||||
|
Include(fStateFlags, sfDraggingOver); // keep scrolling
|
||||||
|
|
||||||
if Accept and (not ReadOnly) and TCustomSynEdit(Source).SelAvail then
|
if Accept and (not ReadOnly) and TCustomSynEdit(Source).SelAvail then
|
||||||
begin
|
begin
|
||||||
//if State = dsDragLeave then //restore prev caret position
|
//if State = dsDragLeave then //restore prev caret position
|
||||||
@ -6353,10 +6443,12 @@ begin
|
|||||||
|
|
||||||
if Accept then begin
|
if Accept then begin
|
||||||
FBlockSelection.IncPersistentLock;
|
FBlockSelection.IncPersistentLock;
|
||||||
|
Include(fStateFlags, sfPreventScrollAfterSelect); // not PaintLocked => setting caret will directly call EnsureCursorPos
|
||||||
try
|
try
|
||||||
FCaret.LineCharPos := FInternalCaret.LineCharPos;
|
FCaret.LineCharPos := FInternalCaret.LineCharPos;
|
||||||
finally
|
finally
|
||||||
FBlockSelection.DecPersistentLock;
|
FBlockSelection.DecPersistentLock;
|
||||||
|
exclude(fStateFlags, sfPreventScrollAfterSelect);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
if DropMove then
|
if DropMove then
|
||||||
@ -6366,6 +6458,9 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
if not (sfDraggingOver in fStateFlags) then
|
||||||
|
fScrollTimer.Enabled := False;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TCustomSynEdit.DragDrop(Source: TObject; X, Y: Integer);
|
procedure TCustomSynEdit.DragDrop(Source: TObject; X, Y: Integer);
|
||||||
|
Loading…
Reference in New Issue
Block a user