IdeDebugger: Rewrite DebugTreeView, embed control into data row, optimize updating (lock and defer) - Change array-navigation-bar to display with data row

This commit is contained in:
Martin 2024-08-17 14:06:58 +02:00
parent 927d0f8980
commit 6da483640e
8 changed files with 952 additions and 329 deletions

View File

@ -2,34 +2,47 @@ object ArrayNavigationBar: TArrayNavigationBar
Left = 0
Height = 24
Top = 0
Width = 457
AutoSize = True
Width = 436
ClientHeight = 24
ClientWidth = 457
ClientWidth = 436
TabOrder = 0
DesignLeft = 518
DesignTop = 777
object btnArrayStart: TSpeedButton
AnchorSideLeft.Control = Owner
AnchorSideTop.Control = Owner
AnchorSideBottom.Control = Owner
AnchorSideBottom.Side = asrBottom
Left = 0
Height = 24
Top = 0
Width = 23
Align = alLeft
Anchors = [akTop, akLeft, akBottom]
Caption = '|<'
Flat = True
OnClick = BtnChangePageClicked
end
object btnArrayFastDown: TSpeedButton
AnchorSideLeft.Control = btnArrayStart
AnchorSideLeft.Side = asrBottom
AnchorSideTop.Control = Owner
AnchorSideBottom.Control = Owner
AnchorSideBottom.Side = asrBottom
Left = 23
Height = 24
Top = 0
Width = 23
Align = alLeft
Anchors = [akTop, akLeft, akBottom]
Caption = '<<'
Flat = True
OnClick = BtnChangePageClicked
end
object edArrayStart: TLazIntegerEdit
AnchorSideLeft.Control = btnArrayFastDown
AnchorSideLeft.Side = asrBottom
AnchorSideTop.Control = Owner
AnchorSideBottom.Control = Owner
AnchorSideBottom.Side = asrBottom
Left = 46
Height = 24
Top = 0
@ -37,52 +50,85 @@ object ArrayNavigationBar: TArrayNavigationBar
Value = 0
MinValue = -9223372036854775808
MaxValue = 9223372036854775807
Align = alLeft
SetDecimalKeys = '#'
HexIndicator = '$'
ToggleHexKeys = '$x'
OctIndicator = '&'
ToggleOctKeys = '&'
BinIndicator = '%'
ToggleBinKeys = '%'
Alignment = taRightJustify
Anchors = [akTop, akLeft, akBottom]
AutoSize = False
TabOrder = 1
Text = '0'
OnEditingDone = edArrayStartEditingDone
OnKeyDown = edArrayStartKeyDown
end
object btnArrayFastUp: TSpeedButton
AnchorSideLeft.Control = edArrayStart
AnchorSideLeft.Side = asrBottom
AnchorSideTop.Control = Owner
AnchorSideBottom.Control = Owner
AnchorSideBottom.Side = asrBottom
Left = 106
Height = 24
Top = 0
Width = 23
Align = alLeft
Anchors = [akTop, akLeft, akBottom]
Caption = '>>'
Flat = True
OnClick = BtnChangePageClicked
end
object btnArrayEnd: TSpeedButton
AnchorSideLeft.Control = btnArrayFastUp
AnchorSideLeft.Side = asrBottom
AnchorSideTop.Control = Owner
AnchorSideBottom.Control = Owner
AnchorSideBottom.Side = asrBottom
Left = 129
Height = 24
Top = 0
Width = 23
Align = alLeft
Anchors = [akTop, akLeft, akBottom]
Caption = '>|'
Flat = True
OnClick = BtnChangePageClicked
end
object Label1: TLabel
AnchorSideLeft.Control = btnArrayEnd
AnchorSideLeft.Side = asrBottom
AnchorSideTop.Control = Owner
AnchorSideBottom.Control = Owner
AnchorSideBottom.Side = asrBottom
Left = 152
Height = 24
Top = 0
Width = 4
Align = alLeft
Anchors = [akTop, akLeft, akBottom]
AutoSize = False
end
object btnArrayPageDec: TSpeedButton
AnchorSideLeft.Control = Label1
AnchorSideLeft.Side = asrBottom
AnchorSideTop.Control = Owner
AnchorSideBottom.Control = Owner
AnchorSideBottom.Side = asrBottom
Left = 156
Height = 24
Top = 0
Width = 23
Align = alLeft
Anchors = [akTop, akLeft, akBottom]
Caption = '-'
Flat = True
OnClick = BtnChangeSizeClicked
end
object edArrayPageSize: TLazIntegerEdit
AnchorSideLeft.Control = btnArrayPageDec
AnchorSideLeft.Side = asrBottom
AnchorSideTop.Control = Owner
AnchorSideBottom.Control = Owner
AnchorSideBottom.Side = asrBottom
Left = 179
Height = 24
Top = 0
@ -90,38 +136,63 @@ object ArrayNavigationBar: TArrayNavigationBar
Value = 10
MinValue = 1
MaxValue = 5000
Align = alLeft
SetDecimalKeys = '#'
HexIndicator = '$'
ToggleHexKeys = '$x'
OctIndicator = '&'
ToggleOctKeys = '&'
BinIndicator = '%'
ToggleBinKeys = '%'
AllowMinus = False
Alignment = taRightJustify
Anchors = [akTop, akLeft, akBottom]
AutoSize = False
TabOrder = 0
Text = '10'
OnEditingDone = edArrayPageSizeEditingDone
OnKeyDown = edArrayPageSizeKeyDown
end
object btnArrayPageInc: TSpeedButton
AnchorSideLeft.Control = edArrayPageSize
AnchorSideLeft.Side = asrBottom
AnchorSideTop.Control = Owner
AnchorSideBottom.Control = Owner
AnchorSideBottom.Side = asrBottom
Left = 219
Height = 24
Top = 0
Width = 23
Align = alLeft
Anchors = [akTop, akLeft, akBottom]
Caption = '+'
Flat = True
OnClick = BtnChangeSizeClicked
end
object lblBounds: TLabel
AnchorSideLeft.Control = btnArrayPageInc
AnchorSideLeft.Side = asrBottom
AnchorSideTop.Control = Owner
AnchorSideBottom.Control = Owner
AnchorSideBottom.Side = asrBottom
Left = 252
Height = 24
Top = 0
Width = 1
Align = alLeft
Anchors = [akTop, akLeft, akBottom]
BorderSpacing.Left = 10
Layout = tlCenter
Visible = False
end
object cbEnforceBound: TCheckBox
AnchorSideLeft.Control = lblBounds
AnchorSideLeft.Side = asrBottom
AnchorSideTop.Control = Owner
AnchorSideBottom.Control = Owner
AnchorSideBottom.Side = asrBottom
Left = 263
Height = 24
Top = 0
Width = 106
Align = alLeft
Anchors = [akTop, akLeft, akBottom]
BorderSpacing.Left = 10
Caption = 'cbEnforceBound'
Checked = True

View File

