Skip to content

Commit

Permalink
Enhancement #708: Improve multi-selection for touch UI by adding opti…
Browse files Browse the repository at this point in the history
…on that synchonizes selection and check-state
  • Loading branch information
sanjayssk committed May 12, 2017
1 parent 185fb6e commit 65db4a3
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 3 deletions.
2 changes: 2 additions & 0 deletions CHANGES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ V6.7: (under development)
* Fixed issue #706: Integer overflow in DetermineScrollDirections when timeGetTime wraps
* Fixed issue #407: TVirtualDrawTree.InvalidateNode does not clear vsHeightMeasured
* Enhancement #669: Create sample project for C++ Builder
* Enhancement #708: Improve multi-selection for touch UI by adding option
that synchonizes selection and check-state

V6.6 (04 Apr 2017)
* Fixed issue #705: Added support for RAD Studio 10.2 Tokyo
Expand Down
49 changes: 46 additions & 3 deletions Source/VirtualTrees.pas
Original file line number Diff line number Diff line change
Expand Up @@ -505,8 +505,11 @@ TCheckStateHelper = record helper for TCheckState
// selection rectangle.
toAlwaysSelectNode, // If this flag is set to true, the tree view tries to always have a node selected.
// This behavior is closer to the Windows TreeView and useful in Windows Explorer style applications.
toRestoreSelection // Set to true if upon refill the previously selected nodes should be selected again.
toRestoreSelection, // Set to true if upon refill the previously selected nodes should be selected again.
// The nodes will be identified by its caption only.
toSyncCheckboxesWithSelection // If checkboxes are shown, they follow the change in selections. When checkboxes are
// changed, the selections follow them and vice-versa.
// **Only supported for ctCheckBox type checkboxes.
);
TVTSelectionOptions = set of TVTSelectionOption;

Expand Down Expand Up @@ -2333,6 +2336,7 @@ TBaseVirtualTree = class(TCustomControl)
function GetChildrenInitialized(Node: PVirtualNode): Boolean;
function GetCutCopyCount: Integer;
function GetDisabled(Node: PVirtualNode): Boolean;
function GetSyncCheckstateWithSelection(Node: PVirtualNode): Boolean;
function GetDragManager: IVTDragManager;
function GetExpanded(Node: PVirtualNode): Boolean;
function GetFiltered(Node: PVirtualNode): Boolean;
Expand Down Expand Up @@ -2811,6 +2815,7 @@ TBaseVirtualTree = class(TCustomControl)
property TextMargin: Integer read FTextMargin write SetTextMargin default 4;
property TreeOptions: TCustomVirtualTreeOptions read FOptions write SetOptions;
property WantTabs: Boolean read FWantTabs write FWantTabs default False;
property SyncCheckstateWithSelection[Node: PVirtualNode]: Boolean read GetSyncCheckstateWithSelection;

property OnAddToSelection: TVTAddToSelectionEvent read FOnAddToSelection write FOnAddToSelection;
property OnAdvancedHeaderDraw: TVTAdvancedHeaderPaintEvent read FOnAdvancedHeaderDraw write FOnAdvancedHeaderDraw;
Expand Down Expand Up @@ -13398,6 +13403,17 @@ function TBaseVirtualTree.GetDisabled(Node: PVirtualNode): Boolean;
Result := Assigned(Node) and (vsDisabled in Node.States);
end;

//----------------------------------------------------------------------------------------------------------------------
// whether the sync of checkbox with selection is allowed for this node
function TBaseVirtualTree.GetSyncCheckstateWithSelection(Node: PVirtualNode): Boolean;

begin
Result := (toSyncCheckboxesWithSelection in FOptions.FSelectionOptions)
and (toCheckSupport in FOptions.FMiscOptions)
and Assigned(FCheckImages)
and (Node.CheckType = ctCheckBox); ;
end;

//----------------------------------------------------------------------------------------------------------------------

