LCL: Improve TTreeView mouse selection. Issue #37145, patch from Joeny Ang.

git-svn-id: trunk@63232 -
This commit is contained in:
juha 2020-05-26 23:24:01 +00:00
parent 5be9338540
commit 257f842d30
2 changed files with 49 additions and 27 deletions

View File

@ -3287,7 +3287,8 @@ type
tvoShowSeparators,
tvoToolTips,
tvoNoDoubleClickExpand,
tvoThemedDraw
tvoThemedDraw,
tvoEmptySpaceUnselect
);
TTreeViewOptions = set of TTreeViewOption;
@ -3340,7 +3341,6 @@ type
FMaxLvl: integer; // maximum level of all nodes
FMaxRight: integer; // maximum text width of all nodes (needed for horizontal scrolling)
FMouseDownPos: TPoint;
FMouseDownNodeSelected: Boolean;
FMouseDownOnFoldingSign: Boolean;
FMultiSelectStyle: TMultiSelectStyle;
FHotTrackColor: TColor;
@ -3425,7 +3425,7 @@ type
function IsStoredBackgroundColor: Boolean;
procedure HintMouseLeave(Sender: TObject);
procedure ImageListChange(Sender: TObject);
function MouseDownNode(X, Y: Integer): TTreeNode;
function NodeIsSelected(aNode: TTreeNode): Boolean;
procedure OnChangeTimer(Sender: TObject);
procedure SetAutoExpand(Value: Boolean);
procedure SetBackgroundColor(Value: TColor);

View File

@ -2797,7 +2797,7 @@ begin
end;
//select again
bGoNext := (FirstNode.Index <= Node.Index);
bGoNext := (FirstNode.AbsoluteIndex <= Node.AbsoluteIndex);
I := FirstNode;
I.MultiSelected:=True;
while (I<>Node) do
@ -3861,6 +3861,7 @@ procedure TCustomTreeView.SetMultiSelect(const AValue: Boolean);
begin
if MultiSelect <> AValue then
begin
ClearSelection;
if AValue then
Include(FOptions,tvoAllowMultiselect)
else
@ -3974,15 +3975,19 @@ end;
function TCustomTreeView.GetNodeAt(X, Y: Integer): TTreeNode;
begin
if (X >= BorderWidth) and (X < ClientWidth - BorderWidth) then
Result := GetNodeAtY(Y)
else
Result := GetNodeAtY(Y);
if Result = nil then Exit;
if (not (tvoRowSelect in Options) and
((X < Result.DisplayStateIconLeft) or (X >= Result.DisplayTextRight)))
or
((tvoRowSelect in Options) and // row select
((X < BorderWidth) or (X >= ClientWidth - BorderWidth)))
then
Result := nil;
end;
procedure TCustomTreeView.GetInsertMarkAt(X, Y: Integer;
out AnInsertMarkNode: TTreeNode; out AnInsertMarkType: TTreeViewInsertMarkType
);
out AnInsertMarkNode: TTreeNode; out AnInsertMarkType: TTreeViewInsertMarkType);
var
ANode: TTreeNode;
NodeRect: TRect;
@ -5574,18 +5579,17 @@ begin
Result := FIndent >= 0;
end;
function TCustomTreeView.MouseDownNode(X, Y: Integer): TTreeNode;
function TCustomTreeView.NodeIsSelected(aNode: TTreeNode): Boolean;
begin
Result := GetNodeAt(X, Y);
// Update the NodeSelected flag.
FMouseDownNodeSelected := Assigned(Result) and
(Result.Selected or ((tvoAllowMultiselect in Options) and Result.MultiSelected));
Result := Assigned(aNode) and
(aNode.Selected or ((tvoAllowMultiselect in Options) and aNode.MultiSelected));
end;
procedure TCustomTreeView.MouseDown(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer);
var
CursorNode: TTreeNode;
CursorNdSelected: Boolean;
LogicalX: Integer;
begin
{$IFDEF VerboseDrag}
@ -5594,23 +5598,33 @@ begin
FMouseDownPos := Point(X,Y);
FStates:=FStates-[tvsEditOnMouseUp,tvsSingleSelectOnMouseUp];
CursorNode := MouseDownNode(X, Y);
CursorNode := GetNodeAt(X, Y);
CursorNdSelected := NodeIsSelected(CursorNode);
LogicalX:=X;
//change selection on right click
if (Button = mbRight) and RightClickSelect and//right click
(([ssDouble, ssTriple, ssQuad] * Shift) = []) and//single or first of a multi click
not AllowMultiSelectWithCtrl(Shift) and//only when CTRL is not pressed
(CursorNode <> nil) and
(LogicalX >= CursorNode.DisplayStateIconLeft)//only after expand sign
if (Button = mbRight) and RightClickSelect and //right click
(([ssDouble, ssTriple, ssQuad] * Shift) = []) and //single or first of a multi click
not AllowMultiSelectWithCtrl(Shift) and //only when CTRL is not pressed
(CursorNode <> nil)
then
begin
if not (tvoRowSelect in Options) and
(tvoEmptySpaceUnselect in Options) and
(LogicalX >= CursorNode.DisplayStateIconLeft) and
(LogicalX > CursorNode.DisplayTextRight) then
ClearSelection
else
if not (tvoAllowMultiselect in Options) then
Selected := CursorNode
else
if not FMouseDownNodeSelected then
if not CursorNdSelected then
Items.SelectOnlyThis(CursorNode);
end;
end
else // empty space below last node
if (Button = mbRight) and RightClickSelect and (CursorNode = nil) and
(tvoEmptySpaceUnselect in Options) then
ClearSelection;
if not Focused and CanFocus then
SetFocus;
@ -5618,7 +5632,8 @@ begin
inherited MouseDown(Button, Shift, X, Y);
//CursorNode must be reassigned again - e.g. in OnMouseDown the node can be deleted or moved.
CursorNode := MouseDownNode(X, Y);
CursorNode := GetNodeAt(LogicalX, Y);
CursorNdSelected := NodeIsSelected(CursorNode);
//Flag is used for DblClick/TripleClick/QuadClick, so set it before testing ShiftState
FMouseDownOnFoldingSign :=
@ -5634,7 +5649,8 @@ begin
if FMouseDownOnFoldingSign then
// mousedown occured on expand sign -> expand/collapse
CursorNode.Expanded := not CursorNode.Expanded
else if LogicalX >= CursorNode.DisplayStateIconLeft then
else if (LogicalX >= CursorNode.DisplayStateIconLeft) or
(tvoRowSelect in Options) then
begin
// mousedown occured in text or icon -> select node and begin drag operation
{$IFDEF VerboseDrag}
@ -5665,18 +5681,24 @@ begin
end
else
begin
if not FMouseDownNodeSelected then
if not CursorNdSelected then
Items.SelectOnlyThis(CursorNode)
else
Include(FStates, tvsSingleSelectOnMouseUp);
end;
end;
end;
end
else if tvoEmptySpaceUnselect in Options then
ClearSelection;
end
else// multi click
if not (tvoNoDoubleClickExpand in Options) and (ssDouble in Shift)
and (Button = mbLeft) and (CursorNode<>nil) then
CursorNode.Expanded := not CursorNode.Expanded;
CursorNode.Expanded := not CursorNode.Expanded
else // empty space below last node
if (Button = mbLeft) and (CursorNode = nil) and (tvoEmptySpaceUnselect in Options) and
not AllowMultiSelectWithShift(Shift) and not AllowMultiSelectWithCtrl(Shift) then
ClearSelection;
end;
procedure TCustomTreeView.MouseMove(Shift: TShiftState; X, Y: Integer);