@ -5,8 +5,8 @@ unit ArrayNavigationFrame;
interface
uses
Classes, SysUtils, Math, Forms, Controls, Buttons, StdCtrls, LCLType, SpinEx, LazNumEdit,
IDEImagesIntf, IdeDebuggerStringConstants;
Classes, SysUtils, Math, Forms, Controls, Buttons, StdCtrls, LCLType, ExtCtrls, SpinEx,
LazNumEdit, IDEImagesIntf, laz.VirtualTrees, IdeDebuggerStringConstants, DebuggerTreeView;
type
@ -44,6 +44,8 @@ type
FOnSizeChanged: TNotifyEvent;
FOwnerData: pointer;
FShowBoundInfo: Boolean;
FTree: TDbgTreeView;
FNode: PVirtualNode;
function GetIndex: int64;
function GetIndexOffs: int64;
function GetLimitedPageSize: int64;
@ -56,9 +58,17 @@ type
procedure SetShowBoundInfo(AValue: Boolean);
procedure UpdateBoundsInfo;
procedure DoOnSizeChanged;
function EnforceBounds: boolean;
procedure DoParentResized(Sender: TObject);
protected
procedure BoundsChanged; override;
procedure VisibleChanged; override;
procedure CreateWnd; override;
procedure SetParent(AParent: TWinControl); override;
public
constructor Create(TheOwner: TComponent); override;
procedure Loaded; override;
constructor Create(TheOwner: TComponent; ATree: TDbgTreeView; ANode: PVirtualNode); reintroduce;
destructor Destroy; override;
function PreferredHeight: integer;
property LowBound: int64 read FLowBound write SetLowBound;
property HighBound: int64 read FHighBound write SetHighBound;
property ShowBoundInfo: Boolean read FShowBoundInfo write SetShowBoundInfo;
@ -98,7 +108,7 @@ begin
edArrayStart.Value := FLowBound
else
if Sender = btnArrayFastDown then begin
if (v < FLowBound) or (v > FHighBound) then
if not EnforceBounds then
edArrayStart.Value := edArrayStart.Value - edArrayPageSize.Value
else
edArrayStart.Value := max(edArrayStart.Value - edArrayPageSize.Value,
@ -106,7 +116,7 @@ begin
end
else
if Sender = btnArrayFastUp then begin
if (v < FLowBound) or (v > FHighBound) then
if not EnforceBounds then
edArrayStart.Value := edArrayStart.Value + edArrayPageSize.Value
else
edArrayStart.Value := min(edArrayStart.Value + edArrayPageSize.Value,
@ -167,9 +177,9 @@ begin
end;
VK_DOWN: begin
if ssCtrl in Shift then
edArrayPageSize.Value := Max(10, v - 5)
edArrayPageSize.Value := Max(1, v - 5)
else
edArrayPageSize.Value := Max(10, v - 1);
edArrayPageSize.Value := Max(1, v - 1);
end;
VK_PRIOR: begin
if ssCtrl in Shift then
@ -181,7 +191,10 @@ begin
if ssCtrl in Shift then
edArrayPageSize.Value := 10
else
edArrayPageSize.Value := Max(10, v - 10);
if v > 10 then
edArrayPageSize.Value := Max(10, v - 10)
else
edArrayPageSize.Value := 1;
end;
end;
end;
@ -219,7 +232,7 @@ begin
if (not FHardLimits) and (ssAlt in Shift) then
cbEnforceBound.Checked := False;
OutOfBnd := (not FHardLimits) and (not cbEnforceBound.Checked);
OutOfBnd := not EnforceBounds;
v := edArrayStart.CurrentValue;
PgSz := edArrayPageSize.CurrentValue;
@ -272,7 +285,7 @@ var
begin
Result := edArrayPageSize.Value;
idx := edArrayStart.Value;
if (idx >= FLowBound) and (idx <= FHighBound) then
if EnforceBounds then
Result := Max(1, Min(Result, FHighBound + 1 - idx));
end;
@ -307,10 +320,13 @@ begin
edArrayPageSize.Value := AValue;
end;
procedure TArrayNavigationBar.Loaded;
function TArrayNavigationBar.PreferredHeight: integer;
var
w, h: Integer;
begin
inherited Loaded;
Constraints.MinWidth := btnArrayPageInc.Left + btnArrayPageInc.Width;
cbEnforceBound.GetPreferredSize(w, Result);
edArrayStart.GetPreferredSize(w, h);
Result := max(Result, h);
end;
procedure TArrayNavigationBar.SetShowBoundInfo(AValue: Boolean);
@ -324,7 +340,7 @@ end;
procedure TArrayNavigationBar.UpdateBoundsInfo;
begin
if FHardLimits or cbEnforceBound.Checked then begin
if EnforceBounds then begin
edArrayPageSize.Visible := FHighBound + 1 - FLowBound > edArrayPageSize.MinValue;
btnArrayPageInc.Visible := FHighBound + 1 - FLowBound > edArrayPageSize.MinValue;
btnArrayPageDec.Visible := FHighBound + 1 - FLowBound > edArrayPageSize.MinValue;
@ -350,8 +366,89 @@ begin
FOnSizeChanged(Self);
end;
constructor TArrayNavigationBar.Create(TheOwner: TComponent);
function TArrayNavigationBar.EnforceBounds: boolean;
begin
Result := FHardLimits or cbEnforceBound.Checked;
end;
procedure TArrayNavigationBar.DoParentResized(Sender: TObject);
begin
if (edArrayStart = nil) or (Parent = nil) or (not HandleAllocated) or (not IsVisible) then
exit;
if (edArrayStart.Left+edArrayStart.Width + Left < 1) or
(edArrayStart.Left+ Left > Parent.ClientWidth - 1) or
(edArrayStart.Top+Top > Parent.ClientHeight + FTree.Header.Height - 1) or
(not Visible)
then
edArrayStart.BorderSpacing.Top := 1
else
edArrayStart.BorderSpacing.Top := 0;
if (edArrayPageSize.Left+edArrayPageSize.Width + Left < 1) or
(edArrayPageSize.Left+ Left > Parent.ClientWidth - 1) or
(edArrayPageSize.Top+Top > Parent.ClientHeight + FTree.Header.Height - 1) or
(not Visible)
then
edArrayPageSize.BorderSpacing.Top := 1
else
edArrayPageSize.BorderSpacing.Top := 0;
if (cbEnforceBound.Left+cbEnforceBound.Width + Left < 1) or
(cbEnforceBound.Left+ Left > Parent.ClientWidth - 1) or
(cbEnforceBound.Top+Top > Parent.ClientHeight + FTree.Header.Height - 1) or
(not Visible)
then
cbEnforceBound.BorderSpacing.Top := 1
else
cbEnforceBound.BorderSpacing.Top := 0;
end;
procedure TArrayNavigationBar.BoundsChanged;
begin
inherited BoundsChanged;
if HandleAllocated and IsVisible then begin
DoParentResized(nil);
end;
//if btnToggle <> nil then
// btnToggle.Width := btnToggle.Height;
end;
procedure TArrayNavigationBar.VisibleChanged;
begin
inherited VisibleChanged;
if HandleAllocated and IsVisible then begin
FTree.NodeControlHeight[FNode] := Max(15, PreferredHeight);
DoParentResized(nil);
end;
end;
procedure TArrayNavigationBar.CreateWnd;
begin
inherited CreateWnd;
FTree.NodeControlHeight[FNode] := Max(15, PreferredHeight);
DoParentResized(nil);
end;
procedure TArrayNavigationBar.SetParent(AParent: TWinControl);
begin
if (AParent = nil) and (Parent <> nil) then
Parent.RemoveHandlerOnResize(@DoParentResized);
inherited SetParent(AParent);
if Parent <> nil then begin
Parent.AddHandlerOnResize(@DoParentResized);
if HandleAllocated and IsVisible then
DoParentResized(nil);
end;
end;
constructor TArrayNavigationBar.Create(TheOwner: TComponent; ATree: TDbgTreeView;
ANode: PVirtualNode);
begin
FTree := ATree;
FNode := ANode;
inherited Create(TheOwner);
Name := '';
Constraints.MinWidth := btnArrayPageInc.Left + btnArrayPageInc.Width;
@ -388,5 +485,12 @@ begin
cbEnforceBound.Caption := arrnavEnforceBounds;
end;
destructor TArrayNavigationBar.Destroy;
begin
if (Parent <> nil) then
Parent.RemoveHandlerOnResize(@DoParentResized);
inherited Destroy;
end;
end.

View File

@ -49,30 +49,28 @@ object BreakpointGroupFrame: TBreakpointGroupFrame
Caption = 'ToolButtonDivider1'
Style = tbsDivider
end
object StaticText1: TStaticText
object StaticText1: TLabel
Left = 60
Height = 16
Height = 15
Top = 2
Width = 57
AutoSize = True
Width = 56
BorderSpacing.Left = 5
BorderSpacing.Right = 5
Caption = 'StaticText1'
TabOrder = 0
Layout = tlCenter
OnDragDrop = FrameDragDrop
OnDragOver = FrameDragOver
OnMouseDown = StaticText1MouseDown
end
object StaticText2: TStaticText
Left = 117
Height = 16
object StaticText2: TLabel
Left = 116
Height = 15
Top = 2
Width = 57
AutoSize = True
Width = 56
BorderSpacing.Left = 5
BorderSpacing.Right = 5
Caption = 'StaticText2'
TabOrder = 1
Layout = tlCenter
OnDragDrop = FrameDragDrop
OnDragOver = FrameDragOver
OnMouseDown = StaticText1MouseDown
@ -80,7 +78,6 @@ object BreakpointGroupFrame: TBreakpointGroupFrame
end
object Panel1: TPanel
AnchorSideTop.Control = ToolBar1
AnchorSideRight.Control = ToolBar1
AnchorSideRight.Side = asrBottom
AnchorSideBottom.Control = ToolBar1
AnchorSideBottom.Side = asrBottom
@ -88,10 +85,9 @@ object BreakpointGroupFrame: TBreakpointGroupFrame
Height = 22
Top = 1
Width = 23
Anchors = [akTop, akRight, akBottom]
Anchors = [akTop, akLeft, akBottom]
AutoSize = True
BorderSpacing.Top = 1
BorderSpacing.Right = 2
BorderSpacing.Bottom = 2
BevelOuter = bvNone
ClientHeight = 22
@ -101,13 +97,12 @@ object BreakpointGroupFrame: TBreakpointGroupFrame
TabOrder = 1
object BtnDelete: TSpeedButton
AnchorSideTop.Control = Panel1
AnchorSideBottom.Control = Panel1
AnchorSideTop.Side = asrCenter
AnchorSideBottom.Side = asrBottom
Left = 0
Height = 22
Top = 0
Width = 23
Anchors = [akTop, akLeft, akBottom]
OnClick = BtnDeleteClick
end
end

View File

@ -29,8 +29,8 @@ type
TBreakpointGroupFrame = class(TFrame)
BtnDelete: TSpeedButton;
Panel1: TPanel;
StaticText1: TStaticText;
StaticText2: TStaticText;
StaticText1: TLabel;
StaticText2: TLabel;
ToolBar1: TToolBar;
ToolButtonEnableAll: TToolButton;
ToolButtonDisableAll: TToolButton;
@ -53,14 +53,15 @@ type
FNode: PVirtualNode;
FBrkGroup: TIDEBreakPointGroup;
procedure DoBrkGroupFreed(Sender: TObject);
procedure DoParentResized(Sender: TObject);
function GetCount: Integer;
function GetName: String;
function GetVisible: boolean;
procedure SetNodeVisible(AValue: boolean);
protected
procedure SetVisible(Value: Boolean); reintroduce;
procedure VisibleChanged; override;
procedure BoundsChanged; override;
procedure CreateWnd; override;
procedure SetParent(AParent: TWinControl); override;
public
constructor Create(TheOwner: TBreakPointsDlgBase; ATree: TDbgTreeView; ANode: PVirtualNode;
ABrkGroup: TIDEBreakPointGroup;
@ -70,7 +71,7 @@ type
procedure UpdateButtons;
function Compare(AnOther: TBreakpointGroupFrame): integer;
property Visible: boolean read GetVisible write SetVisible;
property NodeVisible: boolean write SetNodeVisible;
property GroupKind: TBreakpointGroupFrameKind read FGroupKind;
property BrkGroup: TIDEBreakPointGroup read FBrkGroup;
property Tree: TDbgTreeView read FTree;
@ -186,8 +187,8 @@ begin
if (Source = FTree) and (FTree.SelectedCount > 0) then begin
for VNode in FTree.SelectedNodes(True) do begin
if Brk = nil then Continue; // Header row selected
Brk := TIDEBreakPoint(FTree.NodeItem[VNode]);
if Brk = nil then Continue; // Header row selected
Brk.Group := NewGroup;
end;
end;
@ -252,46 +253,57 @@ begin
UpdateButtons;
end;
procedure TBreakpointGroupFrame.DoParentResized(Sender: TObject);
begin
if (Panel1 <> nil) and HandleAllocated and IsVisible and (Parent <> nil) then
Panel1.Left := Min(Parent.ClientWidth - Left, ClientWidth) - Panel1.Width - 1;
end;
function TBreakpointGroupFrame.GetName: String;
begin
Result := StaticText1.Caption;
end;
function TBreakpointGroupFrame.GetVisible: boolean;
procedure TBreakpointGroupFrame.SetNodeVisible(AValue: boolean);
begin
Result := inherited Visible;
end;
procedure TBreakpointGroupFrame.SetVisible(Value: Boolean);
begin
if (Value = Visible) or
(Value and (FGroupKind = bgfAbandoned))
then
exit;
if not Value then
inherited SetVisible(Value);
FTree.IsVisible[FNode] := Value;
FTree.IsVisible[FNode] := AValue;
end;
procedure TBreakpointGroupFrame.VisibleChanged;
begin
inherited VisibleChanged;
if HandleAllocated and IsVisible then
FTree.NodeHeight[FNode] := Max(15, ToolBar1.Height);
if HandleAllocated and IsVisible then begin
FTree.NodeControlHeight[FNode] := Max(15, ToolBar1.Height);
DoParentResized(nil);
end;
end;
procedure TBreakpointGroupFrame.BoundsChanged;
begin
inherited BoundsChanged;
if HandleAllocated and IsVisible then
FTree.NodeHeight[FNode] := Max(15, ToolBar1.Height);
if HandleAllocated and IsVisible then begin
FTree.NodeControlHeight[FNode] := Max(15, ToolBar1.Height);
DoParentResized(nil);
end;
end;
procedure TBreakpointGroupFrame.CreateWnd;
begin
inherited CreateWnd;
FTree.NodeHeight[FNode] := Max(15, ToolBar1.Height);
FTree.NodeControlHeight[FNode] := Max(15, ToolBar1.Height);
DoParentResized(nil);
end;
procedure TBreakpointGroupFrame.SetParent(AParent: TWinControl);
begin
if (AParent = nil) and (Parent <> nil) then
Parent.RemoveHandlerOnResize(@DoParentResized);
inherited SetParent(AParent);
if Parent <> nil then begin
Parent.AddHandlerOnResize(@DoParentResized);
if HandleAllocated and IsVisible then
DoParentResized(nil);
end;
end;
constructor TBreakpointGroupFrame.Create(TheOwner: TBreakPointsDlgBase;
@ -330,6 +342,8 @@ end;
destructor TBreakpointGroupFrame.Destroy;
begin
if (Parent <> nil) then
Parent.RemoveHandlerOnResize(@DoParentResized);
if FBrkGroup <> nil then
FBrkGroup.RemoveFreeNotification(@DoBrkGroupFreed);
inherited Destroy;

View File

@ -45,39 +45,39 @@ object BreakpointsDlg: TBreakpointsDlg
Action = actDeleteSelected
end
object ToolSep1: TToolButton
Left = 131
Left = 134
Height = 22
Top = 2
Style = tbsDivider
end
object ToolButtonEnableAll: TToolButton
Left = 146
Left = 139
Top = 2
Action = actEnableAll
end
object ToolButtonDisableAll: TToolButton
Left = 169
Left = 162
Top = 2
Action = actDisableAll
end
object ToolButtonTrashAll: TToolButton
Left = 108
Left = 111
Top = 2
Action = actDeleteAll
end
object ToolSep2: TToolButton
Left = 192
Left = 185
Height = 22
Top = 2
Style = tbsDivider
end
object ToolButtonProperties: TToolButton
Left = 197
Left = 190
Top = 2
Action = actProperties
end
object tbGroupByBrkGroup: TToolButton
Left = 220
Left = 213
Top = 2
Caption = 'Grp'
Style = tbsCheck
@ -136,7 +136,7 @@ object BreakpointsDlg: TBreakpointsDlg
Text = 'Group'
Width = 80
end>
Header.Options = [hoColumnResize, hoDrag, hoShowSortGlyphs, hoVisible]
Header.Options = [hoColumnResize, hoShowSortGlyphs, hoVisible]
PopupMenu = mnuPopup
TabOrder = 1
TreeOptions.AutoOptions = [toAutoScroll, toAutoScrollOnExpand, toAutoSort, toAutoTristateTracking, toAutoDeleteMovedNodes, toAutoChangeScale]

View File

@ -435,12 +435,12 @@ begin
PVNode := tvBreakPoints.AddChild(nil, nil);
FUngroupedHeader := TBreakpointGroupFrame.Create(Self, tvBreakPoints, PVNode, nil);
FUngroupedHeader.Visible := tbGroupByBrkGroup.Down;
FUngroupedHeader.NodeVisible:= tbGroupByBrkGroup.Down;
tvBreakPoints.NodeControl[PVNode] := FUngroupedHeader;
PVNode := tvBreakPoints.AddChild(nil, nil);
FAddGroupedHeader := TBreakpointGroupFrame.Create(Self, tvBreakPoints, PVNode, nil, bgfAddNewGroup);
FAddGroupedHeader.Visible := False;
FAddGroupedHeader.NodeVisible := False;
tvBreakPoints.NodeControl[PVNode] := FAddGroupedHeader;
finally
EndUpdate;
@ -473,7 +473,7 @@ begin
try
Result := tvBreakPoints.AddChild(nil, nil);
GrpHeader := TBreakpointGroupFrame.Create(Self, tvBreakPoints, Result, ABrkGroup);
GrpHeader.Visible := tbGroupByBrkGroup.Down;
GrpHeader.NodeVisible := tbGroupByBrkGroup.Down;
GrpHeader.OnDeleteGroup := @DoGroupDeleteBtnClicked;
tvBreakPoints.NodeControl[Result] := GrpHeader;
finally
@ -1189,7 +1189,7 @@ begin
AcceptGroupHeaderDrop(TBreakpointGroupFrame(TToolBar(Source).Owner), TargetNd);
end;
FAddGroupedHeader.Visible := False;
FAddGroupedHeader.NodeVisible:= False;
FDragSource := False;
finally
EndUpdate;
@ -1206,7 +1206,7 @@ var
begin
Accept := False;
if FDragSource and tbGroupByBrkGroup.Down then
FAddGroupedHeader.Visible := True;
FAddGroupedHeader.NodeVisible := True;
TargetNd := tvBreakPoints.GetNodeAt(Pt);
if (TargetNd <> nil) and (Source = tvBreakPoints) and (tvBreakPoints.SelectedCount > 0) then begin
@ -1251,7 +1251,7 @@ end;
procedure TBreakPointsDlg.tvBreakPointsEndDrag(Sender, Target: TObject; X,
Y: Integer);
begin
FAddGroupedHeader.Visible := False;
FAddGroupedHeader.NodeVisible := False;
FDragSource := False;
end;
@ -1551,7 +1551,7 @@ begin
LastAbandoned := nil;
end;
if GrpHeader.GroupKind in [bgfGroup, bgfUngrouped] then
GrpHeader.Visible := tbGroupByBrkGroup.Down;
GrpHeader.NodeVisible := tbGroupByBrkGroup.Down;
if GrpHeader.GroupKind = bgfAbandoned then
LastAbandoned := VNode;
end

View File

@ -28,6 +28,7 @@ type
FTreeView: TDbgTreeView;
FExpandingWatchAbleResult: TObject;
procedure TreeViewCollapsed(Sender: TBaseVirtualTree; Node: PVirtualNode);
procedure TreeViewExpanded(Sender: TBaseVirtualTree; Node: PVirtualNode);
procedure TreeViewInitChildren(Sender: TBaseVirtualTree;
Node: PVirtualNode; var ChildCount: Cardinal);
@ -82,12 +83,9 @@ begin
FTreeView.OnItemRemoved := nil;
FTreeView.NodeItem[VNode] := nil;
if FTreeView.ChildCount[VNode] > 0 then begin
VNode := FTreeView.GetFirstVisible(VNode);
Nav := FTreeView.NodeControl[VNode];
if (Nav <> nil) and (Nav is TArrayNavigationBar) then
TArrayNavigationBar(Nav).OwnerData := nil;
end;
Nav := FTreeView.NodeControl[VNode];
if (Nav <> nil) and (Nav is TArrayNavigationBar) then
TArrayNavigationBar(Nav).OwnerData := nil;
FTreeView.OnItemRemoved := @DoItemRemovedFromView;
end;
@ -154,27 +152,32 @@ begin
exit;
end;
ResData := AWatchAbleResult.ResultData;
while (ResData <> nil) and (ResData.ValueKind = rdkPointerVal) do
ResData := ResData.DerefData;
FTreeView.BeginUpdate;
try
ResData := AWatchAbleResult.ResultData;
while (ResData <> nil) and (ResData.ValueKind = rdkPointerVal) do
ResData := ResData.DerefData;
if (ResData <> nil) and
(ResData.FieldCount > 0) and
(ResData.ValueKind <> rdkConvertRes)
then
DoUpdateStructSubItems(AWatchAble, AWatchAbleResult, AVNode, ChildCount)
else
if (ResData <> nil) and
//(ResData.ValueKind = rdkArray) and
(ResData.ArrayLength > 0)
then
DoUpdateArraySubItems(AWatchAble, AWatchAbleResult, AVNode, ChildCount)
else
if (AWatchAbleResult.TypeInfo <> nil) and (AWatchAbleResult.TypeInfo.Fields <> nil) then
// Old Interface
DoUpdateOldSubItems(AWatchAble, AWatchAbleResult, AVNode, ChildCount);
if (ResData <> nil) and
(ResData.FieldCount > 0) and
(ResData.ValueKind <> rdkConvertRes)
then
DoUpdateStructSubItems(AWatchAble, AWatchAbleResult, AVNode, ChildCount)
else
if (ResData <> nil) and
//(ResData.ValueKind = rdkArray) and
(ResData.ArrayLength > 0)
then
DoUpdateArraySubItems(AWatchAble, AWatchAbleResult, AVNode, ChildCount)
else
if (AWatchAbleResult.TypeInfo <> nil) and (AWatchAbleResult.TypeInfo.Fields <> nil) then
// Old Interface
DoUpdateOldSubItems(AWatchAble, AWatchAbleResult, AVNode, ChildCount);
FTreeView.ChildCount[AVNode] := ChildCount;
FTreeView.ChildCount[AVNode] := ChildCount;
finally
FTreeView.EndUpdate;
end;
FTreeView.Invalidate;
end;
@ -204,15 +207,9 @@ begin
if (ResData.ValueKind <> rdkArray) or (TotalCount = 0) then
TotalCount := ResData.Count;
ExistingNode := FTreeView.GetFirstChildNoInit(AVNode);
if ExistingNode = nil then
ExistingNode := FTreeView.AddChild(AVNode, nil)
else
FTreeView.NodeItem[ExistingNode] := nil;
Nav := TArrayNavigationBar(FTreeView.NodeControl[ExistingNode]);
Nav := TArrayNavigationBar(FTreeView.NodeControl[AVNode]);
if Nav = nil then begin
Nav := TArrayNavigationBar.Create(nil);
Nav := TArrayNavigationBar.Create(nil, FTreeView, AVNode);
Nav.ParentColor := False;
Nav.ParentBackground := False;
Nav.Color := FTreeView.Colors.BackGroundColor;
@ -224,9 +221,8 @@ begin
Nav.OnIndexChanged := @WatchNavChanged;
Nav.OnPageSize := @WatchNavChanged;
Nav.HardLimits := not(ResData.ValueKind = rdkArray);
FTreeView.NodeControl[ExistingNode] := Nav;
FTreeView.NodeText[ExistingNode, 0] := ' ';
FTreeView.NodeText[ExistingNode, 1] := ' ';
FTreeView.NodeControl[AVNode] := Nav;
FTreeView.NodeControlHeight[AVNode] := Nav.PreferredHeight;
end
else begin
ForceIdx := (Nav.LowBound <> ResData.LowBound) or
@ -239,10 +235,17 @@ begin
Nav.Index := ResData.LowBound;
Nav.HardLimits := not(ResData.ValueKind = rdkArray);
end;
FTreeView.NodeControlVisible[AVNode] := True;
Nav.OwnerData := AWatchAble;
ChildCount := Nav.LimitedPageSize;
ExistingNode := FTreeView.GetNextSiblingNoInit(ExistingNode);
if ChildCount > 0 then begin
ExistingNode := FTreeView.GetFirstChildNoInit(AVNode);
if ExistingNode = nil then
ExistingNode := FTreeView.AddChild(AVNode, nil)
else
FTreeView.NodeItem[ExistingNode] := nil;
end;
Offs := Nav.Index;
for i := 0 to ChildCount - 1 do begin
@ -266,8 +269,6 @@ begin
UpdateWatchData(NewWatchAble, nd, nil, True);
end;
inc(ChildCount); // for the nav row
KeepCnt := Nav.PageSize;
KeepBelow := KeepCnt;
KeepCnt := max(max(50, KeepCnt+10),
@ -298,8 +299,6 @@ begin
exit;
ExistingNode := FTreeView.GetFirstChildNoInit(AVNode);
if ExistingNode <> nil then
FTreeView.NodeControl[ExistingNode] := nil;
AnchClass := '';
if ResData.StructType <> dstRecord then
@ -375,6 +374,9 @@ procedure TDbgTreeViewWatchDataMgr.TreeViewExpanded(Sender: TBaseVirtualTree;
var
AWatchAble: TObject;
begin
if TArrayNavigationBar(FTreeView.NodeControl[Node]) <> nil then
FTreeView.NodeControlVisible[Node] := True;
Node := FTreeView.GetFirstChildNoInit(Node);
while Node <> nil do begin
AWatchAble := FTreeView.NodeItem[Node];
@ -384,6 +386,11 @@ begin
end;
end;
procedure TDbgTreeViewWatchDataMgr.TreeViewCollapsed(Sender: TBaseVirtualTree; Node: PVirtualNode);
begin
FTreeView.NodeControlVisible[Node] := False;
end;
procedure TDbgTreeViewWatchDataMgr.TreeViewInitChildren(
Sender: TBaseVirtualTree; Node: PVirtualNode; var ChildCount: Cardinal);
var
@ -400,7 +407,9 @@ begin
end;
FExpandingWatchAbleResult := AWatchAble;
FTreeView.BeginUpdate;
UpdateSubItemsLocked(AWatchAble, AWatchAbleResult, Node, ChildCount);
FTreeView.EndUpdate;
FExpandingWatchAbleResult := nil;
end;
@ -419,6 +428,7 @@ begin
FTreeView := ATreeView;
FTreeView.OnItemRemoved := @DoItemRemovedFromView;
FTreeView.OnExpanded := @TreeViewExpanded;
FTreeView.OnCollapsed := @TreeViewCollapsed;
FTreeView.OnInitChildren := @TreeViewInitChildren;
end;
@ -428,22 +438,27 @@ begin
if AWatchAble = nil then
exit;
if (AVNode <> nil) then begin
FTreeView.NodeItem[AVNode] := AWatchAble;
FTreeView.SelectNode(AVNode);
(AWatchAble as IFreeNotifyingIntf).AddFreeNotification(@DoWatchAbleFreed);
end
else begin
AVNode := FTreeView.FindNodeForItem(AWatchAble);
if AVNode = nil then begin
AVNode := FTreeView.AddChild(nil, AWatchAble);
FTreeView.BeginUpdate;
try
if (AVNode <> nil) then begin
FTreeView.NodeItem[AVNode] := AWatchAble;
FTreeView.SelectNode(AVNode);
(AWatchAble as IFreeNotifyingIntf).AddFreeNotification(@DoWatchAbleFreed);
end
else begin
AVNode := FTreeView.FindNodeForItem(AWatchAble);
if AVNode = nil then begin
AVNode := FTreeView.AddChild(nil, AWatchAble);
FTreeView.SelectNode(AVNode);
(AWatchAble as IFreeNotifyingIntf).AddFreeNotification(@DoWatchAbleFreed);
end;
end;
end;
Result := AVNode;
Result := AVNode;
UpdateWatchData(AWatchAble, AVNode, AWatchAbleResult);
UpdateWatchData(AWatchAble, AVNode, AWatchAbleResult);
finally
FTreeView.EndUpdate;
end;
end;
procedure TDbgTreeViewWatchDataMgr.UpdateWatchData(AWatchAble: TObject;
@ -461,48 +476,55 @@ begin
if AWatchAbleResult = nil then
AWatchAbleResult := WatchAbleResultFromObject(AWatchAble);
UpdateColumnsText(AWatchAble, AWatchAbleResult, AVNode);
FTreeView.Invalidate;
FTreeView.BeginUpdate;
try
UpdateColumnsText(AWatchAble, AWatchAbleResult, AVNode);
FTreeView.Invalidate;
if AWatchAbleResult = nil then
exit;
if AWatchAbleResult = nil then
exit;
// some debuggers may have run Application.ProcessMessages
if CancelUpdate then
exit;
// some debuggers may have run Application.ProcessMessages
if CancelUpdate then
exit;
(* If the watch is ddsRequested or ddsEvaluating => keep any expanded tree-nodes. (Avoid flicker)
> ddsEvaluating includes "not HasAllValidParents"
If the debugger is running => keey any expanded tree-nodes
*)
(* If the watch is ddsRequested or ddsEvaluating => keep any expanded tree-nodes. (Avoid flicker)
> ddsEvaluating includes "not HasAllValidParents"
If the debugger is running => keey any expanded tree-nodes
*)
if (not(AWatchAbleResult.Validity in [ddsRequested, ddsEvaluating])) and
((DebugBoss = nil) or (DebugBoss.State <> dsRun))
then begin
TypInfo := AWatchAbleResult.TypeInfo;
ResData := AWatchAbleResult.ResultData;
while (ResData <> nil) and (ResData.ValueKind = rdkPointerVal) do
ResData := ResData.DerefData;
HasChildren := ( (TypInfo <> nil) and (TypInfo.Fields <> nil) and (TypInfo.Fields.Count > 0) ) or
( (ResData <> nil) and
( ( (ResData.FieldCount > 0) and (ResData.ValueKind <> rdkConvertRes) )
or
//( (ResData.ValueKind = rdkArray) and (ResData.ArrayLength > 0) )
(ResData.ArrayLength > 0)
) );
FTreeView.HasChildren[AVNode] := HasChildren;
if (not(AWatchAbleResult.Validity in [ddsRequested, ddsEvaluating])) and
((DebugBoss = nil) or (DebugBoss.State <> dsRun))
then begin
TypInfo := AWatchAbleResult.TypeInfo;
ResData := AWatchAbleResult.ResultData;
while (ResData <> nil) and (ResData.ValueKind = rdkPointerVal) do
ResData := ResData.DerefData;
HasChildren := ( (TypInfo <> nil) and (TypInfo.Fields <> nil) and (TypInfo.Fields.Count > 0) ) or
( (ResData <> nil) and
( ( (ResData.FieldCount > 0) and (ResData.ValueKind <> rdkConvertRes) )
or
//( (ResData.ValueKind = rdkArray) and (ResData.ArrayLength > 0) )
(ResData.ArrayLength > 0)
) );
FTreeView.HasChildren[AVNode] := HasChildren;
if HasChildren and FTreeView.Expanded[AVNode] then begin
if (AWatchAbleResult.Validity = ddsValid) then begin
(* The current "AWatchAbleResult" should be done. Allow UpdateItem for nested entries *)
if HasChildren and FTreeView.Expanded[AVNode] then begin
if (AWatchAbleResult.Validity = ddsValid) then begin
(* The current "AWatchAbleResult" should be done. Allow UpdateItem for nested entries *)
UpdateSubItems(AWatchAble, AWatchAbleResult, AVNode, c);
UpdateSubItems(AWatchAble, AWatchAbleResult, AVNode, c);
end;
end
else
if AWatchAble <> FExpandingWatchAbleResult then begin
FTreeView.DeleteChildren(AVNode, False);
FTreeView.NodeControl[AVNode] := nil
end;
end
else
if AWatchAble <> FExpandingWatchAbleResult then
FTreeView.DeleteChildren(AVNode, False);
end
finally
FTreeView.EndUpdate;
end;
end;
function TDbgTreeViewWatchDataMgr.GetAsText(AScope: TTreeViewDataScope;

View File

@ -51,7 +51,10 @@ type
ShortenResText: string;
ColWidth: integer;
end;
CachedFirstCellLeft: integer;
Control: TControl;
ControlTop, ControlWidth, ControlHeight: integer; // ControlWidth -1 = full
ControlHidden, ControlOutside: Boolean; // below current node, overlaps next
PrevControlNode, NextControlNode: PVirtualNode;
end;
PDbgTreeNodeData = ^TDbgTreeNodeData;
@ -63,45 +66,77 @@ type
TDbgTreeView = class(TLazVirtualStringTree)
private
FCheckControlsVisibleLock: integer;
FCheckControlsVisibleRunning, FCheckControlsVisibleAgain: Boolean;
FInToggle: boolean;
FFirstControlNode: PVirtualNode; // not ordered
FOnDetermineDropMode: TDetermineDropModeEvent;
FOnItemRemoved: TItemRemovedEvent;
function GetNodeControl(Node: PVirtualNode): TControl;
function GetNodeImageIndex(Node: PVirtualNode; AColumn: integer): Integer;
function GetNodeItem(Node: PVirtualNode): TObject;
function GetNodeText(Node: PVirtualNode; AColumn: integer): String;
procedure SetNodeControl(Node: PVirtualNode; AValue: TControl);
procedure SetNodeImageIndex(Node: PVirtualNode; AColumn: integer;
AValue: Integer);
procedure SetNodeItem(Node: PVirtualNode; AValue: TObject);
// Text/Image
function GetNodeImageIndex(Node: PVirtualNode; AColumn: integer): Integer;
function GetNodeText(Node: PVirtualNode; AColumn: integer): String;
procedure SetNodeImageIndex(Node: PVirtualNode; AColumn: integer; AValue: Integer);
procedure SetNodeText(Node: PVirtualNode; AColumn: integer; AValue: String);
// Item
procedure SetNodeItem(Node: PVirtualNode; AValue: TObject);
function GetNodeItem(Node: PVirtualNode): TObject;
// Control
function GetNodeControl(Node: PVirtualNode): TControl;
function GetNodeControlVisible(Node: PVirtualNode): Boolean;
function GetNodeControlOutside(Node: PVirtualNode): Boolean;
function GetNodeControlWidth(Node: PVirtualNode): Integer;
function GetNodeControlHeight(Node: PVirtualNode): Integer;
procedure SetNodeControl(Node: PVirtualNode; AValue: TControl);
procedure SetNodeControlVisible(Node: PVirtualNode; AValue: Boolean);
procedure SetNodeControlOutside(Node: PVirtualNode; AValue: Boolean);
procedure SetNodeControlWidth(Node: PVirtualNode; AValue: Integer);
procedure SetNodeControlHeight(Node: PVirtualNode; AValue: Integer);
procedure ChangeControl(Node: PVirtualNode; NData: PDbgTreeNodeData; AControl: TControl);
function GetIsVisible(Node: PVirtualNode): Boolean; reintroduce;
procedure SetIsVisible(Node: PVirtualNode; AValue: Boolean); reintroduce;
protected
procedure CheckControlsVisible(SkipPos: boolean = False);
procedure DoAllAutoSize; override;
procedure CheckControlsVisible;
procedure VisibleChanged; override;
// Paint / Invalidate
procedure EndUpdate; override;
function DoSetOffsetXY(Value: TPoint; Options: TScrollUpdateOptions;
ClipRect: PRect = nil): Boolean; override;
function DoCollapsing(Node: PVirtualNode): Boolean; override;
function DoSetOffsetXY(Value: TPoint; Options: TScrollUpdateOptions; ClipRect: PRect = nil): Boolean; override;
function DoCollapsing(Node: PVirtualNode): Boolean; override;
procedure DoExpanded(Node: PVirtualNode); override;
procedure DoStateChange(Enter: TVirtualTreeStates; Leave: TVirtualTreeStates = []); override;
procedure ValidateNodeDataSize(var Size: Integer); override;
procedure DoFreeNode(Node: PVirtualNode); override;
function DetermineLineImageAndSelectLevel(Node: PVirtualNode;
var LineImage: TLineImage): Integer; override;
function DetermineLineImageAndSelectLevel(Node: PVirtualNode; var LineImage: TLineImage): Integer; override;
procedure DoBeforeItemErase(ACanvas: TCanvas; ANode: PVirtualNode; const ItemRect: TRect;
var AColor: TColor; var EraseAction: TItemEraseAction); override;
procedure PrepareCell(var PaintInfo: TVTPaintInfo; WindowOrgX, MaxWidth: Integer); override; // the background
procedure PaintTreeLines(const PaintInfo: TVTPaintInfo; VAlignment, IndentSize: Integer;
LineImage: TLineImage); override;
procedure PaintNodeButton(ACanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex;
const R: TRect; ButtonX, ButtonY: Integer; ABidiMode: TBiDiMode); override;
procedure DoPaintNode(var PaintInfo: TVTPaintInfo); override;
// Mouse
function DetermineDropMode(const P: TPoint; var HitInfo: THitInfo;
var NodeRect: TRect): TDropMode; override;
procedure HandleMouseDown(var Message: TLMMouse; var HitInfo: THitInfo); override;
procedure HandleMouseDblClick(var Message: TLMMouse; const HitInfo: THitInfo); override;
// Data
procedure DoGetText(Node: PVirtualNode; Column: TColumnIndex;
TextType: TVSTTextType; var AText: String); override;
procedure DoPaintNode(var PaintInfo: TVTPaintInfo); override;
function DoGetImageIndex(Node: PVirtualNode; Kind: TVTImageKind;
Column: TColumnIndex; var Ghosted: Boolean; var Index: Integer
): TCustomImageList; override;
function DoGetNodeWidth(ANode: PVirtualNode; AColumn: TColumnIndex; ACanvas: TCanvas =
nil): Integer; override;
function DoShortenString(ACanvas: TCanvas; ANode: PVirtualNode; AColumn: TColumnIndex;
const S: String; AWidth: Integer; AnEllipsisWidth: Integer = 0): String; override;
procedure DoNodeMoved(ANode: PVirtualNode); override;
procedure ValidateNodeDataSize(var Size: Integer); override;
procedure DoFreeNode(Node: PVirtualNode); override;
public
function GetNodeData(Node: PVirtualNode): PDbgTreeNodeData; reintroduce;
function GetFocusedNode(OnlySelected: Boolean = True; AnIncludeControlNodes: Boolean = False): PVirtualNode;
function FocusedData(OnlySelected: Boolean = True): PDbgTreeNodeData;
function FocusedItem(OnlySelected: Boolean = True): TObject;
@ -122,10 +157,18 @@ type
function SelectedItemNodes(ConsiderChildrenAbove: Boolean = False; IncludeNonItemNodes: Boolean = False): TVTVirtualItemNodeEnumeration;
function ControlNodes: TVTVirtualItemNodeEnumeration;
function GetNodeData(Node: PVirtualNode): PDbgTreeNodeData; reintroduce;
property NodeItem[Node: PVirtualNode]: TObject read GetNodeItem write SetNodeItem;
property NodeText[Node: PVirtualNode; AColumn: integer]: String read GetNodeText write SetNodeText;
property NodeImageIndex[Node: PVirtualNode; AColumn: integer]: Integer read GetNodeImageIndex write SetNodeImageIndex;
property IsVisible[Node: PVirtualNode]: Boolean read GetIsVisible write SetIsVisible;
// May need reintroduction //property NodeHeight[Node: PVirtualNode]: Cardinal read GetNodeHeight write SetNodeHeight;
// Control
property NodeControl[Node: PVirtualNode]: TControl read GetNodeControl write SetNodeControl;
property NodeControlVisible[Node: PVirtualNode]: Boolean read GetNodeControlVisible write SetNodeControlVisible;
property NodeControlWidth[Node: PVirtualNode]: Integer read GetNodeControlWidth write SetNodeControlWidth;
property NodeControlHeight[Node: PVirtualNode]: Integer read GetNodeControlHeight write SetNodeControlHeight;
property NodeControlOutside[Node: PVirtualNode]: Boolean read GetNodeControlOutside write SetNodeControlOutside;
property OnItemRemoved: TItemRemovedEvent read FOnItemRemoved write FOnItemRemoved;
property OnDetermineDropMode: TDetermineDropModeEvent read FOnDetermineDropMode write FOnDetermineDropMode;
@ -204,16 +247,6 @@ end;
{ TDbgTreeView }
function TDbgTreeView.GetNodeControl(Node: PVirtualNode): TControl;
var
Data: PDbgTreeNodeData;
begin
Result := nil;
Data := GetNodeData(Node);
if Data <> nil then
Result := Data^.Control;
end;
function TDbgTreeView.GetNodeImageIndex(Node: PVirtualNode; AColumn: integer
): Integer;
var
@ -225,16 +258,6 @@ begin
Result := Data^.ImageIndex[AColumn] - 1;
end;
function TDbgTreeView.GetNodeItem(Node: PVirtualNode): TObject;
var
Data: PDbgTreeNodeData;
begin
Result := nil;
Data := GetNodeData(Node);
if Data <> nil then
Result := Data^.Item;
end;
function TDbgTreeView.GetNodeText(Node: PVirtualNode; AColumn: integer): String;
var
Data: PDbgTreeNodeData;
@ -245,25 +268,6 @@ begin
Result := Data^.CachedText[AColumn];
end;
procedure TDbgTreeView.SetNodeControl(Node: PVirtualNode; AValue: TControl);
var
Data: PDbgTreeNodeData;
begin
Data := GetNodeData(Node);
if Data = nil then
exit;
if Data^.Control = AValue then
exit;
Data^.Control.Free;
ChangeControl(Node, Data, AValue);
if AValue <> nil then begin
AValue.Visible := False;
AValue.Parent := Self;
AValue.AutoSize := False;
end;
end;
procedure TDbgTreeView.SetNodeImageIndex(Node: PVirtualNode; AColumn: integer;
AValue: Integer);
var
@ -277,21 +281,6 @@ begin
end;
end;
procedure TDbgTreeView.SetNodeItem(Node: PVirtualNode; AValue: TObject);
var
Data: PDbgTreeNodeData;
begin
Data := GetNodeData(Node);
if Data <> nil then begin
if (FOnItemRemoved <> nil) and (Data^.Item <> nil) and (Data^.Item <> AValue) then
FOnItemRemoved(Self, Data^.Item, Node);
Data^.Item := AValue;
end;
end;
procedure TDbgTreeView.SetNodeText(Node: PVirtualNode; AColumn: integer;
AValue: String);
var
@ -310,6 +299,216 @@ begin
end;
end;
procedure TDbgTreeView.SetNodeItem(Node: PVirtualNode; AValue: TObject);
var
Data: PDbgTreeNodeData;
begin
Data := GetNodeData(Node);
if Data <> nil then begin
if (FOnItemRemoved <> nil) and (Data^.Item <> nil) and (Data^.Item <> AValue) then
FOnItemRemoved(Self, Data^.Item, Node);
Data^.Item := AValue;
end;
end;
function TDbgTreeView.GetNodeItem(Node: PVirtualNode): TObject;
var
Data: PDbgTreeNodeData;
begin
Result := nil;
Data := GetNodeData(Node);
if Data <> nil then
Result := Data^.Item;
end;
function TDbgTreeView.GetNodeControl(Node: PVirtualNode): TControl;
var
Data: PDbgTreeNodeData;
begin
Result := nil;
Data := GetNodeData(Node);
if Data <> nil then
Result := Data^.Control;
end;
function TDbgTreeView.GetNodeControlVisible(Node: PVirtualNode): Boolean;
var
Data: PDbgTreeNodeData;
begin
Result := False;
Data := GetNodeData(Node);
if Data <> nil then
Result := not Data^.ControlHidden;
end;
function TDbgTreeView.GetNodeControlOutside(Node: PVirtualNode): Boolean;
var
Data: PDbgTreeNodeData;
begin
Result := False;
Data := GetNodeData(Node);
if Data <> nil then
Result := Data^.ControlOutside;
end;
function TDbgTreeView.GetNodeControlWidth(Node: PVirtualNode): Integer;
var
Data: PDbgTreeNodeData;
begin
Result := 0;
Data := GetNodeData(Node);
if Data <> nil then
Result := Data^.ControlWidth;
end;
function TDbgTreeView.GetNodeControlHeight(Node: PVirtualNode): Integer;
var
Data: PDbgTreeNodeData;
begin
Result := 0;
Data := GetNodeData(Node);
if Data <> nil then
Result := Data^.ControlHeight;
end;
procedure TDbgTreeView.SetNodeControl(Node: PVirtualNode; AValue: TControl);
var
Data: PDbgTreeNodeData;
h: LongWord;
begin
Data := GetNodeData(Node);
if Data = nil then
exit;
if Data^.Control = AValue then
exit;
Data^.Control.Free;
ChangeControl(Node, Data, AValue);
if AValue <> nil then begin
AValue.Visible := False;
AValue.Parent := Self;
AValue.AutoSize := False;
end;
if (Data^.Item <> nil) and (Data^.ControlTop = 0) then begin
h := NodeHeight[Node];
Data^.ControlTop := h;
Data^.ControlHeight := DefaultNodeHeight;
if (Data^.Control <> nil) and (not Data^.ControlHidden) and not Data^.ControlOutside then
NodeHeight[Node] := h + Data^.ControlHeight
else
NodeHeight[Node] := h;
end
else
if AValue = nil then begin
if Data^.ControlTop > 0 then
NodeHeight[Node] := Data^.ControlTop;
Data^.ControlTop := 0;
end;
end;
procedure TDbgTreeView.SetNodeControlVisible(Node: PVirtualNode; AValue: Boolean);
var
Data: PDbgTreeNodeData;
h: LongWord;
begin
Data := GetNodeData(Node);
if Data = nil then
exit;
if not Data^.ControlHidden = AValue then
exit;
Data^.ControlHidden := not AValue;
if (Data^.ControlTop = 0) then begin
h := NodeHeight[Node];
if Data^.Item <> nil then
Data^.ControlTop := h;
end
else
h := Data^.ControlTop;
if (Data^.Control <> nil) and Data^.ControlHidden then
Data^.Control.Visible := False;
if (Data^.Item <> nil) then begin
if (Data^.Control <> nil) and (not Data^.ControlHidden) and not Data^.ControlOutside then
NodeHeight[Node] := h + Data^.ControlHeight
else
NodeHeight[Node] := h;
end;
InvalidateToBottom(Node);
end;
procedure TDbgTreeView.SetNodeControlOutside(Node: PVirtualNode; AValue: Boolean);
var
Data: PDbgTreeNodeData;
h: LongWord;
begin
Data := GetNodeData(Node);
if Data = nil then
exit;
if Data^.ControlOutside = AValue then
exit;
Data^.ControlOutside := AValue;
if (Data^.ControlTop = 0) then begin
h := NodeHeight[Node];
if Data^.Item <> nil then
Data^.ControlTop := h;
end
else
h := Data^.ControlTop;
if (Data^.Item <> nil) then begin
if (Data^.Control <> nil) and (not Data^.ControlHidden) and not Data^.ControlOutside then
NodeHeight[Node] := h + Data^.ControlHeight
else
NodeHeight[Node] := h;
end;
InvalidateToBottom(Node);
end;
procedure TDbgTreeView.SetNodeControlWidth(Node: PVirtualNode; AValue: Integer);
var
Data: PDbgTreeNodeData;
begin
Data := GetNodeData(Node);
if Data = nil then
exit;
if Data^.ControlWidth = AValue then
exit;
Data^.ControlWidth := AValue;
InvalidateToBottom(Node);
end;
procedure TDbgTreeView.SetNodeControlHeight(Node: PVirtualNode; AValue: Integer);
var
Data: PDbgTreeNodeData;
begin
Data := GetNodeData(Node);
if Data = nil then
exit;
if AValue < 0 then AValue := 0;
if Data^.ControlHeight = AValue then
exit;
if (Data^.Item = nil) then // control takes full node
NodeHeight[Node] := AValue
else
if (Data^.Control <> nil) and (not Data^.ControlHidden) and not Data^.ControlOutside then
NodeHeight[Node] := NodeHeight[Node] + AValue - Data^.ControlHeight;
Data^.ControlHeight := AValue;
InvalidateToBottom(Node);
end;
procedure TDbgTreeView.ChangeControl(Node: PVirtualNode;
NData: PDbgTreeNodeData; AControl: TControl);
var
@ -354,63 +553,140 @@ begin
end;
end;
procedure TDbgTreeView.CheckControlsVisible(SkipPos: boolean);
function TDbgTreeView.GetIsVisible(Node: PVirtualNode): Boolean;
begin
Result := inherited IsVisible[Node];
end;
procedure TDbgTreeView.SetIsVisible(Node: PVirtualNode; AValue: Boolean);
var
Data: PDbgTreeNodeData;
begin
inherited IsVisible[Node] := AValue;
Data := GetNodeData(Node);
if (Data <> nil) and (Data^.Control <> nil) and (not AValue) then
Data^.Control.Visible := False;
end;
procedure TDbgTreeView.DoAllAutoSize;
begin
FCheckControlsVisibleRunning := True;
inherited DoAllAutoSize;
FCheckControlsVisibleRunning := False;
if FCheckControlsVisibleAgain then
CheckControlsVisible;
end;
procedure TDbgTreeView.CheckControlsVisible;
var
VNode: PVirtualNode;
Y, H, T, B: Integer;
NData: PDbgTreeNodeData;
Y, Y2, H, H2, T, B, offs, Limit: Integer;
Ctrl: TControl;
Chg: Boolean;
r2: TRect;
begin
if (FFirstControlNode = nil) or (UpdateCount > 0) then
FCheckControlsVisibleAgain := FCheckControlsVisibleRunning;
if (FCheckControlsVisibleLock > 0) or FCheckControlsVisibleRunning or
(FFirstControlNode = nil) or (UpdateCount > 0) or
(not TControl(self).IsVisible) or (not HandleAllocated)
then
exit;
T := Header.Height;
B := ClientHeight - 1 + T; // subtracted by laz.VirtualTree
Y := OffsetY + T;
Chg := False;
for VNode in VisibleNoInitNodes do begin
Ctrl := NodeControl[VNode];
H := NodeHeight[VNode];
if (Ctrl <> nil) then begin
if (Y < T) or (Y >= B) then begin
Chg := Chg or Ctrl.Visible;
Ctrl.Visible := False;
end
else begin
Chg := Chg or
(Ctrl.Top <> Y) or
(Ctrl.Height <> H) or
(Ctrl.Visible <> True);
DisableAutoSizing;
FCheckControlsVisibleRunning := True;
try
Limit := 5 + ClientHeight div (DefaultNodeHeight * 2);
repeat
dec(Limit);
T := Header.Height;
B := ClientHeight - 1 + T; // subtracted by laz.VirtualTree
Y := OffsetY + T;
Chg := False;
for VNode in VisibleNoInitNodes do begin
NData := GetNodeData(VNode);
offs := 0;
H := NodeHeight[VNode];
if NData <> nil then begin
Ctrl := NData^.Control;
if NData^.ControlHidden then begin
if (Ctrl <> nil) then
Ctrl.Visible := False;
end
else
if (Ctrl <> nil) then begin
offs := NData^.ControlTop;
Y2 := Y + offs;
if NData^.ControlOutside then
H2 := NData^.ControlHeight
else
H2 := H - offs;
if (Y2 < T) or (Y2 >= B) then begin
Chg := Chg or Ctrl.Visible;
Ctrl.Visible := False;
end
else begin
Chg := Chg or
(Ctrl.Top <> Y2) or
(Ctrl.Height <> H2) or
(Ctrl.Visible <> True);
if (not Ctrl.Visible) or (not SkipPos) then begin
Ctrl.Top := Y;
Ctrl.Height := Min(H, b - 1 - Y);
if NData^.ControlOutside then begin
Ctrl.SetBounds(OffsetX, Y2, Ctrl.Width, H2);
end
else begin
if (NData^.CachedFirstCellLeft <= 0) then begin
r2 := GetDisplayRect(vNode, 0, True, False);
NData^.CachedFirstCellLeft := r2.Left;
end;
Ctrl.SetBounds(NData^.CachedFirstCellLeft + OffsetX, Y2, Ctrl.Width, H2);
end;
ctrl.Visible := True;
H2 := NodeHeight[VNode];
if H <> H2 then
Ctrl.Height := H2 - offs;
end;
end;
end;
Ctrl.Visible := True;
Y := Y + NodeHeight[VNode];
end;
end;
Y := Y + H;
end;
until (not FCheckControlsVisibleAgain) or (Limit <= 0);
if Chg then
Invalidate;
finally
FCheckControlsVisibleAgain := False;
FCheckControlsVisibleRunning := False;
// EnableAutoSizing: Some controls may change their node's height
EnableAutoSizing;
end;
end;
procedure TDbgTreeView.VisibleChanged;
begin
inc(FCheckControlsVisibleLock);
inherited VisibleChanged;
dec(FCheckControlsVisibleLock);
CheckControlsVisible;
end;
procedure TDbgTreeView.EndUpdate;
begin
inc(FCheckControlsVisibleLock);
inherited EndUpdate;
dec(FCheckControlsVisibleLock);
CheckControlsVisible;
end;
function TDbgTreeView.DoSetOffsetXY(Value: TPoint;
Options: TScrollUpdateOptions; ClipRect: PRect): Boolean;
begin
inc(FCheckControlsVisibleLock);
DisableAutoSizing;
Result := inherited DoSetOffsetXY(Value, Options, ClipRect);
{$if defined(LCLGtk) or defined(LCLGtk2)}
dec(FCheckControlsVisibleLock);
CheckControlsVisible;
{$else}
CheckControlsVisible(True);
{$endif}
EnableAutoSizing;
end;
function TDbgTreeView.DoCollapsing(Node: PVirtualNode): Boolean;
@ -419,11 +695,11 @@ function TDbgTreeView.DoCollapsing(Node: PVirtualNode): Boolean;
N2: PVirtualNode;
NData: PDbgTreeNodeData;
begin
NData := GetNodeData(N);
if NData^.Control <> nil then
NData^.Control.Visible := False;
while N <> nil do begin
NData := GetNodeData(N);
if NData^.Control <> nil then
NData^.Control.Visible := False;
N2 := GetFirstChildNoInit(N);
if N2 <> nil then
RecursivelyHideControls(N2);
@ -442,42 +718,36 @@ end;
procedure TDbgTreeView.DoExpanded(Node: PVirtualNode);
begin
inc(FCheckControlsVisibleLock);
inherited DoExpanded(Node);
dec(FCheckControlsVisibleLock);
CheckControlsVisible;
end;
procedure TDbgTreeView.DoStateChange(Enter: TVirtualTreeStates;
Leave: TVirtualTreeStates);
begin
inherited DoStateChange(Enter, Leave);
if tsToggling in Leave then
CheckControlsVisible;
end;
procedure TDbgTreeView.ValidateNodeDataSize(var Size: Integer);
begin
Size := SizeOf(TDbgTreeNodeData);
end;
procedure TDbgTreeView.DoFreeNode(Node: PVirtualNode);
var
NData: PDbgTreeNodeData;
begin
NData := GetNodeData(Node);
if NData <> nil then begin
if (FOnItemRemoved <> nil) and (NData^.Item <> nil) then
FOnItemRemoved(Self, NData^.Item, Node);
NData^.Control.Free;
ChangeControl(Node, NData, nil);
NData^ := Default(TDbgTreeNodeData);
if tsToggling in Enter then begin
if not FInToggle then
inc(FCheckControlsVisibleLock);
FInToggle := True;
end;
inherited DoStateChange(Enter, Leave);
if tsToggling in Leave then begin
if FInToggle then
dec(FCheckControlsVisibleLock);
FInToggle := False;
CheckControlsVisible;
if not AutoSizeDelayed then // e.g. called by mouseclick / update before syncronizing with dbg-results
Update;
end;
inherited DoFreeNode(Node);
end;
function TDbgTreeView.DetermineLineImageAndSelectLevel(Node: PVirtualNode;
var LineImage: TLineImage): Integer;
var
NData: PDbgTreeNodeData;
i: Integer;
begin
Result := inherited DetermineLineImageAndSelectLevel(Node, LineImage);
if Length(LineImage) > 1 then
@ -485,6 +755,145 @@ begin
else
if (Length(LineImage) > 0) and (LineImage[0] <> ltNone) then
LineImage[0] := ltRight;
NData := GetNodeData(Node);
if (NData^.Control <> nil) and (NData^.Item <> nil) then
for i := 1 to Length(LineImage) - 1 do
if LineImage[i] = ltNone then
LineImage[i] := ltTopDown;
end;
procedure TDbgTreeView.DoPaintNode(var PaintInfo: TVTPaintInfo);
var
NData: PDbgTreeNodeData;
r: TRect;
b: LongInt;
begin
NData := GetNodeData(PaintInfo.Node);
b := PaintInfo.ContentRect.Bottom;
if NData^.Item = nil then
exit;
if (NData^.Control <> nil) and (not NData^.ControlHidden) and (not NData^.ControlOutside) then
PaintInfo.ContentRect.Bottom := NData^.ControlTop;
inherited DoPaintNode(PaintInfo);
PaintInfo.ContentRect.Bottom := b;
end;
procedure TDbgTreeView.PaintNodeButton(ACanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex;
const R: TRect; ButtonX, ButtonY: Integer; ABidiMode: TBiDiMode);
var
NData: PDbgTreeNodeData;
offs: Integer;
begin
NData := GetNodeData(Node);
offs := NData^.ControlTop;
if offs > 0 then
ButtonY := ButtonY - (r.Bottom - offs) div 2;
inherited PaintNodeButton(ACanvas, Node, Column, R, ButtonX, ButtonY, ABidiMode);
end;
procedure TDbgTreeView.PaintTreeLines(const PaintInfo: TVTPaintInfo; VAlignment,
IndentSize: Integer; LineImage: TLineImage);
var
NData: PDbgTreeNodeData;
offs: Integer;
PaintI2: TVTPaintInfo;
VAlignment2: LongInt;
begin
NData := GetNodeData(PaintInfo.Node);
offs := NData^.ControlTop;
PaintI2 := PaintInfo;
if offs > 0 then begin
PaintI2.CellRect.Top := min(PaintInfo.CellRect.Top + offs, PaintInfo.CellRect.Bottom);
VAlignment2 := (PaintI2.CellRect.Bottom - PaintI2.CellRect.Top) div 2 - 1;
inherited PaintTreeLines(PaintI2, VAlignment2, IndentSize, LineImage);
end;
inherited PaintTreeLines(PaintInfo, VAlignment, IndentSize -1, LineImage);
end;
procedure TDbgTreeView.PrepareCell(var PaintInfo: TVTPaintInfo; WindowOrgX, MaxWidth: Integer);
var
NData: PDbgTreeNodeData;
offs: Integer;
b, b2: LongInt;
begin
NData := GetNodeData(PaintInfo.Node);
offs := NData^.ControlTop;
if offs = 0 then begin
inherited PrepareCell(PaintInfo, WindowOrgX, MaxWidth);
exit;
end;
b := PaintInfo.CellRect.Bottom;
b2 := PaintInfo.ContentRect.Bottom;
PaintInfo.CellRect.Bottom := PaintInfo.CellRect.Top + offs;
PaintInfo.ContentRect.Bottom := PaintInfo.ContentRect.Top + offs;
inherited PrepareCell(PaintInfo, WindowOrgX, MaxWidth);
PaintInfo.CellRect.Bottom := b;
PaintInfo.ContentRect.Bottom := b2;
end;
procedure TDbgTreeView.DoBeforeItemErase(ACanvas: TCanvas; ANode: PVirtualNode;
const ItemRect: TRect; var AColor: TColor; var EraseAction: TItemEraseAction);
var
NData: PDbgTreeNodeData;
offs: Integer;
r, r2: TRect;
Temp: PVirtualNode;
begin
inherited DoBeforeItemErase(ACanvas, ANode, ItemRect, AColor, EraseAction);
EraseAction := eaColor;
NData := GetNodeData(ANode);
if NData^.Control <> nil then begin
if not NData^.ControlHidden then begin
r := ItemRect;
if NData^.CachedFirstCellLeft <= 0 then begin
r2 := GetDisplayRect(ANode, 0, True, False);
NData^.CachedFirstCellLeft := r2.Left;
r.Top := r2.Top;
end
else begin
r.Top := OffsetY;
Temp := ANode;
repeat
Temp := GetPreviousVisibleNoInit(Temp, True);
if Temp = nil then
Break;
Inc(r.Top, NodeHeight[Temp]);
until False;
if hoVisible in Header.Options then
inc(r.Top, Header.Height);
end;
offs := NData^.ControlTop;
r.Bottom := r.Top + ItemRect.Bottom - ItemRect.Top;
r.Top := r.Top + offs;
if r.Top >= Header.Height then begin
if NData^.ControlOutside then begin
NData^.Control.SetBounds(OffsetX, r.Top, NData^.ControlWidth, NData^.ControlHeight);
end
else begin
r.Left := NData^.CachedFirstCellLeft + OffsetX;
if NData^.ControlWidth <= 0 then
r.Right := RangeX
else
r.Right := r.Left+NData^.ControlWidth;
NData^.Control.BoundsRect := r;
end;
NData^.Control.Visible := True;
end;
end
else
NData^.Control.Visible := False;
end;
end;
function TDbgTreeView.DetermineDropMode(const P: TPoint; var HitInfo: THitInfo;
@ -534,29 +943,13 @@ begin
end;
end;
procedure TDbgTreeView.DoPaintNode(var PaintInfo: TVTPaintInfo);
var
NData: PDbgTreeNodeData;
r: TRect;
function TDbgTreeView.DoGetImageIndex(Node: PVirtualNode; Kind: TVTImageKind;
Column: TColumnIndex; var Ghosted: Boolean; var Index: Integer
): TCustomImageList;
begin
NData := GetNodeData(PaintInfo.Node);
if NData^.Control <> nil then begin
if PaintInfo.Column = 0 then begin
r := GetDisplayRect(PaintInfo.Node, 0, True, False);
if r.Top >= Header.Height then begin
r.Right := ClientWidth - 1;
NData^.Control.BoundsRect := r;
NData^.Control.Visible := True;
if (r.Top < (r.Bottom - r.Height) * 2 + 5) or
(r.Bottom > ClientHeight - (r.Bottom - r.Height) * 2 - 5)
then
NData^.Control.Invalidate;
end;
end;
exit;
end;
inherited DoPaintNode(PaintInfo);
Result := nil;
Ghosted := False;
Index := GetNodeImageIndex(Node, Column);
end;
function TDbgTreeView.DoGetNodeWidth(ANode: PVirtualNode; AColumn: TColumnIndex; ACanvas: TCanvas
@ -614,6 +1007,7 @@ begin
NData^.CachedColumnData[i].ShortenResText := '';
NData^.CachedColumnData[i].ShortenWidth1 := -1;
NData^.CachedColumnData[i].ColWidth := -1;
NData^.CachedFirstCellLeft := -1;
end;
N := GetFirstChildNoInit(ANode);
@ -622,6 +1016,27 @@ begin
if N <> nil then DoNodeMoved(N);
end;
procedure TDbgTreeView.ValidateNodeDataSize(var Size: Integer);
begin
Size := SizeOf(TDbgTreeNodeData);
end;
procedure TDbgTreeView.DoFreeNode(Node: PVirtualNode);
var
NData: PDbgTreeNodeData;
begin
NData := GetNodeData(Node);
if NData <> nil then begin
if (FOnItemRemoved <> nil) and (NData^.Item <> nil) then
FOnItemRemoved(Self, NData^.Item, Node);
NData^.Control.Free;
ChangeControl(Node, NData, nil);
NData^ := Default(TDbgTreeNodeData);
end;
inherited DoFreeNode(Node);
end;
function TDbgTreeView.GetNodeData(Node: PVirtualNode): PDbgTreeNodeData;
begin
@ -632,7 +1047,9 @@ function TDbgTreeView.GetFocusedNode(OnlySelected: Boolean;
AnIncludeControlNodes: Boolean): PVirtualNode;
begin
Result := FocusedNode;
if (not AnIncludeControlNodes) and (Result <> nil) and (NodeControl[Result] <> nil) then
if (not AnIncludeControlNodes) and (Result <> nil) and
(NodeControl[Result] <> nil) and (NodeItem[Result] = nil)
then
Result := nil;
if (Result = nil) or (OnlySelected and not Selected[Result]) then
Result := nil;