function TBaseVirtualTree.GetDragManager: IVTDragManager;
Expand Down Expand Up @@ -19713,7 +19729,17 @@ procedure TBaseVirtualTree.DoCheckClick(Node: PVirtualNode; NewCheckState: TChec

begin
if ChangeCheckState(Node, NewCheckState) then
begin
DoChecked(Node);
if SyncCheckstateWithSelection[Node] then
begin
// selection should follow check state
if (NewCheckState = csCheckedNormal) then
Selected[node] := true
else
Selected[node] := false;
end;
end;
end;

//----------------------------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -23310,10 +23336,13 @@ function TBaseVirtualTree.InternalAddToSelection(const NewItems: TNodeArray; New
FLastSelectionLevel := GetNodeLevelForSelectConstraint(NewItems[0]);
for I := 0 to NewLength - 1 do
begin
//sync path note: when already selected node is clicked or selected again
Include(NewItems[I].States, vsSelected);
Inc(FSelectionCount);
if Assigned(FOnAddToSelection) then
FOnAddToSelection(Self, NewItems[I]);
if SyncCheckstateWithSelection[NewItems[I]] then
checkstate[NewItems[I]] := csCheckedNormal;
end;
end
else
Expand All @@ -23332,10 +23361,13 @@ function TBaseVirtualTree.InternalAddToSelection(const NewItems: TNodeArray; New
Inc(PAnsiChar(NewItems[I]))
else
begin
//sync path note: on click, multi-select ctrl-click and draw selection
Include(NewItems[I].States, vsSelected);
Inc(FSelectionCount);
if Assigned(FOnAddToSelection) then
Inc(FSelectionCount);
if Assigned(FOnAddToSelection) then
FOnAddToSelection(Self, NewItems[I]);
if SyncCheckstateWithSelection[NewItems[I]] then
checkstate[NewItems[I]] := csCheckedNormal;
end;
end;

Expand Down Expand Up @@ -23442,7 +23474,10 @@ procedure TBaseVirtualTree.InternalClearSelection;
while FSelectionCount > 0 do
begin
Dec(FSelectionCount);
//sync path note: deselect when click on another or on outside area
Exclude(FSelection[FSelectionCount].States, vsSelected);
if SyncCheckstateWithSelection[FSelection[FSelectionCount]] then
checkstate[FSelection[FSelectionCount]] := csUncheckedNormal;
DoRemoveFromSelection(FSelection[FSelectionCount]);
end;
ResetRangeAnchor;
Expand Down Expand Up @@ -23696,7 +23731,10 @@ procedure TBaseVirtualTree.InternalRemoveFromSelection(Node: PVirtualNode);
// order in the list preserved.
if FindNodeInSelection(Node, Index, -1, -1) then
begin
//sync path note: deselect when overlapping drawselection is made
Exclude(Node.States, vsSelected);
if SyncCheckstateWithSelection[Node] then
checkstate[Node] := csUncheckedNormal;
Inc(PAnsiChar(FSelection[Index]));
DoRemoveFromSelection(Node);
AdviseChangeEvent(False, Node, crIgnore);
Expand Down Expand Up @@ -24733,6 +24771,7 @@ function TBaseVirtualTree.ReadChunk(Stream: TStream; Version: Integer; Node: PVi
// vsVisible is now in the place where vsSelected was before, but every node was visible in the old version
// so we need to fix this too.
if vsVisible in States then
//sync path note: prior version stream reading, ignored for syncing
Include(States, vsSelected)
else
Include(States, vsVisible);
Expand Down Expand Up @@ -24857,7 +24896,11 @@ procedure TBaseVirtualTree.RemoveFromSelection(Node: PVirtualNode);
if vsSelected in Node.States then
begin
Assert(FSelectionCount > 0, 'if one node has set the vsSelected flag, SelectionCount must be >0.');
//sync path note: deselect when a ctrl click removes a selection
Exclude(Node.States, vsSelected);
if SyncCheckstateWithSelection[Node] then
checkstate[Node] := csUncheckedNormal;

if FindNodeInSelection(Node, Index, -1, -1) and (Index < FSelectionCount - 1) then
Move(FSelection[Index + 1], FSelection[Index], (FSelectionCount - Index - 1) * SizeOf(Pointer));
if FSelectionCount > 0 then
Expand Down

0 comments on commit 65db4a3

Please sign in to comment.