mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-28 21:20:46 +02:00
Debugger: Watches-Win, expand arrays to view entries
This commit is contained in:
parent
6deb576cda
commit
b814c37698
@ -41,11 +41,12 @@ uses
|
|||||||
Classes, Forms, Controls, math, sysutils, LazLoggerBase, LazUTF8, Clipbrd,
|
Classes, Forms, Controls, math, sysutils, LazLoggerBase, LazUTF8, Clipbrd,
|
||||||
{$ifdef Windows} ActiveX, {$else} laz.FakeActiveX, {$endif}
|
{$ifdef Windows} ActiveX, {$else} laz.FakeActiveX, {$endif}
|
||||||
IDEWindowIntf, Menus, ComCtrls, ActnList, ExtCtrls, StdCtrls, LCLType,
|
IDEWindowIntf, Menus, ComCtrls, ActnList, ExtCtrls, StdCtrls, LCLType,
|
||||||
IDEImagesIntf, LazarusIDEStrConsts, DebuggerStrConst, Debugger,
|
LMessages, IDEImagesIntf, LazarusIDEStrConsts, DebuggerStrConst, Debugger,
|
||||||
DebuggerTreeView, IdeDebuggerBase, DebuggerDlg, DbgIntfBaseTypes,
|
DebuggerTreeView, IdeDebuggerBase, DebuggerDlg, DbgIntfBaseTypes,
|
||||||
DbgIntfDebuggerBase, DbgIntfMiscClasses, SynEdit, laz.VirtualTrees,
|
DbgIntfDebuggerBase, DbgIntfMiscClasses, SynEdit, laz.VirtualTrees, SpinEx,
|
||||||
LazDebuggerIntf, LazDebuggerIntfBaseTypes, BaseDebugManager, EnvironmentOpts,
|
LazDebuggerIntf, LazDebuggerIntfBaseTypes, BaseDebugManager, EnvironmentOpts,
|
||||||
StrUtils, IdeDebuggerWatchResult, IdeDebuggerWatchResPrinter;
|
StrUtils, IdeDebuggerWatchResult, IdeDebuggerWatchResPrinter,
|
||||||
|
ArrayNavigationFrame;
|
||||||
|
|
||||||
type
|
type
|
||||||
|
|
||||||
@ -151,6 +152,7 @@ type
|
|||||||
function GetWatches: TIdeWatches;
|
function GetWatches: TIdeWatches;
|
||||||
procedure ContextChanged(Sender: TObject);
|
procedure ContextChanged(Sender: TObject);
|
||||||
procedure SnapshotChanged(Sender: TObject);
|
procedure SnapshotChanged(Sender: TObject);
|
||||||
|
procedure WatchNavChanged(Sender: TArrayNavigationBar; AValue: Int64);
|
||||||
private
|
private
|
||||||
FWatchPrinter: TWatchResultPrinter;
|
FWatchPrinter: TWatchResultPrinter;
|
||||||
FWatchesInView: TIdeWatches;
|
FWatchesInView: TIdeWatches;
|
||||||
@ -168,6 +170,8 @@ type
|
|||||||
|
|
||||||
procedure UpdateInspectPane;
|
procedure UpdateInspectPane;
|
||||||
procedure UpdateItem(const VNode: PVirtualNode; const AWatch: TIdeWatch);
|
procedure UpdateItem(const VNode: PVirtualNode; const AWatch: TIdeWatch);
|
||||||
|
procedure UpdateArraySubItems(const VNode: PVirtualNode;
|
||||||
|
const AWatchValue: TIdeWatchValue; out ChildCount: LongWord);
|
||||||
procedure UpdateSubItems(const VNode: PVirtualNode;
|
procedure UpdateSubItems(const VNode: PVirtualNode;
|
||||||
const AWatchValue: TIdeWatchValue; out ChildCount: LongWord);
|
const AWatchValue: TIdeWatchValue; out ChildCount: LongWord);
|
||||||
procedure UpdateAll;
|
procedure UpdateAll;
|
||||||
@ -175,6 +179,7 @@ type
|
|||||||
function GetSelectedSnapshot: TSnapshot;
|
function GetSelectedSnapshot: TSnapshot;
|
||||||
property Watches: TIdeWatches read GetWatches;
|
property Watches: TIdeWatches read GetWatches;
|
||||||
protected
|
protected
|
||||||
|
function IsShortcut(var Message: TLMKey): Boolean; override;
|
||||||
procedure DoBeginUpdate; override;
|
procedure DoBeginUpdate; override;
|
||||||
procedure DoEndUpdate; override;
|
procedure DoEndUpdate; override;
|
||||||
procedure DoWatchesChanged; override;
|
procedure DoWatchesChanged; override;
|
||||||
@ -495,6 +500,12 @@ var
|
|||||||
s: String;
|
s: String;
|
||||||
NewWatch: TCurrentWatch;
|
NewWatch: TCurrentWatch;
|
||||||
begin
|
begin
|
||||||
|
if (ActiveControl <> nil) and (
|
||||||
|
(ActiveControl is TCustomEdit) or (ActiveControl is TCustomSpinEditEx)
|
||||||
|
)
|
||||||
|
then
|
||||||
|
exit;
|
||||||
|
|
||||||
if (Shift * [ssShift, ssAlt, ssAltGr, ssCtrl] = [ssCtrl]) and (Key = VK_V)
|
if (Shift * [ssShift, ssAlt, ssAltGr, ssCtrl] = [ssCtrl]) and (Key = VK_V)
|
||||||
then begin
|
then begin
|
||||||
Key := 0;
|
Key := 0;
|
||||||
@ -699,6 +710,28 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TWatchesDlg.WatchNavChanged(Sender: TArrayNavigationBar; AValue: Int64
|
||||||
|
);
|
||||||
|
var
|
||||||
|
VNode: PVirtualNode;
|
||||||
|
AWatch: TIdeWatch;
|
||||||
|
WatchValue: TIdeWatchValue;
|
||||||
|
c: LongWord;
|
||||||
|
begin
|
||||||
|
if Sender.OwnerData = nil then
|
||||||
|
exit;
|
||||||
|
|
||||||
|
AWatch := TIdeWatch(Sender.OwnerData);
|
||||||
|
if AWatch.Enabled and AWatch.HasAllValidParents(GetThreadId, GetStackframe) then begin
|
||||||
|
VNode := tvWatches.FindNodeForItem(AWatch);
|
||||||
|
if VNode = nil then
|
||||||
|
exit;
|
||||||
|
|
||||||
|
WatchValue := AWatch.Values[GetThreadId, GetStackframe];
|
||||||
|
UpdateSubItems(VNode, WatchValue, c);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
function TWatchesDlg.GetWatches: TIdeWatches;
|
function TWatchesDlg.GetWatches: TIdeWatches;
|
||||||
var
|
var
|
||||||
Snap: TSnapshot;
|
Snap: TSnapshot;
|
||||||
@ -1058,8 +1091,11 @@ begin
|
|||||||
if DoDelayedDelete then
|
if DoDelayedDelete then
|
||||||
exit;
|
exit;
|
||||||
|
|
||||||
HasChildren := ((TypInfo <> nil) and (TypInfo.Fields <> nil) and (TypInfo.Fields.Count > 0)) or
|
HasChildren := ( (TypInfo <> nil) and (TypInfo.Fields <> nil) and (TypInfo.Fields.Count > 0) ) or
|
||||||
((WatchValue.ResultData <> nil) and (WatchValue.ResultData.FieldCount > 0));
|
( (WatchValue.ResultData <> nil) and
|
||||||
|
( (WatchValue.ResultData.FieldCount > 0) or
|
||||||
|
( (WatchValue.ResultData.ValueKind = rdkArray) and (WatchValue.ResultData.ArrayLength > 0) )
|
||||||
|
) );
|
||||||
tvWatches.HasChildren[VNode] := HasChildren;
|
tvWatches.HasChildren[VNode] := HasChildren;
|
||||||
if HasChildren and (WatchValue.Validity = ddsValid) and tvWatches.Expanded[VNode] then begin
|
if HasChildren and (WatchValue.Validity = ddsValid) and tvWatches.Expanded[VNode] then begin
|
||||||
(* The current "AWatch" should be done. Allow UpdateItem for nested entries *)
|
(* The current "AWatch" should be done. Allow UpdateItem for nested entries *)
|
||||||
@ -1095,6 +1131,93 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TWatchesDlg.UpdateArraySubItems(const VNode: PVirtualNode;
|
||||||
|
const AWatchValue: TIdeWatchValue; out ChildCount: LongWord);
|
||||||
|
var
|
||||||
|
NewWatch, AWatch: TIdeWatch;
|
||||||
|
i, TotalCount: Integer;
|
||||||
|
ResData: TWatchResultData;
|
||||||
|
ExistingNode, nd: PVirtualNode;
|
||||||
|
Nav: TArrayNavigationBar;
|
||||||
|
Idx: String;
|
||||||
|
Offs, KeepCnt, KeepBelow: Int64;
|
||||||
|
begin
|
||||||
|
ChildCount := 0;
|
||||||
|
ResData := AWatchValue.ResultData;
|
||||||
|
if (ResData = nil) then
|
||||||
|
exit;
|
||||||
|
|
||||||
|
TotalCount := ResData.ArrayLength;
|
||||||
|
if (ResData.ValueKind <> rdkArray) or (TotalCount = 0) then
|
||||||
|
TotalCount := ResData.Count;
|
||||||
|
|
||||||
|
AWatch := AWatchValue.Watch;
|
||||||
|
ExistingNode := tvWatches.GetFirstChildNoInit(VNode);
|
||||||
|
if ExistingNode = nil then
|
||||||
|
ExistingNode := tvWatches.AddChild(VNode, nil)
|
||||||
|
else
|
||||||
|
tvWatches.NodeItem[ExistingNode] := nil;
|
||||||
|
|
||||||
|
Nav := TArrayNavigationBar(tvWatches.NodeControl[ExistingNode]);
|
||||||
|
if Nav = nil then begin
|
||||||
|
Nav := TArrayNavigationBar.Create(Self);
|
||||||
|
Nav.ParentColor := False;
|
||||||
|
Nav.ParentBackground := False;
|
||||||
|
Nav.Color := tvWatches.Colors.BackGroundColor;
|
||||||
|
Nav.LowBound := ResData.LowBound;
|
||||||
|
Nav.HighBound := ResData.LowBound + TotalCount - 1;
|
||||||
|
Nav.ShowBoundInfo := True;
|
||||||
|
Nav.Index := ResData.LowBound;
|
||||||
|
Nav.PageSize := 10;
|
||||||
|
Nav.OwnerData := AWatch;
|
||||||
|
Nav.OnIndexChanged := @WatchNavChanged;
|
||||||
|
Nav.OnPageSize := @WatchNavChanged;
|
||||||
|
tvWatches.NodeControl[ExistingNode] := Nav;
|
||||||
|
tvWatches.NodeText[ExistingNode, 0] := ' ';
|
||||||
|
tvWatches.NodeText[ExistingNode, 1] := ' ';
|
||||||
|
end;
|
||||||
|
ChildCount := Nav.LimitedPageSize;
|
||||||
|
|
||||||
|
ExistingNode := tvWatches.GetNextSiblingNoInit(ExistingNode);
|
||||||
|
|
||||||
|
Offs := Nav.Index;
|
||||||
|
for i := 0 to ChildCount do begin
|
||||||
|
Idx := IntToStr(Offs + i);
|
||||||
|
|
||||||
|
NewWatch := AWatch.ChildrenByName[Idx];
|
||||||
|
if NewWatch = nil then begin
|
||||||
|
dec(ChildCount);
|
||||||
|
continue;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if AWatch is TCurrentWatch then begin
|
||||||
|
NewWatch.DisplayFormat := wdfDefault;
|
||||||
|
NewWatch.Enabled := AWatch.Enabled;
|
||||||
|
if EnvironmentOptions.DebuggerAutoSetInstanceFromClass then
|
||||||
|
NewWatch.EvaluateFlags := [defClassAutoCast];
|
||||||
|
end;
|
||||||
|
|
||||||
|
if ExistingNode <> nil then begin
|
||||||
|
tvWatches.NodeItem[ExistingNode] := NewWatch;
|
||||||
|
nd := ExistingNode;
|
||||||
|
ExistingNode := tvWatches.GetNextSiblingNoInit(ExistingNode);
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
nd := tvWatches.AddChild(VNode, NewWatch);
|
||||||
|
end;
|
||||||
|
UpdateItem(nd, NewWatch);
|
||||||
|
end;
|
||||||
|
|
||||||
|
if AWatch is TCurrentWatch then begin
|
||||||
|
KeepCnt := Nav.PageSize;
|
||||||
|
KeepBelow := KeepCnt;
|
||||||
|
KeepCnt := Max(Max(50, KeepCnt+10),
|
||||||
|
Min(KeepCnt*10, 500) );
|
||||||
|
KeepBelow := Min(KeepBelow, KeepCnt - Nav.PageSize);
|
||||||
|
AWatch.LimitChildWatchCount(KeepCnt, ResData.LowBound + KeepBelow);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TWatchesDlg.UpdateSubItems(const VNode: PVirtualNode;
|
procedure TWatchesDlg.UpdateSubItems(const VNode: PVirtualNode;
|
||||||
const AWatchValue: TIdeWatchValue; out ChildCount: LongWord);
|
const AWatchValue: TIdeWatchValue; out ChildCount: LongWord);
|
||||||
var
|
var
|
||||||
@ -1112,6 +1235,8 @@ begin
|
|||||||
ChildCount := ResData.FieldCount;
|
ChildCount := ResData.FieldCount;
|
||||||
AWatch := AWatchValue.Watch;
|
AWatch := AWatchValue.Watch;
|
||||||
ExistingNode := tvWatches.GetFirstChildNoInit(VNode);
|
ExistingNode := tvWatches.GetFirstChildNoInit(VNode);
|
||||||
|
if ExistingNode <> nil then
|
||||||
|
tvWatches.NodeControl[ExistingNode].Free;
|
||||||
|
|
||||||
for i := 0 to ResData.FieldCount-1 do begin
|
for i := 0 to ResData.FieldCount-1 do begin
|
||||||
ChildInfo := ResData.Fields[i];
|
ChildInfo := ResData.Fields[i];
|
||||||
@ -1141,6 +1266,13 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
end
|
end
|
||||||
|
else
|
||||||
|
if (AWatchValue.ResultData <> nil) and
|
||||||
|
(AWatchValue.ResultData.ValueKind = rdkArray) and
|
||||||
|
(AWatchValue.ResultData.ArrayLength > 0)
|
||||||
|
then begin
|
||||||
|
UpdateArraySubItems(VNode, AWatchValue, ChildCount);
|
||||||
|
end
|
||||||
else begin
|
else begin
|
||||||
// Old Interface
|
// Old Interface
|
||||||
TypInfo := AWatchValue.TypeInfo;
|
TypInfo := AWatchValue.TypeInfo;
|
||||||
@ -1258,6 +1390,17 @@ begin
|
|||||||
then Result := SnapshotManager.SelectedEntry;
|
then Result := SnapshotManager.SelectedEntry;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TWatchesDlg.IsShortcut(var Message: TLMKey): Boolean;
|
||||||
|
begin
|
||||||
|
Result := false;
|
||||||
|
if (ActiveControl <> nil) and (
|
||||||
|
(ActiveControl is TCustomEdit) or (ActiveControl is TCustomSpinEditEx)
|
||||||
|
)
|
||||||
|
then
|
||||||
|
exit;
|
||||||
|
Result := inherited IsShortcut(Message);
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TWatchesDlg.WatchAdd(const ASender: TIdeWatches; const AWatch: TIdeWatch);
|
procedure TWatchesDlg.WatchAdd(const ASender: TIdeWatches; const AWatch: TIdeWatch);
|
||||||
var
|
var
|
||||||
VNode: PVirtualNode;
|
VNode: PVirtualNode;
|
||||||
|
@ -107,4 +107,13 @@ object ArrayNavigationBar: TArrayNavigationBar
|
|||||||
Flat = True
|
Flat = True
|
||||||
OnClick = BtnChangeSizeClicked
|
OnClick = BtnChangeSizeClicked
|
||||||
end
|
end
|
||||||
|
object lblBounds: TLabel
|
||||||
|
Left = 252
|
||||||
|
Height = 26
|
||||||
|
Top = 0
|
||||||
|
Width = 1
|
||||||
|
Align = alLeft
|
||||||
|
BorderSpacing.Left = 10
|
||||||
|
Visible = False
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -26,6 +26,7 @@ type
|
|||||||
edArrayPageSize: TSpinEditEx;
|
edArrayPageSize: TSpinEditEx;
|
||||||
edArrayStart: TSpinEditEx;
|
edArrayStart: TSpinEditEx;
|
||||||
Label1: TLabel;
|
Label1: TLabel;
|
||||||
|
lblBounds: TLabel;
|
||||||
procedure BtnChangePageClicked(Sender: TObject);
|
procedure BtnChangePageClicked(Sender: TObject);
|
||||||
procedure BtnChangeSizeClicked(Sender: TObject);
|
procedure BtnChangeSizeClicked(Sender: TObject);
|
||||||
procedure edArrayPageSizeEditingDone(Sender: TObject);
|
procedure edArrayPageSizeEditingDone(Sender: TObject);
|
||||||
@ -35,19 +36,31 @@ type
|
|||||||
FLowBound: int64;
|
FLowBound: int64;
|
||||||
FOnIndexChanged: TArrayNavChangeEvent;
|
FOnIndexChanged: TArrayNavChangeEvent;
|
||||||
FOnPageSize: TArrayNavChangeEvent;
|
FOnPageSize: TArrayNavChangeEvent;
|
||||||
|
FOwnerData: pointer;
|
||||||
|
FShowBoundInfo: Boolean;
|
||||||
function GetIndex: int64;
|
function GetIndex: int64;
|
||||||
|
function GetIndexOffs: int64;
|
||||||
|
function GetLimitedPageSize: int64;
|
||||||
function GetPageSize: int64;
|
function GetPageSize: int64;
|
||||||
procedure SetHighBound(AValue: int64);
|
procedure SetHighBound(AValue: int64);
|
||||||
procedure SetIndex(AValue: int64);
|
procedure SetIndex(AValue: int64);
|
||||||
procedure SetLowBound(AValue: int64);
|
procedure SetLowBound(AValue: int64);
|
||||||
procedure SetPageSize(AValue: int64);
|
procedure SetPageSize(AValue: int64);
|
||||||
|
procedure Loaded; override;
|
||||||
|
procedure SetShowBoundInfo(AValue: Boolean);
|
||||||
|
procedure UpdateBoundsInfo;
|
||||||
public
|
public
|
||||||
constructor Create(TheOwner: TComponent); override;
|
constructor Create(TheOwner: TComponent); override;
|
||||||
property LowBound: int64 read FLowBound write SetLowBound;
|
property LowBound: int64 read FLowBound write SetLowBound;
|
||||||
property HighBound: int64 read FHighBound write SetHighBound;
|
property HighBound: int64 read FHighBound write SetHighBound;
|
||||||
|
property ShowBoundInfo: Boolean read FShowBoundInfo write SetShowBoundInfo;
|
||||||
|
|
||||||
property Index: int64 read GetIndex write SetIndex;
|
property Index: int64 read GetIndex write SetIndex;
|
||||||
property PageSize: int64 read GetPageSize write SetPageSize;
|
property PageSize: int64 read GetPageSize write SetPageSize;
|
||||||
|
property IndexOffs: int64 read GetIndexOffs;
|
||||||
|
property LimitedPageSize: int64 read GetLimitedPageSize;
|
||||||
|
|
||||||
|
property OwnerData: pointer read FOwnerData write FOwnerData;
|
||||||
published
|
published
|
||||||
property OnIndexChanged: TArrayNavChangeEvent read FOnIndexChanged write FOnIndexChanged;
|
property OnIndexChanged: TArrayNavChangeEvent read FOnIndexChanged write FOnIndexChanged;
|
||||||
property OnPageSize: TArrayNavChangeEvent read FOnPageSize write FOnPageSize;
|
property OnPageSize: TArrayNavChangeEvent read FOnPageSize write FOnPageSize;
|
||||||
@ -63,6 +76,7 @@ procedure TArrayNavigationBar.SetHighBound(AValue: int64);
|
|||||||
begin
|
begin
|
||||||
if FHighBound = AValue then Exit;
|
if FHighBound = AValue then Exit;
|
||||||
FHighBound := AValue;
|
FHighBound := AValue;
|
||||||
|
UpdateBoundsInfo;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TArrayNavigationBar.BtnChangePageClicked(Sender: TObject);
|
procedure TArrayNavigationBar.BtnChangePageClicked(Sender: TObject);
|
||||||
@ -123,6 +137,21 @@ begin
|
|||||||
Result := edArrayStart.Value;
|
Result := edArrayStart.Value;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TArrayNavigationBar.GetIndexOffs: int64;
|
||||||
|
begin
|
||||||
|
Result := edArrayStart.Value - FLowBound;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TArrayNavigationBar.GetLimitedPageSize: int64;
|
||||||
|
var
|
||||||
|
idx: Int64;
|
||||||
|
begin
|
||||||
|
Result := edArrayPageSize.Value;
|
||||||
|
idx := edArrayStart.Value;
|
||||||
|
if (idx >= FLowBound) and (idx < FHighBound) then
|
||||||
|
Result := Max(1, Min(Result, FHighBound + 1 - idx));
|
||||||
|
end;
|
||||||
|
|
||||||
function TArrayNavigationBar.GetPageSize: int64;
|
function TArrayNavigationBar.GetPageSize: int64;
|
||||||
begin
|
begin
|
||||||
Result := edArrayPageSize.Value;
|
Result := edArrayPageSize.Value;
|
||||||
@ -137,6 +166,7 @@ procedure TArrayNavigationBar.SetLowBound(AValue: int64);
|
|||||||
begin
|
begin
|
||||||
if FLowBound = AValue then Exit;
|
if FLowBound = AValue then Exit;
|
||||||
FLowBound := AValue;
|
FLowBound := AValue;
|
||||||
|
UpdateBoundsInfo;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TArrayNavigationBar.SetPageSize(AValue: int64);
|
procedure TArrayNavigationBar.SetPageSize(AValue: int64);
|
||||||
@ -144,9 +174,34 @@ begin
|
|||||||
edArrayPageSize.Value := AValue;
|
edArrayPageSize.Value := AValue;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TArrayNavigationBar.Loaded;
|
||||||
|
begin
|
||||||
|
inherited Loaded;
|
||||||
|
Constraints.MinWidth := btnArrayPageInc.Left + btnArrayPageInc.Width;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TArrayNavigationBar.SetShowBoundInfo(AValue: Boolean);
|
||||||
|
begin
|
||||||
|
if FShowBoundInfo = AValue then Exit;
|
||||||
|
FShowBoundInfo := AValue;
|
||||||
|
|
||||||
|
UpdateBoundsInfo;
|
||||||
|
lblBounds.Visible := FShowBoundInfo;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TArrayNavigationBar.UpdateBoundsInfo;
|
||||||
|
begin
|
||||||
|
if not FShowBoundInfo then
|
||||||
|
exit;
|
||||||
|
|
||||||
|
lblBounds.Caption := format(dlgInspectBoundsDD, [FLowBound, FHighBound]);
|
||||||
|
end;
|
||||||
|
|
||||||
constructor TArrayNavigationBar.Create(TheOwner: TComponent);
|
constructor TArrayNavigationBar.Create(TheOwner: TComponent);
|
||||||
begin
|
begin
|
||||||
inherited Create(TheOwner);
|
inherited Create(TheOwner);
|
||||||
|
Name := '';
|
||||||
|
Constraints.MinWidth := btnArrayPageInc.Left + btnArrayPageInc.Width;
|
||||||
|
|
||||||
edArrayStart.Hint := dlgInspectIndexOfFirstItemToShow;
|
edArrayStart.Hint := dlgInspectIndexOfFirstItemToShow;
|
||||||
edArrayPageSize.Hint := dlgInspectAmountOfItemsToShow;
|
edArrayPageSize.Hint := dlgInspectAmountOfItemsToShow;
|
||||||
|
@ -609,6 +609,7 @@ type
|
|||||||
|
|
||||||
procedure BeginChildUpdate;
|
procedure BeginChildUpdate;
|
||||||
procedure EndChildUpdate;
|
procedure EndChildUpdate;
|
||||||
|
procedure LimitChildWatchCount(AMaxCnt: Integer; AKeepIndexEntriesBelow: Int64 = low(Int64));
|
||||||
property ChildrenByName[AName: String]: TIdeWatch read GetChildrenByName;
|
property ChildrenByName[AName: String]: TIdeWatch read GetChildrenByName;
|
||||||
function HasAllValidParents(AThreadId: Integer; AStackFrame: Integer): boolean;
|
function HasAllValidParents(AThreadId: Integer; AStackFrame: Integer): boolean;
|
||||||
property ParentWatch: TIdeWatch read FParentWatch;
|
property ParentWatch: TIdeWatch read FParentWatch;
|
||||||
@ -6230,6 +6231,23 @@ begin
|
|||||||
FChildWatches.EndUpdate;
|
FChildWatches.EndUpdate;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TIdeWatch.LimitChildWatchCount(AMaxCnt: Integer;
|
||||||
|
AKeepIndexEntriesBelow: Int64);
|
||||||
|
var
|
||||||
|
w: TIdeWatch;
|
||||||
|
x: int64;
|
||||||
|
i: Integer;
|
||||||
|
begin
|
||||||
|
i := 0;
|
||||||
|
while (FChildWatches.Count > AMaxCnt) and (i < FChildWatches.Count) do begin
|
||||||
|
w := FChildWatches[i];
|
||||||
|
if TryStrToInt64(w.Expression, x) and (x < AKeepIndexEntriesBelow) then
|
||||||
|
inc(i)
|
||||||
|
else
|
||||||
|
FChildWatches.Delete(0);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
function TIdeWatch.HasAllValidParents(AThreadId: Integer; AStackFrame: Integer
|
function TIdeWatch.HasAllValidParents(AThreadId: Integer; AStackFrame: Integer
|
||||||
): boolean;
|
): boolean;
|
||||||
begin
|
begin
|
||||||
@ -6266,7 +6284,10 @@ var
|
|||||||
begin
|
begin
|
||||||
Result := Expression;
|
Result := Expression;
|
||||||
if FParentWatch <> nil then begin
|
if FParentWatch <> nil then begin
|
||||||
Result := '(' + FParentWatch.GetFullExpression(AThreadId, AStackFrame) + ').' + Result;
|
if (Result <> '') and (Result[1] in ['0'..'9']) then
|
||||||
|
Result := '(' + FParentWatch.GetFullExpression(AThreadId, AStackFrame) + ')[' + Result+']'
|
||||||
|
else
|
||||||
|
Result := '(' + FParentWatch.GetFullExpression(AThreadId, AStackFrame) + ').' + Result;
|
||||||
if (defClassAutoCast in FParentWatch.FEvaluateFlags) then begin
|
if (defClassAutoCast in FParentWatch.FEvaluateFlags) then begin
|
||||||
wv := GetAnyValidParentWatchValue(AThreadId, AStackFrame);
|
wv := GetAnyValidParentWatchValue(AThreadId, AStackFrame);
|
||||||
if wv.ResultData <> nil then
|
if wv.ResultData <> nil then
|
||||||
@ -6463,7 +6484,14 @@ end;
|
|||||||
destructor TCurrentWatch.Destroy;
|
destructor TCurrentWatch.Destroy;
|
||||||
var
|
var
|
||||||
w: TCurrentWatches;
|
w: TCurrentWatches;
|
||||||
|
s: TIdeWatch;
|
||||||
begin
|
begin
|
||||||
|
if FSnapShot <> nil then begin
|
||||||
|
s := FSnapShot;
|
||||||
|
SnapShot := Nil;
|
||||||
|
FreeAndNil(s);
|
||||||
|
end;
|
||||||
|
|
||||||
if (TCurrentWatches(Collection) <> nil)
|
if (TCurrentWatches(Collection) <> nil)
|
||||||
then begin
|
then begin
|
||||||
TCurrentWatches(Collection).NotifyRemove(Self);
|
TCurrentWatches(Collection).NotifyRemove(Self);
|
||||||
|
@ -5,13 +5,14 @@ unit DebuggerTreeView;
|
|||||||
interface
|
interface
|
||||||
|
|
||||||
uses
|
uses
|
||||||
Classes, SysUtils, laz.VirtualTrees, LMessages;
|
Classes, SysUtils, laz.VirtualTrees, SpinEx, LMessages, Controls;
|
||||||
|
|
||||||
type
|
type
|
||||||
|
|
||||||
TDbgTreeNodeData = record
|
TDbgTreeNodeData = record
|
||||||
Item: TObject;
|
Item: TObject; // Must be the first field. Node.AddChild will write the new "Item" at UserData^ (aka the memory at the start of UserData)
|
||||||
CachedText: Array of String;
|
CachedText: Array of String;
|
||||||
|
Control: TControl;
|
||||||
end;
|
end;
|
||||||
PDbgTreeNodeData = ^TDbgTreeNodeData;
|
PDbgTreeNodeData = ^TDbgTreeNodeData;
|
||||||
|
|
||||||
@ -19,11 +20,14 @@ type
|
|||||||
|
|
||||||
TDbgTreeView = class(TLazVirtualStringTree)
|
TDbgTreeView = class(TLazVirtualStringTree)
|
||||||
private
|
private
|
||||||
|
function GetNodeControl(Node: PVirtualNode): TControl;
|
||||||
function GetNodeItem(Node: PVirtualNode): TObject;
|
function GetNodeItem(Node: PVirtualNode): TObject;
|
||||||
function GetNodeText(Node: PVirtualNode; AColumn: integer): String;
|
function GetNodeText(Node: PVirtualNode; AColumn: integer): String;
|
||||||
|
procedure SetNodeControl(Node: PVirtualNode; AValue: TControl);
|
||||||
procedure SetNodeItem(Node: PVirtualNode; AValue: TObject);
|
procedure SetNodeItem(Node: PVirtualNode; AValue: TObject);
|
||||||
procedure SetNodeText(Node: PVirtualNode; AColumn: integer; AValue: String);
|
procedure SetNodeText(Node: PVirtualNode; AColumn: integer; AValue: String);
|
||||||
protected
|
protected
|
||||||
|
function DoCollapsing(Node: PVirtualNode): Boolean; override;
|
||||||
procedure ValidateNodeDataSize(var Size: Integer); override;
|
procedure ValidateNodeDataSize(var Size: Integer); override;
|
||||||
procedure DoFreeNode(Node: PVirtualNode); override;
|
procedure DoFreeNode(Node: PVirtualNode); override;
|
||||||
function DetermineLineImageAndSelectLevel(Node: PVirtualNode;
|
function DetermineLineImageAndSelectLevel(Node: PVirtualNode;
|
||||||
@ -31,6 +35,7 @@ type
|
|||||||
procedure HandleMouseDblClick(var Message: TLMMouse; const HitInfo: THitInfo); override;
|
procedure HandleMouseDblClick(var Message: TLMMouse; const HitInfo: THitInfo); override;
|
||||||
procedure DoGetText(Node: PVirtualNode; Column: TColumnIndex;
|
procedure DoGetText(Node: PVirtualNode; Column: TColumnIndex;
|
||||||
TextType: TVSTTextType; var AText: String); override;
|
TextType: TVSTTextType; var AText: String); override;
|
||||||
|
procedure DoPaintNode(var PaintInfo: TVTPaintInfo); override;
|
||||||
public
|
public
|
||||||
function GetNodeData(Node: PVirtualNode): PDbgTreeNodeData; reintroduce;
|
function GetNodeData(Node: PVirtualNode): PDbgTreeNodeData; reintroduce;
|
||||||
|
|
||||||
@ -44,12 +49,23 @@ type
|
|||||||
|
|
||||||
property NodeItem[Node: PVirtualNode]: TObject read GetNodeItem write SetNodeItem;
|
property NodeItem[Node: PVirtualNode]: TObject read GetNodeItem write SetNodeItem;
|
||||||
property NodeText[Node: PVirtualNode; AColumn: integer]: String read GetNodeText write SetNodeText;
|
property NodeText[Node: PVirtualNode; AColumn: integer]: String read GetNodeText write SetNodeText;
|
||||||
|
property NodeControl[Node: PVirtualNode]: TControl read GetNodeControl write SetNodeControl;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
{ TDbgTreeView }
|
{ 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.GetNodeItem(Node: PVirtualNode): TObject;
|
function TDbgTreeView.GetNodeItem(Node: PVirtualNode): TObject;
|
||||||
var
|
var
|
||||||
Data: PDbgTreeNodeData;
|
Data: PDbgTreeNodeData;
|
||||||
@ -70,6 +86,25 @@ begin
|
|||||||
Result := Data^.CachedText[AColumn];
|
Result := Data^.CachedText[AColumn];
|
||||||
end;
|
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;
|
||||||
|
Data^.Control := AValue;
|
||||||
|
if AValue <> nil then begin
|
||||||
|
AValue.Visible := False;
|
||||||
|
AValue.Parent := Self;
|
||||||
|
AValue.AutoSize := False;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TDbgTreeView.SetNodeItem(Node: PVirtualNode; AValue: TObject);
|
procedure TDbgTreeView.SetNodeItem(Node: PVirtualNode; AValue: TObject);
|
||||||
var
|
var
|
||||||
Data: PDbgTreeNodeData;
|
Data: PDbgTreeNodeData;
|
||||||
@ -92,6 +127,33 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TDbgTreeView.DoCollapsing(Node: PVirtualNode): Boolean;
|
||||||
|
procedure RecursivelyHideControls(N: PVirtualNode);
|
||||||
|
var
|
||||||
|
N2: PVirtualNode;
|
||||||
|
NData: PDbgTreeNodeData;
|
||||||
|
begin
|
||||||
|
NData := GetNodeData(N);
|
||||||
|
if NData^.Control <> nil then
|
||||||
|
NData^.Control.Visible := False;
|
||||||
|
|
||||||
|
while N <> nil do begin
|
||||||
|
N2 := GetFirstChildNoInit(N);
|
||||||
|
if N2 <> nil then
|
||||||
|
RecursivelyHideControls(N2);
|
||||||
|
N := GetNextSiblingNoInit(N);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
var
|
||||||
|
n: PVirtualNode;
|
||||||
|
begin
|
||||||
|
n := GetFirstChildNoInit(Node);
|
||||||
|
if n <> nil then
|
||||||
|
RecursivelyHideControls(n);
|
||||||
|
|
||||||
|
Result := inherited DoCollapsing(Node);
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TDbgTreeView.ValidateNodeDataSize(var Size: Integer);
|
procedure TDbgTreeView.ValidateNodeDataSize(var Size: Integer);
|
||||||
begin
|
begin
|
||||||
Size := SizeOf(TDbgTreeNodeData);
|
Size := SizeOf(TDbgTreeNodeData);
|
||||||
@ -99,6 +161,7 @@ end;
|
|||||||
|
|
||||||
procedure TDbgTreeView.DoFreeNode(Node: PVirtualNode);
|
procedure TDbgTreeView.DoFreeNode(Node: PVirtualNode);
|
||||||
begin
|
begin
|
||||||
|
PDbgTreeNodeData(GetNodeData(Node))^.Control.Free;
|
||||||
PDbgTreeNodeData(GetNodeData(Node))^ := Default(TDbgTreeNodeData);
|
PDbgTreeNodeData(GetNodeData(Node))^ := Default(TDbgTreeNodeData);
|
||||||
inherited DoFreeNode(Node);
|
inherited DoFreeNode(Node);
|
||||||
end;
|
end;
|
||||||
@ -134,6 +197,29 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TDbgTreeView.DoPaintNode(var PaintInfo: TVTPaintInfo);
|
||||||
|
var
|
||||||
|
NData: PDbgTreeNodeData;
|
||||||
|
r: TRect;
|
||||||
|
begin
|
||||||
|
NData := GetNodeData(PaintInfo.Node);
|
||||||
|
if NData^.Control <> nil then begin
|
||||||
|
if PaintInfo.Column = 0 then begin
|
||||||
|
r := GetDisplayRect(PaintInfo.Node, 0, True, False);
|
||||||
|
r.Right := ClientWidth - r.Left - 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;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
inherited DoPaintNode(PaintInfo);
|
||||||
|
end;
|
||||||
|
|
||||||
function TDbgTreeView.GetNodeData(Node: PVirtualNode): PDbgTreeNodeData;
|
function TDbgTreeView.GetNodeData(Node: PVirtualNode): PDbgTreeNodeData;
|
||||||
begin
|
begin
|
||||||
Result := PDbgTreeNodeData(inherited GetNodeData(Node));
|
Result := PDbgTreeNodeData(inherited GetNodeData(Node));
|
||||||
|
@ -10,6 +10,7 @@ interface
|
|||||||
resourcestring
|
resourcestring
|
||||||
dlgInspectIndexOfFirstItemToShow = 'Index of first item to show';
|
dlgInspectIndexOfFirstItemToShow = 'Index of first item to show';
|
||||||
dlgInspectAmountOfItemsToShow = 'Amount of items to show';
|
dlgInspectAmountOfItemsToShow = 'Amount of items to show';
|
||||||
|
dlgInspectBoundsDD = 'Bounds: %d .. %d';
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user