mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-27 19:13:52 +02:00
5019 lines
152 KiB
ObjectPascal
5019 lines
152 KiB
ObjectPascal
{ $Id: objectinspector.pp 17395 2008-11-15 03:53:22Z paul $}
|
|
{
|
|
*****************************************************************************
|
|
* *
|
|
* See the file COPYING.modifiedLGPL.txt, included in this distribution, *
|
|
* for details about the copyright. *
|
|
* *
|
|
* This program is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
|
|
* *
|
|
*****************************************************************************
|
|
|
|
Author: Mattias Gaertner
|
|
|
|
Abstract:
|
|
This unit defines the TObjectInspectorDlg.
|
|
It uses TOIPropertyGrid and TOIPropertyGridRow which are also defined in this
|
|
unit. The object inspector uses property editors (see TPropertyEditor) to
|
|
display and control properties, thus the object inspector is merely an
|
|
object viewer than an editor. The property editors do the real work.
|
|
|
|
|
|
ToDo:
|
|
- backgroundcolor=clNone
|
|
- Define Init values
|
|
- Set to init value
|
|
}
|
|
unit ObjectInspector;
|
|
|
|
{$MODE OBJFPC}{$H+}
|
|
|
|
{off $DEFINE DoNotCatchOIExceptions}
|
|
|
|
interface
|
|
|
|
uses
|
|
// IMPORTANT: the object inspector is a tool and can be used in other programs
|
|
// too. Don't put Lazarus IDE specific things here.
|
|
// FCL
|
|
SysUtils, Types, Classes, TypInfo,
|
|
// LCL
|
|
InterfaceBase, Forms, Buttons, Graphics, GraphType, LCLProc,
|
|
StdCtrls, LCLType, LCLIntf, Controls, ComCtrls, ExtCtrls,
|
|
LMessages, LResources, LazConfigStorage, Menus, Dialogs, Themes,
|
|
ObjInspStrConsts,
|
|
PropEdits, GraphPropEdits, ListViewPropEdit, ImageListEditor,
|
|
ComponentTreeView, ComponentEditors, IDEImagesIntf, OIFavouriteProperties;
|
|
|
|
const
|
|
OIOptionsFileVersion = 3;
|
|
|
|
DefBackgroundColor = clBtnFace;
|
|
DefReferencesColor = clMaroon;
|
|
DefSubPropertiesColor = clGreen;
|
|
DefNameColor = clWindowText;
|
|
DefDefaultValueColor = clWindowText;
|
|
DefValueColor = clMaroon;
|
|
DefReadOnlyColor = clGrayText;
|
|
DefHighlightColor = clHighlight;
|
|
DefHighlightFontColor = clHighlightText;
|
|
DefGutterColor = DefBackgroundColor;
|
|
DefGutterEdgeColor = cl3DShadow;
|
|
|
|
type
|
|
EObjectInspectorException = class(Exception);
|
|
|
|
TObjectInspectorDlg = class;
|
|
TOICustomPropertyGrid = class;
|
|
|
|
// standard ObjectInspector pages
|
|
TObjectInspectorPage = (
|
|
oipgpProperties,
|
|
oipgpEvents,
|
|
oipgpFavourite,
|
|
oipgpRestricted
|
|
);
|
|
TObjectInspectorPages = set of TObjectInspectorPage;
|
|
|
|
|
|
{ TOIOptions }
|
|
|
|
TOIOptions = class
|
|
private
|
|
FComponentTreeHeight: integer;
|
|
FConfigStore: TConfigStorage;
|
|
FDefaultItemHeight: integer;
|
|
FGutterColor: TColor;
|
|
FGutterEdgeColor: TColor;
|
|
FShowComponentTree: boolean;
|
|
|
|
FSaveBounds: boolean;
|
|
FLeft: integer;
|
|
FShowGutter: boolean;
|
|
FShowInfoBox: boolean;
|
|
FShowStatusBar: boolean;
|
|
FTop: integer;
|
|
FWidth: integer;
|
|
FHeight: integer;
|
|
FGridSplitterX: array[TObjectInspectorPage] of integer;
|
|
|
|
FPropertyNameColor: TColor;
|
|
FDefaultValueColor: TColor;
|
|
FSubPropertiesColor: TColor;
|
|
FValueColor: TColor;
|
|
FReadOnlyColor: TColor;
|
|
FReferencesColor: TColor;
|
|
FGridBackgroundColor: TColor;
|
|
FHighlightColor: TColor;
|
|
FHighlightFontColor: TColor;
|
|
|
|
FShowHints: boolean;
|
|
FAutoShow: Boolean;
|
|
FBoldNonDefaultValues: Boolean;
|
|
FDrawGridLines: Boolean;
|
|
function FPropertyGridSplitterX(Page: TObjectInspectorPage): integer;
|
|
procedure FPropertyGridSplitterX(Page: TObjectInspectorPage;
|
|
const AValue: integer);
|
|
public
|
|
constructor Create;
|
|
function Load: boolean;
|
|
function Save: boolean;
|
|
procedure Assign(AnObjInspector: TObjectInspectorDlg);
|
|
procedure AssignTo(AnObjInspector: TObjectInspectorDlg); overload;
|
|
procedure AssignTo(AGrid: TOICustomPropertyGrid); overload;
|
|
|
|
property ConfigStore: TConfigStorage read FConfigStore write FConfigStore;
|
|
|
|
property SaveBounds:boolean read FSaveBounds write FSaveBounds;
|
|
property Left:integer read FLeft write FLeft;
|
|
property Top:integer read FTop write FTop;
|
|
property Width:integer read FWidth write FWidth;
|
|
property Height:integer read FHeight write FHeight;
|
|
property GridSplitterX[Page: TObjectInspectorPage]:integer
|
|
read FPropertyGridSplitterX write FPropertyGridSplitterX;
|
|
property DefaultItemHeight: integer read FDefaultItemHeight
|
|
write FDefaultItemHeight;
|
|
property ShowComponentTree: boolean read FShowComponentTree
|
|
write FShowComponentTree;
|
|
property ComponentTreeHeight: integer read FComponentTreeHeight
|
|
write FComponentTreeHeight;
|
|
|
|
property GridBackgroundColor: TColor read FGridBackgroundColor write FGridBackgroundColor;
|
|
property SubPropertiesColor: TColor read FSubPropertiesColor write FSubPropertiesColor;
|
|
property ReferencesColor: TColor read FReferencesColor write FReferencesColor;
|
|
property ValueColor: TColor read FValueColor write FValueColor;
|
|
property ReadOnlyColor: TColor read FReadOnlyColor write FReadOnlyColor;
|
|
property DefaultValueColor: TColor read FDefaultValueColor write FDefaultValueColor;
|
|
property PropertyNameColor: TColor read FPropertyNameColor write FPropertyNameColor;
|
|
property HighlightColor: TColor read FHighlightColor write FHighlightColor;
|
|
property HighlightFontColor: TColor read FHighlightFontColor write FHighlightFontColor;
|
|
property GutterColor: TColor read FGutterColor write FGutterColor;
|
|
property GutterEdgeColor: TColor read FGutterEdgeColor write FGutterEdgeColor;
|
|
|
|
property ShowHints: boolean read FShowHints
|
|
write FShowHints;
|
|
property AutoShow: boolean read FAutoShow write FAutoShow;
|
|
property BoldNonDefaultValues: boolean read FBoldNonDefaultValues write FBoldNonDefaultValues;
|
|
property DrawGridLines: boolean read FDrawGridLines write FDrawGridLines;
|
|
property ShowGutter: boolean read FShowGutter write FShowGutter;
|
|
property ShowStatusBar: boolean read FShowStatusBar write FShowStatusBar;
|
|
property ShowInfoBox: boolean read FShowInfoBox write FShowInfoBox;
|
|
end;
|
|
|
|
{ TOIPropertyGridRow }
|
|
|
|
TOIPropertyGridRow = class
|
|
private
|
|
FTop:integer;
|
|
FHeight:integer;
|
|
FLvl:integer;
|
|
FName:string;
|
|
FExpanded: boolean;
|
|
FTree:TOICustomPropertyGrid;
|
|
FChildCount:integer;
|
|
FPriorBrother,
|
|
FFirstChild,
|
|
FLastChild,
|
|
FNextBrother,
|
|
FParent: TOIPropertyGridRow;
|
|
FEditor: TPropertyEditor;
|
|
FWidgetSets: TLCLPlatforms;
|
|
|
|
FIndex:integer;
|
|
LastPaintedValue: string;
|
|
|
|
procedure GetLvl;
|
|
public
|
|
constructor Create(PropertyTree: TOICustomPropertyGrid;
|
|
PropEditor:TPropertyEditor; ParentNode:TOIPropertyGridRow; WidgetSets: TLCLPlatforms);
|
|
destructor Destroy; override;
|
|
function ConsistencyCheck: integer;
|
|
function HasChild(Row: TOIPropertyGridRow): boolean;
|
|
procedure WriteDebugReport(const Prefix: string);
|
|
|
|
function GetBottom: integer;
|
|
function IsReadOnly: boolean;
|
|
function IsDisabled: boolean;
|
|
procedure MeasureHeight(ACanvas: TCanvas);
|
|
function Sort(const Compare: TListSortCompare): boolean;// true if changed
|
|
function IsSorted(const Compare: TListSortCompare): boolean;
|
|
function Next: TOIPropertyGridRow;
|
|
function NextSkipChilds: TOIPropertyGridRow;
|
|
|
|
property Editor:TPropertyEditor read FEditor;
|
|
property Top:integer read FTop write FTop;
|
|
property Height:integer read FHeight write FHeight;
|
|
property Bottom: integer read GetBottom;
|
|
property Lvl:integer read FLvl;
|
|
property Name: string read FName;
|
|
property Expanded:boolean read FExpanded;
|
|
property Tree:TOICustomPropertyGrid read FTree;
|
|
property Parent:TOIPropertyGridRow read FParent;
|
|
property ChildCount:integer read FChildCount;
|
|
property FirstChild:TOIPropertyGridRow read FFirstChild;
|
|
property LastChild:TOIPropertyGridRow read FFirstChild;
|
|
property NextBrother:TOIPropertyGridRow read FNextBrother;
|
|
property PriorBrother:TOIPropertyGridRow read FPriorBrother;
|
|
property Index: integer read FIndex;
|
|
end;
|
|
|
|
//----------------------------------------------------------------------------
|
|
TOIPropertyGridState = (
|
|
pgsChangingItemIndex,
|
|
pgsApplyingValue,
|
|
pgsUpdatingEditControl,
|
|
pgsBuildPropertyListNeeded,
|
|
pgsGetComboItemsCalled,
|
|
pgsIdleEnabled
|
|
);
|
|
TOIPropertyGridStates = set of TOIPropertyGridState;
|
|
|
|
{ TOICustomPropertyGrid }
|
|
|
|
TOICustomPropertyGridColumn = (
|
|
oipgcName,
|
|
oipgcValue
|
|
);
|
|
|
|
TOILayout = (
|
|
oilHorizontal,
|
|
oilVertical
|
|
);
|
|
|
|
TOIQuickEdit = (
|
|
oiqeEdit,
|
|
oiqeShowValue
|
|
);
|
|
|
|
TOIPropertyHint = function(Sender: TObject; PointedRow: TOIPropertyGridRow;
|
|
ScreenPos: TPoint; aHintWindow: THintWindow;
|
|
out HintWinRect: TRect; out AHint: string
|
|
): boolean of object;
|
|
|
|
TOICustomPropertyGrid = class(TCustomControl)
|
|
private
|
|
FBackgroundColor: TColor;
|
|
FColumn: TOICustomPropertyGridColumn;
|
|
FGutterColor: TColor;
|
|
FGutterEdgeColor: TColor;
|
|
FHighlightColor: TColor;
|
|
FLayout: TOILayout;
|
|
FOnOIKeyDown: TKeyEvent;
|
|
FOnPropertyHint: TOIPropertyHint;
|
|
FOnSelectionChange: TNotifyEvent;
|
|
FReferencesColor: TColor;
|
|
FReadOnlyColor: TColor;
|
|
FRowSpacing: integer;
|
|
FShowGutter: Boolean;
|
|
FSubPropertiesColor: TColor;
|
|
FChangeStep: integer;
|
|
FCurrentButton: TControl; // nil or ValueButton
|
|
FCurrentEdit: TWinControl; // nil or ValueEdit or ValueComboBox or ValueCheckBox
|
|
FCurrentEditorLookupRoot: TPersistent;
|
|
FDefaultItemHeight:integer;
|
|
FDragging: boolean;
|
|
FExpandedProperties: TStringList;// used to restore expanded state when switching selected component(s)
|
|
FExpandingRow: TOIPropertyGridRow;
|
|
FFavourites: TOIFavouriteProperties;
|
|
FFilter: TTypeKinds;
|
|
FIndent: integer;
|
|
FItemIndex: integer;
|
|
FNameFont, FDefaultValueFont, FValueFont, FHighlightFont: TFont;
|
|
FNewComboBoxItems: TStringList;
|
|
FOnModified: TNotifyEvent;
|
|
FPreferredSplitterX: integer; // best splitter position
|
|
FPropertyEditorHook: TPropertyEditorHook;
|
|
FRows: TFPList;// list of TOIPropertyGridRow
|
|
FSelection: TPersistentSelectionList;
|
|
FNotificationComponents: TFPList;
|
|
FSplitterX: integer; // current splitter position
|
|
FStates: TOIPropertyGridStates;
|
|
FTopY: integer;
|
|
FDrawHorzGridLines: Boolean;
|
|
FActiveRowBmp: TCustomBitmap;
|
|
|
|
// hint stuff
|
|
FHintTimer: TTimer;
|
|
FHintWindow: THintWindow;
|
|
FHintIndex: integer;
|
|
FShowingLongHint: boolean; // last hint was activated by the hinttimer
|
|
|
|
ValueEdit: TEdit;
|
|
ValueComboBox: TComboBox;
|
|
ValueCheckBox: TCheckBox;
|
|
ValueButton: TSpeedButton;
|
|
|
|
procedure HintTimer(Sender: TObject);
|
|
procedure ResetHintTimer;
|
|
procedure HideHint;
|
|
procedure OnUserInput(Sender: TObject; Msg: Cardinal);
|
|
|
|
procedure IncreaseChangeStep;
|
|
function GridIsUpdating: boolean;
|
|
|
|
function GetRow(Index:integer):TOIPropertyGridRow;
|
|
function GetRowCount:integer;
|
|
procedure ClearRows;
|
|
function GetCurrentEditValue: string;
|
|
procedure SetActiveControl(const AControl: TWinControl);
|
|
procedure SetColumn(const AValue: TOICustomPropertyGridColumn);
|
|
procedure SetCurrentEditValue(const NewValue: string);
|
|
procedure SetDrawHorzGridLines(const AValue: Boolean);
|
|
procedure SetFavourites(const AValue: TOIFavouriteProperties);
|
|
procedure SetFilter(const AValue: TTypeKinds);
|
|
procedure SetGutterColor(const AValue: TColor);
|
|
procedure SetGutterEdgeColor(const AValue: TColor);
|
|
procedure SetHighlightColor(const AValue: TColor);
|
|
procedure SetItemIndex(NewIndex:integer);
|
|
function IsCurrentEditorAvailable: Boolean;
|
|
|
|
function GetNameRowHeight: Integer; // temp solution untill TFont.height returns its actual value
|
|
|
|
procedure SetItemsTops;
|
|
procedure AlignEditComponents;
|
|
procedure EndDragSplitter;
|
|
procedure SetRowSpacing(const AValue: integer);
|
|
procedure SetShowGutter(const AValue: Boolean);
|
|
procedure SetSplitterX(const NewValue:integer);
|
|
procedure SetTopY(const NewValue:integer);
|
|
|
|
function GetPropNameColor(ARow: TOIPropertyGridRow):TColor;
|
|
function GetTreeIconX(Index: integer):integer;
|
|
function RowRect(ARow: integer):TRect;
|
|
procedure PaintRow(ARow: integer);
|
|
procedure DoPaint(PaintOnlyChangedValues: boolean);
|
|
|
|
procedure SetSelection(const ASelection:TPersistentSelectionList);
|
|
procedure SetPropertyEditorHook(NewPropertyEditorHook:TPropertyEditorHook);
|
|
procedure UpdateSelectionNotifications;
|
|
|
|
procedure AddPropertyEditor(PropEditor: TPropertyEditor);
|
|
procedure AddStringToComboBox(const s: string);
|
|
procedure ExpandRow(Index: integer);
|
|
procedure ShrinkRow(Index: integer);
|
|
procedure AddSubEditor(PropEditor: TPropertyEditor);
|
|
procedure SortSubEditors(ParentRow: TOIPropertyGridRow);
|
|
function CanExpandRow(Row: TOIPropertyGridRow): boolean;
|
|
|
|
procedure SetRowValue;
|
|
procedure DoCallEdit(Edit: TOIQuickEdit = oiqeEdit);
|
|
procedure RefreshValueEdit;
|
|
procedure ToggleRow;
|
|
procedure ValueEditDblClick(Sender : TObject);
|
|
procedure ValueControlMouseDown(Sender: TObject; Button:TMouseButton;
|
|
Shift: TShiftState; X,Y:integer);
|
|
procedure ValueControlMouseMove(Sender: TObject; Shift: TShiftState;
|
|
X,Y:integer);
|
|
procedure ValueEditKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
|
|
procedure ValueEditKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
|
|
procedure ValueEditExit(Sender: TObject);
|
|
procedure ValueEditChange(Sender: TObject);
|
|
procedure ValueEditMouseUp(Sender: TObject; Button: TMouseButton;
|
|
Shift: TShiftState; X, Y: Integer);
|
|
procedure ValueCheckBoxKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
|
|
procedure ValueCheckBoxKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
|
|
procedure ValueCheckBoxExit(Sender: TObject);
|
|
procedure ValueCheckBoxClick(Sender: TObject);
|
|
procedure ValueComboBoxExit(Sender: TObject);
|
|
procedure ValueComboBoxKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
|
|
procedure ValueComboBoxKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
|
|
procedure ValueComboBoxMouseUp(Sender: TObject; Button: TMouseButton;
|
|
Shift: TShiftState; X, Y: Integer);
|
|
procedure ValueComboBoxCloseUp(Sender: TObject);
|
|
procedure ValueComboBoxGetItems(Sender: TObject);
|
|
procedure ValueButtonClick(Sender: TObject);
|
|
procedure ValueComboBoxMeasureItem(Control: TWinControl; Index: Integer;
|
|
var AHeight: Integer);
|
|
procedure ValueComboBoxDrawItem(Control: TWinControl; Index: Integer;
|
|
ARect: TRect; State: TOwnerDrawState);
|
|
procedure OnIdle(Sender: TObject; var Done: Boolean);
|
|
procedure SetIdleEvent(Enable: boolean);
|
|
|
|
procedure WMVScroll(var Msg: TLMScroll); message LM_VSCROLL;
|
|
procedure WMMouseWheel(var Message: TLMMouseEvent); message
|
|
LM_MOUSEWHEEL;
|
|
procedure SetBackgroundColor(const AValue: TColor);
|
|
procedure SetReferences(const AValue: TColor);
|
|
procedure SetSubPropertiesColor(const AValue: TColor);
|
|
procedure SetReadOnlyColor(const AValue: TColor);
|
|
procedure UpdateScrollBar;
|
|
procedure FillComboboxItems;
|
|
function EditorFilter(const AEditor: TPropertyEditor): Boolean;
|
|
protected
|
|
procedure CreateParams(var Params: TCreateParams); override;
|
|
procedure CreateWnd; override;
|
|
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
|
|
|
|
procedure MouseDown(Button:TMouseButton; Shift:TShiftState; X,Y:integer); override;
|
|
procedure MouseMove(Shift:TShiftState; X,Y:integer); override;
|
|
procedure MouseUp(Button:TMouseButton; Shift:TShiftState; X,Y:integer); override;
|
|
|
|
procedure KeyDown(var Key: Word; Shift: TShiftState); override;
|
|
procedure HandleStandardKeys(var Key: Word; Shift: TShiftState); virtual;
|
|
procedure HandleKeyUp(var Key: Word; Shift: TShiftState); virtual;
|
|
procedure DoTabKey; virtual;
|
|
procedure DoSetBounds(ALeft, ATop, AWidth, AHeight: integer); override;
|
|
procedure DoSelectionChange;
|
|
public
|
|
constructor Create(TheOwner: TComponent); override;
|
|
constructor CreateWithParams(AnOwner: TComponent;
|
|
APropertyEditorHook: TPropertyEditorHook;
|
|
TypeFilter: TTypeKinds;
|
|
DefItemHeight: integer);
|
|
destructor Destroy; override;
|
|
function InitHints: boolean;
|
|
function CanEditRowValue: boolean;
|
|
procedure SaveChanges;
|
|
function ConsistencyCheck: integer;
|
|
procedure EraseBackground(DC: HDC); override;
|
|
function GetActiveRow: TOIPropertyGridRow;
|
|
function GetHintTypeAt(RowIndex: integer; X: integer): TPropEditHint;
|
|
|
|
function GetRowByPath(const PropPath: string): TOIPropertyGridRow;
|
|
function GridHeight: integer;
|
|
function MouseToIndex(y: integer; MustExist: boolean):integer;
|
|
function PropertyPath(Index: integer):string;
|
|
function PropertyPath(Row: TOIPropertyGridRow):string;
|
|
function TopMax: integer;
|
|
procedure BuildPropertyList(OnlyIfNeeded: boolean = false);
|
|
procedure Clear;
|
|
procedure Paint; override;
|
|
procedure PropEditLookupRootChange;
|
|
procedure RefreshPropertyValues;
|
|
procedure ScrollToActiveItem;
|
|
procedure ScrollToItem(NewIndex: Integer);
|
|
procedure SetBounds(aLeft, aTop, aWidth, aHeight: integer); override;
|
|
procedure SetCurrentRowValue(const NewValue: string);
|
|
procedure SetItemIndexAndFocus(NewItemIndex: integer);
|
|
|
|
property BackgroundColor: TColor read FBackgroundColor
|
|
write SetBackgroundColor default DefBackgroundColor;
|
|
property GutterColor: TColor read FGutterColor write SetGutterColor default DefGutterColor;
|
|
property GutterEdgeColor: TColor read FGutterEdgeColor write SetGutterEdgeColor default DefGutterEdgeColor;
|
|
property HighlightColor: TColor read FHighlightColor write SetHighlightColor default DefHighlightColor;
|
|
property ReferencesColor: TColor read FReferencesColor
|
|
write SetReferences default DefReferencesColor;
|
|
property SubPropertiesColor: TColor read FSubPropertiesColor
|
|
write SetSubPropertiesColor default DefSubPropertiesColor;
|
|
property ReadOnlyColor: TColor read FReadOnlyColor
|
|
write SetReadOnlyColor default DefReadOnlyColor;
|
|
property NameFont: TFont read FNameFont write FNameFont;
|
|
property DefaultValueFont: TFont read FDefaultValueFont write FDefaultValueFont;
|
|
property ValueFont: TFont read FValueFont write FValueFont;
|
|
property HighlightFont: TFont read FHighlightFont write FHighlightFont;
|
|
|
|
property BorderStyle default bsSingle;
|
|
property Column: TOICustomPropertyGridColumn read FColumn write SetColumn;
|
|
property CurrentEditValue: string read GetCurrentEditValue
|
|
write SetCurrentEditValue;
|
|
property DefaultItemHeight:integer read FDefaultItemHeight
|
|
write FDefaultItemHeight default 25;
|
|
property DrawHorzGridLines: Boolean read FDrawHorzGridLines write
|
|
SetDrawHorzGridLines default True;
|
|
property ExpandedProperties: TStringList read FExpandedProperties
|
|
write FExpandedProperties;
|
|
property Indent: integer read FIndent write FIndent default 9;
|
|
property ItemIndex: integer read FItemIndex write SetItemIndex;
|
|
property Layout: TOILayout read FLayout write FLayout default oilHorizontal;
|
|
property OnModified: TNotifyEvent read FOnModified write FOnModified;
|
|
property OnOIKeyDown: TKeyEvent read FOnOIKeyDown write FOnOIKeyDown;
|
|
property OnSelectionChange: TNotifyEvent read FOnSelectionChange write FOnSelectionChange;
|
|
property OnPropertyHint: TOIPropertyHint read FOnPropertyHint write FOnPropertyHint;
|
|
property PrefferedSplitterX: integer read FPreferredSplitterX
|
|
write FPreferredSplitterX default 100;
|
|
property PropertyEditorHook: TPropertyEditorHook read FPropertyEditorHook
|
|
write SetPropertyEditorHook;
|
|
property RowCount: integer read GetRowCount;
|
|
property Rows[Index: integer]:TOIPropertyGridRow read GetRow;
|
|
property RowSpacing: integer read FRowSpacing write SetRowSpacing;
|
|
property Selection: TPersistentSelectionList read FSelection
|
|
write SetSelection;
|
|
property ShowGutter: Boolean read FShowGutter write SetShowGutter default True;
|
|
property SplitterX: integer read FSplitterX write SetSplitterX default 100;
|
|
property TopY: integer read FTopY write SetTopY default 0;
|
|
property Favourites: TOIFavouriteProperties read FFavourites
|
|
write SetFavourites;
|
|
property Filter : TTypeKinds read FFilter write SetFilter;
|
|
end;
|
|
|
|
|
|
{ TOIPropertyGrid }
|
|
|
|
TOIPropertyGrid = class(TOICustomPropertyGrid)
|
|
published
|
|
property Align;
|
|
property Anchors;
|
|
property BackgroundColor;
|
|
property BorderStyle;
|
|
property Constraints;
|
|
property DefaultItemHeight;
|
|
property DefaultValueFont;
|
|
property Indent;
|
|
property NameFont;
|
|
property OnChangeBounds;
|
|
property OnClick;
|
|
property OnDblClick;
|
|
property OnEnter;
|
|
property OnExit;
|
|
property OnKeyDown;
|
|
property OnKeyPress;
|
|
property OnKeyUp;
|
|
property OnModified;
|
|
property OnMouseDown;
|
|
property OnMouseEnter;
|
|
property OnMouseLeave;
|
|
property OnMouseMove;
|
|
property OnMouseUp;
|
|
property OnResize;
|
|
property OnSelectionChange;
|
|
property PopupMenu;
|
|
property PrefferedSplitterX;
|
|
property SplitterX;
|
|
property Tabstop;
|
|
property ValueFont;
|
|
property Visible;
|
|
end;
|
|
|
|
|
|
{ TCustomPropertiesGrid }
|
|
|
|
TCustomPropertiesGrid = class(TOICustomPropertyGrid)
|
|
private
|
|
FAutoFreeHook: boolean;
|
|
FSaveOnChangeTIObject: boolean;
|
|
function GetTIObject: TPersistent;
|
|
procedure SetAutoFreeHook(const AValue: boolean);
|
|
procedure SetTIObject(const AValue: TPersistent);
|
|
public
|
|
constructor Create(TheOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
property TIObject: TPersistent read GetTIObject write SetTIObject;
|
|
property AutoFreeHook: boolean read FAutoFreeHook write SetAutoFreeHook;
|
|
property SaveOnChangeTIObject: boolean read FSaveOnChangeTIObject
|
|
write FSaveOnChangeTIObject
|
|
default true;
|
|
end;
|
|
|
|
|
|
//============================================================================
|
|
|
|
|
|
{ TObjectInspectorDlg }
|
|
|
|
TOnAddAvailablePersistent = procedure(APersistent: TPersistent;
|
|
var Allowed: boolean) of object;
|
|
|
|
TOIFlag = (
|
|
oifRebuildPropListsNeeded
|
|
);
|
|
TOIFlags = set of TOIFlag;
|
|
|
|
{ TObjectInspectorDlg }
|
|
|
|
TObjectInspectorDlg = class(TForm)
|
|
AddToFavoritesPopupMenuItem: TMenuItem;
|
|
ViewRestrictedPropertiesPopupMenuItem: TMenuItem;
|
|
AvailPersistentComboBox: TComboBox;
|
|
ComponentTree: TComponentTreeView;
|
|
InfoPanel: TPanel;
|
|
CopyPopupmenuItem: TMenuItem;
|
|
CutPopupmenuItem: TMenuItem;
|
|
DeletePopupmenuItem: TMenuItem;
|
|
EventGrid: TOICustomPropertyGrid;
|
|
FavouriteGrid: TOICustomPropertyGrid;
|
|
RestrictedGrid: TOICustomPropertyGrid;
|
|
RestrictedPanel: TPanel;
|
|
RestrictedInnerPanel: TPanel;
|
|
WidgetSetsRestrictedLabel: TLabel;
|
|
WidgetSetsRestrictedBox: TPaintBox;
|
|
ComponentRestrictedLabel: TLabel;
|
|
ComponentRestrictedBox: TPaintBox;
|
|
FindDeclarationPopupmenuItem: TMenuItem;
|
|
MainPopupMenu: TPopupMenu;
|
|
NoteBook: TNoteBook;
|
|
OptionsSeparatorMenuItem2: TMenuItem;
|
|
PastePopupmenuItem: TMenuItem;
|
|
PropertyGrid: TOICustomPropertyGrid;
|
|
RemoveFromFavoritesPopupMenuItem: TMenuItem;
|
|
SetDefaultPopupMenuItem: TMenuItem;
|
|
ShowComponentTreePopupMenuItem: TMenuItem;
|
|
ShowHintsPopupMenuItem: TMenuItem;
|
|
ShowOptionsPopupMenuItem: TMenuItem;
|
|
Splitter1: TSplitter;
|
|
Splitter2: TSplitter;
|
|
StatusBar: TStatusBar;
|
|
UndoPropertyPopupMenuItem: TMenuItem;
|
|
procedure AvailComboBoxCloseUp(Sender: TObject);
|
|
procedure ComponentTreeDblClick(Sender: TObject);
|
|
procedure ComponentTreeKeyDown(Sender: TObject; var Key: Word;
|
|
Shift: TShiftState);
|
|
procedure ComponentTreeSelectionChanged(Sender: TObject);
|
|
procedure ObjectInspectorResize(Sender: TObject);
|
|
procedure OnGridKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
|
|
procedure OnGridKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
|
|
procedure OnGridDblClick(Sender: TObject);
|
|
procedure OnSetDefaultPopupmenuItemClick(Sender: TObject);
|
|
procedure OnAddToFavoritesPopupmenuItemClick(Sender: TObject);
|
|
procedure OnRemoveFromFavoritesPopupmenuItemClick(Sender: TObject);
|
|
procedure OnViewRestrictionsPopupmenuItemClick(Sender: TObject);
|
|
procedure OnUndoPopupmenuItemClick(Sender: TObject);
|
|
procedure OnFindDeclarationPopupmenuItemClick(Sender: TObject);
|
|
procedure OnCutPopupmenuItemClick(Sender: TObject);
|
|
procedure OnCopyPopupmenuItemClick(Sender: TObject);
|
|
procedure OnPastePopupmenuItemClick(Sender: TObject);
|
|
procedure OnDeletePopupmenuItemClick(Sender: TObject);
|
|
procedure OnShowHintPopupMenuItemClick(Sender: TObject);
|
|
procedure OnShowOptionsPopupMenuItemClick(Sender: TObject);
|
|
procedure OnShowComponentTreePopupMenuItemClick(Sender: TObject);
|
|
procedure OnMainPopupMenuPopup(Sender: TObject);
|
|
procedure RestrictedPageShow(Sender: TObject);
|
|
procedure WidgetSetRestrictedPaint(Sender: TObject);
|
|
procedure ComponentRestrictedPaint(Sender: TObject);
|
|
procedure DoUpdateRestricted;
|
|
procedure DoViewRestricted;
|
|
private
|
|
FAutoShow: Boolean;
|
|
FFavourites: TOIFavouriteProperties;
|
|
FInfoBoxHeight: integer;
|
|
FOnPropertyHint: TOIPropertyHint;
|
|
FOnSelectionChange: TNotifyEvent;
|
|
FRestricted: TOIRestrictedProperties;
|
|
FOnAddToFavourites: TNotifyEvent;
|
|
FOnFindDeclarationOfProperty: TNotifyEvent;
|
|
FOnOIKeyDown: TKeyEvent;
|
|
FOnRemainingKeyDown: TKeyEvent;
|
|
FOnRemainingKeyUp: TKeyEvent;
|
|
FOnRemoveFromFavourites: TNotifyEvent;
|
|
FOnUpdateRestricted: TNotifyEvent;
|
|
FOnViewRestricted: TNotifyEvent;
|
|
FSelection: TPersistentSelectionList;
|
|
FComponentTreeHeight: integer;
|
|
FDefaultItemHeight: integer;
|
|
FFlags: TOIFlags;
|
|
FOnShowOptions: TNotifyEvent;
|
|
FPropertyEditorHook: TPropertyEditorHook;
|
|
FOnAddAvailablePersistent: TOnAddAvailablePersistent;
|
|
FOnSelectPersistentsInOI: TNotifyEvent;
|
|
FOnModified: TNotifyEvent;
|
|
FShowComponentTree: boolean;
|
|
FShowFavorites: Boolean;
|
|
FShowInfoBox: Boolean;
|
|
FShowRestricted: Boolean;
|
|
FShowStatusBar: Boolean;
|
|
FUpdateLock: integer;
|
|
FUpdatingAvailComboBox: boolean;
|
|
function GetGridControl(Page: TObjectInspectorPage): TOICustomPropertyGrid;
|
|
procedure SetFavourites(const AValue: TOIFavouriteProperties);
|
|
procedure SetComponentTreeHeight(const AValue: integer);
|
|
procedure SetDefaultItemHeight(const AValue: integer);
|
|
procedure SetInfoBoxHeight(const AValue: integer);
|
|
procedure SetRestricted(const AValue: TOIRestrictedProperties);
|
|
procedure SetOnShowOptions(const AValue: TNotifyEvent);
|
|
procedure SetPropertyEditorHook(NewValue: TPropertyEditorHook);
|
|
procedure SetSelection(const ASelection: TPersistentSelectionList);
|
|
procedure SetShowComponentTree(const AValue: boolean);
|
|
procedure SetShowFavorites(const AValue: Boolean);
|
|
procedure SetShowInfoBox(const AValue: Boolean);
|
|
procedure SetShowRestricted(const AValue: Boolean);
|
|
procedure SetShowStatusBar(const AValue: Boolean);
|
|
procedure ShowNextPage(Delta: integer);
|
|
procedure RestrictedPaint(
|
|
ABox: TPaintBox; const ARestrictions: TWidgetSetRestrictionsArray);
|
|
protected
|
|
function PersistentToString(APersistent: TPersistent): string;
|
|
procedure AddPersistentToList(APersistent: TPersistent; List: TStrings);
|
|
procedure HookLookupRootChange;
|
|
procedure OnGridModified(Sender: TObject);
|
|
procedure OnGridSelectionChange(Sender: TObject);
|
|
function OnGridPropertyHint(Sender: TObject; PointedRow: TOIPropertyGridRow;
|
|
ScreenPos: TPoint; aHintWindow: THintWindow;
|
|
out HintWinRect: TRect; out AHint: string): boolean;
|
|
procedure SetAvailComboBoxText;
|
|
procedure HookGetSelection(const ASelection: TPersistentSelectionList);
|
|
procedure HookSetSelection(const ASelection: TPersistentSelectionList);
|
|
procedure CreateSplitter(TopSplitter: Boolean);
|
|
procedure DestroyNoteBook;
|
|
procedure CreateNoteBook;
|
|
procedure KeyDown(var Key: Word; Shift: TShiftState); override;
|
|
procedure KeyUp(var Key: Word; Shift: TShiftState); override;
|
|
public
|
|
constructor Create(AnOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
procedure RefreshSelection;
|
|
procedure RefreshComponentTreeSelection;
|
|
procedure SaveChanges;
|
|
procedure RefreshPropertyValues;
|
|
procedure RebuildPropertyLists;
|
|
procedure FillPersistentComboBox;
|
|
procedure BeginUpdate;
|
|
procedure EndUpdate;
|
|
function GetActivePropertyGrid: TOICustomPropertyGrid;
|
|
function GetActivePropertyRow: TOIPropertyGridRow;
|
|
function GetCurRowDefaultValue(var DefaultStr: string): boolean;
|
|
procedure HookRefreshPropertyValues;
|
|
procedure ActivateGrid(Grid: TOICustomPropertyGrid);
|
|
procedure FocusGrid(Grid: TOICustomPropertyGrid = nil);
|
|
|
|
property AutoShow: Boolean read FAutoShow write FAutoShow;
|
|
property DefaultItemHeight: integer read FDefaultItemHeight
|
|
write SetDefaultItemHeight;
|
|
property Selection: TPersistentSelectionList
|
|
read FSelection write SetSelection;
|
|
property OnAddAvailPersistent: TOnAddAvailablePersistent
|
|
read FOnAddAvailablePersistent write FOnAddAvailablePersistent;
|
|
property OnSelectPersistentsInOI: TNotifyEvent
|
|
read FOnSelectPersistentsInOI write FOnSelectPersistentsInOI;
|
|
property PropertyEditorHook: TPropertyEditorHook
|
|
read FPropertyEditorHook write SetPropertyEditorHook;
|
|
property OnModified: TNotifyEvent read FOnModified write FOnModified;
|
|
property OnSelectionChange: TNotifyEvent read FOnSelectionChange write FOnSelectionChange;
|
|
property OnPropertyHint: TOIPropertyHint read FOnPropertyHint write FOnPropertyHint;
|
|
property OnShowOptions: TNotifyEvent read FOnShowOptions
|
|
write SetOnShowOptions;
|
|
property OnRemainingKeyUp: TKeyEvent read FOnRemainingKeyUp
|
|
write FOnRemainingKeyUp;
|
|
property OnRemainingKeyDown: TKeyEvent read FOnRemainingKeyDown
|
|
write FOnRemainingKeyDown;
|
|
property OnUpdateRestricted: TNotifyEvent read FOnUpdateRestricted
|
|
write FOnUpdateRestricted;
|
|
property ShowComponentTree: boolean read FShowComponentTree
|
|
write SetShowComponentTree;
|
|
property ShowFavorites: Boolean read FShowFavorites write SetShowFavorites;
|
|
property ShowRestricted: Boolean read FShowRestricted write SetShowRestricted;
|
|
property ComponentTreeHeight: integer read FComponentTreeHeight
|
|
write SetComponentTreeHeight;
|
|
property InfoBoxHeight: integer read FInfoBoxHeight write SetInfoBoxHeight;
|
|
property ShowStatusBar: Boolean read FShowStatusBar write SetShowStatusBar;
|
|
property ShowInfoBox: Boolean read FShowInfoBox write SetShowInfoBox;
|
|
property GridControl[Page: TObjectInspectorPage]: TOICustomPropertyGrid
|
|
read GetGridControl;
|
|
property Favourites: TOIFavouriteProperties read FFavourites write SetFavourites;
|
|
property RestrictedProps: TOIRestrictedProperties read FRestricted write SetRestricted;
|
|
property OnAddToFavourites: TNotifyEvent read FOnAddToFavourites
|
|
write FOnAddToFavourites;
|
|
property OnRemoveFromFavourites: TNotifyEvent read FOnRemoveFromFavourites
|
|
write FOnRemoveFromFavourites;
|
|
property OnViewRestricted: TNotifyEvent read FOnViewRestricted write FOnViewRestricted;
|
|
property OnOIKeyDown: TKeyEvent read FOnOIKeyDown write FOnOIKeyDown;
|
|
property OnFindDeclarationOfProperty: TNotifyEvent
|
|
read FOnFindDeclarationOfProperty write FOnFindDeclarationOfProperty;
|
|
end;
|
|
|
|
const
|
|
DefaultObjectInspectorName: string = 'ObjectInspectorDlg';
|
|
|
|
implementation
|
|
|
|
uses
|
|
math;
|
|
|
|
const
|
|
DefaultOIPageNames: array[TObjectInspectorPage] of shortstring = (
|
|
'PropertyPage',
|
|
'EventPage',
|
|
'FavouritePage',
|
|
'RestrictedPage'
|
|
);
|
|
DefaultOIGridNames: array[TObjectInspectorPage] of shortstring = (
|
|
'PropertyGrid',
|
|
'EventGrid',
|
|
'FavouriteGrid',
|
|
'RestrictedGrid'
|
|
);
|
|
|
|
function SortGridRows(Item1, Item2 : pointer) : integer;
|
|
begin
|
|
Result:=SysUtils.CompareText(TOIPropertyGridRow(Item1).Name,
|
|
TOIPropertyGridRow(Item2).Name);
|
|
end;
|
|
|
|
{ TOICustomPropertyGrid }
|
|
|
|
constructor TOICustomPropertyGrid.CreateWithParams(AnOwner:TComponent;
|
|
APropertyEditorHook:TPropertyEditorHook; TypeFilter:TTypeKinds;
|
|
DefItemHeight: integer);
|
|
begin
|
|
inherited Create(AnOwner);
|
|
FLayout := oilHorizontal;
|
|
|
|
FSelection:=TPersistentSelectionList.Create;
|
|
FNotificationComponents:=TFPList.Create;
|
|
FPropertyEditorHook:=APropertyEditorHook;
|
|
FFilter:=TypeFilter;
|
|
FItemIndex:=-1;
|
|
FStates:=[];
|
|
FColumn := oipgcValue;
|
|
FRows:=TFPList.Create;
|
|
FExpandingRow:=nil;
|
|
FDragging:=false;
|
|
FExpandedProperties:=TStringList.Create;
|
|
FCurrentEdit:=nil;
|
|
FCurrentButton:=nil;
|
|
|
|
// visible values
|
|
FTopY:=0;
|
|
FSplitterX:=100;
|
|
FPreferredSplitterX:=FSplitterX;
|
|
FIndent:=9;
|
|
|
|
FBackgroundColor:=DefBackgroundColor;
|
|
FReferencesColor:=DefReferencesColor;
|
|
FSubPropertiesColor:=DefSubPropertiesColor;
|
|
FReadOnlyColor:=DefReadOnlyColor;
|
|
FHighlightColor:=DefHighlightColor;
|
|
FGutterColor:=DefGutterColor;
|
|
FGutterEdgeColor:=DefGutterEdgeColor;
|
|
|
|
FNameFont:=TFont.Create;
|
|
FNameFont.Color:=DefNameColor;
|
|
FValueFont:=TFont.Create;
|
|
FValueFont.Color:=DefValueColor;
|
|
FDefaultValueFont:=TFont.Create;
|
|
FDefaultValueFont.Color:=DefDefaultValueColor;
|
|
FHighlightFont:=TFont.Create;
|
|
FHighlightFont.Color:=DefHighlightFontColor;
|
|
|
|
FDrawHorzGridLines := True;
|
|
FShowGutter := True;
|
|
|
|
SetInitialBounds(0,0,200,130);
|
|
ControlStyle:=ControlStyle+[csAcceptsControls,csOpaque];
|
|
BorderWidth:=0;
|
|
BorderStyle := bsSingle;
|
|
|
|
// create sub components
|
|
ValueEdit:=TEdit.Create(Self);
|
|
with ValueEdit do
|
|
begin
|
|
Name:='ValueEdit';
|
|
Visible:=false;
|
|
Enabled:=false;
|
|
AutoSize:=false;
|
|
SetBounds(0,-30,80,25); // hidden
|
|
Parent:=Self;
|
|
OnMouseDown := @ValueControlMouseDown;
|
|
OnMouseMove := @ValueControlMouseMove;
|
|
OnDblClick := @ValueEditDblClick;
|
|
OnExit:=@ValueEditExit;
|
|
OnChange:=@ValueEditChange;
|
|
OnKeyDown:=@ValueEditKeyDown;
|
|
OnKeyUp:=@ValueEditKeyUp;
|
|
OnMouseUp:=@ValueEditMouseUp;
|
|
end;
|
|
|
|
ValueComboBox:=TComboBox.Create(Self);
|
|
with ValueComboBox do
|
|
begin
|
|
Name:='ValueComboBox';
|
|
Sorted:=true;
|
|
AutoSelect:=true;
|
|
AutoComplete:=true;
|
|
Visible:=false;
|
|
Enabled:=false;
|
|
AutoSize:=false;
|
|
SetBounds(0,-30,Width,Height); // hidden
|
|
DropDownCount:=20;
|
|
Parent:=Self;
|
|
OnMouseDown := @ValueControlMouseDown;
|
|
OnMouseMove := @ValueControlMouseMove;
|
|
OnDblClick := @ValueEditDblClick;
|
|
OnExit:=@ValueComboBoxExit;
|
|
//OnChange:=@ValueComboBoxChange; the on change event is called even,
|
|
// if the user is still editing
|
|
OnKeyDown:=@ValueComboBoxKeyDown;
|
|
OnKeyUp:=@ValueComboBoxKeyUp;
|
|
OnMouseUp:=@ValueComboBoxMouseUp;
|
|
OnGetItems:=@ValueComboBoxGetItems;
|
|
OnCloseUp:=@ValueComboBoxCloseUp;
|
|
OnMeasureItem:=@ValueComboBoxMeasureItem;
|
|
OnDrawItem:=@ValueComboBoxDrawItem;
|
|
end;
|
|
|
|
ValueCheckBox:=TCheckBox.Create(Self);
|
|
with ValueCheckBox do
|
|
begin
|
|
Name:='ValueCheckBox';
|
|
Visible:=false;
|
|
AutoSize:=false;
|
|
Enabled:=false;
|
|
SetBounds(0,-30,Width,Height); // hidden
|
|
Parent:=Self;
|
|
OnMouseDown := @ValueControlMouseDown;
|
|
OnMouseMove := @ValueControlMouseMove;
|
|
OnExit:=@ValueCheckBoxExit;
|
|
OnKeyDown:=@ValueCheckBoxKeyDown;
|
|
OnKeyUp:=@ValueCheckBoxKeyUp;
|
|
end;
|
|
|
|
ValueButton:=TSpeedButton.Create(Self);
|
|
with ValueButton do
|
|
begin
|
|
Name:='ValueButton';
|
|
Visible:=false;
|
|
Enabled:=false;
|
|
Transparent:=false;
|
|
OnClick:=@ValueButtonClick;
|
|
Caption := '...';
|
|
SetBounds(0,-30,Width,Height); // hidden
|
|
Parent:=Self;
|
|
end;
|
|
|
|
FActiveRowBmp := CreateBitmapFromLazarusResource('pg_active_row');
|
|
|
|
if DefItemHeight<3 then
|
|
FDefaultItemHeight:=ValueComboBox.Height-3
|
|
else
|
|
FDefaultItemHeight:=DefItemHeight;
|
|
|
|
BuildPropertyList;
|
|
|
|
Application.AddOnUserInputHandler(@OnUserInput,true);
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.UpdateScrollBar;
|
|
var
|
|
ScrollInfo: TScrollInfo;
|
|
begin
|
|
if HandleAllocated then begin
|
|
ScrollInfo.cbSize := SizeOf(ScrollInfo);
|
|
ScrollInfo.fMask := SIF_ALL or SIF_DISABLENOSCROLL;
|
|
ScrollInfo.nMin := 0;
|
|
ScrollInfo.nTrackPos := 0;
|
|
ScrollInfo.nMax := TopMax+ClientHeight-1;
|
|
ScrollInfo.nPage := ClientHeight;
|
|
if ScrollInfo.nPage<1 then ScrollInfo.nPage:=1;
|
|
if TopY > ScrollInfo.nMax then TopY:=ScrollInfo.nMax;
|
|
ScrollInfo.nPos := TopY;
|
|
ShowScrollBar(Handle, SB_VERT, True);
|
|
SetScrollInfo(Handle, SB_VERT, ScrollInfo, True);
|
|
end;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.FillComboboxItems;
|
|
var
|
|
ExcludeUpdateFlag: boolean;
|
|
CurRow: TOIPropertyGridRow;
|
|
begin
|
|
ExcludeUpdateFlag:=not (pgsUpdatingEditControl in FStates);
|
|
Include(FStates,pgsUpdatingEditControl);
|
|
ValueComboBox.Items.BeginUpdate;
|
|
try
|
|
CurRow:=Rows[FItemIndex];
|
|
if FNewComboBoxItems<>nil then FNewComboBoxItems.Clear;
|
|
CurRow.Editor.GetValues(@AddStringToComboBox);
|
|
if FNewComboBoxItems<>nil then begin
|
|
FNewComboBoxItems.Sorted:=paSortList in CurRow.Editor.GetAttributes;
|
|
if not ValueComboBox.Items.Equals(FNewComboBoxItems) then begin
|
|
ValueComboBox.Items.Assign(FNewComboBoxItems);
|
|
end;
|
|
//debugln('TOICustomPropertyGrid.FillComboboxItems "',FNewComboBoxItems.Text,'" Cur="',ValueComboBox.Items.Text,'" ValueComboBox.Items.Count=',dbgs(ValueComboBox.Items.Count));
|
|
end else begin
|
|
ValueComboBox.Items.Text:='';
|
|
ValueComboBox.Items.Clear;
|
|
//debugln('TOICustomPropertyGrid.FillComboboxItems FNewComboBoxItems=nil Cur="',ValueComboBox.Items.Text,'" ValueComboBox.Items.Count=',dbgs(ValueComboBox.Items.Count));
|
|
end;
|
|
finally
|
|
FreeAndNil(FNewComboBoxItems);
|
|
ValueComboBox.Items.EndUpdate;
|
|
if ExcludeUpdateFlag then
|
|
Exclude(FStates,pgsUpdatingEditControl);
|
|
end;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.CreateParams(var Params: TCreateParams);
|
|
const
|
|
ClassStylesOff = CS_VREDRAW or CS_HREDRAW;
|
|
begin
|
|
inherited CreateParams(Params);
|
|
with Params do begin
|
|
{$R-}
|
|
WindowClass.Style := WindowClass.Style and not ClassStylesOff;
|
|
Style := Style or WS_VSCROLL or WS_CLIPCHILDREN;
|
|
{$R+}
|
|
ExStyle := ExStyle or WS_EX_CLIENTEDGE;
|
|
end;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.CreateWnd;
|
|
begin
|
|
inherited CreateWnd;
|
|
// handle just created, set scrollbar
|
|
UpdateScrollBar;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.Notification(AComponent: TComponent;
|
|
Operation: TOperation);
|
|
var
|
|
i: LongInt;
|
|
begin
|
|
if (Operation=opRemove) and (FNotificationComponents<>nil) then begin
|
|
FNotificationComponents.Remove(AComponent);
|
|
i:=FSelection.IndexOf(AComponent);
|
|
if i>=0 then begin
|
|
FSelection.Delete(i);
|
|
Include(FStates,pgsBuildPropertyListNeeded);
|
|
end;
|
|
end;
|
|
inherited Notification(AComponent, Operation);
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.WMVScroll(var Msg: TLMScroll);
|
|
begin
|
|
case Msg.ScrollCode of
|
|
// Scrolls to start / end of the text
|
|
SB_TOP: TopY := 0;
|
|
SB_BOTTOM: TopY := TopMax;
|
|
// Scrolls one line up / down
|
|
SB_LINEDOWN: TopY := TopY + DefaultItemHeight div 2;
|
|
SB_LINEUP: TopY := TopY - DefaultItemHeight div 2;
|
|
// Scrolls one page of lines up / down
|
|
SB_PAGEDOWN: TopY := TopY + ClientHeight - DefaultItemHeight;
|
|
SB_PAGEUP: TopY := TopY - ClientHeight + DefaultItemHeight;
|
|
// Scrolls to the current scroll bar position
|
|
SB_THUMBPOSITION,
|
|
SB_THUMBTRACK: TopY := Msg.Pos;
|
|
// Ends scrolling
|
|
SB_ENDSCROLL: SetCaptureControl(nil); // release scrollbar capture
|
|
end;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.WMMouseWheel(var Message: TLMMouseEvent);
|
|
begin
|
|
// -1 : scroll by page
|
|
if Mouse.WheelScrollLines=-1
|
|
then TopY := TopY -
|
|
(Message.WheelDelta * (ClientHeight - DefaultItemHeight)) div 120
|
|
// scrolling one line -> scroll half an item, see SB_LINEDOWN and SB_LINEUP
|
|
// handler in WMVScrol
|
|
else TopY := TopY -
|
|
(Message.WheelDelta * Mouse.WheelScrollLines*DefaultItemHeight) div 240;
|
|
Message.Result := 1;
|
|
end;
|
|
|
|
destructor TOICustomPropertyGrid.Destroy;
|
|
var
|
|
a: integer;
|
|
begin
|
|
SetIdleEvent(false);
|
|
Application.RemoveOnUserInputHandler(@OnUserInput);
|
|
FItemIndex := -1;
|
|
for a := 0 to FRows.Count - 1 do
|
|
Rows[a].Free;
|
|
FreeAndNil(FRows);
|
|
FreeAndNil(FSelection);
|
|
FreeAndNil(FNotificationComponents);
|
|
FreeAndNil(FValueFont);
|
|
FreeAndNil(FDefaultValueFont);
|
|
FreeAndNil(FNameFont);
|
|
FreeAndNil(FHighlightFont);
|
|
FreeAndNil(FExpandedProperties);
|
|
FreeAndNil(FHintTimer);
|
|
FreeAndNil(FHintWindow);
|
|
FreeAndNil(FNewComboBoxItems);
|
|
FreeAndNil(FActiveRowBmp);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TOICustomPropertyGrid.InitHints: boolean;
|
|
begin
|
|
if not ShowHint then exit(false);
|
|
|
|
Result := true;
|
|
if FHintTimer = nil then
|
|
begin
|
|
FHintIndex := -1;
|
|
FShowingLongHint := False;
|
|
FHintTimer := TTimer.Create(nil);
|
|
FHintTimer.Interval := 500;
|
|
FHintTimer.Enabled := False;
|
|
FHintTimer.OnTimer := @HintTimer;
|
|
|
|
FHintWindow := THintWindow.Create(Self);
|
|
|
|
FHIntWindow.Visible := False;
|
|
FHintWindow.Caption := 'This is a hint window'#13#10'Neat huh?';
|
|
FHintWindow.HideInterval := 4000;
|
|
FHintWindow.AutoHide := True;
|
|
end
|
|
end;
|
|
|
|
function TOICustomPropertyGrid.IsCurrentEditorAvailable: Boolean;
|
|
begin
|
|
Result := (FCurrentEdit <> nil) and InRange(FItemIndex, 0, FRows.Count - 1);
|
|
end;
|
|
|
|
function TOICustomPropertyGrid.ConsistencyCheck: integer;
|
|
var
|
|
i: integer;
|
|
begin
|
|
for i:=0 to FRows.Count-1 do begin
|
|
if Rows[i]=nil then begin
|
|
Result:=-1;
|
|
exit;
|
|
end;
|
|
if Rows[i].Index<>i then begin
|
|
Result:=-2;
|
|
exit;
|
|
end;
|
|
Result:=Rows[i].ConsistencyCheck;
|
|
if Result<>0 then begin
|
|
dec(Result,100);
|
|
exit;
|
|
end;
|
|
end;
|
|
Result:=0;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.SetSelection(
|
|
const ASelection: TPersistentSelectionList);
|
|
var
|
|
CurRow:TOIPropertyGridRow;
|
|
OldSelectedRowPath:string;
|
|
begin
|
|
OldSelectedRowPath:=PropertyPath(ItemIndex);
|
|
ItemIndex:=-1;
|
|
ClearRows;
|
|
FSelection.Assign(ASelection);
|
|
UpdateSelectionNotifications;
|
|
BuildPropertyList;
|
|
CurRow:=GetRowByPath(OldSelectedRowPath);
|
|
if CurRow<>nil then
|
|
ItemIndex:=CurRow.Index;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.SetPropertyEditorHook(
|
|
NewPropertyEditorHook:TPropertyEditorHook);
|
|
begin
|
|
if FPropertyEditorHook=NewPropertyEditorHook then exit;
|
|
FPropertyEditorHook:=NewPropertyEditorHook;
|
|
IncreaseChangeStep;
|
|
SetSelection(FSelection);
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.UpdateSelectionNotifications;
|
|
var
|
|
i: Integer;
|
|
AComponent: TComponent;
|
|
begin
|
|
for i:=0 to FSelection.Count-1 do begin
|
|
if FSelection[i] is TComponent then begin
|
|
AComponent:=TComponent(FSelection[i]);
|
|
if FNotificationComponents.IndexOf(AComponent)<0 then begin
|
|
FNotificationComponents.Add(AComponent);
|
|
AComponent.FreeNotification(Self);
|
|
end;
|
|
end;
|
|
end;
|
|
for i:=FNotificationComponents.Count-1 downto 0 do begin
|
|
AComponent:=TComponent(FNotificationComponents[i]);
|
|
if FSelection.IndexOf(AComponent)<0 then begin
|
|
FNotificationComponents.Delete(i);
|
|
AComponent.RemoveFreeNotification(Self);
|
|
end;
|
|
end;
|
|
//DebugLn(['TOICustomPropertyGrid.UpdateSelectionNotifications FNotificationComponents=',FNotificationComponents.Count,' FSelection=',FSelection.Count]);
|
|
end;
|
|
|
|
function TOICustomPropertyGrid.PropertyPath(Index:integer):string;
|
|
begin
|
|
if (Index>=0) and (Index<FRows.Count) then begin
|
|
Result:=PropertyPath(Rows[Index]);
|
|
end else
|
|
Result:='';
|
|
end;
|
|
|
|
function TOICustomPropertyGrid.PropertyPath(Row: TOIPropertyGridRow): string;
|
|
begin
|
|
if Row=nil then begin
|
|
Result:='';
|
|
exit;
|
|
end;
|
|
Result:=Row.Name;
|
|
Row:=Row.Parent;
|
|
while Row<>nil do begin
|
|
Result:=Row.Name+'.'+Result;
|
|
Row:=Row.Parent;
|
|
end;
|
|
end;
|
|
|
|
function TOICustomPropertyGrid.GetRowByPath(
|
|
const PropPath: string): TOIPropertyGridRow;
|
|
// searches PropPath. Expands automatically parent rows
|
|
var CurName:string;
|
|
s,e:integer;
|
|
CurParentRow:TOIPropertyGridRow;
|
|
begin
|
|
Result:=nil;
|
|
if FRows.Count=0 then exit;
|
|
CurParentRow:=nil;
|
|
s:=1;
|
|
while (s<=length(PropPath)) do begin
|
|
e:=s;
|
|
while (e<=length(PropPath)) and (PropPath[e]<>'.') do inc(e);
|
|
CurName:=uppercase(copy(PropPath,s,e-s));
|
|
s:=e+1;
|
|
// search name in childs
|
|
if CurParentRow=nil then
|
|
Result:=Rows[0]
|
|
else
|
|
Result:=CurParentRow.FirstChild;
|
|
while (Result<>nil) and (uppercase(Result.Name)<>CurName) do
|
|
Result:=Result.NextBrother;
|
|
if Result=nil then begin
|
|
exit;
|
|
end else begin
|
|
// expand row
|
|
CurParentRow:=Result;
|
|
ExpandRow(CurParentRow.Index);
|
|
end;
|
|
end;
|
|
if s<=length(PropPath) then Result:=nil;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.SetRowValue;
|
|
var
|
|
CurRow: TOIPropertyGridRow;
|
|
NewValue: string;
|
|
OldExpanded: boolean;
|
|
OldChangeStep: integer;
|
|
begin
|
|
//debugln(['TOICustomPropertyGrid.SetRowValue A ',dbgs(FStates*[pgsChangingItemIndex,pgsApplyingValue]<>[]),' FItemIndex=',dbgs(FItemIndex),' CanEditRowValue=',CanEditRowValue]);
|
|
if not CanEditRowValue or Rows[FItemIndex].IsReadOnly then exit;
|
|
|
|
NewValue:=GetCurrentEditValue;
|
|
|
|
CurRow:=Rows[FItemIndex];
|
|
if length(NewValue)>CurRow.Editor.GetEditLimit then
|
|
NewValue:=LeftStr(NewValue,CurRow.Editor.GetEditLimit);
|
|
|
|
//DebugLn(['TOICustomPropertyGrid.SetRowValue Old="',CurRow.Editor.GetVisualValue,'" New="',NewValue,'"']);
|
|
if CurRow.Editor.GetVisualValue=NewValue then exit;
|
|
|
|
OldChangeStep:=fChangeStep;
|
|
Include(FStates,pgsApplyingValue);
|
|
try
|
|
{$IFNDEF DoNotCatchOIExceptions}
|
|
try
|
|
{$ENDIF}
|
|
//debugln(['TOICustomPropertyGrid.SetRowValue B ClassName=',CurRow.Editor.ClassName,' Visual=',CurRow.Editor.GetVisualValue,' NewValue=',NewValue,' AllEqual=',CurRow.Editor.AllEqual]);
|
|
CurRow.Editor.SetValue(NewValue);
|
|
//debugln(['TOICustomPropertyGrid.SetRowValue C ClassName=',CurRow.Editor.ClassName,' Visual=',CurRow.Editor.GetVisualValue,' NewValue=',NewValue,' AllEqual=',CurRow.Editor.AllEqual]);
|
|
{$IFNDEF DoNotCatchOIExceptions}
|
|
except
|
|
on E: Exception do begin
|
|
MessageDlg(oisError, E.Message, mtError, [mbOk], 0);
|
|
end;
|
|
end;
|
|
{$ENDIF}
|
|
if (OldChangeStep<>FChangeStep) then begin
|
|
// the selection has changed
|
|
// => CurRow does not exist any more
|
|
exit;
|
|
end;
|
|
|
|
// set value in edit control
|
|
SetCurrentEditValue(CurRow.Editor.GetVisualValue);
|
|
|
|
// update volatile sub properties
|
|
if (paVolatileSubProperties in CurRow.Editor.GetAttributes)
|
|
and ((CurRow.Expanded) or (CurRow.ChildCount>0)) then begin
|
|
OldExpanded:=CurRow.Expanded;
|
|
ShrinkRow(FItemIndex);
|
|
if OldExpanded then
|
|
ExpandRow(FItemIndex);
|
|
end;
|
|
//debugln(['TOICustomPropertyGrid.SetRowValue D ClassName=',CurRow.Editor.ClassName,' Visual=',CurRow.Editor.GetVisualValue,' NewValue=',NewValue,' AllEqual=',CurRow.Editor.AllEqual]);
|
|
finally
|
|
Exclude(FStates,pgsApplyingValue);
|
|
end;
|
|
if FPropertyEditorHook=nil then
|
|
DoPaint(true)
|
|
else
|
|
FPropertyEditorHook.RefreshPropertyValues;
|
|
//DebugLn(['TOICustomPropertyGrid.SetRowValue ',CurRow.Name,' ',CurRow.Editor.GetVisualValue,' ',Assigned(FOnModified)]);
|
|
if Assigned(FOnModified) then FOnModified(Self);
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.DoCallEdit(Edit: TOIQuickEdit);
|
|
var
|
|
CurRow:TOIPropertyGridRow;
|
|
OldChangeStep: integer;
|
|
begin
|
|
//writeln('#################### TOICustomPropertyGrid.DoCallEdit ...');
|
|
if not CanEditRowValue then exit;
|
|
|
|
OldChangeStep:=fChangeStep;
|
|
CurRow:=Rows[FItemIndex];
|
|
if paDialog in CurRow.Editor.GetAttributes then begin
|
|
{$IFNDEF DoNotCatchOIExceptions}
|
|
try
|
|
{$ENDIF}
|
|
DebugLn(['#################### TOICustomPropertyGrid.DoCallEdit for ',CurRow.Editor.ClassName,' Edit=',Edit=oiqeEdit]);
|
|
Include(FStates,pgsApplyingValue);
|
|
try
|
|
if Edit=oiqeShowValue then
|
|
CurRow.Editor.ShowValue
|
|
else
|
|
CurRow.Editor.Edit;
|
|
finally
|
|
Exclude(FStates,pgsApplyingValue);
|
|
end;
|
|
{$IFNDEF DoNotCatchOIExceptions}
|
|
except
|
|
on E: Exception do begin
|
|
MessageDlg(oisError, E.Message, mtError, [mbOk], 0);
|
|
end;
|
|
end;
|
|
{$ENDIF}
|
|
|
|
if (OldChangeStep<>FChangeStep) then begin
|
|
// the selection has changed
|
|
// => CurRow does not exist any more
|
|
RefreshPropertyValues;
|
|
exit;
|
|
end;
|
|
|
|
// update value
|
|
RefreshValueEdit;
|
|
|
|
//invalidate changed subproperties
|
|
DoPaint(True);
|
|
end;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.RefreshValueEdit;
|
|
var
|
|
CurRow: TOIPropertyGridRow;
|
|
NewValue: string;
|
|
begin
|
|
if not GridIsUpdating and IsCurrentEditorAvailable then begin
|
|
CurRow:=Rows[FItemIndex];
|
|
NewValue:=CurRow.Editor.GetVisualValue;
|
|
SetCurrentEditValue(NewValue);
|
|
end;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.ValueEditKeyDown(Sender: TObject; var Key: Word;
|
|
Shift: TShiftState);
|
|
begin
|
|
ScrollToActiveItem;
|
|
HandleStandardKeys(Key,Shift);
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.ValueEditKeyUp(Sender: TObject; var Key: Word;
|
|
Shift: TShiftState);
|
|
begin
|
|
HandleKeyUp(Key,Shift);
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.ValueEditExit(Sender: TObject);
|
|
begin
|
|
SetRowValue;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.ValueEditChange(Sender: TObject);
|
|
var CurRow: TOIPropertyGridRow;
|
|
begin
|
|
if (pgsUpdatingEditControl in FStates) or not IsCurrentEditorAvailable then exit;
|
|
CurRow:=Rows[FItemIndex];
|
|
if paAutoUpdate in CurRow.Editor.GetAttributes then
|
|
SetRowValue;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.ValueEditMouseUp(Sender: TObject;
|
|
Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
|
|
begin
|
|
if (Button=mbLeft) and (Shift=[ssCtrl,ssLeft]) then
|
|
DoCallEdit(oiqeShowValue);
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.ValueCheckBoxKeyDown(Sender: TObject;
|
|
var Key: Word; Shift: TShiftState);
|
|
begin
|
|
ScrollToActiveItem;
|
|
HandleStandardKeys(Key,Shift);
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.ValueCheckBoxKeyUp(Sender: TObject;
|
|
var Key: Word; Shift: TShiftState);
|
|
begin
|
|
HandleKeyUp(Key,Shift);
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.ValueCheckBoxExit(Sender: TObject);
|
|
begin
|
|
SetRowValue;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.ValueCheckBoxClick(Sender: TObject);
|
|
var
|
|
CurRow: TOIPropertyGridRow;
|
|
begin
|
|
if (pgsUpdatingEditControl in FStates) or not IsCurrentEditorAvailable then exit;
|
|
CurRow:=Rows[FItemIndex];
|
|
if paAutoUpdate in CurRow.Editor.GetAttributes then
|
|
SetRowValue;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.ValueComboBoxExit(Sender: TObject);
|
|
begin
|
|
if pgsUpdatingEditControl in FStates then exit;
|
|
SetRowValue;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.ValueComboBoxKeyDown(Sender: TObject;
|
|
var Key: Word; Shift: TShiftState);
|
|
begin
|
|
ScrollToActiveItem;
|
|
HandleStandardKeys(Key,Shift);
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.ValueComboBoxKeyUp(Sender: TObject;
|
|
var Key: Word; Shift: TShiftState);
|
|
begin
|
|
HandleKeyUp(Key,Shift);
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.ValueComboBoxMouseUp(Sender: TObject;
|
|
Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
|
|
begin
|
|
if (Button=mbLeft) and (Shift=[ssCtrl,ssLeft]) then
|
|
DoCallEdit(oiqeShowValue);
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.ValueButtonClick(Sender: TObject);
|
|
begin
|
|
ScrollToActiveItem;
|
|
DoCallEdit;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.ValueComboBoxMeasureItem(Control: TWinControl;
|
|
Index: Integer; var AHeight: Integer);
|
|
var
|
|
CurRow: TOIPropertyGridRow;
|
|
begin
|
|
if (FItemIndex >= 0) and (FItemIndex < FRows.Count) then
|
|
begin
|
|
CurRow := Rows[FItemIndex];
|
|
CurRow.Editor.ListMeasureHeight('Fj', Index, ValueComboBox.Canvas, AHeight);
|
|
AHeight := Max(AHeight, ValueComboBox.ItemHeight);
|
|
end;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.SetItemIndex(NewIndex:integer);
|
|
var
|
|
NewRow: TOIPropertyGridRow;
|
|
NewValue: string;
|
|
EditorAttributes: TPropertyAttributes;
|
|
begin
|
|
if GridIsUpdating or (FItemIndex = NewIndex) then
|
|
exit;
|
|
|
|
// save old edit value
|
|
SetRowValue;
|
|
|
|
Include(FStates, pgsChangingItemIndex);
|
|
if (FItemIndex >= 0) and (FItemIndex < FRows.Count) then
|
|
Rows[FItemIndex].Editor.Deactivate;
|
|
if CanFocus then
|
|
SetCaptureControl(nil);
|
|
|
|
FItemIndex := NewIndex;
|
|
if FCurrentEdit <> nil then
|
|
begin
|
|
FCurrentEdit.Visible:=false;
|
|
FCurrentEdit.Enabled:=false;
|
|
FCurrentEdit:=nil;
|
|
end;
|
|
if FCurrentButton<>nil then
|
|
begin
|
|
FCurrentButton.Visible:=false;
|
|
FCurrentButton.Enabled:=false;
|
|
FCurrentButton:=nil;
|
|
end;
|
|
FCurrentEditorLookupRoot:=nil;
|
|
if (NewIndex>=0) and (NewIndex<FRows.Count) then
|
|
begin
|
|
NewRow:=Rows[NewIndex];
|
|
|
|
ScrollToItem(NewIndex);
|
|
|
|
if CanFocus then
|
|
NewRow.Editor.Activate;
|
|
EditorAttributes:=NewRow.Editor.GetAttributes;
|
|
if paDialog in EditorAttributes then begin
|
|
FCurrentButton:=ValueButton;
|
|
FCurrentButton.Visible:=true;
|
|
//DebugLn(['TOICustomPropertyGrid.SetItemIndex FCurrentButton.BoundsRect=',dbgs(FCurrentButton.BoundsRect)]);
|
|
end;
|
|
NewValue:=NewRow.Editor.GetVisualValue;
|
|
{$IFDEF UseOICheckBox}
|
|
if (NewRow.Editor is TBoolPropertyEditor) then begin
|
|
FCurrentEdit:=ValueCheckBox;
|
|
ValueCheckBox.Enabled:=not NewRow.IsReadOnly;
|
|
ValueCheckBox.Caption:=NewValue;
|
|
ValueCheckBox.Checked:=(NewValue='True');
|
|
end else
|
|
{$ENDIF}
|
|
if paValueList in EditorAttributes then begin
|
|
FCurrentEdit:=ValueComboBox;
|
|
if paPickList in EditorAttributes then begin
|
|
// text field should be readonly
|
|
if paCustomDrawn in EditorAttributes then
|
|
ValueComboBox.Style:=csOwnerDrawVariable
|
|
else
|
|
ValueComboBox.Style:=csDropDownList;
|
|
end else begin
|
|
if paCustomDrawn in EditorAttributes then
|
|
ValueComboBox.Style:=csOwnerDrawVariable
|
|
else
|
|
ValueComboBox.Style:=csDropDown;
|
|
end;
|
|
ValueComboBox.MaxLength:=NewRow.Editor.GetEditLimit;
|
|
ValueComboBox.Sorted:=paSortList in NewRow.Editor.GetAttributes;
|
|
ValueComboBox.Enabled:=not NewRow.IsReadOnly;
|
|
// Do not fill the items here, because it can be very slow.
|
|
// Just fill in some values and update the values, before the combobox
|
|
// popups
|
|
ValueComboBox.Items.Text:=NewValue;
|
|
Exclude(FStates,pgsGetComboItemsCalled);
|
|
SetIdleEvent(true);
|
|
ValueComboBox.Text:=NewValue;
|
|
end else begin
|
|
FCurrentEdit:=ValueEdit;
|
|
ValueEdit.ReadOnly:=NewRow.IsReadOnly;
|
|
ValueEdit.Enabled:=true;
|
|
ValueEdit.MaxLength:=NewRow.Editor.GetEditLimit;
|
|
ValueEdit.Text:=NewValue;
|
|
end;
|
|
AlignEditComponents;
|
|
if FCurrentEdit<>nil then begin
|
|
if FPropertyEditorHook<>nil then
|
|
FCurrentEditorLookupRoot:=FPropertyEditorHook.LookupRoot;
|
|
FCurrentEdit.Visible:=true;
|
|
if (FDragging=false) and (FCurrentEdit.Showing)
|
|
and FCurrentEdit.Enabled
|
|
and (not NewRow.IsReadOnly)
|
|
and CanFocus then begin
|
|
if (Column=oipgcValue) then
|
|
SetActiveControl(FCurrentEdit);
|
|
end;
|
|
end;
|
|
if FCurrentButton<>nil then
|
|
FCurrentButton.Enabled:=not NewRow.IsDisabled;
|
|
end;
|
|
//DebugLn(['TOICustomPropertyGrid.SetItemIndex Vis=',ValueComboBox.Visible,' Ena=',ValueComboBox.Enabled,' Items.Count=',ValueComboBox.Items.Count ,' Text=',ValueComboBox.Text]);
|
|
Exclude(FStates, pgsChangingItemIndex);
|
|
DoSelectionChange;
|
|
Invalidate;
|
|
end;
|
|
|
|
function TOICustomPropertyGrid.GetNameRowHeight: Integer;
|
|
begin
|
|
Result := Abs(FNameFont.Height);
|
|
if Result = 0
|
|
then Result := 16;
|
|
Inc(Result, 2); // margin
|
|
end;
|
|
|
|
function TOICustomPropertyGrid.GetRowCount:integer;
|
|
begin
|
|
Result:=FRows.Count;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.BuildPropertyList(OnlyIfNeeded: boolean);
|
|
var
|
|
a: integer;
|
|
CurRow: TOIPropertyGridRow;
|
|
OldSelectedRowPath: string;
|
|
begin
|
|
if OnlyIfNeeded and (not (pgsBuildPropertyListNeeded in FStates)) then exit;
|
|
Exclude(FStates,pgsBuildPropertyListNeeded);
|
|
|
|
OldSelectedRowPath:=PropertyPath(ItemIndex);
|
|
// unselect
|
|
ItemIndex:=-1;
|
|
// clear
|
|
for a:=0 to FRows.Count-1 do Rows[a].Free;
|
|
FRows.Clear;
|
|
// get properties
|
|
GetPersistentProperties(
|
|
FSelection, FFilter + [tkClass], FPropertyEditorHook, @AddPropertyEditor,
|
|
@EditorFilter);
|
|
// sort
|
|
FRows.Sort(@SortGridRows);
|
|
for a:=0 to FRows.Count-1 do begin
|
|
if a>0 then
|
|
Rows[a].FPriorBrother:=Rows[a-1]
|
|
else
|
|
Rows[a].FPriorBrother:=nil;
|
|
if a<FRows.Count-1 then
|
|
Rows[a].FNextBrother:=Rows[a+1]
|
|
else
|
|
Rows[a].FNextBrother:=nil;
|
|
end;
|
|
// set indices and tops
|
|
SetItemsTops;
|
|
// restore expands
|
|
for a:=FExpandedProperties.Count-1 downto 0 do begin
|
|
CurRow:=GetRowByPath(FExpandedProperties[a]);
|
|
if CurRow<>nil then
|
|
ExpandRow(CurRow.Index);
|
|
end;
|
|
// update scrollbar
|
|
FTopY:=0;
|
|
UpdateScrollBar;
|
|
// reselect
|
|
CurRow:=GetRowByPath(OldSelectedRowPath);
|
|
if CurRow<>nil then begin
|
|
ItemIndex:=CurRow.Index;
|
|
end;
|
|
// paint
|
|
Invalidate;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.AddPropertyEditor(PropEditor: TPropertyEditor);
|
|
var
|
|
NewRow: TOIPropertyGridRow;
|
|
WidgetSets: TLCLPlatforms;
|
|
begin
|
|
WidgetSets := [];
|
|
if Favourites<>nil then begin
|
|
//debugln('TOICustomPropertyGrid.AddPropertyEditor A ',PropEditor.GetName);
|
|
if Favourites is TOIRestrictedProperties then
|
|
begin
|
|
WidgetSets := (Favourites as TOIRestrictedProperties).AreRestricted(
|
|
Selection,PropEditor.GetName);
|
|
if WidgetSets = [] then
|
|
begin
|
|
PropEditor.Free;
|
|
Exit;
|
|
end;
|
|
end
|
|
else
|
|
if not Favourites.AreFavourites(Selection,PropEditor.GetName) then begin
|
|
PropEditor.Free;
|
|
exit;
|
|
end;
|
|
end;
|
|
if PropEditor is TClassPropertyEditor then
|
|
(PropEditor as TClassPropertyEditor).SubPropsTypeFilter := FFilter;
|
|
NewRow := TOIPropertyGridRow.Create(Self, PropEditor, nil, WidgetSets);
|
|
FRows.Add(NewRow);
|
|
if FRows.Count>1 then begin
|
|
NewRow.FPriorBrother:=Rows[FRows.Count-2];
|
|
NewRow.FPriorBrother.FNextBrother:=NewRow;
|
|
end;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.AddStringToComboBox(const s: string);
|
|
begin
|
|
if FNewComboBoxItems=nil then
|
|
FNewComboBoxItems:=TStringList.Create;
|
|
FNewComboBoxItems.Add(s);
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.ExpandRow(Index:integer);
|
|
var
|
|
a: integer;
|
|
CurPath: string;
|
|
AlreadyInExpandList: boolean;
|
|
ActiveRow: TOIPropertyGridRow;
|
|
begin
|
|
// Save ItemIndex
|
|
if ItemIndex <> -1 then
|
|
ActiveRow := Rows[ItemIndex]
|
|
else
|
|
ActiveRow := nil;
|
|
FExpandingRow := Rows[Index];
|
|
if (FExpandingRow.Expanded) or (not CanExpandRow(FExpandingRow)) then
|
|
begin
|
|
FExpandingRow := nil;
|
|
Exit;
|
|
end;
|
|
FExpandingRow.Editor.GetProperties(@AddSubEditor);
|
|
SortSubEditors(FExpandingRow);
|
|
SetItemsTops;
|
|
FExpandingRow.FExpanded := True;
|
|
a := 0;
|
|
CurPath:=uppercase(PropertyPath(FExpandingRow.Index));
|
|
AlreadyInExpandList:=false;
|
|
while a < FExpandedProperties.Count do
|
|
begin
|
|
if FExpandedProperties[a]=copy(CurPath,1,length(FExpandedProperties[a])) then
|
|
begin
|
|
if Length(FExpandedProperties[a]) = Length(CurPath) then
|
|
begin
|
|
AlreadyInExpandList := True;
|
|
inc(a);
|
|
end
|
|
else
|
|
FExpandedProperties.Delete(a);
|
|
end
|
|
else
|
|
inc(a);
|
|
end;
|
|
if not AlreadyInExpandList then
|
|
FExpandedProperties.Add(CurPath);
|
|
FExpandingRow := nil;
|
|
// restore ItemIndex
|
|
if ActiveRow <> nil then
|
|
FItemIndex := ActiveRow.Index
|
|
else
|
|
FItemIndex := -1;
|
|
UpdateScrollBar;
|
|
Invalidate;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.ShrinkRow(Index:integer);
|
|
var
|
|
CurRow, ARow: TOIPropertyGridRow;
|
|
StartIndex, EndIndex, a: integer;
|
|
CurPath: string;
|
|
begin
|
|
CurRow := Rows[Index];
|
|
if (not CurRow.Expanded) then
|
|
Exit;
|
|
// calculate all childs (between StartIndex..EndIndex)
|
|
StartIndex := CurRow.Index + 1;
|
|
EndIndex := FRows.Count - 1;
|
|
ARow := CurRow;
|
|
while ARow <> nil do
|
|
begin
|
|
if ARow.NextBrother <> nil then
|
|
begin
|
|
EndIndex := ARow.NextBrother.Index - 1;
|
|
break;
|
|
end;
|
|
ARow := ARow.Parent;
|
|
end;
|
|
if (FItemIndex >= StartIndex) and (FItemIndex <= EndIndex) then
|
|
// current row delete, set new current row
|
|
ItemIndex:=0
|
|
else
|
|
if FItemIndex > EndIndex then
|
|
// adjust current index for deleted rows
|
|
FItemIndex := FItemIndex - (EndIndex - StartIndex + 1);
|
|
for a := EndIndex downto StartIndex do
|
|
begin
|
|
Rows[a].Free;
|
|
FRows.Delete(a);
|
|
end;
|
|
SetItemsTops;
|
|
CurRow.FExpanded := False;
|
|
CurPath := UpperCase(PropertyPath(CurRow.Index));
|
|
a := 0;
|
|
while a < FExpandedProperties.Count do
|
|
begin
|
|
if copy(FExpandedProperties[a], 1, length(CurPath)) = CurPath then
|
|
FExpandedProperties.Delete(a)
|
|
else
|
|
inc(a);
|
|
end;
|
|
if CurRow.Parent <> nil then
|
|
FExpandedProperties.Add(PropertyPath(CurRow.Parent.Index));
|
|
UpdateScrollBar;
|
|
Invalidate;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.AddSubEditor(PropEditor:TPropertyEditor);
|
|
var NewRow:TOIPropertyGridRow;
|
|
NewIndex:integer;
|
|
begin
|
|
if PropEditor is TClassPropertyEditor then
|
|
(PropEditor as TClassPropertyEditor).SubPropsTypeFilter := FFilter;
|
|
NewRow:=TOIPropertyGridRow.Create(Self,PropEditor,FExpandingRow, []);
|
|
NewIndex:=FExpandingRow.Index+1+FExpandingRow.ChildCount;
|
|
NewRow.FIndex:=NewIndex;
|
|
FRows.Insert(NewIndex,NewRow);
|
|
if NewIndex<FItemIndex
|
|
then inc(FItemIndex);
|
|
if FExpandingRow.FFirstChild=nil then
|
|
FExpandingRow.FFirstChild:=NewRow;
|
|
NewRow.FPriorBrother:=FExpandingRow.FLastChild;
|
|
FExpandingRow.FLastChild:=NewRow;
|
|
if NewRow.FPriorBrother<>nil then
|
|
NewRow.FPriorBrother.FNextBrother:=NewRow;
|
|
inc(FExpandingRow.FChildCount);
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.SortSubEditors(ParentRow: TOIPropertyGridRow);
|
|
var
|
|
Item: TOIPropertyGridRow;
|
|
Index: Integer;
|
|
Next: TOIPropertyGridRow;
|
|
begin
|
|
if not ParentRow.Sort(@SortGridRows) then exit;
|
|
// update FRows
|
|
Item:=ParentRow.FirstChild;
|
|
Index:=ParentRow.Index+1;
|
|
Next:=ParentRow.NextSkipChilds;
|
|
while (Item<>nil) and (Item<>Next) do begin
|
|
FRows[Index]:=Item;
|
|
Item.FIndex:=Index;
|
|
Item:=Item.Next;
|
|
inc(Index);
|
|
end;
|
|
end;
|
|
|
|
function TOICustomPropertyGrid.CanExpandRow(Row: TOIPropertyGridRow): boolean;
|
|
var
|
|
AnObject: TPersistent;
|
|
ParentRow: TOIPropertyGridRow;
|
|
begin
|
|
Result:=false;
|
|
if (Row=nil) or (Row.Editor=nil) then exit;
|
|
if (not (paSubProperties in Row.Editor.GetAttributes)) then exit;
|
|
// check if circling
|
|
if (Row.Editor is TPersistentPropertyEditor) then begin
|
|
AnObject:=TPersistent(Row.Editor.GetObjectValue);
|
|
if FSelection.IndexOf(AnObject)>=0 then exit;
|
|
ParentRow:=Row.Parent;
|
|
while ParentRow<>nil do begin
|
|
if (ParentRow.Editor is TPersistentPropertyEditor)
|
|
and (ParentRow.Editor.GetObjectValue=AnObject) then
|
|
exit;
|
|
ParentRow:=ParentRow.Parent;
|
|
end;
|
|
end;
|
|
Result:=true;
|
|
end;
|
|
|
|
function TOICustomPropertyGrid.MouseToIndex(y:integer;MustExist:boolean):integer;
|
|
var l,r,m:integer;
|
|
begin
|
|
l:=0;
|
|
r:=FRows.Count-1;
|
|
inc(y,FTopY);
|
|
while (l<=r) do begin
|
|
m:=(l+r) shr 1;
|
|
if Rows[m].Top>y then begin
|
|
r:=m-1;
|
|
end else if Rows[m].Bottom<=y then begin
|
|
l:=m+1;
|
|
end else begin
|
|
Result:=m; exit;
|
|
end;
|
|
end;
|
|
if (MustExist=false) and (FRows.Count>0) then begin
|
|
if y<0 then Result:=0
|
|
else Result:=FRows.Count-1;
|
|
end else Result:=-1;
|
|
end;
|
|
|
|
function TOICustomPropertyGrid.GetActiveRow: TOIPropertyGridRow;
|
|
begin
|
|
Result:=nil;
|
|
if ItemIndex<0 then exit;
|
|
Result:=Rows[ItemIndex];
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.SetCurrentRowValue(const NewValue: string);
|
|
begin
|
|
if not CanEditRowValue or Rows[FItemIndex].IsReadOnly then exit;
|
|
// SetRowValue reads the value from the current edit control and writes it
|
|
// to the property editor
|
|
// -> set the text in the current edit control without changing FLastEditValue
|
|
SetCurrentEditValue(NewValue);
|
|
SetRowValue;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.SetItemIndexAndFocus(NewItemIndex: integer);
|
|
begin
|
|
if not InRange(NewItemIndex, 0, FRows.Count - 1) then exit;
|
|
ItemIndex:=NewItemIndex;
|
|
if FCurrentEdit<>nil then
|
|
begin
|
|
SetActiveControl(FCurrentEdit);
|
|
if (FCurrentEdit is TCustomEdit) then
|
|
TCustomEdit(FCurrentEdit).SelectAll;
|
|
end;
|
|
end;
|
|
|
|
function TOICustomPropertyGrid.CanEditRowValue: boolean;
|
|
begin
|
|
Result:=
|
|
not GridIsUpdating and IsCurrentEditorAvailable
|
|
and ((FCurrentEditorLookupRoot = nil)
|
|
or (FPropertyEditorHook = nil)
|
|
or (FPropertyEditorHook.LookupRoot = FCurrentEditorLookupRoot));
|
|
if Result then begin
|
|
{DebugLn(['TOICustomPropertyGrid.CanEditRowValue',
|
|
' pgsChangingItemIndex=',pgsChangingItemIndex in FStates,
|
|
' pgsApplyingValue=',pgsApplyingValue in FStates,
|
|
' pgsUpdatingEditControl=',pgsUpdatingEditControl in FStates,
|
|
' FCurrentEdit=',dbgsName(FCurrentEdit),
|
|
' FItemIndex=',FItemIndex,
|
|
' FCurrentEditorLookupRoot=',dbgsName(FCurrentEditorLookupRoot),
|
|
' FPropertyEditorHook.LookupRoot=',dbgsName(FPropertyEditorHook.LookupRoot)
|
|
]);}
|
|
end;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.SaveChanges;
|
|
begin
|
|
SetRowValue;
|
|
end;
|
|
|
|
function TOICustomPropertyGrid.GetHintTypeAt(RowIndex: integer; X: integer): TPropEditHint;
|
|
var
|
|
IconX: integer;
|
|
begin
|
|
Result := pehNone;
|
|
if (RowIndex < 0) or (RowIndex >= RowCount) then
|
|
Exit;
|
|
if SplitterX <= X then
|
|
begin
|
|
if (FCurrentButton <> nil) and (FCurrentButton.Left <= X) then
|
|
Result := pehEditButton
|
|
else
|
|
Result := pehValue;
|
|
end else
|
|
begin
|
|
IconX := GetTreeIconX(RowIndex);
|
|
if IconX + Indent > X then
|
|
Result := pehTree
|
|
else
|
|
Result := pehName;
|
|
end;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.MouseDown(Button:TMouseButton; Shift:TShiftState;
|
|
X,Y:integer);
|
|
var
|
|
IconX,Index:integer;
|
|
PointedRow:TOIpropertyGridRow;
|
|
begin
|
|
//ShowMessageDialog('X'+IntToStr(X)+',Y'+IntToStr(Y));
|
|
inherited MouseDown(Button,Shift,X,Y);
|
|
|
|
HideHint;
|
|
|
|
if Button=mbLeft then begin
|
|
if Cursor=crHSplit then begin
|
|
FDragging:=true;
|
|
end
|
|
else
|
|
begin
|
|
Index:=MouseToIndex(Y,false);
|
|
if (Index>=0) and (Index<FRows.Count) then
|
|
begin
|
|
PointedRow:=Rows[Index];
|
|
if CanExpandRow(PointedRow) then
|
|
begin
|
|
IconX:=GetTreeIconX(Index);
|
|
if ((X>=IconX) and (X<=IconX+FIndent)) or (ssDouble in Shift) then
|
|
begin
|
|
if PointedRow.Expanded then
|
|
ShrinkRow(Index)
|
|
else
|
|
ExpandRow(Index);
|
|
end;
|
|
end;
|
|
|
|
SetItemIndexAndFocus(Index);
|
|
SetCaptureControl(Self);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.MouseMove(Shift:TShiftState; X,Y:integer);
|
|
var
|
|
SplitDistance:integer;
|
|
Index: Integer;
|
|
fPropRow: TOIPropertyGridRow;
|
|
fHint: String;
|
|
fpoint: TPoint;
|
|
fHintRect: TRect;
|
|
begin
|
|
inherited MouseMove(Shift,X,Y);
|
|
SplitDistance:=X-SplitterX;
|
|
if FDragging then begin
|
|
if ssLeft in Shift then begin
|
|
SplitterX:=SplitterX+SplitDistance;
|
|
end else begin
|
|
EndDragSplitter;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
if (abs(SplitDistance)<=2) then begin
|
|
Cursor:=crHSplit;
|
|
end else begin
|
|
Cursor:=crDefault;
|
|
end;
|
|
|
|
if ssLeft in Shift then
|
|
begin
|
|
Index := MouseToIndex(Y, False);
|
|
SetItemIndexAndFocus(Index);
|
|
SetCaptureControl(Self);
|
|
end;
|
|
|
|
// to check if the property text fits in its box, if not show a hint
|
|
if ShowHint then
|
|
begin
|
|
Index := MouseToIndex(y,false);
|
|
if (Index > -1)
|
|
and (not FShowingLongHint)
|
|
and ((FHintWindow=nil) or (not FHintWindow.Visible)
|
|
or (Index<>FHintIndex))
|
|
then begin
|
|
FHintIndex:=Index;
|
|
FShowingLongHint:=false;
|
|
fPropRow := GetRow(Index);
|
|
if X < SplitterX then
|
|
begin
|
|
// Mouse is over property name...
|
|
fHint := fPropRow.Name;
|
|
if InitHints and ((Canvas.TextWidth(fHint) + BorderWidth + GetTreeIconX(Index) + Indent) >= SplitterX) then
|
|
begin
|
|
fHintRect := FHintWindow.CalcHintRect(0,fHint,nil);
|
|
fPoint := ClientToScreen(
|
|
Point(BorderWidth+GetTreeIconX(Index)+Indent,
|
|
fPropRow.Bottom - TopY-1));
|
|
MoveRect(fHintRect,fPoint.x,fPoint.y);
|
|
FHintWindow.ActivateHint(fHintRect,fHint);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
// Mouse is over property value...
|
|
fHint := fPropRow.LastPaintedValue;
|
|
if length(fHint) > 100 then fHint := copy(fHint, 1, 100) + '...';
|
|
if (Canvas.TextWidth(fHint) > (ClientWidth - BorderWidth - SplitterX)) and
|
|
InitHints then
|
|
begin
|
|
fHintRect := FHintWindow.CalcHintRect(0,fHint,nil);
|
|
fpoint := ClientToScreen(Point(SplitterX, fPropRow.Bottom - TopY - 1));
|
|
MoveRect(fHintRect, fPoint.x, fPoint.y);
|
|
FHintWindow.ActivateHint(fHintRect, fHint);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.MouseUp(Button:TMouseButton; Shift:TShiftState;
|
|
X,Y:integer);
|
|
begin
|
|
if FDragging then EndDragSplitter;
|
|
SetCaptureControl(nil);
|
|
inherited MouseUp(Button,Shift,X,Y);
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.KeyDown(var Key: Word; Shift: TShiftState);
|
|
begin
|
|
HandleStandardKeys(Key,Shift);
|
|
inherited KeyDown(Key, Shift);
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.HandleStandardKeys(
|
|
var Key: Word; Shift: TShiftState);
|
|
|
|
var
|
|
Handled: Boolean;
|
|
|
|
procedure FindPropertyByFirstLetter;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
if Column = oipgcName then
|
|
for i := 0 to RowCount - 1 do
|
|
if (Rows[i].Lvl = Rows[ItemIndex].Lvl) and
|
|
(Ord(upCase(Rows[i].Name[1])) = Key) then
|
|
begin
|
|
SetItemIndexAndFocus(i);
|
|
exit;
|
|
end;
|
|
Handled := false;
|
|
end;
|
|
|
|
procedure HandleUnshifted;
|
|
const
|
|
Page = 20;
|
|
begin
|
|
Handled := true;
|
|
case Key of
|
|
VK_UP : SetItemIndexAndFocus(ItemIndex - 1);
|
|
VK_DOWN : SetItemIndexAndFocus(ItemIndex + 1);
|
|
VK_PRIOR: SetItemIndexAndFocus(Max(ItemIndex - Page, 0));
|
|
VK_NEXT : SetItemIndexAndFocus(Min(ItemIndex + Page, FRows.Count - 1));
|
|
|
|
VK_TAB: DoTabKey;
|
|
|
|
VK_RETURN:
|
|
begin
|
|
SetRowValue;
|
|
if FCurrentEdit is TCustomEdit then
|
|
TCustomEdit(FCurrentEdit).SelectAll;
|
|
end;
|
|
|
|
VK_ESCAPE: RefreshValueEdit;
|
|
|
|
Ord('A')..Ord('Z'): FindPropertyByFirstLetter;
|
|
|
|
else
|
|
Handled := false;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
//writeln('TOICustomPropertyGrid.HandleStandardKeys ',Key);
|
|
Handled := false;
|
|
if (Shift = []) or (Shift = [ssShift]) then
|
|
begin
|
|
if not (FCurrentEdit is TCustomCombobox) or
|
|
not TCustomCombobox(FCurrentEdit).DroppedDown then
|
|
HandleUnshifted;
|
|
end
|
|
else
|
|
if Shift = [ssCtrl] then
|
|
begin
|
|
case Key of
|
|
VK_RETURN:
|
|
begin
|
|
ToggleRow;
|
|
Handled := true;
|
|
end;
|
|
end;
|
|
end
|
|
else
|
|
if Shift = [ssAlt] then
|
|
case Key of
|
|
VK_LEFT:
|
|
begin
|
|
Handled := (ItemIndex >= 0) and Rows[ItemIndex].Expanded;
|
|
if Handled then ShrinkRow(ItemIndex);
|
|
end;
|
|
|
|
VK_RIGHT:
|
|
begin
|
|
Handled := (ItemIndex >= 0) and not Rows[ItemIndex].Expanded and
|
|
CanExpandRow(Rows[ItemIndex]);
|
|
if Handled then ExpandRow(ItemIndex)
|
|
end;
|
|
end;
|
|
|
|
|
|
if not Handled and Assigned(OnOIKeyDown) then
|
|
begin
|
|
OnOIKeyDown(Self, Key, Shift);
|
|
Handled := Key = VK_UNKNOWN;
|
|
end;
|
|
|
|
//writeln('TOICustomPropertyGrid.HandleStandardKeys ',Key,' Handled=',Handled);
|
|
if Handled then
|
|
Key := VK_UNKNOWN;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.HandleKeyUp(var Key: Word; Shift: TShiftState);
|
|
begin
|
|
if (Key<>VK_UNKNOWN) and Assigned(OnKeyUp) then OnKeyUp(Self,Key,Shift);
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.DoTabKey;
|
|
begin
|
|
if Column = oipgcValue then
|
|
begin
|
|
Column := oipgcName;
|
|
Self.SetFocus;
|
|
end else
|
|
begin
|
|
Column := oipgcValue;
|
|
if FCurrentEdit <> nil then
|
|
FCurrentEdit.SetFocus;
|
|
end;
|
|
end;
|
|
|
|
function TOICustomPropertyGrid.EditorFilter(
|
|
const AEditor: TPropertyEditor): Boolean;
|
|
begin
|
|
Result := IsInteresting(AEditor, FFilter);
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.EraseBackground(DC: HDC);
|
|
begin
|
|
// everything is painted, so erasing the background is not needed
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.DoSetBounds(ALeft, ATop, AWidth, AHeight: integer);
|
|
begin
|
|
inherited DoSetBounds(ALeft, ATop, AWidth, AHeight);
|
|
UpdateScrollBar;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.DoSelectionChange;
|
|
begin
|
|
if Assigned(FOnSelectionChange) then
|
|
OnSelectionChange(Self);
|
|
end;
|
|
|
|
constructor TOICustomPropertyGrid.Create(TheOwner: TComponent);
|
|
begin
|
|
CreateWithParams(TheOwner,nil,AllTypeKinds,25);
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.OnUserInput(Sender: TObject; Msg: Cardinal);
|
|
begin
|
|
ResetHintTimer;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.EndDragSplitter;
|
|
begin
|
|
if FDragging then begin
|
|
Cursor:=crDefault;
|
|
FDragging:=false;
|
|
FPreferredSplitterX:=FSplitterX;
|
|
if FCurrentEdit<>nil then begin
|
|
SetCaptureControl(nil);
|
|
if Column=oipgcValue then
|
|
FCurrentEdit.SetFocus
|
|
else
|
|
Self.SetFocus;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.SetReadOnlyColor(const AValue: TColor);
|
|
begin
|
|
if FReadOnlyColor = AValue then Exit;
|
|
FReadOnlyColor := AValue;
|
|
Invalidate;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.SetRowSpacing(const AValue: integer);
|
|
begin
|
|
if FRowSpacing = AValue then exit;
|
|
FRowSpacing := AValue;
|
|
SetItemsTops;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.SetShowGutter(const AValue: Boolean);
|
|
begin
|
|
if FShowGutter=AValue then exit;
|
|
FShowGutter:=AValue;
|
|
invalidate;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.SetSplitterX(const NewValue:integer);
|
|
var AdjustedValue:integer;
|
|
begin
|
|
AdjustedValue:=NewValue;
|
|
if AdjustedValue>ClientWidth then AdjustedValue:=ClientWidth;
|
|
if AdjustedValue<1 then AdjustedValue:=1;
|
|
if FSplitterX<>AdjustedValue then begin
|
|
FSplitterX:=AdjustedValue;
|
|
AlignEditComponents;
|
|
Invalidate;
|
|
end;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.SetTopY(const NewValue:integer);
|
|
var
|
|
NewTopY: integer;
|
|
begin
|
|
NewTopY := TopMax;
|
|
if NewValue < NewTopY then
|
|
NewTopY := NewValue;
|
|
if NewTopY < 0 then
|
|
NewTopY := 0;
|
|
if FTopY<>NewTopY then begin
|
|
FTopY:=NewTopY;
|
|
UpdateScrollBar;
|
|
AlignEditComponents;
|
|
Invalidate;
|
|
end;
|
|
end;
|
|
|
|
function TOICustomPropertyGrid.GetPropNameColor(ARow:TOIPropertyGridRow):TColor;
|
|
|
|
function HasWriter(APropInfo: PPropInfo): Boolean; inline;
|
|
begin
|
|
Result := Assigned(APropInfo) and Assigned(APropInfo^.SetProc);
|
|
end;
|
|
|
|
var
|
|
ParentRow:TOIPropertyGridRow;
|
|
IsObjectSubProperty:Boolean;
|
|
begin
|
|
// Try to guest if ARow, or one of its parents, is a subproperty
|
|
// of an object (and not an item of a set)
|
|
IsObjectSubProperty:=false;
|
|
ParentRow:=ARow.Parent;
|
|
while Assigned(ParentRow) do
|
|
begin
|
|
if ParentRow.Editor is TPersistentPropertyEditor then
|
|
IsObjectSubProperty:=true;
|
|
ParentRow:=ParentRow.Parent;
|
|
end;
|
|
|
|
if (ItemIndex <> -1) and (ItemIndex = ARow.Index) then
|
|
Result := FHighlightFont.Color
|
|
else
|
|
if not HasWriter(ARow.Editor.GetPropInfo) then
|
|
Result := FReadOnlyColor
|
|
else
|
|
if ARow.Editor is TPersistentPropertyEditor then
|
|
Result := FReferencesColor
|
|
else
|
|
if IsObjectSubProperty then
|
|
Result := FSubPropertiesColor
|
|
else
|
|
Result := FNameFont.Color;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.SetBounds(aLeft,aTop,aWidth,aHeight:integer);
|
|
begin
|
|
//writeln('[TOICustomPropertyGrid.SetBounds] ',Name,' ',aLeft,',',aTop,',',aWidth,',',aHeight,' Visible=',Visible);
|
|
inherited SetBounds(aLeft,aTop,aWidth,aHeight);
|
|
if Visible then begin
|
|
if not FDragging then begin
|
|
if (SplitterX<5) and (aWidth>20) then
|
|
SplitterX:=100
|
|
else
|
|
SplitterX:=FPreferredSplitterX;
|
|
end;
|
|
AlignEditComponents;
|
|
end;
|
|
end;
|
|
|
|
function TOICustomPropertyGrid.GetTreeIconX(Index:integer):integer;
|
|
begin
|
|
Result:=Rows[Index].Lvl*Indent+2;
|
|
end;
|
|
|
|
function TOICustomPropertyGrid.TopMax:integer;
|
|
begin
|
|
Result:=GridHeight-ClientHeight+2*integer(BorderWidth);
|
|
if Result<0 then Result:=0;
|
|
end;
|
|
|
|
function TOICustomPropertyGrid.GridHeight:integer;
|
|
begin
|
|
if FRows.Count>0 then
|
|
Result:=Rows[FRows.Count-1].Bottom
|
|
else
|
|
Result:=0;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.AlignEditComponents;
|
|
var RRect,EditCompRect,EditBtnRect:TRect;
|
|
|
|
function CompareRectangles(r1,r2:TRect):boolean;
|
|
begin
|
|
Result:=(r1.Left=r2.Left) and (r1.Top=r2.Top) and (r1.Right=r2.Right)
|
|
and (r1.Bottom=r2.Bottom);
|
|
end;
|
|
|
|
// AlignEditComponents
|
|
begin
|
|
if ItemIndex>=0
|
|
then begin
|
|
RRect := RowRect(ItemIndex);
|
|
EditCompRect := RRect;
|
|
EditCompRect.Bottom := EditCompRect.Bottom - 1;
|
|
|
|
if Layout = oilHorizontal
|
|
then begin
|
|
EditCompRect.Left := RRect.Left + SplitterX;
|
|
end
|
|
else begin
|
|
EditCompRect.Top := RRect.Top + GetNameRowHeight;
|
|
EditCompRect.Left := RRect.Left + GetTreeIconX(ItemIndex) + Indent;
|
|
end;
|
|
|
|
if FCurrentButton<>nil then begin
|
|
// edit dialog button
|
|
with EditBtnRect do begin
|
|
Top := EditCompRect.Top;
|
|
Left := EditCompRect.Right - 20;
|
|
Bottom := EditCompRect.Bottom;
|
|
Right := EditCompRect.Right;
|
|
EditCompRect.Right := Left;
|
|
end;
|
|
if not CompareRectangles(FCurrentButton.BoundsRect,EditBtnRect) then begin
|
|
FCurrentButton.BoundsRect:=EditBtnRect;
|
|
end;
|
|
//DebugLn(['TOICustomPropertyGrid.AlignEditComponents FCurrentButton.BoundsRect=',dbgs(FCurrentButton.BoundsRect),' EditBtnRect=',dbgs(EditBtnRect)]);
|
|
end;
|
|
if FCurrentEdit<>nil then begin
|
|
// resize the edit component
|
|
Dec(EditCompRect.Left);
|
|
Dec(EditCompRect.Top);
|
|
Inc(EditCompRect.Bottom);
|
|
//debugln('TOICustomPropertyGrid.AlignEditComponents A ',dbgsName(FCurrentEdit),' ',dbgs(EditCompRect));
|
|
if not CompareRectangles(FCurrentEdit.BoundsRect,EditCompRect) then begin
|
|
FCurrentEdit.BoundsRect:=EditCompRect;
|
|
if FCurrentEdit is TComboBox then
|
|
TComboBox(FCurrentEdit).ItemHeight:=
|
|
EditCompRect.Bottom-EditCompRect.Top-6;
|
|
FCurrentEdit.Invalidate;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.PaintRow(ARow: integer);
|
|
var
|
|
FullRect,NameRect,NameIconRect,NameTextRect,ValueRect, ParentRect:TRect;
|
|
IconX,IconY:integer;
|
|
CurRow:TOIPropertyGridRow;
|
|
DrawState:TPropEditDrawState;
|
|
OldFont:TFont;
|
|
lclPlatform: TLCLPlatform;
|
|
X, Y: Integer;
|
|
NameBgColor: TColor;
|
|
|
|
procedure DrawTreeIcon(X, Y: Integer; Minus: Boolean);
|
|
const
|
|
PlusMinusDetail: array[Boolean] of TThemedTreeview =
|
|
(
|
|
ttGlyphClosed,
|
|
ttGlyphOpened
|
|
);
|
|
var
|
|
Details: TThemedElementDetails;
|
|
begin
|
|
Details := ThemeServices.GetElementDetails(PlusMinusDetail[Minus]);
|
|
ThemeServices.DrawElement(Canvas.Handle, Details, Rect(X, Y, X + 9, Y + 9), nil);
|
|
end;
|
|
|
|
procedure DrawActiveRow(X, Y: Integer);
|
|
begin
|
|
Canvas.Draw(X, Y, FActiveRowBmp);
|
|
end;
|
|
|
|
// PaintRow
|
|
begin
|
|
CurRow := Rows[ARow];
|
|
FullRect := RowRect(ARow);
|
|
NameRect := FullRect;
|
|
ValueRect := FullRect;
|
|
Inc(FullRect.Bottom, FRowSpacing);
|
|
|
|
if ARow = FItemIndex then
|
|
begin
|
|
if Layout = oilHorizontal then
|
|
begin
|
|
if Assigned(FCurrentButton) and (FCurrentButton.Visible) then
|
|
Dec(FullRect.Right, FCurrentButton.Width);
|
|
|
|
if Assigned(FCurrentEdit) and (FCurrentEdit.Visible) then
|
|
Dec(FullRect.Right, FCurrentEdit.Width);
|
|
end;
|
|
end;
|
|
|
|
if Layout = oilHorizontal
|
|
then begin
|
|
NameRect.Right:=SplitterX;
|
|
ValueRect.Left:=SplitterX;
|
|
end
|
|
else begin
|
|
NameRect.Bottom := NameRect.Top + GetNameRowHeight;
|
|
ValueRect.Top := NameRect.Bottom;
|
|
end;
|
|
|
|
IconX:=GetTreeIconX(ARow);
|
|
IconY:=((NameRect.Bottom-NameRect.Top-9) div 2)+NameRect.Top;
|
|
NameIconRect := NameRect;
|
|
NameIconRect.Right := IconX + Indent;
|
|
NameTextRect := NameRect;
|
|
NameTextRect.Left := NameIconRect.Right;
|
|
|
|
if Layout = oilVertical then
|
|
ValueRect.Left := NameTextRect.Left
|
|
else
|
|
begin
|
|
inc(NameIconRect.Right, 2 + Ord(ShowGutter));
|
|
inc(NameTextRect.Left, 3 + + Ord(ShowGutter));
|
|
end;
|
|
|
|
DrawState:=[];
|
|
if ARow = FItemIndex then
|
|
Include(DrawState, pedsSelected);
|
|
|
|
with Canvas do
|
|
begin
|
|
// clear background in one go
|
|
|
|
if (ARow = FItemIndex) and (FHighlightColor <> clNone) then
|
|
NameBgColor := FHighlightColor
|
|
else
|
|
NameBgColor := FBackgroundColor;
|
|
|
|
if FBackgroundColor <> clNone then
|
|
begin
|
|
Brush.Color := FBackgroundColor;
|
|
FillRect(FullRect);
|
|
end;
|
|
|
|
if ShowGutter and (Layout = oilHorizontal) and
|
|
(FGutterColor <> FBackgroundColor) and (FGutterColor <> clNone) then
|
|
begin
|
|
Brush.Color := FGutterColor;
|
|
FillRect(NameIconRect);
|
|
end;
|
|
|
|
// draw icon
|
|
if CanExpandRow(CurRow) then
|
|
DrawTreeIcon(IconX, IconY, CurRow.Expanded)
|
|
else
|
|
if (ARow = FItemIndex) then
|
|
DrawActiveRow(IconX, IconY);
|
|
|
|
// draw name
|
|
OldFont:=Font;
|
|
Font:=FNameFont;
|
|
Font.Color := GetPropNameColor(CurRow);
|
|
// set bg color to highlight if needed
|
|
if (NameBgColor <> FBackgroundColor) and (NameBgColor <> clNone) then
|
|
begin
|
|
Brush.Color := NameBgColor;
|
|
FillRect(NameTextRect);
|
|
end;
|
|
CurRow.Editor.PropDrawName(Canvas, NameTextRect, DrawState);
|
|
Font := OldFont;
|
|
|
|
if (FBackgroundColor <> clNone) then // return color back to background
|
|
Brush.Color := FBackgroundColor;
|
|
|
|
// draw widgetsets
|
|
X := NameRect.Right - 2;
|
|
Y := (NameRect.Top + NameRect.Bottom - IDEImages.Images_16.Height) div 2;
|
|
OldFont:=Font;
|
|
Font:=FNameFont;
|
|
Font.Color := clRed;
|
|
for lclPlatform := High(TLCLPlatform) downto Low(TLCLPlatform) do
|
|
begin
|
|
if lclPlatform in CurRow.FWidgetSets then
|
|
begin
|
|
Dec(X, IDEImages.Images_16.Width);
|
|
IDEImages.Images_16.Draw(Canvas, X, Y,
|
|
IDEImages.LoadImage(16, 'issue_'+LCLPlatformDirNames[lclPlatform]));
|
|
end;
|
|
end;
|
|
Font:=OldFont;
|
|
|
|
// draw value
|
|
if ARow<>ItemIndex
|
|
then begin
|
|
OldFont:=Font;
|
|
if CurRow.Editor.IsNotDefaultValue then
|
|
Font:=FValueFont
|
|
else
|
|
Font:=FDefaultValueFont;
|
|
CurRow.Editor.PropDrawValue(Canvas,ValueRect,DrawState);
|
|
Font:=OldFont;
|
|
end;
|
|
CurRow.LastPaintedValue:=CurRow.Editor.GetVisualValue;
|
|
|
|
|
|
// -----------------
|
|
// frames
|
|
// -----------------
|
|
|
|
if Layout = oilHorizontal then
|
|
begin
|
|
// Row Divider
|
|
|
|
if DrawHorzGridLines then
|
|
begin
|
|
Pen.Style := psDot;
|
|
Pen.EndCap := pecFlat;
|
|
Pen.Cosmetic := False;
|
|
Pen.Color := cl3DShadow;
|
|
if FRowSpacing <> 0 then
|
|
begin
|
|
MoveTo(NameTextRect.Left, NameRect.Top - 1);
|
|
LineTo(ValueRect.Right, NameRect.Top - 1);
|
|
end;
|
|
MoveTo(NameTextRect.Left, NameRect.Bottom - 1);
|
|
LineTo(ValueRect.Right, NameRect.Bottom - 1);
|
|
end;
|
|
|
|
// Split lines between: icon and name, name and value
|
|
Pen.Style := psSolid;
|
|
Pen.Cosmetic := True;
|
|
Pen.Color := cl3DHiLight;
|
|
MoveTo(NameRect.Right - 1, NameRect.Bottom - 1);
|
|
LineTo(NameRect.Right - 1, NameRect.Top - 1 - FRowSpacing);
|
|
Pen.Color := cl3DShadow;
|
|
MoveTo(NameRect.Right - 2, NameRect.Bottom - 1);
|
|
LineTo(NameRect.Right - 2, NameRect.Top - 1 - FRowSpacing);
|
|
|
|
// draw gutter line
|
|
if ShowGutter then
|
|
begin
|
|
Pen.Color := GutterEdgeColor;
|
|
MoveTo(NameIconRect.Right, NameRect.Bottom - 1);
|
|
LineTo(NameIconRect.Right, NameRect.Top - 1 - FRowSpacing);
|
|
|
|
if CurRow.Lvl > 0 then
|
|
begin
|
|
// draw to parent
|
|
if ARow > 0 then
|
|
begin
|
|
ParentRect := RowRect(ARow - 1);
|
|
X := ParentRect.Left + GetTreeIconX(ARow - 1) + Indent + 3;
|
|
if X <> NameIconRect.Right then
|
|
begin
|
|
MoveTo(NameIconRect.Right, NameRect.Top - 1 - FRowSpacing);
|
|
LineTo(X - 1, NameRect.Top - 1 - FRowSpacing);
|
|
end;
|
|
end;
|
|
// to to parent next sibling
|
|
if ARow < FRows.Count - 1 then
|
|
begin
|
|
ParentRect := RowRect(ARow + 1);
|
|
X := ParentRect.Left + GetTreeIconX(ARow + 1) + Indent + 3;
|
|
if X <> NameIconRect.Right then
|
|
begin
|
|
MoveTo(NameIconRect.Right, NameRect.Bottom - 1);
|
|
LineTo(X - 1, NameRect.Bottom - 1);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end
|
|
else begin
|
|
Pen.Style := psSolid;
|
|
Pen.Color := cl3DLight;
|
|
MoveTo(ValueRect.Left, ValueRect.Bottom - 1);
|
|
LineTo(ValueRect.Left, NameTextRect.Top);
|
|
LineTo(ValueRect.Right - 1, NameTextRect.Top);
|
|
Pen.Color:=cl3DHiLight;
|
|
LineTo(ValueRect.Right - 1, ValueRect.Bottom - 1);
|
|
LineTo(ValueRect.Left, ValueRect.Bottom - 1);
|
|
|
|
MoveTo(NameTextRect.Left + 1, NametextRect.Bottom);
|
|
LineTo(NameTextRect.Left + 1, NameTextRect.Top + 1);
|
|
LineTo(NameTextRect.Right - 2, NameTextRect.Top + 1);
|
|
Pen.Color:=cl3DLight;
|
|
LineTo(NameTextRect.Right - 2, NameTextRect.Bottom - 1);
|
|
LineTo(NameTextRect.Left + 2, NameTextRect.Bottom - 1);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.DoPaint(PaintOnlyChangedValues: boolean);
|
|
var
|
|
a: integer;
|
|
SpaceRect: TRect;
|
|
GutterX: Integer;
|
|
begin
|
|
BuildPropertyList(true);
|
|
if not PaintOnlyChangedValues then
|
|
begin
|
|
with Canvas do
|
|
begin
|
|
// draw properties
|
|
for a := 0 to FRows.Count - 1 do
|
|
PaintRow(a);
|
|
// draw unused space below rows
|
|
SpaceRect := Rect(BorderWidth, BorderWidth,
|
|
ClientWidth - BorderWidth + 1, ClientHeight - BorderWidth + 1);
|
|
if FRows.Count > 0 then
|
|
SpaceRect.Top := Rows[FRows.Count - 1].Bottom - FTopY + BorderWidth;
|
|
if FBackgroundColor <> clNone then
|
|
begin
|
|
Brush.Color := FBackgroundColor;
|
|
FillRect(SpaceRect);
|
|
end;
|
|
|
|
// draw gutter if needed
|
|
if ShowGutter and (Layout = oilHorizontal) then
|
|
begin
|
|
if FRows.Count > 0 then
|
|
GutterX := RowRect(FRows.Count - 1).Left + GetTreeIconX(FRows.Count - 1)
|
|
else
|
|
GutterX := BorderWidth + 2;
|
|
inc(GutterX, Indent + 3);
|
|
SpaceRect.Right := GutterX;
|
|
if GutterColor <> clNone then
|
|
begin
|
|
Brush.Color := GutterColor;
|
|
FillRect(SpaceRect);
|
|
end;
|
|
MoveTo(GutterX, SpaceRect.Top);
|
|
LineTo(GutterX, SpaceRect.Bottom);
|
|
end;
|
|
// don't draw border: borderstyle=bsSingle
|
|
end;
|
|
end else
|
|
begin
|
|
for a := 0 to FRows.Count-1 do
|
|
begin
|
|
if Rows[a].Editor.GetVisualValue <> Rows[a].LastPaintedValue then
|
|
PaintRow(a);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.Paint;
|
|
begin
|
|
inherited Paint;
|
|
DoPaint(false);
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.RefreshPropertyValues;
|
|
begin
|
|
RefreshValueEdit;
|
|
DoPaint(true);
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.ScrollToActiveItem;
|
|
begin
|
|
ScrollToItem(FItemIndex);
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.ScrollToItem(NewIndex: Integer);
|
|
var
|
|
NewRow: TOIPropertyGridRow;
|
|
begin
|
|
if (NewIndex >= 0) and (NewIndex < FRows.Count) then
|
|
begin
|
|
NewRow := Rows[NewIndex];
|
|
if NewRow.Bottom >= TopY + (ClientHeight - 2*BorderWidth) then
|
|
TopY := NewRow.Bottom- (ClientHeight - 2*BorderWidth) + 1
|
|
else
|
|
if NewRow.Top < TopY then TopY := NewRow.Top;
|
|
end;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.PropEditLookupRootChange;
|
|
begin
|
|
// When the LookupRoot changes, no changes can be stored
|
|
// -> undo the value editor changes
|
|
RefreshValueEdit;
|
|
if PropertyEditorHook<>nil then
|
|
FCurrentEditorLookupRoot:=PropertyEditorHook.LookupRoot;
|
|
end;
|
|
|
|
function TOICustomPropertyGrid.RowRect(ARow:integer):TRect;
|
|
const
|
|
ScrollBarWidth=0;
|
|
begin
|
|
Result.Left:=BorderWidth;
|
|
Result.Top:=Rows[ARow].Top-FTopY+BorderWidth;
|
|
Result.Right:=ClientWidth-ScrollBarWidth;
|
|
Result.Bottom:=Rows[ARow].Bottom-FTopY+BorderWidth;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.SetItemsTops;
|
|
// compute row tops from row heights
|
|
// set indices of all rows
|
|
var a:integer;
|
|
begin
|
|
for a:=0 to FRows.Count-1 do begin
|
|
Rows[a].FIndex:=a;
|
|
Rows[a].MeasureHeight(Canvas);
|
|
end;
|
|
if FRows.Count>0 then
|
|
Rows[0].Top:=0;
|
|
for a:=1 to FRows.Count-1 do
|
|
Rows[a].FTop:=Rows[a-1].Bottom + FRowSpacing;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.ClearRows;
|
|
var a:integer;
|
|
begin
|
|
IncreaseChangeStep;
|
|
// reverse order to make sure child rows are freed before parent rows
|
|
for a:=FRows.Count-1 downto 0 do begin
|
|
Rows[a].Free;
|
|
end;
|
|
FRows.Clear;
|
|
end;
|
|
|
|
function TOICustomPropertyGrid.GetCurrentEditValue: string;
|
|
begin
|
|
if FCurrentEdit=ValueEdit then
|
|
Result:=ValueEdit.Text
|
|
else if FCurrentEdit=ValueComboBox then
|
|
Result:=ValueComboBox.Text
|
|
else if FCurrentEdit=ValueCheckBox then
|
|
Result:=ValueCheckBox.Caption
|
|
else
|
|
Result:='';
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.SetActiveControl(const AControl: TWinControl);
|
|
var
|
|
F: TCustomForm;
|
|
begin
|
|
F := GetParentForm(Self);
|
|
if F <> nil then
|
|
F.ActiveControl := AControl;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.SetColumn(
|
|
const AValue: TOICustomPropertyGridColumn);
|
|
begin
|
|
if FColumn=AValue then exit;
|
|
FColumn:=AValue;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.SetCurrentEditValue(const NewValue: string);
|
|
begin
|
|
if FCurrentEdit=ValueEdit then
|
|
ValueEdit.Text:=NewValue
|
|
else if FCurrentEdit=ValueComboBox then
|
|
ValueComboBox.Text:=NewValue
|
|
else if FCurrentEdit=ValueCheckBox then begin
|
|
ValueCheckBox.Caption:=NewValue;
|
|
ValueCheckBox.Checked:=NewValue='True';
|
|
end;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.SetDrawHorzGridLines(const AValue: Boolean);
|
|
begin
|
|
if FDrawHorzGridLines = AValue then Exit;
|
|
FDrawHorzGridLines := AValue;
|
|
Invalidate;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.SetFavourites(
|
|
const AValue: TOIFavouriteProperties);
|
|
begin
|
|
//debugln('TOICustomPropertyGrid.SetFavourites ',dbgsName(Self));
|
|
if FFavourites=AValue then exit;
|
|
FFavourites:=AValue;
|
|
BuildPropertyList;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.SetFilter(const AValue: TTypeKinds);
|
|
begin
|
|
if (AValue<>FFilter) then
|
|
begin
|
|
FFilter:=AValue;
|
|
BuildPropertyList;
|
|
end;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.SetGutterColor(const AValue: TColor);
|
|
begin
|
|
if FGutterColor=AValue then exit;
|
|
FGutterColor:=AValue;
|
|
invalidate;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.SetGutterEdgeColor(const AValue: TColor);
|
|
begin
|
|
if FGutterEdgeColor=AValue then exit;
|
|
FGutterEdgeColor:=AValue;
|
|
invalidate;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.SetHighlightColor(const AValue: TColor);
|
|
begin
|
|
if FHighlightColor=AValue then exit;
|
|
FHighlightColor:=AValue;
|
|
Invalidate;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.Clear;
|
|
begin
|
|
ClearRows;
|
|
end;
|
|
|
|
function TOICustomPropertyGrid.GetRow(Index:integer):TOIPropertyGridRow;
|
|
begin
|
|
Result:=TOIPropertyGridRow(FRows[Index]);
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.ValueComboBoxCloseUp(Sender: TObject);
|
|
begin
|
|
SetRowValue;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.ValueComboBoxGetItems(Sender: TObject);
|
|
var
|
|
CurRow: TOIPropertyGridRow;
|
|
MaxItemWidth, CurItemWidth, i, Cnt: integer;
|
|
ItemValue, CurValue: string;
|
|
NewItemIndex: LongInt;
|
|
ExcludeUpdateFlag: boolean;
|
|
begin
|
|
Include(FStates,pgsGetComboItemsCalled);
|
|
if (FItemIndex>=0) and (FItemIndex<FRows.Count) then begin
|
|
//debugln('TOICustomPropertyGrid.ValueComboBoxDropDown A');
|
|
ExcludeUpdateFlag:=not (pgsUpdatingEditControl in FStates);
|
|
Include(FStates,pgsUpdatingEditControl);
|
|
ValueComboBox.Items.BeginUpdate;
|
|
try
|
|
CurRow:=Rows[FItemIndex];
|
|
|
|
// Items
|
|
FillComboboxItems;
|
|
|
|
// Text and ItemIndex
|
|
CurValue:=CurRow.Editor.GetVisualValue;
|
|
ValueComboBox.Text:=CurValue;
|
|
NewItemIndex:=ValueComboBox.Items.IndexOf(CurValue);
|
|
if NewItemIndex>=0 then
|
|
ValueComboBox.ItemIndex:=NewItemIndex;
|
|
|
|
// ItemWidth
|
|
MaxItemWidth:=ValueComboBox.Width;
|
|
Cnt:=ValueComboBox.Items.Count;
|
|
for i:=0 to Cnt-1 do begin
|
|
ItemValue:=ValueComboBox.Items[i];
|
|
CurItemWidth:=ValueComboBox.Canvas.TextWidth(ItemValue);
|
|
CurRow.Editor.ListMeasureWidth(ItemValue,i,ValueComboBox.Canvas,
|
|
CurItemWidth);
|
|
if MaxItemWidth<CurItemWidth then
|
|
MaxItemWidth:=CurItemWidth;
|
|
end;
|
|
ValueComboBox.ItemWidth:=MaxItemWidth;
|
|
finally
|
|
ValueComboBox.Items.EndUpdate;
|
|
if ExcludeUpdateFlag then
|
|
Exclude(FStates,pgsUpdatingEditControl);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.ValueComboBoxDrawItem(Control: TWinControl;
|
|
Index: Integer; ARect: TRect; State: TOwnerDrawState);
|
|
var
|
|
CurRow: TOIPropertyGridRow;
|
|
ItemValue: string;
|
|
AState: TPropEditDrawState;
|
|
begin
|
|
if (FItemIndex>=0) and (FItemIndex<FRows.Count) then begin
|
|
CurRow:=Rows[FItemIndex];
|
|
if (Index>=0) and (Index<ValueComboBox.Items.Count) then
|
|
ItemValue:=ValueComboBox.Items[Index]
|
|
else
|
|
ItemValue:='';
|
|
AState:=[];
|
|
if odPainted in State then Include(AState,pedsPainted);
|
|
if odSelected in State then Include(AState,pedsSelected);
|
|
if odFocused in State then Include(AState,pedsFocused);
|
|
if odComboBoxEdit in State then
|
|
Include(AState,pedsInEdit)
|
|
else
|
|
Include(AState,pedsInComboList);
|
|
|
|
// clear background
|
|
with ValueComboBox.Canvas do begin
|
|
Brush.Color:=clWhite;
|
|
Pen.Color:=clBlack;
|
|
Font.Color:=Pen.Color;
|
|
FillRect(ARect);
|
|
end;
|
|
CurRow.Editor.ListDrawValue(ItemValue,Index,ValueComboBox.Canvas,ARect,
|
|
AState);
|
|
end;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.OnIdle(Sender: TObject; var Done: Boolean);
|
|
begin
|
|
if (not (pgsGetComboItemsCalled in FStates))
|
|
and (FCurrentEdit=ValueComboBox)
|
|
and ValueComboBox.Enabled
|
|
then begin
|
|
ValueComboBoxGetItems(Self);
|
|
end;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.SetIdleEvent(Enable: boolean);
|
|
begin
|
|
if (pgsIdleEnabled in FStates)=Enable then exit;
|
|
if Enable then begin
|
|
Application.AddOnIdleHandler(@OnIdle);
|
|
Include(FStates,pgsIdleEnabled);
|
|
end else begin
|
|
Application.RemoveOnIdleHandler(@OnIdle);
|
|
Exclude(FStates,pgsIdleEnabled);
|
|
end;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.HintTimer(sender : TObject);
|
|
var
|
|
Rect : TRect;
|
|
AHint : String;
|
|
Position : TPoint;
|
|
Index: integer;
|
|
PointedRow:TOIpropertyGridRow;
|
|
Window: TWinControl;
|
|
HintType: TPropEditHint;
|
|
ClientPosition: TPoint;
|
|
begin
|
|
if FHintTimer <> nil then
|
|
FHintTimer.Enabled := False;
|
|
if (not InitHints) then exit;
|
|
|
|
Position := Mouse.CursorPos;
|
|
|
|
Window := FindLCLWindow(Position);
|
|
if not Assigned(Window) then Exit;
|
|
If (Window <> Self) and (not IsParentOf(Window)) then exit;
|
|
|
|
ClientPosition := ScreenToClient(Position);
|
|
if ((ClientPosition.X <=0) or (ClientPosition.X >= Width) or
|
|
(ClientPosition.Y <= 0) or (ClientPosition.Y >= Height)) then
|
|
Exit;
|
|
|
|
AHint := '';
|
|
Index := MouseToIndex(ClientPosition.Y, False);
|
|
if (Index >= 0) and (Index < FRows.Count) then
|
|
begin
|
|
//IconX:=GetTreeIconX(Index);
|
|
PointedRow := Rows[Index];
|
|
if Assigned(PointedRow) and Assigned(PointedRow.Editor) then
|
|
begin
|
|
if Index <> ItemIndex then
|
|
begin
|
|
HintType := GetHintTypeAt(Index,Position.X);
|
|
if (HintType = pehName) and Assigned(OnPropertyHint) then
|
|
begin
|
|
if OnPropertyHint(Self, PointedRow, Position, FHintWindow, Rect, AHint) and
|
|
(AHint <> '') then
|
|
begin
|
|
FHintIndex := Index;
|
|
FShowingLongHint := True;
|
|
//DebugLn(['TOICustomPropertyGrid.HintTimer ',dbgs(Rect),' ',AHint,' ',dbgs(Position)]);
|
|
FHintWindow.ActivateHint(Rect, AHint);
|
|
end;
|
|
exit;
|
|
end;
|
|
AHint := PointedRow.Editor.GetHint(HintType, Position.X, Position.Y);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
if AHint = '' then Exit;
|
|
FHintIndex := Index;
|
|
FShowingLongHint := True;
|
|
Rect := FHintWindow.CalcHintRect(0, AHint, nil); //no maxwidth
|
|
Rect.Left := Position.X + 10;
|
|
Rect.Top := Position.Y + 10;
|
|
Rect.Right := Rect.Left + Rect.Right + 3;
|
|
Rect.Bottom := Rect.Top + Rect.Bottom + 3;
|
|
//DebugLn(['TOICustomPropertyGrid.HintTimer ',dbgs(Rect),' ',AHint,' ',dbgs(Position)]);
|
|
|
|
FHintWindow.ActivateHint(Rect, AHint);
|
|
end;
|
|
|
|
Procedure TOICustomPropertyGrid.ResetHintTimer;
|
|
begin
|
|
if FHintWindow = nil then exit;
|
|
|
|
HideHint;
|
|
|
|
FHintTimer.Enabled := False;
|
|
if RowCount > 0 then
|
|
FHintTimer.Enabled := not FDragging;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.HideHint;
|
|
begin
|
|
if FHintWindow = nil then Exit;
|
|
FHintWindow.Visible := False;
|
|
FHintIndex := -1;
|
|
FShowingLongHint := False;
|
|
while FHintWindow.ControlCount > 0 do
|
|
FHintWindow.Controls[0].Free;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.ValueControlMouseDown(Sender : TObject;
|
|
Button: TMouseButton; Shift: TShiftState; X, Y: integer);
|
|
begin
|
|
HideHint;
|
|
ScrollToActiveItem;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.ValueControlMouseMove(Sender: TObject;
|
|
Shift: TShiftState; X, Y: integer);
|
|
begin
|
|
// when the cursor is divider change it to default
|
|
if (Sender as TControl).Parent.Cursor <> crDefault then
|
|
(Sender as TControl).Parent.Cursor := crDefault;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.IncreaseChangeStep;
|
|
begin
|
|
if FChangeStep<>$7fffffff then
|
|
inc(FChangeStep)
|
|
else
|
|
FChangeStep:=-$7fffffff;
|
|
end;
|
|
|
|
function TOICustomPropertyGrid.GridIsUpdating: boolean;
|
|
begin
|
|
Result:=(FStates*[pgsChangingItemIndex,pgsApplyingValue,
|
|
pgsBuildPropertyListNeeded]<>[])
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.ToggleRow;
|
|
var
|
|
CurRow: TOIPropertyGridRow;
|
|
TypeKind : TTypeKind;
|
|
begin
|
|
if not CanEditRowValue then exit;
|
|
|
|
if FHintTimer <> nil then
|
|
FHintTimer.Enabled := False;
|
|
|
|
if (FCurrentEdit = ValueComboBox) then
|
|
begin
|
|
//either an Event or an enumeration or Boolean
|
|
CurRow := Rows[FItemIndex];
|
|
TypeKind := CurRow.Editor.GetPropType^.Kind;
|
|
if TypeKind in [tkEnumeration, tkBool, tkSet] then
|
|
begin
|
|
// set value to next value in list
|
|
FillComboboxItems;
|
|
if ValueComboBox.Items.Count = 0 then Exit;
|
|
if ValueComboBox.ItemIndex < (ValueComboBox.Items.Count - 1) then
|
|
ValueComboBox.ItemIndex := ValueComboBox.ItemIndex + 1
|
|
else
|
|
ValueComboBox.ItemIndex := 0;
|
|
SetRowValue;
|
|
exit;
|
|
end;
|
|
end;
|
|
DoCallEdit;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.ValueEditDblClick(Sender: TObject);
|
|
begin
|
|
ToggleRow;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.SetBackgroundColor(const AValue: TColor);
|
|
begin
|
|
if FBackgroundColor=AValue then exit;
|
|
FBackgroundColor:=AValue;
|
|
Invalidate;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.SetReferences(const AValue: TColor);
|
|
begin
|
|
if FReferencesColor=AValue then exit;
|
|
FReferencesColor:=AValue;
|
|
Invalidate;
|
|
end;
|
|
|
|
procedure TOICustomPropertyGrid.SetSubPropertiesColor(const AValue: TColor);
|
|
begin
|
|
if FSubPropertiesColor=AValue then exit;
|
|
FSubPropertiesColor:=AValue;
|
|
Invalidate;
|
|
end;
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
{ TOIPropertyGridRow }
|
|
|
|
constructor TOIPropertyGridRow.Create(PropertyTree: TOICustomPropertyGrid;
|
|
PropEditor:TPropertyEditor; ParentNode:TOIPropertyGridRow; WidgetSets: TLCLPlatforms);
|
|
begin
|
|
inherited Create;
|
|
// tree pointer
|
|
FTree:=PropertyTree;
|
|
FParent:=ParentNode;
|
|
FNextBrother:=nil;
|
|
FPriorBrother:=nil;
|
|
FExpanded:=false;
|
|
// child nodes
|
|
FChildCount:=0;
|
|
FFirstChild:=nil;
|
|
FLastChild:=nil;
|
|
// director
|
|
FEditor:=PropEditor;
|
|
GetLvl;
|
|
FName:=FEditor.GetName;
|
|
FTop:=0;
|
|
FHeight:=FTree.DefaultItemHeight;
|
|
FIndex:=-1;
|
|
LastPaintedValue:='';
|
|
FWidgetSets := WidgetSets;
|
|
end;
|
|
|
|
destructor TOIPropertyGridRow.Destroy;
|
|
begin
|
|
if FPriorBrother<>nil then FPriorBrother.FNextBrother:=FNextBrother;
|
|
if FNextBrother<>nil then FNextBrother.FPriorBrother:=FPriorBrother;
|
|
if FParent<>nil then begin
|
|
if FParent.FFirstChild=Self then FParent.FFirstChild:=FNextBrother;
|
|
if FParent.FLastChild=Self then FParent.FLastChild:=FPriorBrother;
|
|
dec(FParent.FChildCount);
|
|
end;
|
|
if FEditor<>nil then FEditor.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TOIPropertyGridRow.ConsistencyCheck: integer;
|
|
var
|
|
OldLvl, RealChildCount: integer;
|
|
AChild: TOIPropertyGridRow;
|
|
begin
|
|
if Top<0 then begin
|
|
Result:=-1;
|
|
exit;
|
|
end;
|
|
if Height<0 then begin
|
|
Result:=-2;
|
|
exit;
|
|
end;
|
|
if Lvl<0 then begin
|
|
Result:=-3;
|
|
exit;
|
|
end;
|
|
OldLvl:=Lvl;
|
|
GetLvl;
|
|
if Lvl<>OldLvl then begin
|
|
Result:=-4;
|
|
exit;
|
|
end;
|
|
if Name='' then begin
|
|
Result:=-5;
|
|
exit;
|
|
end;
|
|
if NextBrother<>nil then begin
|
|
if NextBrother.PriorBrother<>Self then begin
|
|
Result:=-6;
|
|
exit;
|
|
end;
|
|
if NextBrother.Index<Index+1 then begin
|
|
Result:=-7;
|
|
exit;
|
|
end;
|
|
end;
|
|
if PriorBrother<>nil then begin
|
|
if PriorBrother.NextBrother<>Self then begin
|
|
Result:=-8;
|
|
exit;
|
|
end;
|
|
if PriorBrother.Index>Index-1 then begin
|
|
Result:=-9
|
|
end;
|
|
end;
|
|
if (Parent<>nil) then begin
|
|
// has parent
|
|
if (not Parent.HasChild(Self)) then begin
|
|
Result:=-10;
|
|
exit;
|
|
end;
|
|
end else begin
|
|
// no parent
|
|
end;
|
|
if FirstChild<>nil then begin
|
|
if Expanded then begin
|
|
if (FirstChild.Index<>Index+1) then begin
|
|
Result:=-11;
|
|
exit;
|
|
end;
|
|
end;
|
|
end else begin
|
|
if LastChild<>nil then begin
|
|
Result:=-12;
|
|
exit;
|
|
end;
|
|
end;
|
|
RealChildCount:=0;
|
|
AChild:=FirstChild;
|
|
while AChild<>nil do begin
|
|
if AChild.Parent<>Self then begin
|
|
Result:=-13;
|
|
exit;
|
|
end;
|
|
inc(RealChildCount);
|
|
AChild:=AChild.NextBrother;
|
|
end;
|
|
if RealChildCount<>ChildCount then begin
|
|
Result:=-14;
|
|
exit;
|
|
end;
|
|
Result:=0;
|
|
end;
|
|
|
|
function TOIPropertyGridRow.HasChild(Row: TOIPropertyGridRow): boolean;
|
|
var
|
|
ChildRow: TOIPropertyGridRow;
|
|
begin
|
|
ChildRow:=FirstChild;
|
|
while ChildRow<>nil do begin
|
|
if ChildRow=Row then begin
|
|
Result:=true;
|
|
exit;
|
|
end;
|
|
end;
|
|
Result:=false;
|
|
end;
|
|
|
|
procedure TOIPropertyGridRow.WriteDebugReport(const Prefix: string);
|
|
var
|
|
i: Integer;
|
|
Item: TOIPropertyGridRow;
|
|
begin
|
|
DebugLn([Prefix+'TOIPropertyGridRow.WriteDebugReport ',Name]);
|
|
i:=0;
|
|
Item:=FirstChild;
|
|
while Item<>nil do begin
|
|
DebugLn([Prefix+' ',i,' ',Item.Name]);
|
|
inc(i);
|
|
Item:=Item.NextBrother;
|
|
end;
|
|
end;
|
|
|
|
procedure TOIPropertyGridRow.GetLvl;
|
|
var n:TOIPropertyGridRow;
|
|
begin
|
|
FLvl:=0;
|
|
n:=FParent;
|
|
while n<>nil do begin
|
|
inc(FLvl);
|
|
n:=n.FParent;
|
|
end;
|
|
end;
|
|
|
|
function TOIPropertyGridRow.GetBottom:integer;
|
|
begin
|
|
Result:=FTop+FHeight;
|
|
if FTree.Layout = oilVertical
|
|
then Inc(Result, FTree.GetNameRowHeight);
|
|
end;
|
|
|
|
function TOIPropertyGridRow.IsReadOnly: boolean;
|
|
begin
|
|
Result:=Editor.IsReadOnly or IsDisabled;
|
|
end;
|
|
|
|
function TOIPropertyGridRow.IsDisabled: boolean;
|
|
var
|
|
ParentRow: TOIPropertyGridRow;
|
|
begin
|
|
Result:=false;
|
|
ParentRow:=Parent;
|
|
while (ParentRow<>nil) do begin
|
|
if paDisableSubProperties in ParentRow.Editor.GetAttributes then begin
|
|
Result:=true;
|
|
exit;
|
|
end;
|
|
ParentRow:=ParentRow.Parent;
|
|
end;
|
|
end;
|
|
|
|
procedure TOIPropertyGridRow.MeasureHeight(ACanvas: TCanvas);
|
|
begin
|
|
FHeight:=FTree.DefaultItemHeight;
|
|
Editor.PropMeasureHeight(Name,ACanvas,FHeight);
|
|
end;
|
|
|
|
function TOIPropertyGridRow.Sort(const Compare: TListSortCompare): boolean;
|
|
var
|
|
List: TFPList;
|
|
Item: TOIPropertyGridRow;
|
|
i: Integer;
|
|
begin
|
|
if IsSorted(Compare) then exit(false);
|
|
List:=TFPList.Create;
|
|
try
|
|
// create a TFPList of the childs
|
|
List.Capacity:=ChildCount;
|
|
Item:=FirstChild;
|
|
while Item<>nil do begin
|
|
List.Add(Item);
|
|
Item:=Item.NextBrother;
|
|
end;
|
|
// sort the TFPList
|
|
List.Sort(Compare);
|
|
// sort in double linked list
|
|
for i:=0 to List.Count-1 do begin
|
|
Item:=TOIPropertyGridRow(List[i]);
|
|
if i=0 then begin
|
|
FFirstChild:=Item;
|
|
Item.FPriorBrother:=nil;
|
|
end else
|
|
Item.FPriorBrother:=TOIPropertyGridRow(List[i-1]);
|
|
if i=List.Count-1 then begin
|
|
FLastChild:=Item;
|
|
Item.FNextBrother:=nil;
|
|
end else
|
|
Item.FNextBrother:=TOIPropertyGridRow(List[i+1]);
|
|
end;
|
|
finally
|
|
List.Free;
|
|
end;
|
|
Result:=true;
|
|
end;
|
|
|
|
function TOIPropertyGridRow.IsSorted(const Compare: TListSortCompare): boolean;
|
|
var
|
|
Item1: TOIPropertyGridRow;
|
|
Item2: TOIPropertyGridRow;
|
|
begin
|
|
if ChildCount<2 then exit(true);
|
|
Item1:=FirstChild;
|
|
while true do begin
|
|
Item2:=Item1.NextBrother;
|
|
if Item2=nil then break;
|
|
if Compare(Item1,Item2)>0 then exit(false);
|
|
Item1:=Item2;
|
|
end;
|
|
Result:=true;
|
|
end;
|
|
|
|
function TOIPropertyGridRow.Next: TOIPropertyGridRow;
|
|
begin
|
|
if fFirstChild<>nil then
|
|
Result:=fFirstChild
|
|
else
|
|
Result:=NextSkipChilds;
|
|
end;
|
|
|
|
function TOIPropertyGridRow.NextSkipChilds: TOIPropertyGridRow;
|
|
begin
|
|
Result:=Self;
|
|
while (Result<>nil) do begin
|
|
if Result.NextBrother<>nil then begin
|
|
Result:=Result.NextBrother;
|
|
exit;
|
|
end;
|
|
Result:=Result.Parent;
|
|
end;
|
|
end;
|
|
|
|
//==============================================================================
|
|
|
|
|
|
{ TOIOptions }
|
|
|
|
function TOIOptions.FPropertyGridSplitterX(Page: TObjectInspectorPage): integer;
|
|
begin
|
|
Result:=FGridSplitterX[Page];
|
|
end;
|
|
|
|
procedure TOIOptions.FPropertyGridSplitterX(Page: TObjectInspectorPage;
|
|
const AValue: integer);
|
|
begin
|
|
FGridSplitterX[Page]:=AValue;
|
|
end;
|
|
|
|
constructor TOIOptions.Create;
|
|
var
|
|
p: TObjectInspectorPage;
|
|
begin
|
|
inherited Create;
|
|
|
|
FSaveBounds:=false;
|
|
FLeft:=0;
|
|
FTop:=0;
|
|
FWidth:=250;
|
|
FHeight:=400;
|
|
for p:=Low(TObjectInspectorPage) to High(TObjectInspectorPage) do
|
|
FGridSplitterX[p]:=110;
|
|
FDefaultItemHeight:=20;
|
|
FShowComponentTree:=true;
|
|
FComponentTreeHeight:=100;
|
|
|
|
FGridBackgroundColor := DefBackgroundColor;
|
|
FDefaultValueColor := DefDefaultValueColor;
|
|
FSubPropertiesColor := DefSubPropertiesColor;
|
|
FValueColor := DefValueColor;
|
|
FReadOnlyColor := DefReadOnlyColor;
|
|
FReferencesColor := DefReferencesColor;
|
|
FPropertyNameColor := DefNameColor;
|
|
FHighlightColor := DefHighlightColor;
|
|
FHighlightFontColor := DefHighlightFontColor;
|
|
FGutterColor := DefGutterColor;
|
|
FGutterEdgeColor := DefGutterEdgeColor;
|
|
|
|
FBoldNonDefaultValues := True;
|
|
FDrawGridLines := True;
|
|
FShowGutter := True;
|
|
FShowStatusBar := True;
|
|
FShowInfoBox := False;
|
|
end;
|
|
|
|
function TOIOptions.Load: boolean;
|
|
var
|
|
Path: String;
|
|
FileVersion: integer;
|
|
Page: TObjectInspectorPage;
|
|
begin
|
|
Result:=false;
|
|
if ConfigStore=nil then exit;
|
|
try
|
|
Path:='ObjectInspectorOptions/';
|
|
FileVersion:=ConfigStore.GetValue(Path+'Version/Value',0);
|
|
|
|
FSaveBounds:=ConfigStore.GetValue(Path+'Bounds/Valid'
|
|
,false);
|
|
if FSaveBounds then begin
|
|
FLeft:=ConfigStore.GetValue(Path+'Bounds/Left',0);
|
|
FTop:=ConfigStore.GetValue(Path+'Bounds/Top',0);
|
|
FWidth:=ConfigStore.GetValue(Path+'Bounds/Width',250);
|
|
FHeight:=ConfigStore.GetValue(Path+'Bounds/Height',400);
|
|
end;
|
|
|
|
if FileVersion>=2 then begin
|
|
for Page:=Low(TObjectInspectorPage) to High(TObjectInspectorPage) do
|
|
FGridSplitterX[Page]:=ConfigStore.GetValue(
|
|
Path+'Bounds/'+DefaultOIPageNames[Page]+'/SplitterX',110);
|
|
end else begin
|
|
FGridSplitterX[oipgpProperties]:=ConfigStore.GetValue(
|
|
Path+'Bounds/PropertyGridSplitterX',110);
|
|
FGridSplitterX[oipgpEvents]:=ConfigStore.GetValue(
|
|
Path+'Bounds/EventGridSplitterX',110);
|
|
end;
|
|
for Page:=Low(TObjectInspectorPage) to High(TObjectInspectorPage) do
|
|
if FGridSplitterX[Page]<10 then FGridSplitterX[Page]:=10;
|
|
|
|
FDefaultItemHeight:=ConfigStore.GetValue(
|
|
Path+'Bounds/DefaultItemHeight',20);
|
|
if FDefaultItemHeight<0 then FDefaultItemHeight:=20;
|
|
FShowComponentTree:=ConfigStore.GetValue(
|
|
Path+'ComponentTree/Show/Value',true);
|
|
FComponentTreeHeight:=ConfigStore.GetValue(
|
|
Path+'ComponentTree/Height/Value',100);
|
|
|
|
FGridBackgroundColor:=ConfigStore.GetValue(
|
|
Path+'Color/GridBackground',DefBackgroundColor);
|
|
FDefaultValueColor:=ConfigStore.GetValue(
|
|
Path+'Color/DefaultValue', DefDefaultValueColor);
|
|
FSubPropertiesColor:=ConfigStore.GetValue(
|
|
Path+'Color/SubProperties', DefSubPropertiesColor);
|
|
FValueColor:=ConfigStore.GetValue(
|
|
Path+'Color/Value', DefValueColor);
|
|
FReadOnlyColor:=ConfigStore.GetValue(
|
|
Path+'Color/ReadOnly', DefReadOnlyColor);
|
|
FReferencesColor:=ConfigStore.GetValue(
|
|
Path+'Color/References',DefReferencesColor);
|
|
FPropertyNameColor:=ConfigStore.GetValue(
|
|
Path+'Color/PropertyName',DefNameColor);
|
|
FHighlightColor:=ConfigStore.GetValue(
|
|
Path+'Color/Highlight',DefHighlightColor);
|
|
FHighlightFontColor:=ConfigStore.GetValue(
|
|
Path+'Color/HighlightFont',DefHighlightFontColor);
|
|
FGutterColor:=ConfigStore.GetValue(
|
|
Path+'Color/Gutter',DefGutterColor);
|
|
FGutterEdgeColor:=ConfigStore.GetValue(
|
|
Path+'Color/GutterEdge',DefGutterEdgeColor);
|
|
|
|
FShowHints:=ConfigStore.GetValue(
|
|
Path+'ShowHints',FileVersion>=3);
|
|
FAutoShow := ConfigStore.GetValue(
|
|
Path+'AutoShow',true);
|
|
FBoldNonDefaultValues := ConfigStore.GetValue(
|
|
Path+'BoldNonDefaultValues',true);
|
|
FDrawGridLines := ConfigStore.GetValue(
|
|
Path+'DrawGridLines',true);
|
|
FShowGutter := ConfigStore.GetValue(
|
|
Path+'ShowGutter',true);
|
|
FShowStatusBar := ConfigStore.GetValue(
|
|
Path+'ShowStatusBar',true);
|
|
FShowInfoBox := ConfigStore.GetValue(
|
|
Path+'ShowInfoBox',false);
|
|
except
|
|
on E: Exception do begin
|
|
DebugLn('ERROR: TOIOptions.Load: ',E.Message);
|
|
exit;
|
|
end;
|
|
end;
|
|
Result:=true;
|
|
end;
|
|
|
|
function TOIOptions.Save: boolean;
|
|
var
|
|
Page: TObjectInspectorPage;
|
|
Path: String;
|
|
begin
|
|
Result:=false;
|
|
if ConfigStore=nil then exit;
|
|
try
|
|
Path:='ObjectInspectorOptions/';
|
|
ConfigStore.SetValue(Path+'Version/Value',OIOptionsFileVersion);
|
|
|
|
ConfigStore.SetDeleteValue(Path+'Bounds/Valid',FSaveBounds,
|
|
false);
|
|
|
|
ConfigStore.SetDeleteValue(Path+'Bounds/Valid',FSaveBounds,
|
|
false);
|
|
if FSaveBounds then begin
|
|
ConfigStore.SetValue(Path+'Bounds/Left',FLeft);
|
|
ConfigStore.SetValue(Path+'Bounds/Top',FTop);
|
|
ConfigStore.SetValue(Path+'Bounds/Width',FWidth);
|
|
ConfigStore.SetValue(Path+'Bounds/Height',FHeight);
|
|
end;
|
|
for Page:=Low(TObjectInspectorPage) to High(TObjectInspectorPage) do
|
|
ConfigStore.SetDeleteValue(
|
|
Path+'Bounds/'+DefaultOIPageNames[Page]+'/SplitterX',
|
|
FGridSplitterX[Page],110);
|
|
ConfigStore.SetDeleteValue(Path+'Bounds/DefaultItemHeight',
|
|
FDefaultItemHeight,20);
|
|
ConfigStore.SetDeleteValue(Path+'ComponentTree/Show/Value',
|
|
FShowComponentTree,true);
|
|
ConfigStore.SetDeleteValue(Path+'ComponentTree/Height/Value',
|
|
FComponentTreeHeight,100);
|
|
|
|
ConfigStore.SetDeleteValue(Path+'Color/GridBackground',
|
|
FGridBackgroundColor,DefBackgroundColor);
|
|
ConfigStore.SetDeleteValue(Path+'Color/DefaultValue',
|
|
FDefaultValueColor,DefDefaultValueColor);
|
|
ConfigStore.SetDeleteValue(Path+'Color/SubProperties',
|
|
FSubPropertiesColor,DefSubPropertiesColor);
|
|
ConfigStore.SetDeleteValue(Path+'Color/Value',
|
|
FValueColor,DefValueColor);
|
|
ConfigStore.SetDeleteValue(Path+'Color/ReadOnly',
|
|
FReadOnlyColor,DefReadOnlyColor);
|
|
ConfigStore.SetDeleteValue(Path+'Color/References',
|
|
FReferencesColor,DefReferencesColor);
|
|
ConfigStore.SetDeleteValue(Path+'Color/PropertyName',
|
|
FPropertyNameColor,DefNameColor);
|
|
ConfigStore.SetDeleteValue(Path+'Color/Highlight',
|
|
FHighlightColor,DefHighlightColor);
|
|
ConfigStore.SetDeleteValue(Path+'Color/HighlightFont',
|
|
FHighlightFontColor,DefHighlightFontColor);
|
|
ConfigStore.SetDeleteValue(Path+'Color/Gutter',
|
|
FGutterColor,DefGutterColor);
|
|
ConfigStore.SetDeleteValue(Path+'Color/GutterEdge',
|
|
FGutterEdgeColor,DefGutterEdgeColor);
|
|
|
|
ConfigStore.SetDeleteValue(Path+'ShowHints',FShowHints, True);
|
|
ConfigStore.SetDeleteValue(Path+'AutoShow',FAutoShow, True);
|
|
ConfigStore.SetDeleteValue(Path+'BoldNonDefaultValues',FBoldNonDefaultValues, True);
|
|
ConfigStore.SetDeleteValue(Path+'DrawGridLines',FDrawGridLines, True);
|
|
ConfigStore.SetDeleteValue(Path+'ShowGutter',FShowGutter, True);
|
|
ConfigStore.SetDeleteValue(Path+'ShowStatusBar',FShowStatusBar, True);
|
|
ConfigStore.SetDeleteValue(Path+'ShowInfoBox',FShowInfoBox, False);
|
|
except
|
|
on E: Exception do begin
|
|
DebugLn('ERROR: TOIOptions.Save: ',E.Message);
|
|
exit;
|
|
end;
|
|
end;
|
|
Result:=true;
|
|
end;
|
|
|
|
procedure TOIOptions.Assign(AnObjInspector: TObjectInspectorDlg);
|
|
var
|
|
Page: TObjectInspectorPage;
|
|
begin
|
|
FLeft:=AnObjInspector.Left;
|
|
FTop:=AnObjInspector.Top;
|
|
FWidth:=AnObjInspector.Width;
|
|
FHeight:=AnObjInspector.Height;
|
|
for Page:=Low(TObjectInspectorPage) to High(TObjectInspectorPage) do
|
|
if AnObjInspector.GridControl[Page]<>nil then
|
|
FGridSplitterX[Page]:=AnObjInspector.GridControl[Page].PrefferedSplitterX;
|
|
FDefaultItemHeight:=AnObjInspector.DefaultItemHeight;
|
|
FShowComponentTree:=AnObjInspector.ShowComponentTree;
|
|
FComponentTreeHeight:=AnObjInspector.ComponentTreeHeight;
|
|
|
|
FGridBackgroundColor:=AnObjInspector.PropertyGrid.BackgroundColor;
|
|
FSubPropertiesColor:=AnObjInspector.PropertyGrid.SubPropertiesColor;
|
|
FReferencesColor:=AnObjInspector.PropertyGrid.ReferencesColor;
|
|
FValueColor:=AnObjInspector.PropertyGrid.ValueFont.Color;
|
|
FDefaultValueColor:=AnObjInspector.PropertyGrid.DefaultValueFont.Color;
|
|
FReadOnlyColor:=AnObjInspector.PropertyGrid.ReadOnlyColor;
|
|
FPropertyNameColor:=AnObjInspector.PropertyGrid.NameFont.Color;
|
|
FHighlightColor:=AnObjInspector.PropertyGrid.HighlightColor;
|
|
FHighlightFontColor:=AnObjInspector.PropertyGrid.HighlightFont.Color;
|
|
FGutterColor:=AnObjInspector.PropertyGrid.GutterColor;
|
|
FGutterEdgeColor:=AnObjInspector.PropertyGrid.GutterEdgeColor;
|
|
|
|
FShowHints := AnObjInspector.PropertyGrid.ShowHint;
|
|
FAutoShow := AnObjInspector.AutoShow;
|
|
FBoldNonDefaultValues := fsBold in AnObjInspector.PropertyGrid.ValueFont.Style;
|
|
FDrawGridLines := AnObjInspector.PropertyGrid.DrawHorzGridLines;
|
|
FShowGutter := AnObjInspector.PropertyGrid.ShowGutter;
|
|
FShowStatusBar := AnObjInspector.ShowStatusBar;
|
|
FShowInfoBox := AnObjInspector.ShowInfoBox;
|
|
end;
|
|
|
|
procedure TOIOptions.AssignTo(AnObjInspector: TObjectInspectorDlg);
|
|
var
|
|
Page: TObjectInspectorPage;
|
|
Grid: TOICustomPropertyGrid;
|
|
begin
|
|
if FSaveBounds then
|
|
begin
|
|
AnObjInspector.SetBounds(FLeft,FTop,FWidth,FHeight);
|
|
end;
|
|
|
|
for Page := Low(TObjectInspectorPage) to High(TObjectInspectorPage) do
|
|
begin
|
|
Grid := AnObjInspector.GridControl[Page];
|
|
if Grid = nil then
|
|
Continue;
|
|
Grid.PrefferedSplitterX := FGridSplitterX[Page];
|
|
Grid.SplitterX := FGridSplitterX[Page];
|
|
AssignTo(Grid);
|
|
end;
|
|
AnObjInspector.DefaultItemHeight := FDefaultItemHeight;
|
|
AnObjInspector.ShowComponentTree := FShowComponentTree;
|
|
AnObjInspector.ShowInfoBox := FShowInfoBox;
|
|
AnObjInspector.ComponentTreeHeight := FComponentTreeHeight;
|
|
AnObjInspector.AutoShow := AutoShow;
|
|
AnObjInspector.ShowStatusBar := ShowStatusBar;
|
|
end;
|
|
|
|
procedure TOIOptions.AssignTo(AGrid: TOICustomPropertyGrid);
|
|
begin
|
|
AGrid.BackgroundColor := FGridBackgroundColor;
|
|
AGrid.SubPropertiesColor := FSubPropertiesColor;
|
|
AGrid.ReferencesColor := FReferencesColor;
|
|
AGrid.ReadOnlyColor := FReadOnlyColor;
|
|
AGrid.ValueFont.Color := FValueColor;
|
|
if FBoldNonDefaultValues then
|
|
AGrid.ValueFont.Style := [fsBold]
|
|
else
|
|
AGrid.ValueFont.Style := [];
|
|
AGrid.DefaultValueFont.Color := FDefaultValueColor;
|
|
AGrid.NameFont.Color := FPropertyNameColor;
|
|
AGrid.HighlightColor := FHighlightColor;
|
|
AGrid.HighlightFont.Color := FHighlightFontColor;
|
|
AGrid.GutterColor := FGutterColor;
|
|
AGrid.GutterEdgeColor := FGutterEdgeColor;
|
|
AGrid.ShowHint := FShowHints;
|
|
AGrid.DrawHorzGridLines := FDrawGridLines;
|
|
AGrid.ShowGutter := FShowGutter;
|
|
end;
|
|
|
|
|
|
//==============================================================================
|
|
|
|
|
|
{ TObjectInspectorDlg }
|
|
|
|
constructor TObjectInspectorDlg.Create(AnOwner: TComponent);
|
|
|
|
procedure AddPopupMenuItem(var NewMenuItem: TMenuItem;
|
|
ParentMenuItem: TMenuItem; const AName, ACaption, AHint, AResourceName: string;
|
|
AnOnClick: TNotifyEvent; CheckedFlag, EnabledFlag, VisibleFlag: boolean);
|
|
begin
|
|
NewMenuItem:=TMenuItem.Create(Self);
|
|
with NewMenuItem do
|
|
begin
|
|
Name:=AName;
|
|
Caption:=ACaption;
|
|
Hint:=AHint;
|
|
OnClick:=AnOnClick;
|
|
Checked:=CheckedFlag;
|
|
Enabled:=EnabledFlag;
|
|
Visible:=VisibleFlag;
|
|
if AResourceName <> '' then
|
|
ImageIndex := IDEImages.LoadImage(16, AResourceName);
|
|
end;
|
|
if ParentMenuItem<>nil then
|
|
ParentMenuItem.Add(NewMenuItem)
|
|
else
|
|
MainPopupMenu.Items.Add(NewMenuItem);
|
|
end;
|
|
|
|
procedure AddSeparatorMenuItem(ParentMenuItem: TMenuItem;
|
|
const AName: string; VisibleFlag: boolean);
|
|
var
|
|
NewMenuItem: TMenuItem;
|
|
begin
|
|
NewMenuItem:=TMenuItem.Create(Self);
|
|
with NewMenuItem do begin
|
|
Name:=AName;
|
|
Caption:='-';
|
|
Visible:=VisibleFlag;
|
|
end;
|
|
if ParentMenuItem<>nil then
|
|
ParentMenuItem.Add(NewMenuItem)
|
|
else
|
|
MainPopupMenu.Items.Add(NewMenuItem);
|
|
end;
|
|
|
|
begin
|
|
inherited Create(AnOwner);
|
|
FPropertyEditorHook:=nil;
|
|
FSelection:=TPersistentSelectionList.Create;
|
|
FAutoShow := True;
|
|
FUpdatingAvailComboBox:=false;
|
|
FDefaultItemHeight := 22;
|
|
FComponentTreeHeight:=100;
|
|
FShowComponentTree := True;
|
|
FShowFavorites := False;
|
|
FShowRestricted := False;
|
|
FShowStatusBar := True;
|
|
FInfoBoxHeight := 80;
|
|
FShowInfoBox := False;
|
|
|
|
Caption := oisObjectInspector;
|
|
StatusBar.SimpleText := oisAll;
|
|
|
|
MainPopupMenu.Images := IDEImages.Images_16;
|
|
|
|
AddPopupMenuItem(SetDefaultPopupmenuItem,nil,'SetDefaultPopupMenuItem',
|
|
'Set to Default value','Set property value to Default', '',
|
|
@OnSetDefaultPopupmenuItemClick,false,true,true);
|
|
AddPopupMenuItem(AddToFavoritesPopupMenuItem,nil,'AddToFavoritePopupMenuItem',
|
|
oisAddtofavorites,'Add property to favorites properties', '',
|
|
@OnAddToFavoritesPopupmenuItemClick,false,true,true);
|
|
AddPopupMenuItem(RemoveFromFavoritesPopupMenuItem,nil,
|
|
'RemoveFromFavoritesPopupMenuItem',
|
|
oisRemovefromfavorites,'Remove property from favorites properties', '',
|
|
@OnRemoveFromFavoritesPopupmenuItemClick,false,true,true);
|
|
AddPopupMenuItem(ViewRestrictedPropertiesPopupMenuItem,nil,
|
|
'ViewRestrictedPropertiesPopupMenuItem',
|
|
oisViewRestrictedProperties,'View restricted property descriptions', '',
|
|
@OnViewRestrictionsPopupmenuItemClick,false,true,true);
|
|
AddPopupMenuItem(UndoPropertyPopupMenuItem,nil,'UndoPropertyPopupMenuItem',
|
|
oisUndo,'Set property value to last valid value', '',
|
|
@OnUndoPopupmenuItemClick,false,true,true);
|
|
AddPopupMenuItem(FindDeclarationPopupmenuItem,nil,'FindDeclarationPopupmenuItem',
|
|
oisFinddeclaration,'Jump to declaration of property', '',
|
|
@OnFindDeclarationPopupmenuItemClick,false,true,false);
|
|
AddSeparatorMenuItem(nil,'OptionsSeparatorMenuItem',true);
|
|
AddPopupMenuItem(CutPopupMenuItem,nil,'CutPopupMenuItem',
|
|
oisCutComponents,'Cut selected item', 'laz_cut',
|
|
@OnCutPopupmenuItemClick,false,true,true);
|
|
AddPopupMenuItem(CopyPopupMenuItem,nil,'CopyPopupMenuItem',
|
|
oisCopyComponents,'Copy selected item', 'laz_copy',
|
|
@OnCopyPopupmenuItemClick,false,true,true);
|
|
AddPopupMenuItem(PastePopupMenuItem,nil,'PastePopupMenuItem',
|
|
oisPasteComponents,'Paste selected item', 'laz_paste',
|
|
@OnPastePopupmenuItemClick,false,true,true);
|
|
AddPopupMenuItem(DeletePopupMenuItem,nil,'DeletePopupMenuItem',
|
|
oisDeleteComponents,'Delete selected item', '',
|
|
@OnDeletePopupmenuItemClick,false,true,true);
|
|
AddPopupMenuItem(OptionsSeparatorMenuItem2,nil, '',
|
|
'-','','',nil,false,true,true);
|
|
AddPopupMenuItem(ShowHintsPopupMenuItem,nil
|
|
,'ShowHintPopupMenuItem',oisShowHints,'Grid hints', ''
|
|
,@OnShowHintPopupMenuItemClick,false,true,true);
|
|
ShowHintsPopupMenuItem.ShowAlwaysCheckable:=true;
|
|
AddPopupMenuItem(ShowComponentTreePopupMenuItem,nil
|
|
,'ShowComponentTreePopupMenuItem',oisShowComponentTree, '', ''
|
|
,@OnShowComponentTreePopupMenuItemClick,FShowComponentTree,true,true);
|
|
ShowComponentTreePopupMenuItem.ShowAlwaysCheckable:=true;
|
|
AddPopupMenuItem(ShowOptionsPopupMenuItem,nil
|
|
,'ShowOptionsPopupMenuItem',oisOptions,'', 'menu_environment_options'
|
|
,@OnShowOptionsPopupMenuItemClick,false,true,FOnShowOptions<>nil);
|
|
|
|
// combobox at top (filled with available persistents)
|
|
with AvailPersistentComboBox do begin
|
|
Sorted:=true;
|
|
AutoSelect:=true;
|
|
AutoComplete:=true;
|
|
DropDownCount := 12;
|
|
Visible:=not FShowComponentTree;
|
|
end;
|
|
|
|
// Component Tree at top (filled with available components)
|
|
ComponentTree := TComponentTreeView.Create(Self);
|
|
with ComponentTree do
|
|
begin
|
|
Name:='ComponentTree';
|
|
Constraints.MinHeight:=16;
|
|
Height:=ComponentTreeHeight;
|
|
Parent:=Self;
|
|
Align:=alTop;
|
|
OnDblClick := @ComponentTreeDblClick;
|
|
OnKeyDown := @ComponentTreeKeyDown;
|
|
OnSelectionChanged := @ComponentTreeSelectionChanged;
|
|
Visible := FShowComponentTree;
|
|
Scrollbars := ssAutoBoth;
|
|
end;
|
|
|
|
InfoPanel := TPanel.Create(Self);
|
|
with InfoPanel do
|
|
begin
|
|
Name := 'InfoPanel';
|
|
Caption := '';
|
|
Height := InfoBoxHeight;
|
|
Parent := Self;
|
|
BevelOuter := bvLowered;
|
|
Align := alBottom;
|
|
Visible := FShowInfoBox;
|
|
end;
|
|
|
|
if ShowComponentTree then
|
|
CreateSplitter(True);
|
|
|
|
if ShowInfoBox then
|
|
CreateSplitter(False);
|
|
|
|
CreateNoteBook;
|
|
end;
|
|
|
|
destructor TObjectInspectorDlg.Destroy;
|
|
begin
|
|
FreeAndNil(FSelection);
|
|
inherited Destroy;
|
|
FreeAndNil(FFavourites);
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.SetPropertyEditorHook(NewValue:TPropertyEditorHook);
|
|
var
|
|
Page: TObjectInspectorPage;
|
|
begin
|
|
if FPropertyEditorHook=NewValue then exit;
|
|
if FPropertyEditorHook<>nil then begin
|
|
FPropertyEditorHook.RemoveAllHandlersForObject(Self);
|
|
end;
|
|
FPropertyEditorHook:=NewValue;
|
|
if FPropertyEditorHook<>nil then begin
|
|
FPropertyEditorHook.AddHandlerChangeLookupRoot(@HookLookupRootChange);
|
|
FPropertyEditorHook.AddHandlerRefreshPropertyValues(
|
|
@HookRefreshPropertyValues);
|
|
FPropertyEditorHook.AddHandlerGetSelection(@HookGetSelection);
|
|
FPropertyEditorHook.AddHandlerSetSelection(@HookSetSelection);
|
|
// select root component
|
|
FSelection.Clear;
|
|
if (FPropertyEditorHook<>nil) and (FPropertyEditorHook.LookupRoot<>nil)
|
|
and (FPropertyEditorHook.LookupRoot is TComponent) then
|
|
FSelection.Add(TComponent(FPropertyEditorHook.LookupRoot));
|
|
FillPersistentComboBox;
|
|
for Page:=Low(TObjectInspectorPage) to High(TObjectInspectorPage) do
|
|
if GridControl[Page]<>nil then
|
|
GridControl[Page].PropertyEditorHook:=FPropertyEditorHook;
|
|
ComponentTree.PropertyEditorHook:=FPropertyEditorHook;
|
|
RefreshSelection;
|
|
end;
|
|
end;
|
|
|
|
function TObjectInspectorDlg.PersistentToString(APersistent: TPersistent): string;
|
|
begin
|
|
if APersistent is TComponent then
|
|
Result:=TComponent(APersistent).GetNamePath+': '+APersistent.ClassName
|
|
else
|
|
Result:=APersistent.ClassName;
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.SetComponentTreeHeight(const AValue: integer);
|
|
begin
|
|
if FComponentTreeHeight=AValue then exit;
|
|
FComponentTreeHeight:=AValue;
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.SetDefaultItemHeight(const AValue: integer);
|
|
var
|
|
NewValue: Integer;
|
|
Page: TObjectInspectorPage;
|
|
begin
|
|
NewValue:=AValue;
|
|
if NewValue<0 then
|
|
NewValue:=0
|
|
else if NewValue=0 then
|
|
NewValue:=22
|
|
else if (NewValue>0) and (NewValue<10) then
|
|
NewValue:=10
|
|
else if NewValue>100 then NewValue:=100;
|
|
if FDefaultItemHeight=NewValue then exit;
|
|
FDefaultItemHeight:=NewValue;
|
|
for Page:=Low(TObjectInspectorPage) to High(TObjectInspectorPage) do
|
|
if GridControl[Page]<>nil then
|
|
GridControl[Page].DefaultItemHeight:=FDefaultItemHeight;
|
|
RebuildPropertyLists;
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.SetInfoBoxHeight(const AValue: integer);
|
|
begin
|
|
if FInfoBoxHeight=AValue then exit;
|
|
FInfoBoxHeight:=AValue;
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.SetRestricted(const AValue: TOIRestrictedProperties);
|
|
begin
|
|
if FRestricted = AValue then exit;
|
|
//DebugLn('TObjectInspectorDlg.SetRestricted Count: ', DbgS(AValue.Count));
|
|
FRestricted := AValue;
|
|
RestrictedGrid.Favourites := FRestricted;
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.SetOnShowOptions(const AValue: TNotifyEvent);
|
|
begin
|
|
if FOnShowOptions=AValue then exit;
|
|
FOnShowOptions:=AValue;
|
|
ShowOptionsPopupMenuItem.Visible:=FOnShowOptions<>nil;
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.AddPersistentToList(APersistent: TPersistent;
|
|
List: TStrings);
|
|
var
|
|
Allowed: boolean;
|
|
begin
|
|
if (APersistent is TComponent)
|
|
and (csDestroying in TComponent(APersistent).ComponentState) then exit;
|
|
Allowed:=true;
|
|
if Assigned(FOnAddAvailablePersistent) then
|
|
FOnAddAvailablePersistent(APersistent,Allowed);
|
|
if Allowed then
|
|
List.AddObject(PersistentToString(APersistent),APersistent);
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.HookLookupRootChange;
|
|
var
|
|
Page: TObjectInspectorPage;
|
|
begin
|
|
for Page:=Low(TObjectInspectorPage) to High(TObjectInspectorPage) do
|
|
if GridControl[Page]<>nil then
|
|
GridControl[Page].PropEditLookupRootChange;
|
|
FillPersistentComboBox;
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.FillPersistentComboBox;
|
|
var a:integer;
|
|
Root:TComponent;
|
|
OldText:AnsiString;
|
|
NewList: TStringList;
|
|
begin
|
|
//writeln('[TObjectInspectorDlg.FillComponentComboBox] A ',FUpdatingAvailComboBox
|
|
//,' ',FPropertyEditorHook<>nil,' ',FPropertyEditorHook.LookupRoot<>nil);
|
|
if FUpdatingAvailComboBox then exit;
|
|
FUpdatingAvailComboBox:=true;
|
|
if ComponentTree<>nil then
|
|
ComponentTree.Selection:=FSelection;
|
|
NewList:=TStringList.Create;
|
|
try
|
|
if (FPropertyEditorHook<>nil)
|
|
and (FPropertyEditorHook.LookupRoot<>nil) then begin
|
|
AddPersistentToList(FPropertyEditorHook.LookupRoot,NewList);
|
|
if FPropertyEditorHook.LookupRoot is TComponent then begin
|
|
Root:=TComponent(FPropertyEditorHook.LookupRoot);
|
|
//writeln('[TObjectInspectorDlg.FillComponentComboBox] B ',Root.Name,' ',Root.ComponentCount);
|
|
for a:=0 to Root.ComponentCount-1 do
|
|
AddPersistentToList(Root.Components[a],NewList);
|
|
end;
|
|
end;
|
|
|
|
if AvailPersistentComboBox.Items.Equals(NewList) then exit;
|
|
|
|
AvailPersistentComboBox.Items.BeginUpdate;
|
|
if AvailPersistentComboBox.Items.Count=1 then
|
|
OldText:=AvailPersistentComboBox.Text
|
|
else
|
|
OldText:='';
|
|
AvailPersistentComboBox.Items.Assign(NewList);
|
|
AvailPersistentComboBox.Items.EndUpdate;
|
|
a:=AvailPersistentComboBox.Items.IndexOf(OldText);
|
|
if (OldText='') or (a<0) then
|
|
SetAvailComboBoxText
|
|
else
|
|
AvailPersistentComboBox.ItemIndex:=a;
|
|
|
|
finally
|
|
NewList.Free;
|
|
FUpdatingAvailComboBox:=false;
|
|
end;
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.BeginUpdate;
|
|
begin
|
|
inc(FUpdateLock);
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.EndUpdate;
|
|
begin
|
|
dec(FUpdateLock);
|
|
if FUpdateLock<0 then begin
|
|
DebugLn('ERROR TObjectInspectorDlg.EndUpdate');
|
|
end;
|
|
if FUpdateLock=0 then begin
|
|
if oifRebuildPropListsNeeded in FFLags then
|
|
RebuildPropertyLists;
|
|
end;
|
|
end;
|
|
|
|
function TObjectInspectorDlg.GetActivePropertyGrid: TOICustomPropertyGrid;
|
|
begin
|
|
Result:=nil;
|
|
if NoteBook=nil then exit;
|
|
case NoteBook.PageIndex of
|
|
0: Result:=PropertyGrid;
|
|
1: Result:=EventGrid;
|
|
2: Result:=FavouriteGrid;
|
|
3: Result:=RestrictedGrid;
|
|
end;
|
|
end;
|
|
|
|
function TObjectInspectorDlg.GetActivePropertyRow: TOIPropertyGridRow;
|
|
var
|
|
CurGrid: TOICustomPropertyGrid;
|
|
begin
|
|
Result:=nil;
|
|
CurGrid:=GetActivePropertyGrid;
|
|
if CurGrid=nil then exit;
|
|
Result:=CurGrid.GetActiveRow;
|
|
end;
|
|
|
|
function TObjectInspectorDlg.GetCurRowDefaultValue(var DefaultStr: string): boolean;
|
|
var
|
|
CurRow: TOIPropertyGridRow;
|
|
begin
|
|
Result:=false;
|
|
DefaultStr:='';
|
|
CurRow:=GetActivePropertyRow;
|
|
if (CurRow=nil) or (not (paHasDefaultValue in CurRow.Editor.GetAttributes))
|
|
then exit;
|
|
try
|
|
DefaultStr:=CurRow.Editor.GetDefaultValue;
|
|
Result:=true;
|
|
except
|
|
DefaultStr:='';
|
|
end;
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.SetSelection(
|
|
const ASelection:TPersistentSelectionList);
|
|
begin
|
|
if not ASelection.ForceUpdate and FSelection.IsEqual(ASelection) then
|
|
Exit;
|
|
//if (FSelection.Count=1) and (FSelection[0] is TCollectionItem)
|
|
//and (ASelection.Count=0) then RaiseGDBException('');
|
|
FSelection.Assign(ASelection);
|
|
SetAvailComboBoxText;
|
|
RefreshSelection;
|
|
if Assigned(FOnSelectPersistentsInOI) then
|
|
FOnSelectPersistentsInOI(Self);
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.RefreshSelection;
|
|
var
|
|
Page: TObjectInspectorPage;
|
|
begin
|
|
if NoteBook.Page[3].Visible then
|
|
begin
|
|
DoUpdateRestricted;
|
|
|
|
// invalidate RestrictedProps
|
|
WidgetSetsRestrictedBox.Invalidate;
|
|
ComponentRestrictedBox.Invalidate;
|
|
end;
|
|
|
|
for Page := Low(TObjectInspectorPage) to High(TObjectInspectorPage) do
|
|
if GridControl[Page] <> nil then
|
|
GridControl[Page].Selection := FSelection;
|
|
RefreshComponentTreeSelection;
|
|
if (not Visible) and AutoShow and (FSelection.Count > 0) then
|
|
Visible := True;
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.RefreshComponentTreeSelection;
|
|
begin
|
|
ComponentTree.Selection := FSelection;
|
|
ComponentTree.MakeSelectionVisible;
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.SaveChanges;
|
|
var
|
|
Page: TObjectInspectorPage;
|
|
begin
|
|
for Page:=Low(TObjectInspectorPage) to High(TObjectInspectorPage) do
|
|
if GridControl[Page]<>nil then
|
|
GridControl[Page].SaveChanges;
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.RefreshPropertyValues;
|
|
var
|
|
Page: TObjectInspectorPage;
|
|
begin
|
|
for Page:=Low(TObjectInspectorPage) to High(TObjectInspectorPage) do
|
|
if GridControl[Page]<>nil then
|
|
GridControl[Page].RefreshPropertyValues;
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.RebuildPropertyLists;
|
|
var
|
|
Page: TObjectInspectorPage;
|
|
begin
|
|
if FUpdateLock>0 then
|
|
Include(FFLags,oifRebuildPropListsNeeded)
|
|
else begin
|
|
Exclude(FFLags,oifRebuildPropListsNeeded);
|
|
for Page:=Low(TObjectInspectorPage) to High(TObjectInspectorPage) do
|
|
if GridControl[Page]<>nil then
|
|
GridControl[Page].BuildPropertyList;
|
|
end;
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.AvailComboBoxCloseUp(Sender:TObject);
|
|
var NewComponent,Root:TComponent;
|
|
a:integer;
|
|
|
|
procedure SetSelectedPersistent(c:TPersistent);
|
|
begin
|
|
if (FSelection.Count=1) and (FSelection[0]=c) then exit;
|
|
FSelection.Clear;
|
|
FSelection.Add(c);
|
|
RefreshSelection;
|
|
if Assigned(FOnSelectPersistentsInOI) then
|
|
FOnSelectPersistentsInOI(Self);
|
|
end;
|
|
|
|
// AvailComboBoxChange
|
|
begin
|
|
if FUpdatingAvailComboBox then exit;
|
|
if (FPropertyEditorHook=nil) or (FPropertyEditorHook.LookupRoot=nil) then
|
|
exit;
|
|
if not (FPropertyEditorHook.LookupRoot is TComponent) then begin
|
|
// not a TComponent => no childs => select always only the root
|
|
SetSelectedPersistent(FPropertyEditorHook.LookupRoot);
|
|
exit;
|
|
end;
|
|
Root:=TComponent(FPropertyEditorHook.LookupRoot);
|
|
if (AvailPersistentComboBox.Text=PersistentToString(Root)) then begin
|
|
SetSelectedPersistent(Root);
|
|
end else begin
|
|
for a:=0 to Root.ComponentCount-1 do begin
|
|
NewComponent:=Root.Components[a];
|
|
if AvailPersistentComboBox.Text=PersistentToString(NewComponent) then
|
|
begin
|
|
SetSelectedPersistent(NewComponent);
|
|
break;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.ComponentTreeDblClick(Sender: TObject);
|
|
var
|
|
AComponent: TComponent;
|
|
CompEditor: TBaseComponentEditor;
|
|
ADesigner: TIDesigner;
|
|
begin
|
|
if (PropertyEditorHook=nil) or (PropertyEditorHook.LookupRoot=nil) then
|
|
Exit;
|
|
if not FSelection.IsEqual(ComponentTree.Selection) then
|
|
ComponentTreeSelectionChanged(Sender);
|
|
if not Assigned(ComponentTree.Selected) then
|
|
Exit;
|
|
AComponent := TComponent(ComponentTree.Selected.Data);
|
|
ADesigner := FindRootDesigner(AComponent);
|
|
if not (ADesigner is TComponentEditorDesigner) then
|
|
Exit;
|
|
CompEditor := GetComponentEditor(AComponent, TComponentEditorDesigner(ADesigner));
|
|
if Assigned(CompEditor) then
|
|
CompEditor.Edit;
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.ComponentTreeKeyDown(Sender: TObject;
|
|
var Key: Word; Shift: TShiftState);
|
|
begin
|
|
if (Shift = []) and (Key = VK_DELETE) and
|
|
(Selection.Count > 0) and (Selection[0] is TComponent) and
|
|
(MessageDlg(oisDeleteComponents, mtConfirmation,[mbYes, mbNo],0) = mrYes) then
|
|
begin
|
|
OnDeletePopupmenuItemClick(nil);
|
|
end;
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.ComponentTreeSelectionChanged(Sender: TObject);
|
|
begin
|
|
if (PropertyEditorHook=nil) or (PropertyEditorHook.LookupRoot=nil) then exit;
|
|
if FSelection.IsEqual(ComponentTree.Selection) then exit;
|
|
Fselection.Assign(ComponentTree.Selection);
|
|
RefreshSelection;
|
|
if Assigned(FOnSelectPersistentsInOI) then
|
|
FOnSelectPersistentsInOI(Self);
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.ObjectInspectorResize(Sender: TObject);
|
|
begin
|
|
if (ComponentTree<>nil) and (ComponentTree.Visible)
|
|
and (ComponentTree.Parent=Self) then
|
|
ComponentTree.Height:=ClientHeight div 4;
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.OnGridKeyDown(Sender: TObject; var Key: Word;
|
|
Shift: TShiftState);
|
|
var
|
|
Handled: Boolean;
|
|
begin
|
|
Handled := false;
|
|
|
|
//CTRL-[Shift]-TAB will select next or previous notebook tab
|
|
if Key=VK_TAB then
|
|
begin
|
|
if Shift = [ssCtrl] then
|
|
begin
|
|
Handled := true;
|
|
ShowNextPage(1);
|
|
end else if Shift = [ssCtrl, ssShift] then
|
|
begin
|
|
Handled := true;
|
|
ShowNextPage(-1);
|
|
end;
|
|
end;
|
|
|
|
//Allow combobox navigation while it has focus
|
|
if not Handled
|
|
then Handled := AvailPersistentComboBox.Focused;
|
|
|
|
if not Handled then
|
|
begin
|
|
//CTRL-ArrowDown will dropdown the component combobox
|
|
if (Key=VK_DOWN) and (ssCtrl in Shift) then
|
|
begin
|
|
Handled := true;
|
|
if AvailPersistentComboBox.Canfocus
|
|
then AvailPersistentComboBox.SetFocus;
|
|
AvailPersistentComboBox.DroppedDown := true;
|
|
end;
|
|
end;
|
|
|
|
if not Handled then
|
|
begin
|
|
if Assigned(OnOIKeyDown) then
|
|
OnOIKeyDown(Self,Key,Shift);
|
|
if (Key<>VK_UNKNOWN) and Assigned(OnRemainingKeyDown) then
|
|
OnRemainingKeyDown(Self,Key,Shift);
|
|
end
|
|
else
|
|
Key := VK_UNKNOWN;
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.OnGridKeyUp(Sender: TObject; var Key: Word;
|
|
Shift: TShiftState);
|
|
begin
|
|
if Assigned(OnRemainingKeyUp) then OnRemainingKeyUp(Self,Key,Shift);
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.OnGridDblClick(Sender: TObject);
|
|
begin
|
|
//
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.OnSetDefaultPopupmenuItemClick(Sender: TObject);
|
|
var
|
|
CurGrid: TOICustomPropertyGrid;
|
|
DefaultStr: string;
|
|
begin
|
|
if not GetCurRowDefaultValue(DefaultStr) then exit;
|
|
CurGrid:=GetActivePropertyGrid;
|
|
if CurGrid=nil then exit;
|
|
CurGrid.SetCurrentRowValue(DefaultStr);
|
|
RefreshPropertyValues;
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.OnAddToFavoritesPopupmenuItemClick(Sender: TObject);
|
|
begin
|
|
//debugln('TObjectInspectorDlg.OnAddToFavouritePopupmenuItemClick');
|
|
if Assigned(OnAddToFavourites) then OnAddToFavourites(Self);
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.OnRemoveFromFavoritesPopupmenuItemClick(
|
|
Sender: TObject);
|
|
begin
|
|
if Assigned(OnRemoveFromFavourites) then OnRemoveFromFavourites(Self);
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.OnViewRestrictionsPopupmenuItemClick(Sender: TObject);
|
|
begin
|
|
DoViewRestricted;
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.OnUndoPopupmenuItemClick(Sender: TObject);
|
|
var
|
|
CurGrid: TOICustomPropertyGrid;
|
|
CurRow: TOIPropertyGridRow;
|
|
begin
|
|
CurGrid:=GetActivePropertyGrid;
|
|
CurRow:=GetActivePropertyRow;
|
|
if CurRow=nil then exit;
|
|
CurGrid.CurrentEditValue:=CurRow.Editor.GetVisualValue;
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.OnFindDeclarationPopupmenuItemClick(Sender: TObject
|
|
);
|
|
begin
|
|
if Assigned(OnFindDeclarationOfProperty) then
|
|
OnFindDeclarationOfProperty(Self);
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.OnCutPopupmenuItemClick(Sender: TObject);
|
|
var
|
|
ADesigner: TIDesigner;
|
|
begin
|
|
if (Selection.Count > 0) and (Selection[0] is TComponent) then begin
|
|
ADesigner:=FindRootDesigner(TComponent(Selection[0]));
|
|
if ADesigner is TComponentEditorDesigner then begin
|
|
TComponentEditorDesigner(ADesigner).CutSelection;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.OnCopyPopupmenuItemClick(Sender: TObject);
|
|
var
|
|
ADesigner: TIDesigner;
|
|
begin
|
|
if (Selection.Count > 0) and (Selection[0] is TComponent) then
|
|
begin
|
|
ADesigner:=FindRootDesigner(TComponent(Selection[0]));
|
|
if ADesigner is TComponentEditorDesigner then begin
|
|
TComponentEditorDesigner(ADesigner).CopySelection;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.OnPastePopupmenuItemClick(Sender: TObject);
|
|
var
|
|
ADesigner: TIDesigner;
|
|
begin
|
|
if Selection.Count > 0 then begin
|
|
ADesigner:=FindRootDesigner(TComponent(Selection[0]));
|
|
if ADesigner is TComponentEditorDesigner then begin
|
|
TComponentEditorDesigner(ADesigner).PasteSelection([]);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.OnDeletePopupmenuItemClick(Sender: TObject);
|
|
var
|
|
ADesigner: TIDesigner;
|
|
begin
|
|
if (Selection.Count > 0) and (Selection[0] is TComponent) then
|
|
begin
|
|
ADesigner:=FindRootDesigner(TComponent(Selection[0]));
|
|
if ADesigner is TComponentEditorDesigner then begin
|
|
TComponentEditorDesigner(ADesigner).DeleteSelection;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.OnGridModified(Sender: TObject);
|
|
begin
|
|
if Assigned(FOnModified) then FOnModified(Self);
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.OnGridSelectionChange(Sender: TObject);
|
|
begin
|
|
if Assigned(FOnSelectionChange) then OnSelectionChange(Self);
|
|
end;
|
|
|
|
function TObjectInspectorDlg.OnGridPropertyHint(Sender: TObject;
|
|
PointedRow: TOIPropertyGridRow; ScreenPos: TPoint; aHintWindow: THintWindow;
|
|
out HintWinRect: TRect; out AHint: string): boolean;
|
|
begin
|
|
Result := False;
|
|
if Assigned(FOnPropertyHint) then
|
|
Result := FOnPropertyHint(Sender, PointedRow, ScreenPos, aHintWindow, HintWinRect, AHint);
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.SetAvailComboBoxText;
|
|
begin
|
|
case FSelection.Count of
|
|
0: // none selected
|
|
AvailPersistentComboBox.Text:='';
|
|
1: // single selection
|
|
AvailPersistentComboBox.Text:=PersistentToString(FSelection[0]);
|
|
else
|
|
// multi selection
|
|
AvailPersistentComboBox.Text:=Format(oisItemsSelected, [FSelection.Count]);
|
|
end;
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.HookGetSelection(
|
|
const ASelection: TPersistentSelectionList);
|
|
begin
|
|
if ASelection=nil then exit;
|
|
ASelection.Assign(FSelection);
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.HookSetSelection(
|
|
const ASelection: TPersistentSelectionList);
|
|
begin
|
|
if ASelection=nil then exit;
|
|
if FSelection.IsEqual(ASelection) then exit;
|
|
Selection:=ASelection;
|
|
if Assigned(FOnSelectPersistentsInOI) then
|
|
FOnSelectPersistentsInOI(Self);
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.SetShowComponentTree(const AValue: boolean);
|
|
begin
|
|
if FShowComponentTree=AValue then exit;
|
|
FShowComponentTree:=AValue;
|
|
BeginUpdate;
|
|
try
|
|
ShowComponentTreePopupMenuItem.Checked:=FShowComponentTree;
|
|
// hide controls while rebuilding
|
|
if Splitter1<>nil then
|
|
Splitter1.Visible:=false;
|
|
DestroyNoteBook;
|
|
ComponentTree.Visible:=false;
|
|
AvailPersistentComboBox.Visible:=false;
|
|
// rebuild controls
|
|
ComponentTree.Parent:=Self;
|
|
ComponentTree.Align:=alTop;
|
|
if FShowComponentTree then
|
|
CreateSplitter(True)
|
|
else begin
|
|
ComponentTree.Height:=ComponentTreeHeight;
|
|
FreeAndNil(Splitter1);
|
|
end;
|
|
ComponentTree.Visible:=FShowComponentTree;
|
|
AvailPersistentComboBox.Visible:=not FShowComponentTree;
|
|
CreateNoteBook;
|
|
finally
|
|
EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.SetShowFavorites(const AValue: Boolean);
|
|
begin
|
|
if FShowFavorites = AValue then exit;
|
|
FShowFavorites := AValue;
|
|
NoteBook.Page[2].TabVisible := AValue;
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.SetShowInfoBox(const AValue: Boolean);
|
|
begin
|
|
if FShowInfoBox = AValue then exit;
|
|
FShowInfoBox := AValue;
|
|
|
|
InfoPanel.Visible := AValue;
|
|
|
|
if AValue then
|
|
CreateSplitter(False)
|
|
else
|
|
FreeAndNil(Splitter2);
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.SetShowRestricted(const AValue: Boolean);
|
|
begin
|
|
if FShowRestricted = AValue then exit;
|
|
FShowRestricted := AValue;
|
|
NoteBook.Page[3].TabVisible := AValue;
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.SetShowStatusBar(const AValue: Boolean);
|
|
begin
|
|
if FShowStatusBar = AValue then exit;
|
|
FShowStatusBar := AValue;
|
|
StatusBar.Visible := AValue;
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.ShowNextPage(Delta: integer);
|
|
var
|
|
NewPageIndex: Integer;
|
|
begin
|
|
NewPageIndex := NoteBook.PageIndex;
|
|
repeat
|
|
NewPageIndex := NewPageIndex + Delta;
|
|
if NewPageIndex >= NoteBook.PageCount then
|
|
NewPageIndex := 0;
|
|
if NewPageIndex < 0 then
|
|
NewPageIndex := NoteBook.PageCount - 1;
|
|
if NoteBook.Page[NewPageIndex].TabVisible then
|
|
begin
|
|
NoteBook.PageIndex := NewPageIndex;
|
|
break;
|
|
end;
|
|
until NewPageIndex = NoteBook.PageIndex;
|
|
end;
|
|
|
|
|
|
procedure TObjectInspectorDlg.RestrictedPageShow(Sender: TObject);
|
|
begin
|
|
//DebugLn('RestrictedPageShow');
|
|
DoUpdateRestricted;
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.RestrictedPaint(
|
|
ABox: TPaintBox; const ARestrictions: TWidgetSetRestrictionsArray);
|
|
|
|
function OutVertCentered(AX: Integer; const AStr: String): TSize;
|
|
begin
|
|
Result := ABox.Canvas.TextExtent(AStr);
|
|
ABox.Canvas.TextOut(AX, (ABox.Height - Result.CY) div 2, AStr);
|
|
end;
|
|
|
|
var
|
|
X, Y: Integer;
|
|
lclPlatform: TLCLPlatform;
|
|
None: Boolean;
|
|
OldStyle: TBrushStyle;
|
|
begin
|
|
X := 0;
|
|
Y := (ABox.Height - IDEImages.Images_16.Height) div 2;
|
|
OldStyle := ABox.Canvas.Brush.Style;
|
|
try
|
|
ABox.Canvas.Brush.Style := bsClear;
|
|
None := True;
|
|
for lclPlatform := Low(TLCLPlatform) to High(TLCLPlatform) do
|
|
begin
|
|
if ARestrictions[lclPlatform] = 0 then continue;
|
|
None := False;
|
|
IDEImages.Images_16.Draw(
|
|
ABox.Canvas, X, Y,
|
|
IDEImages.LoadImage(16, 'issue_' + LCLPlatformDirNames[lclPlatform]));
|
|
Inc(X, 16);
|
|
Inc(X, OutVertCentered(X, IntToStr(ARestrictions[lclPlatform])).CX);
|
|
end;
|
|
|
|
if None then
|
|
OutVertCentered(4, oisNone);
|
|
finally
|
|
ABox.Canvas.Brush.Style := OldStyle;
|
|
end;
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.WidgetSetRestrictedPaint(Sender: TObject);
|
|
begin
|
|
if RestrictedProps <> nil then
|
|
RestrictedPaint(
|
|
WidgetSetsRestrictedBox, RestrictedProps.WidgetSetRestrictions);
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.ComponentRestrictedPaint(Sender: TObject);
|
|
var
|
|
I, J: Integer;
|
|
WidgetSetRestrictions: TWidgetSetRestrictionsArray;
|
|
begin
|
|
if (RestrictedProps = nil) or (Selection = nil) then exit;
|
|
|
|
FillChar(WidgetSetRestrictions, SizeOf(WidgetSetRestrictions), 0);
|
|
for I := 0 to RestrictedProps.Count - 1 do
|
|
begin
|
|
if RestrictedProps.Items[I] is TOIRestrictedProperty then
|
|
for J := 0 to Selection.Count - 1 do
|
|
with RestrictedProps.Items[I] as TOIRestrictedProperty do
|
|
CheckRestrictions(Selection[J].ClassType, WidgetSetRestrictions);
|
|
end;
|
|
|
|
RestrictedPaint(ComponentRestrictedBox, WidgetSetRestrictions);
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.CreateSplitter(TopSplitter: Boolean);
|
|
begin
|
|
// vertical splitter between component tree and notebook
|
|
if TopSplitter then
|
|
begin
|
|
Splitter1 := TSplitter.Create(Self);
|
|
with Splitter1 do
|
|
begin
|
|
Name := 'Splitter1';
|
|
Parent := Self;
|
|
Align := alTop;
|
|
Top := ComponentTreeHeight;
|
|
Height := 5;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
Splitter2 := TSplitter.Create(Self);
|
|
with Splitter2 do
|
|
begin
|
|
Name := 'Splitter2';
|
|
Parent := Self;
|
|
Align := alBottom;
|
|
Top := InfoPanel.Top - 1;
|
|
Height := 5;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.DestroyNoteBook;
|
|
begin
|
|
if NoteBook<>nil then
|
|
NoteBook.Visible:=false;
|
|
FreeAndNil(PropertyGrid);
|
|
FreeAndNil(EventGrid);
|
|
FreeAndNil(FavouriteGrid);
|
|
FreeAndNil(RestrictedGrid);
|
|
FreeAndNil(NoteBook);
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.CreateNoteBook;
|
|
|
|
function CreateGrid(
|
|
ATypeFilter: TTypeKinds; AOIPage: TObjectInspectorPage;
|
|
ANotebookPage: Integer): TOICustomPropertyGrid;
|
|
begin
|
|
Result:=TOICustomPropertyGrid.CreateWithParams(
|
|
Self, PropertyEditorHook, ATypeFilter, FDefaultItemHeight);
|
|
with Result do begin
|
|
Name := DefaultOIGridNames[AOIPage];
|
|
Selection := Self.FSelection;
|
|
Align := alClient;
|
|
PopupMenu := MainPopupMenu;
|
|
OnModified := @OnGridModified;
|
|
OnSelectionChange := @OnGridSelectionChange;
|
|
OnPropertyHint := @OnGridPropertyHint;
|
|
OnOIKeyDown := @OnGridKeyDown;
|
|
OnKeyUp := @OnGridKeyUp;
|
|
OnDblClick := @OnGridDblClick;
|
|
|
|
Parent := NoteBook.Page[ANotebookPage];
|
|
end;
|
|
end;
|
|
|
|
const
|
|
PROPS = [
|
|
tkUnknown, tkInteger, tkChar, tkEnumeration, tkFloat, tkSet,{ tkMethod,}
|
|
tkSString, tkLString, tkAString, tkWString, tkVariant,
|
|
{tkArray, tkRecord, tkInterface,} tkClass, tkObject, tkWChar, tkBool,
|
|
tkInt64, tkQWord];
|
|
begin
|
|
DestroyNoteBook;
|
|
|
|
// NoteBook
|
|
NoteBook:=TNoteBook.Create(Self);
|
|
with NoteBook do begin
|
|
Name:='NoteBook';
|
|
Parent:=Self;
|
|
Align:= alClient;
|
|
if PageCount>0 then
|
|
Pages.Strings[0]:=oisProperties
|
|
else
|
|
Pages.Add(oisProperties);
|
|
Page[0].Name:=DefaultOIPageNames[oipgpProperties];
|
|
|
|
Pages.Add(oisEvents);
|
|
Page[1].Name:=DefaultOIPageNames[oipgpEvents];
|
|
|
|
Pages.Add(oisFavorites);
|
|
Page[2].Name:=DefaultOIPageNames[oipgpFavourite];
|
|
Page[2].TabVisible := ShowFavorites;
|
|
|
|
Pages.Add(oisRestricted);
|
|
Page[3].Name:=DefaultOIPageNames[oipgpRestricted];
|
|
Page[3].TabVisible := ShowRestricted;
|
|
Page[3].OnShow := @RestrictedPageShow;
|
|
|
|
PageIndex:=0;
|
|
PopupMenu:=MainPopupMenu;
|
|
end;
|
|
|
|
PropertyGrid := CreateGrid(PROPS, oipgpProperties, 0);
|
|
EventGrid := CreateGrid([tkMethod], oipgpEvents, 1);
|
|
FavouriteGrid := CreateGrid(PROPS + [tkMethod], oipgpFavourite, 2);
|
|
FavouriteGrid.Favourites := FFavourites;
|
|
RestrictedGrid := CreateGrid(PROPS + [tkMethod], oipgpRestricted, 3);
|
|
|
|
RestrictedPanel := TPanel.Create(Self);
|
|
with RestrictedPanel do
|
|
begin
|
|
Align := alTop;
|
|
BevelOuter := bvNone;
|
|
Parent := NoteBook.Page[3];
|
|
end;
|
|
|
|
RestrictedInnerPanel := TPanel.Create(Self);
|
|
with RestrictedInnerPanel do
|
|
begin
|
|
BevelOuter := bvNone;
|
|
BorderSpacing.Around := 6;
|
|
Parent := RestrictedPanel;
|
|
end;
|
|
|
|
WidgetSetsRestrictedLabel := TLabel.Create(Self);
|
|
with WidgetSetsRestrictedLabel do
|
|
begin
|
|
Caption := oisWidgetSetRestrictions;
|
|
Top := 1;
|
|
Align := alTop;
|
|
AutoSize := True;
|
|
Parent := RestrictedInnerPanel;
|
|
end;
|
|
|
|
WidgetSetsRestrictedBox := TPaintBox.Create(Self);
|
|
with WidgetSetsRestrictedBox do
|
|
begin
|
|
Top := 2;
|
|
Align := alTop;
|
|
Height := 24;
|
|
OnPaint := @WidgetSetRestrictedPaint;
|
|
Parent := RestrictedInnerPanel;
|
|
end;
|
|
|
|
ComponentRestrictedLabel := TLabel.Create(Self);
|
|
with ComponentRestrictedLabel do
|
|
begin
|
|
Caption := oisComponentRestrictions;
|
|
Top := 3;
|
|
Align := alTop;
|
|
AutoSize := True;
|
|
Parent := RestrictedInnerPanel;
|
|
end;
|
|
|
|
ComponentRestrictedBox := TPaintBox.Create(Self);
|
|
with ComponentRestrictedBox do
|
|
begin
|
|
Top := 4;
|
|
Align := alTop;
|
|
Height := 24;
|
|
OnPaint := @ComponentRestrictedPaint;
|
|
Parent := RestrictedInnerPanel;
|
|
end;
|
|
|
|
RestrictedInnerPanel.AutoSize := True;
|
|
RestrictedPanel.AutoSize := True;
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.KeyDown(var Key: Word; Shift: TShiftState);
|
|
var
|
|
CurGrid: TOICustomPropertyGrid;
|
|
begin
|
|
CurGrid:=GetActivePropertyGrid;
|
|
//Do not disturb the combobox navigation while it has focus
|
|
if not AvailPersistentComboBox.DroppedDown then begin
|
|
if CurGrid<>nil then begin
|
|
CurGrid.HandleStandardKeys(Key,Shift);
|
|
if Key=VK_UNKNOWN then exit;
|
|
end;
|
|
end;
|
|
inherited KeyDown(Key, Shift);
|
|
if (Key<>VK_UNKNOWN) and Assigned(OnRemainingKeyDown) then
|
|
OnRemainingKeyDown(Self,Key,Shift);
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.KeyUp(var Key: Word; Shift: TShiftState);
|
|
begin
|
|
inherited KeyUp(Key, Shift);
|
|
if (Key<>VK_UNKNOWN) and Assigned(OnRemainingKeyUp) then
|
|
OnRemainingKeyUp(Self,Key,Shift);
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.OnShowHintPopupMenuItemClick(Sender : TObject);
|
|
var
|
|
Page: TObjectInspectorPage;
|
|
begin
|
|
for Page := Low(TObjectInspectorPage) to High(TObjectInspectorPage) do
|
|
if GridControl[Page] <> nil then
|
|
GridControl[Page].ShowHint := not GridControl[Page].ShowHint;
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.OnShowOptionsPopupMenuItemClick(Sender: TObject);
|
|
begin
|
|
if Assigned(FOnShowOptions) then FOnShowOptions(Sender);
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.OnShowComponentTreePopupMenuItemClick(Sender: TObject
|
|
);
|
|
begin
|
|
ShowComponentTree:=not ShowComponentTree;
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.OnMainPopupMenuPopup(Sender: TObject);
|
|
var
|
|
DefaultStr: String;
|
|
CurGrid: TOICustomPropertyGrid;
|
|
CurRow: TOIPropertyGridRow;
|
|
begin
|
|
SetDefaultPopupMenuItem.Enabled:=GetCurRowDefaultValue(DefaultStr);
|
|
if SetDefaultPopupMenuItem.Enabled then
|
|
SetDefaultPopupMenuItem.Caption:=Format(oisSetToDefault, [DefaultStr])
|
|
else
|
|
SetDefaultPopupMenuItem.Caption:=oisSetToDefaultValue;
|
|
|
|
AddToFavoritesPopupMenuItem.Visible:=(Favourites<>nil) and ShowFavorites
|
|
and (GetActivePropertyGrid<>FavouriteGrid)
|
|
and Assigned(OnAddToFavourites) and (GetActivePropertyRow<>nil);
|
|
RemoveFromFavoritesPopupMenuItem.Visible:=(Favourites<>nil) and ShowFavorites
|
|
and (GetActivePropertyGrid=FavouriteGrid)
|
|
and Assigned(OnRemoveFromFavourites) and (GetActivePropertyRow<>nil);
|
|
|
|
CurGrid:=GetActivePropertyGrid;
|
|
CurRow:=GetActivePropertyRow;
|
|
if (CurRow<>nil) and (CurRow.Editor.GetVisualValue<>CurGrid.CurrentEditValue)
|
|
then
|
|
UndoPropertyPopupMenuItem.Enabled:=true
|
|
else
|
|
UndoPropertyPopupMenuItem.Enabled:=false;
|
|
ShowHintsPopupMenuItem.Checked:=PropertyGrid.ShowHint;
|
|
if (Selection.Count > 0) and FShowComponentTree then begin
|
|
CutPopupMenuItem.Visible := true;
|
|
CopyPopupMenuItem.Visible := true;
|
|
PastePopupMenuItem.Visible := true;
|
|
DeletePopupMenuItem.visible := true;
|
|
OptionsSeparatorMenuItem2.visible := true;
|
|
end else begin
|
|
CutPopupMenuItem.Visible := false;
|
|
CopyPopupMenuItem.Visible := false;
|
|
PastePopupMenuItem.Visible := false;
|
|
DeletePopupMenuItem.visible := false;
|
|
OptionsSeparatorMenuItem2.visible := false;
|
|
end;
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.DoUpdateRestricted;
|
|
begin
|
|
if Assigned(FOnUpdateRestricted) then FOnUpdateRestricted(Self);
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.DoViewRestricted;
|
|
begin
|
|
if Assigned(FOnViewRestricted) then FOnViewRestricted(Self);
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.HookRefreshPropertyValues;
|
|
begin
|
|
RefreshPropertyValues;
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.ActivateGrid(Grid: TOICustomPropertyGrid);
|
|
begin
|
|
if Grid=PropertyGrid then NoteBook.PageIndex:=0
|
|
else if Grid=EventGrid then NoteBook.PageIndex:=1
|
|
else if Grid=FavouriteGrid then NoteBook.PageIndex:=2
|
|
else if Grid=RestrictedGrid then NoteBook.PageIndex:=3;
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.FocusGrid(Grid: TOICustomPropertyGrid);
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if Grid=nil then
|
|
Grid := GetActivePropertyGrid
|
|
else
|
|
ActivateGrid(Grid);
|
|
if Grid <> nil then
|
|
begin
|
|
Index := Grid.ItemIndex;
|
|
if Index < 0 then
|
|
Index := 0;
|
|
Grid.SetItemIndexAndFocus(Index);
|
|
end;
|
|
end;
|
|
|
|
function TObjectInspectorDlg.GetGridControl(Page: TObjectInspectorPage
|
|
): TOICustomPropertyGrid;
|
|
begin
|
|
case Page of
|
|
oipgpFavourite: Result:=FavouriteGrid;
|
|
oipgpEvents: Result:=EventGrid;
|
|
oipgpRestricted: Result:=RestrictedGrid;
|
|
else Result:=PropertyGrid;
|
|
end;
|
|
end;
|
|
|
|
procedure TObjectInspectorDlg.SetFavourites(const AValue: TOIFavouriteProperties);
|
|
begin
|
|
//debugln('TObjectInspectorDlg.SetFavourites ',dbgsName(Self));
|
|
if FFavourites=AValue then exit;
|
|
FFavourites:=AValue;
|
|
FavouriteGrid.Favourites:=FFavourites;
|
|
end;
|
|
|
|
{ TCustomPropertiesGrid }
|
|
|
|
function TCustomPropertiesGrid.GetTIObject: TPersistent;
|
|
begin
|
|
if PropertyEditorHook<>nil then Result:=PropertyEditorHook.LookupRoot;
|
|
end;
|
|
|
|
procedure TCustomPropertiesGrid.SetAutoFreeHook(const AValue: boolean);
|
|
begin
|
|
if FAutoFreeHook=AValue then exit;
|
|
FAutoFreeHook:=AValue;
|
|
end;
|
|
|
|
procedure TCustomPropertiesGrid.SetTIObject(const AValue: TPersistent);
|
|
var
|
|
NewSelection: TPersistentSelectionList;
|
|
begin
|
|
if (TIObject=AValue) then begin
|
|
if ((AValue<>nil) and (Selection.Count=1) and (Selection[0]=AValue))
|
|
or (AValue=nil) then
|
|
exit;
|
|
end;
|
|
if SaveOnChangeTIObject then
|
|
SaveChanges;
|
|
if PropertyEditorHook=nil then
|
|
PropertyEditorHook:=TPropertyEditorHook.Create;
|
|
PropertyEditorHook.LookupRoot:=AValue;
|
|
if (AValue<>nil) and ((Selection.Count<>1) or (Selection[0]<>AValue)) then
|
|
begin
|
|
NewSelection:=TPersistentSelectionList.Create;
|
|
try
|
|
if AValue<>nil then
|
|
NewSelection.Add(AValue);
|
|
Selection:=NewSelection;
|
|
finally
|
|
NewSelection.Free;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
constructor TCustomPropertiesGrid.Create(TheOwner: TComponent);
|
|
var
|
|
Hook: TPropertyEditorHook;
|
|
begin
|
|
Hook:=TPropertyEditorHook.Create;
|
|
FSaveOnChangeTIObject:=true;
|
|
FAutoFreeHook:=true;
|
|
CreateWithParams(TheOwner,Hook,AllTypeKinds,25);
|
|
end;
|
|
|
|
destructor TCustomPropertiesGrid.Destroy;
|
|
begin
|
|
if FAutoFreeHook then
|
|
FPropertyEditorHook.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
initialization
|
|
{$I objectinspector.lrs}
|
|
{$I objectinspector_img.lrs}
|
|
|
|
finalization
|
|
|
|
end.
|
|
|