1{ 2 ***************************************************************************** 3 See the file COPYING.modifiedLGPL.txt, included in this distribution, 4 for details about the license. 5 ***************************************************************************** 6 7 Author: Mattias Gaertner 8 9 Abstract: 10 This unit defines the TObjectInspectorDlg. 11 It uses TOIPropertyGrid and TOIPropertyGridRow which are also defined in this 12 unit. The object inspector uses property editors (see TPropertyEditor) to 13 display and control properties, thus the object inspector is merely an 14 object viewer than an editor. The property editors do the real work. 15 16 ToDo: 17 - backgroundcolor=clNone 18 - Define Init values 19 - Set to init value 20} 21unit ObjectInspector; 22 23{$Mode objfpc}{$H+} 24 25{off $DEFINE DoNotCatchOIExceptions} 26 27interface 28 29uses 30 // IMPORTANT: the object inspector is a tool and can be used in other programs 31 // too. Don't put Lazarus IDE specific things here. 32 // RTL / FCL 33 Classes, SysUtils, Types, TypInfo, StrUtils, math, 34 // LCL 35 LCLPlatformDef, InterfaceBase, LCLType, LCLIntf, Forms, Buttons, Graphics, 36 StdCtrls, Controls, ComCtrls, ExtCtrls, Menus, Dialogs, Themes, LMessages, 37 ImgList, ActnList, 38 // LazControls 39 {$IFnDEF UseOINormalCheckBox} CheckBoxThemed, {$ENDIF} 40 TreeFilterEdit, ListFilterEdit, 41 // LazUtils 42 GraphType, LazConfigStorage, LazLoggerBase, LazStringUtils, LazUTF8, 43 // IdeIntf 44 IDEImagesIntf, IDEHelpIntf, ObjInspStrConsts, 45 PropEdits, PropEditUtils, ComponentTreeView, OIFavoriteProperties, 46 ComponentEditors, ChangeParentDlg; 47 48const 49 OIOptionsFileVersion = 3; 50 51 DefBackgroundColor = clBtnFace; 52 DefReferencesColor = clMaroon; 53 DefSubPropertiesColor = clGreen; 54 DefNameColor = clWindowText; 55 DefValueColor = clMaroon; 56 DefDefaultValueColor = clWindowText; 57 DefValueDifferBackgrndColor = $F0F0FF; // Sort of pink. 58 DefReadOnlyColor = clGrayText; 59 DefHighlightColor = clHighlight; 60 DefHighlightFontColor = clHighlightText; 61 DefGutterColor = DefBackgroundColor; 62 DefGutterEdgeColor = cl3DShadow; 63 64 DefaultOITypeKinds = [ 65 tkUnknown, tkInteger, tkChar, tkEnumeration, tkFloat, tkSet,{ tkMethod,} 66 tkSString, tkLString, tkAString, tkWString, tkVariant, 67 {tkArray, tkRecord,} tkInterface, tkClass, tkObject, tkWChar, tkBool, 68 tkInt64, tkQWord, tkUString, tkUChar]; 69type 70 EObjectInspectorException = class(Exception); 71 72 TObjectInspectorDlg = class; 73 TOICustomPropertyGrid = class; 74 75 // standard ObjectInspector pages 76 TObjectInspectorPage = ( 77 oipgpProperties, 78 oipgpEvents, 79 oipgpFavorite, 80 oipgpRestricted 81 ); 82 TObjectInspectorPages = set of TObjectInspectorPage; 83 84 85 { TOIOptions } 86 87 TOIOptions = class 88 private 89 FComponentTreeHeight: integer; 90 FConfigStore: TConfigStorage; 91 FDefaultItemHeight: integer; 92 FGutterColor: TColor; 93 FGutterEdgeColor: TColor; 94 FShowComponentTree: boolean; 95 96 FSaveBounds: boolean; 97 FLeft: integer; 98 FShowPropertyFilter: boolean; 99 FShowGutter: boolean; 100 FShowInfoBox: boolean; 101 FInfoBoxHeight: integer; 102 FShowStatusBar: boolean; 103 FTop: integer; 104 FWidth: integer; 105 FHeight: integer; 106 FGridSplitterX: array[TObjectInspectorPage] of integer; 107 108 FPropertyNameColor: TColor; 109 FSubPropertiesColor: TColor; 110 FValueColor: TColor; 111 FDefaultValueColor: TColor; 112 FValueDifferBackgrndColor: TColor; 113 FReadOnlyColor: TColor; 114 FReferencesColor: TColor; 115 FGridBackgroundColor: TColor; 116 FHighlightColor: TColor; 117 FHighlightFontColor: TColor; 118 119 FShowHints: Boolean; 120 FAutoShow: Boolean; 121 FCheckboxForBoolean: Boolean; 122 FBoldNonDefaultValues: Boolean; 123 FDrawGridLines: Boolean; 124 function FPropertyGridSplitterX(Page: TObjectInspectorPage): integer; 125 procedure FPropertyGridSplitterX(Page: TObjectInspectorPage; 126 const AValue: integer); 127 public 128 constructor Create; 129 function Load: boolean; 130 function Save: boolean; 131 procedure Assign(AnObjInspector: TObjectInspectorDlg); 132 procedure AssignTo(AnObjInspector: TObjectInspectorDlg); overload; 133 procedure AssignTo(AGrid: TOICustomPropertyGrid); overload; 134 135 property ConfigStore: TConfigStorage read FConfigStore write FConfigStore; 136 137 property SaveBounds:boolean read FSaveBounds write FSaveBounds; 138 property Left:integer read FLeft write FLeft; 139 property Top:integer read FTop write FTop; 140 property Width:integer read FWidth write FWidth; 141 property Height:integer read FHeight write FHeight; 142 property GridSplitterX[Page: TObjectInspectorPage]:integer 143 read FPropertyGridSplitterX write FPropertyGridSplitterX; 144 property DefaultItemHeight: integer read FDefaultItemHeight 145 write FDefaultItemHeight; 146 property ShowComponentTree: boolean read FShowComponentTree 147 write FShowComponentTree; 148 property ComponentTreeHeight: integer read FComponentTreeHeight 149 write FComponentTreeHeight; 150 151 property GridBackgroundColor: TColor read FGridBackgroundColor write FGridBackgroundColor; 152 property SubPropertiesColor: TColor read FSubPropertiesColor write FSubPropertiesColor; 153 property ReferencesColor: TColor read FReferencesColor write FReferencesColor; 154 property ReadOnlyColor: TColor read FReadOnlyColor write FReadOnlyColor; 155 property ValueColor: TColor read FValueColor write FValueColor; 156 property DefaultValueColor: TColor read FDefaultValueColor write FDefaultValueColor; 157 property ValueDifferBackgrndColor: TColor read FValueDifferBackgrndColor write FValueDifferBackgrndColor; 158 property PropertyNameColor: TColor read FPropertyNameColor write FPropertyNameColor; 159 property HighlightColor: TColor read FHighlightColor write FHighlightColor; 160 property HighlightFontColor: TColor read FHighlightFontColor write FHighlightFontColor; 161 property GutterColor: TColor read FGutterColor write FGutterColor; 162 property GutterEdgeColor: TColor read FGutterEdgeColor write FGutterEdgeColor; 163 164 property ShowHints: boolean read FShowHints write FShowHints; 165 property AutoShow: boolean read FAutoShow write FAutoShow; 166 property CheckboxForBoolean: boolean read FCheckboxForBoolean write FCheckboxForBoolean; 167 property BoldNonDefaultValues: boolean read FBoldNonDefaultValues write FBoldNonDefaultValues; 168 property DrawGridLines: boolean read FDrawGridLines write FDrawGridLines; 169 property ShowPropertyFilter: boolean read FShowPropertyFilter write FShowPropertyFilter; 170 property ShowGutter: boolean read FShowGutter write FShowGutter; 171 property ShowStatusBar: boolean read FShowStatusBar write FShowStatusBar; 172 property ShowInfoBox: boolean read FShowInfoBox write FShowInfoBox; 173 property InfoBoxHeight: integer read FInfoBoxHeight write FInfoBoxHeight; 174 end; 175 176 { TOIPropertyGridRow } 177 178 TOIPropertyGridRow = class 179 private 180 FTop: integer; 181 FHeight: integer; 182 FLvl: integer; 183 FName: string; 184 FExpanded: boolean; 185 FTree: TOICustomPropertyGrid; 186 FChildCount:integer; 187 FPriorBrother, 188 FFirstChild, 189 FLastChild, 190 FNextBrother, 191 FParent: TOIPropertyGridRow; 192 FEditor: TPropertyEditor; 193 FWidgetSets: TLCLPlatforms; 194 195 FIndex:integer; 196 LastPaintedValue: string; 197 198 procedure GetLvl; 199 public 200 constructor Create(PropertyTree: TOICustomPropertyGrid; 201 PropEditor:TPropertyEditor; ParentNode:TOIPropertyGridRow; WidgetSets: TLCLPlatforms); 202 destructor Destroy; override; 203 function ConsistencyCheck: integer; 204 function HasChild(Row: TOIPropertyGridRow): boolean; 205 procedure WriteDebugReport(const Prefix: string); 206 207 function GetBottom: integer; 208 function IsReadOnly: boolean; 209 function IsDisabled: boolean; 210 procedure MeasureHeight(ACanvas: TCanvas); 211 function Sort(const Compare: TListSortCompare): boolean; // true if changed 212 function IsSorted(const Compare: TListSortCompare): boolean; 213 function Next: TOIPropertyGridRow; 214 function NextSkipChilds: TOIPropertyGridRow; 215 216 property Editor: TPropertyEditor read FEditor; 217 property Top: integer read FTop write FTop; 218 property Height: integer read FHeight write FHeight; 219 property Bottom: integer read GetBottom; 220 property Lvl: integer read FLvl; 221 property Name: string read FName; 222 property Expanded: boolean read FExpanded; 223 property Tree: TOICustomPropertyGrid read FTree; 224 property Parent: TOIPropertyGridRow read FParent; 225 property ChildCount: integer read FChildCount; 226 property FirstChild: TOIPropertyGridRow read FFirstChild; 227 property LastChild: TOIPropertyGridRow read FLastChild; 228 property NextBrother: TOIPropertyGridRow read FNextBrother; 229 property PriorBrother: TOIPropertyGridRow read FPriorBrother; 230 property Index: integer read FIndex; 231 end; 232 233 //---------------------------------------------------------------------------- 234 TOIPropertyGridState = ( 235 pgsChangingItemIndex, 236 pgsApplyingValue, 237 pgsUpdatingEditControl, 238 pgsBuildPropertyListNeeded, 239 pgsGetComboItemsCalled, 240 pgsIdleEnabled, 241 pgsCallingEdit, // calling property editor Edit 242 pgsFocusPropertyEditorDisabled // by building PropertyList no editor should be focused 243 ); 244 TOIPropertyGridStates = set of TOIPropertyGridState; 245 246 { TOICustomPropertyGrid } 247 248 TOICustomPropertyGridColumn = ( 249 oipgcName, 250 oipgcValue 251 ); 252 253 TOILayout = ( 254 oilHorizontal, 255 oilVertical 256 ); 257 258 TOIQuickEdit = ( 259 oiqeEdit, 260 oiqeShowValue 261 ); 262 263 TOIPropertyHintEvent = function(Sender: TObject; PointedRow: TOIPropertyGridRow; 264 out AHint: string): boolean of object; 265 266 TOIEditorFilterEvent = procedure(Sender: TObject; aEditor: TPropertyEditor; 267 var aShow: boolean) of object; 268 269 TOICustomPropertyGrid = class(TCustomControl) 270 private 271 FBackgroundColor: TColor; 272 FColumn: TOICustomPropertyGridColumn; 273 FGutterColor: TColor; 274 FGutterEdgeColor: TColor; 275 FHighlightColor: TColor; 276 FLayout: TOILayout; 277 FOnEditorFilter: TOIEditorFilterEvent; 278 FOnOIKeyDown: TKeyEvent; 279 FOnPropertyHint: TOIPropertyHintEvent; 280 FOnSelectionChange: TNotifyEvent; 281 FReferencesColor: TColor; 282 FReadOnlyColor: TColor; 283 FRowSpacing: integer; 284 FShowGutter: Boolean; 285 FCheckboxForBoolean: Boolean; 286 FSubPropertiesColor: TColor; 287 FChangeStep: integer; 288 FCurrentButton: TControl; // nil or ValueButton 289 FCurrentEdit: TWinControl; // nil or ValueEdit or ValueComboBox or ValueCheckBox 290 FCurrentEditorLookupRoot: TPersistent; 291 FDefaultItemHeight:integer; 292 FDragging: boolean; 293 FExpandedProperties: TStringList;// used to restore expanded state when switching selected component(s) 294 FExpandingRow: TOIPropertyGridRow; 295 FFavorites: TOIFavoriteProperties; 296 FFilter: TTypeKinds; 297 FIndent: integer; 298 FItemIndex: integer; 299 FNameFont, FDefaultValueFont, FValueFont, FHighlightFont: TFont; 300 FValueDifferBackgrndColor: TColor; 301 FNewComboBoxItems: TStringListUTF8Fast; 302 FOnModified: TNotifyEvent; 303 FRows: TFPList;// list of TOIPropertyGridRow 304 FSelection: TPersistentSelectionList; 305 FNotificationComponents: TFPList; 306 FPropertyEditorHook: TPropertyEditorHook; 307 FPreferredSplitterX: integer; // best splitter position 308 FSplitterX: integer; // current splitter position 309 FStates: TOIPropertyGridStates; 310 FTopY: integer; 311 FDrawHorzGridLines: Boolean; 312 FActiveRowImages: TLCLGlyphs; 313 FFirstClickTime: DWORD; 314 FKeySearchText: string; 315 FHideClassNames: Boolean; 316 FPropNameFilter : String; 317 FPaintRc: TRect; 318 319 // hint stuff 320 FLongHintTimer: TTimer; 321 FHintManager: THintWindowManager; 322 FHintIndex: integer; 323 FHintType: TPropEditHint; 324 FShowingLongHint: boolean; // last hint was activated by the hinttimer 325 326 ValueEdit: TEdit; 327 ValueComboBox: TComboBox; 328 {$IFnDEF UseOINormalCheckBox} 329 ValueCheckBox: TCheckBoxThemed; 330 {$ELSE} 331 ValueCheckBox: TCheckBox; 332 {$ENDIF} 333 ValueButton: TSpeedButton; 334 335 procedure ActiveRowImagesGetWidthForPPI(Sender: TCustomImageList; 336 {%H-}AImageWidth, {%H-}APPI: Integer; var AResultWidth: Integer); 337 procedure HintMouseLeave(Sender: TObject); 338 procedure HintTimer(Sender: TObject); 339 procedure HideHint; 340 procedure HintMouseDown(Sender: TObject; Button: TMouseButton; 341 Shift: TShiftState; X, Y: Integer); 342 procedure IncreaseChangeStep; 343 function GridIsUpdating: boolean; 344 345 function GetRow(Index:integer):TOIPropertyGridRow; 346 function GetRowCount:integer; 347 procedure ClearRows; 348 function GetCurrentEditValue: string; 349 procedure SetActiveControl(const AControl: TWinControl); 350 procedure SetCheckboxState(NewValue: string); 351 procedure SetColumn(const AValue: TOICustomPropertyGridColumn); 352 procedure SetCurrentEditValue(const NewValue: string); 353 procedure SetDrawHorzGridLines(const AValue: Boolean); 354 procedure SetFavorites(const AValue: TOIFavoriteProperties); 355 procedure SetFilter(const AValue: TTypeKinds); 356 procedure SetGutterColor(const AValue: TColor); 357 procedure SetGutterEdgeColor(const AValue: TColor); 358 procedure SetHighlightColor(const AValue: TColor); 359 procedure SetItemIndex(NewIndex:integer); 360 function IsCurrentEditorAvailable: Boolean; 361 362 function GetNameRowHeight: Integer; // temp solution untill TFont.height returns its actual value 363 364 procedure SetItemsTops; 365 procedure AlignEditComponents; 366 procedure EndDragSplitter; 367 procedure SetRowSpacing(const AValue: integer); 368 procedure SetShowGutter(const AValue: Boolean); 369 procedure SetSplitterX(const NewValue:integer); 370 procedure SetTopY(const NewValue:integer); 371 372 function GetPropNameColor(ARow: TOIPropertyGridRow):TColor; 373 function GetTreeIconX(Index: integer):integer; 374 function RowRect(ARow: integer):TRect; 375 procedure PaintRow(ARow: integer); 376 procedure DoPaint(PaintOnlyChangedValues: boolean); 377 378 procedure SetSelection(const ASelection:TPersistentSelectionList); 379 procedure SetPropertyEditorHook(NewPropertyEditorHook:TPropertyEditorHook); 380 procedure UpdateSelectionNotifications; 381 procedure HookGetCheckboxForBoolean(var Value: Boolean); 382 383 procedure AddPropertyEditor(PropEditor: TPropertyEditor); 384 procedure AddStringToComboBox(const s: string); 385 procedure ExpandRow(Index: integer); 386 procedure ShrinkRow(Index: integer); 387 procedure AddSubEditor(PropEditor: TPropertyEditor); 388 procedure SortSubEditors(ParentRow: TOIPropertyGridRow); 389 function CanExpandRow(Row: TOIPropertyGridRow): boolean; 390 391 procedure SetRowValue(CheckFocus, ForceValue: boolean); 392 procedure DoCallEdit(Edit: TOIQuickEdit = oiqeEdit); 393 procedure RefreshValueEdit; 394 procedure ToggleRow; 395 procedure ValueEditDblClick(Sender : TObject); 396 procedure ValueControlMouseDown(Sender: TObject; {%H-}Button:TMouseButton; 397 {%H-}Shift: TShiftState; {%H-}X,{%H-}Y:integer); 398 procedure ValueControlMouseMove(Sender: TObject; {%H-}Shift: TShiftState; 399 {%H-}X,{%H-}Y:integer); 400 procedure ValueEditKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); 401 procedure ValueEditKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); 402 procedure ValueEditExit(Sender: TObject); 403 procedure ValueEditChange(Sender: TObject); 404 procedure ValueEditMouseUp(Sender: TObject; Button: TMouseButton; 405 Shift: TShiftState; {%H-}X, {%H-}Y: Integer); 406 procedure ValueCheckBoxKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); 407 procedure ValueCheckBoxKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); 408 procedure ValueCheckBoxExit(Sender: TObject); 409 procedure ValueCheckBoxClick(Sender: TObject); 410 procedure ValueComboBoxExit(Sender: TObject); 411 procedure ValueComboBoxKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); 412 procedure ValueComboBoxKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); 413 procedure ValueComboBoxMouseUp(Sender: TObject; Button: TMouseButton; 414 Shift: TShiftState; {%H-}X, {%H-}Y: Integer); 415 procedure ValueComboBoxCloseUp(Sender: TObject); 416 procedure ValueComboBoxGetItems(Sender: TObject); 417 procedure ValueButtonClick(Sender: TObject); 418 procedure ValueComboBoxMeasureItem({%H-}Control: TWinControl; Index: Integer; 419 var AHeight: Integer); 420 procedure ValueComboBoxDrawItem({%H-}Control: TWinControl; Index: Integer; 421 ARect: TRect; State: TOwnerDrawState); 422 procedure OnIdle(Sender: TObject; var {%H-}Done: Boolean); 423 procedure SetIdleEvent(Enable: boolean); 424 procedure OnGridMouseWheel(Sender: TObject; {%H-}Shift: TShiftState; 425 WheelDelta: Integer; {%H-}MousePos: TPoint; var Handled: Boolean); 426 427 procedure WMVScroll(var Msg: TLMScroll); message LM_VSCROLL; 428 procedure SetBackgroundColor(const AValue: TColor); 429 procedure SetReferences(const AValue: TColor); 430 procedure SetSubPropertiesColor(const AValue: TColor); 431 procedure SetReadOnlyColor(const AValue: TColor); 432 procedure SetValueDifferBackgrndColor(AValue: TColor); 433 procedure UpdateScrollBar; 434 function FillComboboxItems: boolean; // true if something changed 435 function EditorFilter(const AEditor: TPropertyEditor): Boolean; 436 protected 437 procedure CreateParams(var Params: TCreateParams); override; 438 procedure CreateWnd; override; 439 procedure Notification(AComponent: TComponent; Operation: TOperation); override; 440 441 function DoMouseWheel(Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint): Boolean; override; 442 procedure MouseDown(Button:TMouseButton; Shift:TShiftState; X,Y:integer); override; 443 procedure MouseMove(Shift:TShiftState; X,Y:integer); override; 444 procedure MouseUp(Button:TMouseButton; Shift:TShiftState; X,Y:integer); override; 445 procedure MouseLeave; override; 446 447 procedure KeyDown(var Key: Word; Shift: TShiftState); override; 448 procedure HandleStandardKeys(var Key: Word; Shift: TShiftState); virtual; 449 procedure HandleKeyUp(var Key: Word; Shift: TShiftState); virtual; 450 procedure DoTabKey; virtual; 451 procedure DoSetBounds(ALeft, ATop, AWidth, AHeight: integer); override; 452 procedure DoSelectionChange; 453 public 454 constructor Create(TheOwner: TComponent); override; 455 constructor CreateWithParams(AnOwner: TComponent; 456 APropertyEditorHook: TPropertyEditorHook; 457 TypeFilter: TTypeKinds; 458 DefItemHeight: integer); 459 destructor Destroy; override; 460 function CanEditRowValue(CheckFocus: boolean): boolean; 461 procedure FocusCurrentEditor; 462 procedure SaveChanges; 463 function ConsistencyCheck: integer; 464 procedure EraseBackground({%H-}DC: HDC); override; 465 function GetActiveRow: TOIPropertyGridRow; 466 function GetHintTypeAt(RowIndex: integer; X: integer): TPropEditHint; 467 468 function GetRowByPath(const PropPath: string): TOIPropertyGridRow; 469 function GridHeight: integer; 470 function RealDefaultItemHeight: integer; 471 function MouseToIndex(y: integer; MustExist: boolean): integer; 472 function PropertyPath(Index: integer):string; 473 function PropertyPath(Row: TOIPropertyGridRow):string; 474 function PropertyEditorByName(const PropName: string): TPropertyEditor; 475 function TopMax: integer; 476 procedure BuildPropertyList(OnlyIfNeeded: Boolean = False; FocusEditor: Boolean = True); 477 procedure Clear; 478 procedure Paint; override; 479 procedure PropEditLookupRootChange; 480 procedure RefreshPropertyValues; 481 procedure ScrollToActiveItem; 482 procedure ScrollToItem(NewIndex: Integer); 483 procedure SetBounds(aLeft, aTop, aWidth, aHeight: integer); override; 484 procedure SetCurrentRowValue(const NewValue: string); 485 procedure SetItemIndexAndFocus(NewItemIndex: integer; 486 WasValueClick: Boolean = False); 487 488 property BackgroundColor: TColor read FBackgroundColor 489 write SetBackgroundColor default DefBackgroundColor; 490 property GutterColor: TColor read FGutterColor write SetGutterColor default DefGutterColor; 491 property GutterEdgeColor: TColor read FGutterEdgeColor write SetGutterEdgeColor default DefGutterEdgeColor; 492 property HighlightColor: TColor read FHighlightColor write SetHighlightColor default DefHighlightColor; 493 property ReferencesColor: TColor read FReferencesColor 494 write SetReferences default DefReferencesColor; 495 property SubPropertiesColor: TColor read FSubPropertiesColor 496 write SetSubPropertiesColor default DefSubPropertiesColor; 497 property ReadOnlyColor: TColor read FReadOnlyColor 498 write SetReadOnlyColor default DefReadOnlyColor; 499 property ValueDifferBackgrndColor: TColor read FValueDifferBackgrndColor 500 write SetValueDifferBackgrndColor default DefValueDifferBackgrndColor; 501 502 property NameFont: TFont read FNameFont write FNameFont; 503 property DefaultValueFont: TFont read FDefaultValueFont write FDefaultValueFont; 504 property ValueFont: TFont read FValueFont write FValueFont; 505 property HighlightFont: TFont read FHighlightFont write FHighlightFont; 506 507 property BorderStyle default bsSingle; 508 property Column: TOICustomPropertyGridColumn read FColumn write SetColumn; 509 property CurrentEditValue: string read GetCurrentEditValue 510 write SetCurrentEditValue; 511 property DefaultItemHeight:integer read FDefaultItemHeight 512 write FDefaultItemHeight default 0; 513 property DrawHorzGridLines: Boolean read FDrawHorzGridLines write 514 SetDrawHorzGridLines default True; 515 property ExpandedProperties: TStringList read FExpandedProperties; 516 property Indent: integer read FIndent write FIndent; 517 property ItemIndex: integer read FItemIndex write SetItemIndex; 518 property Layout: TOILayout read FLayout write FLayout default oilHorizontal; 519 property OnEditorFilter: TOIEditorFilterEvent read FOnEditorFilter write FOnEditorFilter; 520 property OnModified: TNotifyEvent read FOnModified write FOnModified; 521 property OnOIKeyDown: TKeyEvent read FOnOIKeyDown write FOnOIKeyDown; 522 property OnSelectionChange: TNotifyEvent read FOnSelectionChange write FOnSelectionChange; 523 property OnPropertyHint: TOIPropertyHintEvent read FOnPropertyHint write FOnPropertyHint; 524 property PropertyEditorHook: TPropertyEditorHook read FPropertyEditorHook 525 write SetPropertyEditorHook; 526 property RowCount: integer read GetRowCount; 527 property Rows[Index: integer]: TOIPropertyGridRow read GetRow; 528 property RowSpacing: integer read FRowSpacing write SetRowSpacing; 529 property Selection: TPersistentSelectionList read FSelection write SetSelection; 530 property ShowGutter: Boolean read FShowGutter write SetShowGutter default True; 531 property CheckboxForBoolean: Boolean read FCheckboxForBoolean write FCheckboxForBoolean; 532 property PreferredSplitterX: integer read FPreferredSplitterX 533 write FPreferredSplitterX default 100; 534 property SplitterX: integer read FSplitterX write SetSplitterX default 100; 535 property TopY: integer read FTopY write SetTopY default 0; 536 property Favorites: TOIFavoriteProperties read FFavorites write SetFavorites; 537 property Filter : TTypeKinds read FFilter write SetFilter; 538 property HideClassNames: Boolean read FHideClassNames write FHideClassNames; 539 property PropNameFilter : String read FPropNameFilter write FPropNameFilter; 540 end; 541 542 543 { TOIPropertyGrid } 544 545 TOIPropertyGrid = class(TOICustomPropertyGrid) 546 published 547 property Align; 548 property Anchors; 549 property BackgroundColor; 550 property BorderStyle; 551 property Constraints; 552 property DefaultItemHeight; 553 property DefaultValueFont; 554 property Indent; 555 property NameFont; 556 property OnChangeBounds; 557 property OnClick; 558 property OnDblClick; 559 property OnEnter; 560 property OnExit; 561 property OnKeyDown; 562 property OnKeyPress; 563 property OnKeyUp; 564 property OnModified; 565 property OnMouseDown; 566 property OnMouseEnter; 567 property OnMouseLeave; 568 property OnMouseMove; 569 property OnMouseUp; 570 property OnResize; 571 property OnSelectionChange; 572 property PopupMenu; 573 property PreferredSplitterX; 574 property SplitterX; 575 property Tabstop; 576 property ValueFont; 577 property Visible; 578 end; 579 580 581 { TCustomPropertiesGrid } 582 583 TCustomPropertiesGrid = class(TOICustomPropertyGrid) 584 private 585 FAutoFreeHook: boolean; 586 FSaveOnChangeTIObject: boolean; 587 function GetTIObject: TPersistent; 588 procedure SetAutoFreeHook(const AValue: boolean); 589 procedure SetTIObject(const AValue: TPersistent); 590 public 591 constructor Create(TheOwner: TComponent); override; 592 destructor Destroy; override; 593 property TIObject: TPersistent read GetTIObject write SetTIObject; 594 property AutoFreeHook: boolean read FAutoFreeHook write SetAutoFreeHook; 595 property SaveOnChangeTIObject: boolean read FSaveOnChangeTIObject 596 write FSaveOnChangeTIObject 597 default true; 598 end; 599 600 601 //============================================================================ 602 603 TAddAvailablePersistentEvent = procedure(APersistent: TPersistent; 604 var Allowed: boolean) of object; 605 //copy of TGetPersistentImageIndexEvent 606 TOnOINodeGetImageEvent = procedure(APersistent: TPersistent; 607 var AImageIndex: integer) of object; 608 609 TOIFlag = ( 610 oifRebuildPropListsNeeded 611 ); 612 TOIFlags = set of TOIFlag; 613 614 { TObjectInspectorDlg } 615 616 TObjectInspectorDlg = class(TForm) 617 MainPopupMenu: TPopupMenu; 618 AvailPersistentComboBox: TComboBox; 619 ComponentPanel: TPanel; 620 CompFilterLabel: TLabel; 621 CompFilterEdit: TTreeFilterEdit; 622 PnlClient: TPanel; 623 StatusBar: TStatusBar; 624 procedure FormResize(Sender: TObject); 625 procedure MainPopupMenuClose(Sender: TObject); 626 procedure MainPopupMenuPopup(Sender: TObject); 627 procedure AvailComboBoxCloseUp(Sender: TObject); 628 private 629 // These are created at run-time, no need for default published section. 630 PropertyPanel: TPanel; 631 PropFilterPanel: TPanel; 632 PropFilterLabel: TLabel; 633 PropFilterEdit: TListFilterEdit; 634 RestrictedPanel: TPanel; 635 RestrictedInnerPanel: TPanel; 636 WidgetSetsRestrictedLabel: TLabel; 637 WidgetSetsRestrictedBox: TPaintBox; 638 ComponentRestrictedLabel: TLabel; 639 ComponentRestrictedBox: TPaintBox; 640 NoteBook: TPageControl; 641 Splitter1: TSplitter; 642 Splitter2: TSplitter; 643 // MenuItems 644 AddToFavoritesPopupMenuItem: TMenuItem; 645 ViewRestrictedPropertiesPopupMenuItem: TMenuItem; 646 CopyPopupmenuItem: TMenuItem; 647 CutPopupmenuItem: TMenuItem; 648 PastePopupmenuItem: TMenuItem; 649 DeletePopupmenuItem: TMenuItem; 650 ChangeClassPopupmenuItem: TMenuItem; 651 ChangeParentPopupmenuItem: TMenuItem; 652 FindDeclarationPopupmenuItem: TMenuItem; 653 OptionsSeparatorMenuItem: TMenuItem; 654 OptionsSeparatorMenuItem2: TMenuItem; 655 OptionsSeparatorMenuItem3: TMenuItem; 656 RemoveFromFavoritesPopupMenuItem: TMenuItem; 657 ShowComponentTreePopupMenuItem: TMenuItem; 658 ShowPropertyFilterPopupMenuItem: TMenuItem; 659 ShowHintsPopupMenuItem: TMenuItem; 660 ShowInfoBoxPopupMenuItem: TMenuItem; 661 ShowStatusBarPopupMenuItem: TMenuItem; 662 ShowOptionsPopupMenuItem: TMenuItem; 663 UndoPropertyPopupMenuItem: TMenuItem; 664 // Variables 665 FAutoShow: Boolean; 666 FCheckboxForBoolean: Boolean; 667 FComponentEditor: TBaseComponentEditor; 668 FDefaultItemHeight: integer; 669 FEnableHookGetSelection: boolean; 670 FFavorites: TOIFavoriteProperties; 671 FFilter: TTypeKinds; 672 FFlags: TOIFlags; 673 FInfoBoxHeight: integer; 674 FLastActiveRowName: String; 675 FPropertyEditorHook: TPropertyEditorHook; 676 FPropFilterUpdating: Boolean; 677 FRefreshingSelectionCount: integer; 678 FRestricted: TOIRestrictedProperties; 679 FSelection: TPersistentSelectionList; 680 FSettingSelectionCount: integer; 681 FShowComponentTree: Boolean; 682 FShowPropertyFilter: boolean; 683 FShowFavorites: Boolean; 684 FShowInfoBox: Boolean; 685 FShowRestricted: Boolean; 686 FShowStatusBar: Boolean; 687 FStateOfHintsOnMainPopupMenu: Boolean; 688 FUpdateLock: integer; 689 FUpdatingAvailComboBox: Boolean; 690 // Events 691 FOnAddAvailablePersistent: TAddAvailablePersistentEvent; 692 FOnAddToFavorites: TNotifyEvent; 693 FOnAutoShow: TNotifyEvent; 694 FOnFindDeclarationOfProperty: TNotifyEvent; 695 FOnModified: TNotifyEvent; 696 FOnNodeGetImageIndex: TOnOINodeGetImageEvent; 697 FOnOIKeyDown: TKeyEvent; 698 FOnPropertyHint: TOIPropertyHintEvent; 699 FOnRemainingKeyDown: TKeyEvent; 700 FOnRemainingKeyUp: TKeyEvent; 701 FOnRemoveFromFavorites: TNotifyEvent; 702 FOnSelectionChange: TNotifyEvent; 703 FOnSelectPersistentsInOI: TNotifyEvent; 704 FOnShowOptions: TNotifyEvent; 705 FOnUpdateRestricted: TNotifyEvent; 706 FOnViewRestricted: TNotifyEvent; 707 FLastTreeSize: TRect; 708 709 // These event handlers are assigned at run-time, no need for default published section. 710 procedure ComponentTreeDblClick(Sender: TObject); 711 procedure ComponentTreeGetNodeImageIndex(APersistent: TPersistent; var AIndex: integer); 712 procedure ComponentTreeKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); 713 procedure ComponentTreeSelectionChanged(Sender: TObject); 714 procedure GridKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); 715 procedure GridKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); 716 procedure GridDblClick(Sender: TObject); 717 procedure GridModified(Sender: TObject); 718 procedure GridSelectionChange(Sender: TObject); 719 function GridPropertyHint(Sender: TObject; PointedRow: TOIPropertyGridRow; 720 out AHint: string): boolean; 721 procedure PropEditPopupClick(Sender: TObject); 722 procedure AddToFavoritesPopupmenuItemClick(Sender: TObject); 723 procedure RemoveFromFavoritesPopupmenuItemClick(Sender: TObject); 724 procedure ViewRestrictionsPopupmenuItemClick(Sender: TObject); 725 procedure UndoPopupmenuItemClick(Sender: TObject); 726 procedure FindDeclarationPopupmenuItemClick(Sender: TObject); 727 procedure CutPopupmenuItemClick(Sender: TObject); 728 procedure CopyPopupmenuItemClick(Sender: TObject); 729 procedure PastePopupmenuItemClick(Sender: TObject); 730 procedure DeletePopupmenuItemClick(Sender: TObject); 731 procedure ChangeClassPopupmenuItemClick(Sender: TObject); 732 procedure ComponentTreeModified(Sender: TObject); 733 procedure ShowComponentTreePopupMenuItemClick(Sender: TObject); 734 procedure ShowPropertyFilterPopupMenuItemClick(Sender: TObject); 735 procedure ShowHintPopupMenuItemClick(Sender: TObject); 736 procedure ShowInfoBoxPopupMenuItemClick(Sender: TObject); 737 procedure ShowStatusBarPopupMenuItemClick(Sender: TObject); 738 procedure ShowOptionsPopupMenuItemClick(Sender: TObject); 739 procedure RestrictedPageShow(Sender: TObject); 740 procedure WidgetSetRestrictedPaint(Sender: TObject); 741 procedure ComponentRestrictedPaint(Sender: TObject); 742 procedure PropFilterEditAfterFilter(Sender: TObject); 743 procedure NoteBookPageChange(Sender: TObject); 744 procedure ChangeParentItemClick(Sender: TObject); 745 procedure CollectionAddItem(Sender: TObject); 746 procedure ComponentEditorVerbMenuItemClick(Sender: TObject); 747 procedure ZOrderItemClick(Sender: TObject); 748 procedure TopSplitterMoved(Sender: TObject); 749 // Methods 750 procedure DoModified; 751 procedure DoUpdateRestricted; 752 procedure DoViewRestricted; 753 function GetComponentPanelHeight: integer; 754 function GetGridControl(Page: TObjectInspectorPage): TOICustomPropertyGrid; 755 function GetInfoBoxHeight: integer; 756 function GetParentCandidates: TFPList; 757 function GetSelectedPersistent: TPersistent; 758 function GetComponentEditorForSelection: TBaseComponentEditor; 759 procedure CreateBottomSplitter; 760 procedure CreateTopSplitter; 761 procedure DefSelectionVisibleInDesigner; 762 procedure RestrictedPaint( 763 ABox: TPaintBox; const ARestrictions: TWidgetSetRestrictionsArray); 764 function PersistentToString(APersistent: TPersistent): string; 765 procedure AddPersistentToList(APersistent: TPersistent; List: TStrings); 766 procedure HookLookupRootChange; 767 procedure HookRefreshPropertyValues; 768 procedure FillPersistentComboBox; 769 procedure SetAvailComboBoxText; 770 procedure HookGetSelection(const ASelection: TPersistentSelectionList); 771 procedure HookSetSelection(const ASelection: TPersistentSelectionList); 772 procedure DestroyNoteBook; 773 procedure CreateNoteBook; 774 procedure ShowNextPage(Delta: integer); 775 // Setter 776 procedure SetComponentEditor(const AValue: TBaseComponentEditor); 777 procedure SetComponentPanelHeight(const AValue: integer); 778 procedure SetDefaultItemHeight(const AValue: integer); 779 procedure SetEnableHookGetSelection(AValue: boolean); 780 procedure SetFavorites(const AValue: TOIFavoriteProperties); 781 procedure SetFilter(const AValue: TTypeKinds); 782 procedure SetInfoBoxHeight(const AValue: integer); 783 procedure SetOnShowOptions(const AValue: TNotifyEvent); 784 procedure SetPropertyEditorHook(const AValue: TPropertyEditorHook); 785 procedure SetRestricted(const AValue: TOIRestrictedProperties); 786 procedure SetSelection(const ASelection: TPersistentSelectionList); 787 procedure SetShowComponentTree(const AValue: boolean); 788 procedure SetShowPropertyFilter(const AValue: Boolean); 789 procedure SetShowFavorites(const AValue: Boolean); 790 procedure SetShowInfoBox(const AValue: Boolean); 791 procedure SetShowRestricted(const AValue: Boolean); 792 procedure SetShowStatusBar(const AValue: Boolean); 793 protected 794 function CanDeleteSelection: Boolean; 795 procedure KeyDown(var Key: Word; Shift: TShiftState); override; 796 procedure KeyUp(var Key: Word; Shift: TShiftState); override; 797 procedure Resize; override; 798 public 799 // These are created at run-time, no need for default published section. 800 ComponentTree: TComponentTreeView; 801 InfoPanel: TPanel; 802 EventGrid: TOICustomPropertyGrid; 803 FavoriteGrid: TOICustomPropertyGrid; 804 RestrictedGrid: TOICustomPropertyGrid; 805 PropertyGrid: TOICustomPropertyGrid; 806 // 807 constructor Create(AnOwner: TComponent); override; 808 destructor Destroy; override; 809 procedure RefreshSelection; 810 procedure RefreshComponentTreeSelection; 811 procedure SaveChanges; 812 procedure RefreshPropertyValues; 813 procedure RebuildPropertyLists; 814 procedure ChangeCompZOrderInList(APersistent: TPersistent; AZOrder: TZOrderDelete); 815 procedure DeleteCompFromList(APersistent: TPersistent); 816 procedure FillComponentList(AWholeTree: Boolean); 817 procedure UpdateComponentValues; 818 procedure BeginUpdate; 819 procedure EndUpdate; 820 function GetActivePropertyGrid: TOICustomPropertyGrid; 821 function GetActivePropertyRow: TOIPropertyGridRow; 822 function GetCurRowDefaultValue(var DefaultStr: string): Boolean; 823 function HasParentCandidates: Boolean; 824 procedure ChangeParent; 825 procedure ActivateGrid(Grid: TOICustomPropertyGrid); 826 procedure FocusGrid(Grid: TOICustomPropertyGrid = nil); 827 public 828 property ComponentEditor: TBaseComponentEditor read FComponentEditor write SetComponentEditor; 829 property ComponentPanelHeight: integer read GetComponentPanelHeight 830 write SetComponentPanelHeight; 831 property DefaultItemHeight: integer read FDefaultItemHeight 832 write SetDefaultItemHeight; 833 property EnableHookGetSelection: Boolean read FEnableHookGetSelection 834 write SetEnableHookGetSelection; 835 property Favorites: TOIFavoriteProperties read FFavorites write SetFavorites; 836 property Filter: TTypeKinds read FFilter write SetFilter; 837 property GridControl[Page: TObjectInspectorPage]: TOICustomPropertyGrid 838 read GetGridControl; 839 property InfoBoxHeight: integer read GetInfoBoxHeight write SetInfoBoxHeight; 840 property PropertyEditorHook: TPropertyEditorHook read FPropertyEditorHook 841 write SetPropertyEditorHook; 842 property RestrictedProps: TOIRestrictedProperties read FRestricted write SetRestricted; 843 property Selection: TPersistentSelectionList read FSelection write SetSelection; 844 property AutoShow: Boolean read FAutoShow write FAutoShow; 845 property ShowComponentTree: Boolean read FShowComponentTree write SetShowComponentTree; 846 property ShowPropertyFilter: boolean read FShowPropertyFilter write SetShowPropertyFilter; 847 property ShowFavorites: Boolean read FShowFavorites write SetShowFavorites; 848 property ShowInfoBox: Boolean read FShowInfoBox write SetShowInfoBox; 849 property ShowRestricted: Boolean read FShowRestricted write SetShowRestricted; 850 property ShowStatusBar: Boolean read FShowStatusBar write SetShowStatusBar; 851 property LastActiveRowName: string read FLastActiveRowName; 852 // Events 853 property OnAddAvailPersistent: TAddAvailablePersistentEvent 854 read FOnAddAvailablePersistent write FOnAddAvailablePersistent; 855 property OnAddToFavorites: TNotifyEvent read FOnAddToFavorites write FOnAddToFavorites; 856 property OnAutoShow: TNotifyEvent read FOnAutoShow write FOnAutoShow; 857 property OnFindDeclarationOfProperty: TNotifyEvent read FOnFindDeclarationOfProperty 858 write FOnFindDeclarationOfProperty; 859 property OnModified: TNotifyEvent read FOnModified write FOnModified; 860 property OnOIKeyDown: TKeyEvent read FOnOIKeyDown write FOnOIKeyDown; 861 property OnPropertyHint: TOIPropertyHintEvent read FOnPropertyHint write FOnPropertyHint; 862 property OnRemainingKeyDown: TKeyEvent read FOnRemainingKeyDown 863 write FOnRemainingKeyDown; 864 property OnRemainingKeyUp: TKeyEvent read FOnRemainingKeyUp 865 write FOnRemainingKeyUp; 866 property OnRemoveFromFavorites: TNotifyEvent read FOnRemoveFromFavorites 867 write FOnRemoveFromFavorites; 868 property OnSelectionChange: TNotifyEvent read FOnSelectionChange write FOnSelectionChange; 869 property OnSelectPersistentsInOI: TNotifyEvent read FOnSelectPersistentsInOI 870 write FOnSelectPersistentsInOI; 871 property OnShowOptions: TNotifyEvent read FOnShowOptions write SetOnShowOptions; 872 property OnUpdateRestricted: TNotifyEvent read FOnUpdateRestricted 873 write FOnUpdateRestricted; 874 property OnViewRestricted: TNotifyEvent read FOnViewRestricted write FOnViewRestricted; 875 property OnNodeGetImageIndex : TOnOINodeGetImageEvent read FOnNodeGetImageIndex 876 write FOnNodeGetImageIndex; 877 end; 878 879const 880 DefaultObjectInspectorName: string = 'ObjectInspectorDlg'; 881 882// the ObjectInspector descendant of the IDE can be found in FormEditingIntf 883 884function dbgs(s: TOIPropertyGridState): string; overload; 885function dbgs(States: TOIPropertyGridStates): string; overload; 886 887function GetChangeParentCandidates(PropertyEditorHook: TPropertyEditorHook; 888 Selection: TPersistentSelectionList): TFPList; 889 890const 891 DefaultOIPageNames: array[TObjectInspectorPage] of shortstring = ( 892 'PropertyPage', 893 'EventPage', 894 'FavoritePage', 895 'RestrictedPage' 896 ); 897 DefaultOIGridNames: array[TObjectInspectorPage] of shortstring = ( 898 'PropertyGrid', 899 'EventGrid', 900 'FavoriteGrid', 901 'RestrictedGrid' 902 ); 903 904implementation 905 906{$R *.lfm} 907{$R images\ideintf_images.res} 908 909function SortGridRows(Item1, Item2 : pointer) : integer; 910begin 911 Result:=CompareText(TOIPropertyGridRow(Item1).Name, 912 TOIPropertyGridRow(Item2).Name); 913end; 914 915function dbgs(s: TOIPropertyGridState): string; 916begin 917 Result:=GetEnumName(TypeInfo(s),ord(s)); 918end; 919 920function dbgs(States: TOIPropertyGridStates): string; 921var 922 s: TOIPropertyGridState; 923begin 924 Result:=''; 925 for s in States do 926 begin 927 if not (s in States) then continue; 928 if Result<>'' then Result+=','; 929 Result+=dbgs(s); 930 end; 931 Result:='['+Result+']'; 932end; 933 934function GetChangeParentCandidates(PropertyEditorHook: TPropertyEditorHook; 935 Selection: TPersistentSelectionList): TFPList; 936 937 function CanBeParent(Child, Parent: TPersistent): boolean; 938 begin 939 Result:=false; 940 if Child = Parent then exit; 941 if not (Parent is TWinControl) then exit; 942 if not (Child is TControl) then exit; 943 if (Child is TWinControl) and 944 (Child = TWinControl(Parent).Parent) then 945 exit; 946 if not ControlAcceptsStreamableChildComponent(TWinControl(Parent), 947 TComponentClass(Child.ClassType), PropertyEditorHook.LookupRoot) 948 then 949 exit; 950 try 951 TControl(Child).CheckNewParent(TWinControl(Parent)); 952 except 953 exit; 954 end; 955 Result:=true; 956 end; 957 958 function CanBeParentOfSelection(Parent: TPersistent): boolean; 959 var 960 i: Integer; 961 begin 962 for i:=0 to Selection.Count-1 do 963 if not CanBeParent(Selection[i],Parent) then exit(false); 964 Result:=true; 965 end; 966 967var 968 i: Integer; 969 Candidate: TWinControl; 970begin 971 Result := TFPList.Create; 972 if not (PropertyEditorHook.LookupRoot is TWinControl) then 973 exit; // only LCL controls are supported at the moment 974 975 // check if any selected control can be moved 976 i := Selection.Count-1; 977 while i >= 0 do 978 begin 979 if (Selection[i] is TControl) 980 and (TControl(Selection[i]).Owner = PropertyEditorHook.LookupRoot) 981 then 982 // this one can be moved 983 break; 984 dec(i); 985 end; 986 if i < 0 then Exit; 987 988 // find possible new parents 989 for i := 0 to TWinControl(PropertyEditorHook.LookupRoot).ComponentCount-1 do 990 begin 991 Candidate := TWinControl(TWinControl(PropertyEditorHook.LookupRoot).Components[i]); 992 if CanBeParentOfSelection(Candidate) then 993 Result.Add(Candidate); 994 end; 995 if CanBeParentOfSelection(PropertyEditorHook.LookupRoot) then 996 Result.Add(PropertyEditorHook.LookupRoot); 997end; 998 999{ TOICustomPropertyGrid } 1000 1001constructor TOICustomPropertyGrid.CreateWithParams(AnOwner:TComponent; 1002 APropertyEditorHook:TPropertyEditorHook; TypeFilter:TTypeKinds; DefItemHeight: integer); 1003var 1004 Details: TThemedElementDetails; 1005begin 1006 inherited Create(AnOwner); 1007 FLayout := oilHorizontal; 1008 1009 FSelection:=TPersistentSelectionList.Create; 1010 FNotificationComponents:=TFPList.Create; 1011 PropertyEditorHook:=APropertyEditorHook; // Through property setter. 1012 FFilter:=TypeFilter; 1013 FItemIndex:=-1; 1014 FStates:=[]; 1015 FColumn := oipgcValue; 1016 FRows:=TFPList.Create; 1017 FExpandingRow:=nil; 1018 FDragging:=false; 1019 FExpandedProperties:=TStringList.Create; 1020 FCurrentEdit:=nil; 1021 FCurrentButton:=nil; 1022 1023 // visible values 1024 FTopY:=0; 1025 FSplitterX:=100; 1026 FPreferredSplitterX:=FSplitterX; 1027 Details := ThemeServices.GetElementDetails(ttGlyphOpened); 1028 FIndent := ThemeServices.GetDetailSize(Details).cx; 1029 1030 FBackgroundColor:=DefBackgroundColor; 1031 FReferencesColor:=DefReferencesColor; 1032 FSubPropertiesColor:=DefSubPropertiesColor; 1033 FReadOnlyColor:=DefReadOnlyColor; 1034 FHighlightColor:=DefHighlightColor; 1035 FGutterColor:=DefGutterColor; 1036 FGutterEdgeColor:=DefGutterEdgeColor; 1037 FValueDifferBackgrndColor:=DefValueDifferBackgrndColor; 1038 1039 FNameFont:=TFont.Create; 1040 FNameFont.Color:=DefNameColor; 1041 FValueFont:=TFont.Create; 1042 FValueFont.Color:=DefValueColor; 1043 FDefaultValueFont:=TFont.Create; 1044 FDefaultValueFont.Color:=DefDefaultValueColor; 1045 FHighlightFont:=TFont.Create; 1046 FHighlightFont.Color:=DefHighlightFontColor; 1047 1048 FDrawHorzGridLines := True; 1049 FShowGutter := True; 1050 1051 SetInitialBounds(0,0,200,130); 1052 ControlStyle:=ControlStyle+[csAcceptsControls,csOpaque]; 1053 BorderWidth:=0; 1054 BorderStyle := bsSingle; 1055 1056 // create sub components 1057 ValueEdit:=TEdit.Create(Self); 1058 with ValueEdit do 1059 begin 1060 Name:='ValueEdit'; 1061 Visible:=false; 1062 Enabled:=false; 1063 AutoSize:=false; 1064 SetBounds(0,-30,80,25); // hidden 1065 Parent:=Self; 1066 OnMouseDown := @ValueControlMouseDown; 1067 OnMouseMove := @ValueControlMouseMove; 1068 OnDblClick := @ValueEditDblClick; 1069 OnExit:=@ValueEditExit; 1070 OnChange:=@ValueEditChange; 1071 OnKeyDown:=@ValueEditKeyDown; 1072 OnKeyUp:=@ValueEditKeyUp; 1073 OnMouseUp:=@ValueEditMouseUp; 1074 OnMouseWheel:=@OnGridMouseWheel; 1075 end; 1076 1077 ValueComboBox:=TComboBox.Create(Self); 1078 with ValueComboBox do 1079 begin 1080 Name:='ValueComboBox'; 1081 Sorted:=true; 1082 AutoSelect:=true; 1083 AutoComplete:=true; 1084 Visible:=false; 1085 Enabled:=false; 1086 AutoSize:=false; 1087 SetBounds(0,-30,Width,Height); // hidden 1088 DropDownCount:=20; 1089 ItemHeight:=MulDiv(17, Screen.PixelsPerInch, 96); 1090 Parent:=Self; 1091 OnMouseDown := @ValueControlMouseDown; 1092 OnMouseMove := @ValueControlMouseMove; 1093 OnDblClick := @ValueEditDblClick; 1094 OnExit:=@ValueComboBoxExit; 1095 //OnChange:=@ValueComboBoxChange; the on change event is called even, 1096 // if the user is still editing 1097 OnKeyDown:=@ValueComboBoxKeyDown; 1098 OnKeyUp:=@ValueComboBoxKeyUp; 1099 OnMouseUp:=@ValueComboBoxMouseUp; 1100 OnGetItems:=@ValueComboBoxGetItems; 1101 OnCloseUp:=@ValueComboBoxCloseUp; 1102 OnMeasureItem:=@ValueComboBoxMeasureItem; 1103 OnDrawItem:=@ValueComboBoxDrawItem; 1104 OnMouseWheel:=@OnGridMouseWheel; 1105 end; 1106 1107 ValueCheckBox:={$IFnDEF UseOINormalCheckBox} TCheckBoxThemed.Create(Self); {$ELSE} TCheckBox.Create(Self); {$ENDIF} 1108 with ValueCheckBox do 1109 begin 1110 Name:='ValueCheckBox'; 1111 Visible:=false; 1112 Enabled:=false; 1113 {$IFnDEF UseOINormalCheckBox} 1114 AutoSize := false; 1115 {$ELSE} 1116 AutoSize := true; // SetBounds does not work for CheckBox, AutoSize does. 1117 {$ENDIF} 1118 Parent:=Self; 1119 Top := -30; 1120 OnMouseDown := @ValueControlMouseDown; 1121 OnMouseMove := @ValueControlMouseMove; 1122 OnExit:=@ValueCheckBoxExit; 1123 OnKeyDown:=@ValueCheckBoxKeyDown; 1124 OnKeyUp:=@ValueCheckBoxKeyUp; 1125 OnClick:=@ValueCheckBoxClick; 1126 OnMouseWheel:=@OnGridMouseWheel; 1127 end; 1128 1129 ValueButton:=TSpeedButton.Create(Self); 1130 with ValueButton do 1131 begin 1132 Name:='ValueButton'; 1133 Visible:=false; 1134 Enabled:=false; 1135 Transparent:=false; 1136 OnClick:=@ValueButtonClick; 1137 Caption := '...'; 1138 SetBounds(0,-30,Width,Height); // hidden 1139 Parent:=Self; 1140 OnMouseWheel:=@OnGridMouseWheel; 1141 end; 1142 1143 FHintManager := THintWindowManager.Create; 1144 FActiveRowImages := TLCLGlyphs.Create(Self); 1145 FActiveRowImages.Width := 9; 1146 FActiveRowImages.Height := 9; 1147 FActiveRowImages.RegisterResolutions([9, 13, 18], [100, 150, 200]); 1148 FActiveRowImages.OnGetWidthForPPI := @ActiveRowImagesGetWidthForPPI; 1149 1150 FDefaultItemHeight:=DefItemHeight; 1151 1152 BuildPropertyList; 1153end; 1154 1155procedure TOICustomPropertyGrid.ActiveRowImagesGetWidthForPPI( 1156 Sender: TCustomImageList; AImageWidth, APPI: Integer; 1157 var AResultWidth: Integer); 1158begin 1159 if (12<=AResultWidth) and (AResultWidth<=16) then 1160 AResultWidth := 13; 1161end; 1162 1163constructor TOICustomPropertyGrid.Create(TheOwner: TComponent); 1164begin 1165 CreateWithParams(TheOwner,nil,AllTypeKinds,0); 1166end; 1167 1168destructor TOICustomPropertyGrid.Destroy; 1169var 1170 a: integer; 1171begin 1172 SetIdleEvent(false); 1173 FItemIndex := -1; 1174 for a := 0 to FRows.Count - 1 do 1175 Rows[a].Free; 1176 FreeAndNil(FRows); 1177 FreeAndNil(FSelection); 1178 FreeAndNil(FNotificationComponents); 1179 FreeAndNil(FValueFont); 1180 FreeAndNil(FDefaultValueFont); 1181 FreeAndNil(FNameFont); 1182 FreeAndNil(FHighlightFont); 1183 FreeAndNil(FExpandedProperties); 1184 FreeAndNil(FLongHintTimer); 1185 FreeAndNil(FHintManager); 1186 FreeAndNil(FNewComboBoxItems); 1187 inherited Destroy; 1188end; 1189 1190procedure TOICustomPropertyGrid.UpdateScrollBar; 1191var 1192 ScrollInfo: TScrollInfo; 1193 ATopMax: Integer; 1194begin 1195 if HandleAllocated then begin 1196 ATopMax := TopMax; 1197 ScrollInfo.cbSize := SizeOf(ScrollInfo); 1198 ScrollInfo.fMask := SIF_ALL or SIF_DISABLENOSCROLL; 1199 ScrollInfo.nMin := 0; 1200 ScrollInfo.nTrackPos := 0; 1201 ScrollInfo.nMax := ATopMax+ClientHeight-1; 1202 if ClientHeight < 2 then 1203 ScrollInfo.nPage := 1 1204 else 1205 ScrollInfo.nPage := ClientHeight-1; 1206 if TopY > ATopMax then 1207 TopY := ATopMax; 1208 ScrollInfo.nPos := TopY; 1209 SetScrollInfo(Handle, SB_VERT, ScrollInfo, True); 1210 end; 1211end; 1212 1213function TOICustomPropertyGrid.FillComboboxItems: boolean; 1214var 1215 ExcludeUpdateFlag: boolean; 1216 CurRow: TOIPropertyGridRow; 1217begin 1218 Result:=false; 1219 ExcludeUpdateFlag:=not (pgsUpdatingEditControl in FStates); 1220 Include(FStates,pgsUpdatingEditControl); 1221 ValueComboBox.Items.BeginUpdate; 1222 try 1223 CurRow:=Rows[FItemIndex]; 1224 if FNewComboBoxItems<>nil then FNewComboBoxItems.Clear; 1225 CurRow.Editor.GetValues(@AddStringToComboBox); 1226 if FNewComboBoxItems<>nil then begin 1227 FNewComboBoxItems.Sorted:=paSortList in CurRow.Editor.GetAttributes; 1228 if ValueComboBox.Items.Equals(FNewComboBoxItems) then exit; 1229 ValueComboBox.Items.Assign(FNewComboBoxItems); 1230 //debugln('TOICustomPropertyGrid.FillComboboxItems "',FNewComboBoxItems.Text,'" Cur="',ValueComboBox.Items.Text,'" ValueComboBox.Items.Count=',dbgs(ValueComboBox.Items.Count)); 1231 end else if ValueComboBox.Items.Count=0 then begin 1232 exit; 1233 end else begin 1234 ValueComboBox.Items.Text:=''; 1235 ValueComboBox.Items.Clear; 1236 //debugln('TOICustomPropertyGrid.FillComboboxItems FNewComboBoxItems=nil Cur="',ValueComboBox.Items.Text,'" ValueComboBox.Items.Count=',dbgs(ValueComboBox.Items.Count)); 1237 end; 1238 Result:=true; 1239 //debugln(['TOICustomPropertyGrid.FillComboboxItems CHANGED']); 1240 finally 1241 FreeAndNil(FNewComboBoxItems); 1242 ValueComboBox.Items.EndUpdate; 1243 if ExcludeUpdateFlag then 1244 Exclude(FStates,pgsUpdatingEditControl); 1245 end; 1246end; 1247 1248procedure TOICustomPropertyGrid.CreateParams(var Params: TCreateParams); 1249const 1250 ClassStylesOff = CS_VREDRAW or CS_HREDRAW; 1251begin 1252 inherited CreateParams(Params); 1253 with Params do begin 1254 {$IFOPT R+}{$DEFINE RangeChecking}{$ENDIF} 1255 {$R-} 1256 WindowClass.Style := WindowClass.Style and not ClassStylesOff; 1257 Style := Style or WS_VSCROLL or WS_CLIPCHILDREN; 1258 {$IFDEF RangeChecking}{$R+}{$UNDEF RangeChecking}{$ENDIF} 1259 ExStyle := ExStyle or WS_EX_CLIENTEDGE; 1260 end; 1261end; 1262 1263procedure TOICustomPropertyGrid.CreateWnd; 1264begin 1265 inherited CreateWnd; 1266 // handle just created, set scrollbar 1267 ShowScrollBar(Handle, SB_VERT, True); 1268 UpdateScrollBar; 1269end; 1270 1271procedure TOICustomPropertyGrid.Notification(AComponent: TComponent; 1272 Operation: TOperation); 1273var 1274 i: LongInt; 1275begin 1276 if (Operation=opRemove) and (FNotificationComponents<>nil) then begin 1277 FNotificationComponents.Remove(AComponent); 1278 i:=FSelection.IndexOf(AComponent); 1279 if i>=0 then begin 1280 FSelection.Delete(i); 1281 Include(FStates,pgsBuildPropertyListNeeded); 1282 end; 1283 end; 1284 inherited Notification(AComponent, Operation); 1285end; 1286 1287procedure TOICustomPropertyGrid.WMVScroll(var Msg: TLMScroll); 1288begin 1289 case Msg.ScrollCode of 1290 // Scrolls to start / end of the text 1291 SB_TOP: TopY := 0; 1292 SB_BOTTOM: TopY := TopMax; 1293 // Scrolls one line up / down 1294 SB_LINEDOWN: TopY := TopY + RealDefaultItemHeight div 2; 1295 SB_LINEUP: TopY := TopY - RealDefaultItemHeight div 2; 1296 // Scrolls one page of lines up / down 1297 SB_PAGEDOWN: TopY := TopY + ClientHeight - RealDefaultItemHeight; 1298 SB_PAGEUP: TopY := TopY - ClientHeight + RealDefaultItemHeight; 1299 // Scrolls to the current scroll bar position 1300 SB_THUMBPOSITION, 1301 SB_THUMBTRACK: TopY := Msg.Pos; 1302 // Ends scrolling 1303 SB_ENDSCROLL: SetCaptureControl(nil); // release scrollbar capture 1304 end; 1305end; 1306 1307function TOICustomPropertyGrid.DoMouseWheel(Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint): Boolean; 1308var 1309 H: Boolean; 1310begin 1311 H := False; 1312 OnGridMouseWheel(Self, Shift, WheelDelta, MousePos, H); 1313 Result:=true; 1314end; 1315 1316procedure TOICustomPropertyGrid.OnGridMouseWheel(Sender: TObject; Shift: TShiftState; 1317 WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean); 1318begin 1319 if Mouse.WheelScrollLines=-1 then 1320 // -1 : scroll by page 1321 TopY := TopY - (WheelDelta * (ClientHeight - RealDefaultItemHeight)) div 120 1322 else 1323 // scrolling one line -> scroll half an item, see SB_LINEDOWN and SB_LINEUP 1324 // handler in WMVScroll 1325 TopY := TopY - (WheelDelta * Mouse.WheelScrollLines*RealDefaultItemHeight) div 240; 1326 Handled := True; 1327end; 1328 1329function TOICustomPropertyGrid.IsCurrentEditorAvailable: Boolean; 1330begin 1331 Result := (FCurrentEdit <> nil) and InRange(FItemIndex, 0, FRows.Count - 1); 1332end; 1333 1334procedure TOICustomPropertyGrid.FocusCurrentEditor; 1335begin 1336 if (IsCurrentEditorAvailable) and (FCurrentEdit.CanFocus) then 1337 begin 1338 FCurrentEdit.SetFocus; 1339 if (FCurrentEdit is TEdit) then 1340 TEdit(FCurrentEdit).SelStart := Length((FCurrentEdit as TEdit).Text); 1341 end; 1342end; 1343 1344function TOICustomPropertyGrid.ConsistencyCheck: integer; 1345var 1346 i: integer; 1347begin 1348 for i:=0 to FRows.Count-1 do 1349 begin 1350 if Rows[i]=nil then 1351 Exit(-1); 1352 if Rows[i].Index<>i then 1353 Exit(-2); 1354 Result:=Rows[i].ConsistencyCheck; 1355 if Result<>0 then 1356 Exit(Result-100); 1357 end; 1358 Result:=0; 1359end; 1360 1361procedure TOICustomPropertyGrid.SetSelection(const ASelection: TPersistentSelectionList); 1362var 1363 CurRow:TOIPropertyGridRow; 1364 OldSelectedRowPath:string; 1365begin 1366 if ASelection=nil then exit; 1367 if (not ASelection.ForceUpdate) and FSelection.IsEqual(ASelection) then exit; 1368 1369 OldSelectedRowPath:=PropertyPath(ItemIndex); 1370 if FCurrentEdit = ValueEdit then 1371 ValueEditExit(Self); 1372 ItemIndex:=-1; 1373 ClearRows; 1374 FSelection.Assign(ASelection); 1375 UpdateSelectionNotifications; 1376 BuildPropertyList; 1377 CurRow:=GetRowByPath(OldSelectedRowPath); 1378 if CurRow<>nil then 1379 ItemIndex:=CurRow.Index; 1380 Column := oipgcValue; 1381end; 1382 1383procedure TOICustomPropertyGrid.SetPropertyEditorHook( 1384 NewPropertyEditorHook:TPropertyEditorHook); 1385begin 1386 if FPropertyEditorHook=NewPropertyEditorHook then exit; 1387 FPropertyEditorHook:=NewPropertyEditorHook; 1388 IncreaseChangeStep; 1389 SetSelection(FSelection); 1390end; 1391 1392procedure TOICustomPropertyGrid.UpdateSelectionNotifications; 1393var 1394 i: Integer; 1395 AComponent: TComponent; 1396begin 1397 for i:=0 to FSelection.Count-1 do begin 1398 if FSelection[i] is TComponent then begin 1399 AComponent:=TComponent(FSelection[i]); 1400 if FNotificationComponents.IndexOf(AComponent)<0 then begin 1401 FNotificationComponents.Add(AComponent); 1402 AComponent.FreeNotification(Self); 1403 end; 1404 end; 1405 end; 1406 for i:=FNotificationComponents.Count-1 downto 0 do begin 1407 AComponent:=TComponent(FNotificationComponents[i]); 1408 if FSelection.IndexOf(AComponent)<0 then begin 1409 FNotificationComponents.Delete(i); 1410 AComponent.RemoveFreeNotification(Self); 1411 end; 1412 end; 1413 //DebugLn(['TOICustomPropertyGrid.UpdateSelectionNotifications FNotificationComponents=',FNotificationComponents.Count,' FSelection=',FSelection.Count]); 1414end; 1415 1416procedure TOICustomPropertyGrid.HookGetCheckboxForBoolean(var Value: Boolean); 1417begin 1418 Value := FCheckboxForBoolean; 1419end; 1420 1421function TOICustomPropertyGrid.PropertyPath(Index:integer):string; 1422begin 1423 if (Index>=0) and (Index<FRows.Count) then 1424 Result:=PropertyPath(Rows[Index]) 1425 else 1426 Result:=''; 1427end; 1428 1429function TOICustomPropertyGrid.PropertyPath(Row: TOIPropertyGridRow): string; 1430begin 1431 if Row=nil then 1432 Exit(''); 1433 Result:=Row.Name; 1434 Row:=Row.Parent; 1435 while Row<>nil do begin 1436 Result:=Row.Name+'.'+Result; 1437 Row:=Row.Parent; 1438 end; 1439end; 1440 1441function TOICustomPropertyGrid.PropertyEditorByName(const PropName: string): TPropertyEditor; 1442var 1443 AOIPropertyGridRow: TOIPropertyGridRow; 1444 i: Integer; 1445begin 1446 Result := nil; 1447 for i := 0 to FRows.Count - 1 do 1448 begin 1449 AOIPropertyGridRow := TOIPropertyGridRow(FRows[i]); 1450 if Assigned(AOIPropertyGridRow.Editor) and (AOIPropertyGridRow.Editor.GetName = PropName) then 1451 Exit(AOIPropertyGridRow.Editor); 1452 end; 1453end; 1454 1455function TOICustomPropertyGrid.RealDefaultItemHeight: integer; 1456begin 1457 Result := FDefaultItemHeight; 1458 if (Result<=0) then 1459 Result := Canvas.TextHeight('Hg')*5 div 4 + 4; 1460end; 1461 1462function TOICustomPropertyGrid.GetRowByPath(const PropPath: string): TOIPropertyGridRow; 1463// searches PropPath. Expands automatically parent rows 1464var 1465 CurName:string; 1466 s,e:integer; 1467 CurParentRow:TOIPropertyGridRow; 1468begin 1469 Result:=nil; 1470 if (PropPath='') or (FRows.Count=0) then exit; 1471 CurParentRow:=nil; 1472 s:=1; 1473 while (s<=length(PropPath)) do begin 1474 e:=s; 1475 while (e<=length(PropPath)) and (PropPath[e]<>'.') do inc(e); 1476 CurName:=copy(PropPath,s,e-s); 1477 s:=e+1; 1478 // search name in children 1479 if CurParentRow=nil then 1480 Result:=Rows[0] 1481 else 1482 Result:=CurParentRow.FirstChild; 1483 while (Result<>nil) and (CompareText(Result.Name, CurName)<>0) do 1484 Result:=Result.NextBrother; 1485 if Result=nil then begin 1486 exit; 1487 end else begin 1488 // expand row 1489 CurParentRow:=Result; 1490 if s<=length(PropPath) then 1491 ExpandRow(CurParentRow.Index); 1492 end; 1493 end; 1494 if s<=length(PropPath) then Result:=nil; 1495end; 1496 1497procedure TOICustomPropertyGrid.SetRowValue(CheckFocus, ForceValue: boolean); 1498 1499 function GetPropValue(Editor: TPropertyEditor; Index: integer): string; 1500 var 1501 PropKind: TTypeKind; 1502 PropInfo: PPropInfo; 1503 BoolVal: Boolean; 1504 begin 1505 Result:=''; 1506 PropInfo := Editor.GetPropInfo; 1507 PropKind := PropInfo^.PropType^.Kind; 1508 case PropKind of 1509 tkInteger, tkInt64: 1510 Result := IntToStr(Editor.GetInt64ValueAt(Index)); 1511 tkChar, tkWChar, tkUChar: 1512 Result := Char(Editor.GetOrdValueAt(Index)); 1513 tkEnumeration: 1514 Result := GetEnumName(PropInfo^.PropType, Editor.GetOrdValueAt(Index)); 1515 tkFloat: 1516 Result := FloatToStr(Editor.GetFloatValueAt(Index)); 1517 tkBool: begin 1518 BoolVal := Boolean(Editor.GetOrdValueAt(Index)); 1519 if FCheckboxForBoolean then 1520 Result := BoolToStr(BoolVal, '(True)', '(False)') 1521 else 1522 Result := BoolToStr(BoolVal, 'True', 'False'); 1523 end; 1524 tkString, tkLString, tkAString, tkUString, tkWString: 1525 Result := Editor.GetStrValueAt(Index); 1526 tkSet: 1527 Result := Editor.GetSetValueAt(Index,true); 1528 tkVariant: 1529 if Editor.GetVarValueAt(Index) <> Null then 1530 Result := Editor.GetVarValueAt(Index) 1531 else 1532 Result := '(Null)'; 1533 end; 1534 end; 1535 1536var 1537 CurRow: TOIPropertyGridRow; 1538 NewValue: string; 1539 OldExpanded: boolean; 1540 OldChangeStep: integer; 1541 RootDesigner: TIDesigner; 1542 CompEditDsg: TComponentEditorDesigner; 1543 APersistent: TPersistent; 1544 i: integer; 1545 UndoVal: string; 1546 OldUndoValues: array of string; 1547 isExcept: boolean; 1548 prpInfo: PPropInfo; 1549 Editor: TPropertyEditor; 1550begin 1551 //if FItemIndex > -1 then 1552 // debugln(['TOICustomPropertyGrid.SetRowValue A, FItemIndex=',dbgs(FItemIndex), 1553 // ', CanEditRowValue=', CanEditRowValue(CheckFocus), ', IsReadOnly=', Rows[FItemIndex].IsReadOnly]); 1554 1555 if not CanEditRowValue(CheckFocus) or Rows[FItemIndex].IsReadOnly then exit; 1556 1557 NewValue:=GetCurrentEditValue; 1558 CurRow:=Rows[FItemIndex]; 1559 if length(NewValue)>CurRow.Editor.GetEditLimit then 1560 NewValue:=LeftStr(NewValue,CurRow.Editor.GetEditLimit); 1561 1562 //DebugLn(['TOICustomPropertyGrid.SetRowValue Old="',CurRow.Editor.GetVisualValue,'" New="',NewValue,'"']); 1563 if (CurRow.Editor.GetVisualValue=NewValue) and not ForceValue then exit; 1564 1565 RootDesigner := FindRootDesigner(FCurrentEditorLookupRoot); 1566 if (RootDesigner is TComponentEditorDesigner) then begin 1567 CompEditDsg := TComponentEditorDesigner(RootDesigner); 1568 if CompEditDsg.IsUndoLocked then Exit; 1569 end else 1570 CompEditDsg := nil; 1571 1572 // store old values for undo 1573 isExcept := false; 1574 Editor:=CurRow.Editor; 1575 prpInfo := nil; 1576 if (CompEditDsg<>nil) and (paRevertable in Editor.GetAttributes) then begin 1577 SetLength(OldUndoValues, Editor.PropCount); 1578 prpInfo := Editor.GetPropInfo; 1579 if prpInfo<>nil then 1580 for i := 0 to Editor.PropCount - 1 do 1581 OldUndoValues[i] := GetPropValue(Editor,i); 1582 end; 1583 1584 OldChangeStep:=fChangeStep; 1585 Include(FStates,pgsApplyingValue); 1586 try 1587 {$IFNDEF DoNotCatchOIExceptions} 1588 try 1589 {$ENDIF} 1590 //debugln(['TOICustomPropertyGrid.SetRowValue B ClassName=',CurRow.Editor.ClassName,' Visual="',CurRow.Editor.GetVisualValue,'" NewValue="',NewValue,'" AllEqual=',CurRow.Editor.AllEqual]); 1591 CurRow.Editor.SetValue(NewValue); 1592 //debugln(['TOICustomPropertyGrid.SetRowValue C ClassName=',CurRow.Editor.ClassName,' Visual="',CurRow.Editor.GetVisualValue,'" NewValue="',NewValue,'" AllEqual=',CurRow.Editor.AllEqual]); 1593 {$IFNDEF DoNotCatchOIExceptions} 1594 except 1595 on E: Exception do begin 1596 MessageDlg(oisError, E.Message, mtError, [mbOk], 0); 1597 isExcept := true; 1598 end; 1599 end; 1600 {$ENDIF} 1601 if (OldChangeStep<>FChangeStep) then begin 1602 // the selection has changed => CurRow does not exist any more 1603 exit; 1604 end; 1605 1606 // add Undo action 1607 if (not isExcept) and (CompEditDsg<>nil) and (paRevertable in Editor.GetAttributes) then 1608 begin 1609 for i := 0 to Editor.PropCount - 1 do 1610 begin 1611 APersistent := Editor.GetComponent(i); 1612 if APersistent=nil then continue; 1613 UndoVal := GetPropValue(Editor,i); 1614 CompEditDsg.AddUndoAction(APersistent, uopChange, i = 0, 1615 Editor.GetName, OldUndoValues[i], UndoVal); 1616 end; 1617 end; 1618 1619 // set value in edit control 1620 SetCurrentEditValue(Editor.GetVisualValue); 1621 1622 // update volatile sub properties 1623 if (paVolatileSubProperties in Editor.GetAttributes) 1624 and ((CurRow.Expanded) or (CurRow.ChildCount>0)) then begin 1625 OldExpanded:=CurRow.Expanded; 1626 ShrinkRow(FItemIndex); 1627 if OldExpanded then 1628 ExpandRow(FItemIndex); 1629 end; 1630 //debugln(['TOICustomPropertyGrid.SetRowValue D ClassName=',CurRow.Editor.ClassName,' Visual="',CurRow.Editor.GetVisualValue,'" NewValue="',NewValue,'" AllEqual=',CurRow.Editor.AllEqual]); 1631 finally 1632 Exclude(FStates,pgsApplyingValue); 1633 end; 1634 if Assigned(FPropertyEditorHook) then 1635 FPropertyEditorHook.RefreshPropertyValues; 1636 if Assigned(FOnModified) then 1637 FOnModified(Self); 1638end; 1639 1640procedure TOICustomPropertyGrid.DoCallEdit(Edit: TOIQuickEdit); 1641var 1642 CurRow:TOIPropertyGridRow; 1643 OldChangeStep: integer; 1644begin 1645 //debugln(['TOICustomPropertyGrid.DoCallEdit ',dbgs(GetFocus),' ',DbgSName(FindControl(GetFocus))]); 1646 if not CanEditRowValue(false) then exit; 1647 1648 OldChangeStep:=fChangeStep; 1649 CurRow:=Rows[FItemIndex]; 1650 if paDialog in CurRow.Editor.GetAttributes then begin 1651 {$IFnDEF DoNotCatchOIExceptions} 1652 try 1653 {$ENDIF} 1654 //if FSelection.Count > 0 then 1655 // DebugLn(['# TOICustomPropertyGrid.DoCallEdit for ', CurRow.Editor.ClassName, 1656 // ', Edit=', Edit=oiqeEdit, ', SelectionCount=', FSelection.Count, 1657 // ', SelectionName=', FSelection[0].GetNamePath]); 1658 Include(FStates,pgsCallingEdit); 1659 try 1660 if Edit=oiqeShowValue then 1661 CurRow.Editor.ShowValue 1662 else if (FSelection.Count > 0) and (FSelection[0] is TComponent) then 1663 CurRow.Editor.Edit(TComponent(FSelection[0])) 1664 else 1665 CurRow.Editor.Edit; 1666 finally 1667 Exclude(FStates,pgsCallingEdit); 1668 end; 1669 {$IFnDEF DoNotCatchOIExceptions} 1670 except 1671 on E: Exception do 1672 MessageDlg(oisError, E.Message, mtError, [mbOk], 0); 1673 end; 1674 {$ENDIF} 1675 // CurRow is now invalid, do not access CurRow 1676 1677 if (OldChangeStep<>FChangeStep) then begin 1678 // the selection has changed => CurRow does not exist any more 1679 RefreshPropertyValues; 1680 exit; 1681 end; 1682 RefreshValueEdit; // update value 1683 Invalidate; //invalidate changed subproperties 1684 end; 1685end; 1686 1687procedure TOICustomPropertyGrid.RefreshValueEdit; 1688var 1689 CurRow: TOIPropertyGridRow; 1690 NewValue: string; 1691begin 1692 if not GridIsUpdating and IsCurrentEditorAvailable then begin 1693 CurRow:=Rows[FItemIndex]; 1694 NewValue:=CurRow.Editor.GetVisualValue; 1695 {$IFDEF LCLCarbon} 1696 NewValue:=StringReplace(NewValue,LineEnding,LineFeedSymbolUTF8,[rfReplaceAll]); 1697 {$ENDIF} 1698 SetCurrentEditValue(NewValue); 1699 end; 1700end; 1701 1702procedure TOICustomPropertyGrid.ValueEditKeyDown(Sender: TObject; var Key: Word; 1703 Shift: TShiftState); 1704begin 1705 ScrollToActiveItem; 1706 HandleStandardKeys(Key,Shift); 1707end; 1708 1709procedure TOICustomPropertyGrid.ValueEditKeyUp(Sender: TObject; var Key: Word; 1710 Shift: TShiftState); 1711begin 1712 HandleKeyUp(Key,Shift); 1713end; 1714 1715procedure TOICustomPropertyGrid.ValueEditExit(Sender: TObject); 1716begin 1717 SetRowValue(false, false); 1718end; 1719 1720procedure TOICustomPropertyGrid.ValueEditChange(Sender: TObject); 1721var CurRow: TOIPropertyGridRow; 1722begin 1723 if (pgsUpdatingEditControl in FStates) or not IsCurrentEditorAvailable then exit; 1724 CurRow:=Rows[FItemIndex]; 1725 if paAutoUpdate in CurRow.Editor.GetAttributes then 1726 SetRowValue(true, true); 1727end; 1728 1729procedure TOICustomPropertyGrid.ValueEditMouseUp(Sender: TObject; 1730 Button: TMouseButton; Shift: TShiftState; X, Y: Integer); 1731begin 1732 if (Button=mbLeft) and (Shift=[ssCtrl,ssLeft]) then 1733 DoCallEdit(oiqeShowValue); 1734end; 1735 1736procedure TOICustomPropertyGrid.ValueCheckBoxKeyDown(Sender: TObject; 1737 var Key: Word; Shift: TShiftState); 1738begin 1739 ScrollToActiveItem; 1740 HandleStandardKeys(Key,Shift); 1741end; 1742 1743procedure TOICustomPropertyGrid.ValueCheckBoxKeyUp(Sender: TObject; 1744 var Key: Word; Shift: TShiftState); 1745begin 1746 HandleKeyUp(Key,Shift); 1747end; 1748 1749procedure TOICustomPropertyGrid.ValueCheckBoxExit(Sender: TObject); 1750begin 1751 SetRowValue(false, false); 1752end; 1753 1754procedure TOICustomPropertyGrid.ValueCheckBoxClick(Sender: TObject); 1755begin 1756 if (pgsUpdatingEditControl in FStates) or not IsCurrentEditorAvailable then exit; 1757 ValueCheckBox.Caption:=BoolToStr(ValueCheckBox.Checked, '(True)', '(False)'); 1758 SetRowValue(true, true); 1759end; 1760 1761procedure TOICustomPropertyGrid.ValueComboBoxExit(Sender: TObject); 1762begin 1763 if pgsUpdatingEditControl in FStates then exit; 1764 SetRowValue(false, false); 1765end; 1766 1767procedure TOICustomPropertyGrid.ValueComboBoxKeyDown(Sender: TObject; 1768 var Key: Word; Shift: TShiftState); 1769begin 1770 ScrollToActiveItem; 1771 HandleStandardKeys(Key,Shift); 1772end; 1773 1774procedure TOICustomPropertyGrid.ValueComboBoxKeyUp(Sender: TObject; 1775 var Key: Word; Shift: TShiftState); 1776begin 1777 HandleKeyUp(Key,Shift); 1778end; 1779 1780procedure TOICustomPropertyGrid.ValueComboBoxMouseUp(Sender: TObject; 1781 Button: TMouseButton; Shift: TShiftState; X, Y: Integer); 1782begin 1783 if (Button=mbLeft) then begin 1784 if (Shift=[ssCtrl,ssLeft]) then 1785 DoCallEdit(oiqeShowValue) 1786 else 1787 if (FFirstClickTime<>0) and (GetTickCount <= FFirstClickTime + GetDoubleClickTime) 1788 and (not ValueComboBox.DroppedDown) then 1789 begin 1790 FFirstClickTime:=0; 1791 ToggleRow; 1792 end; 1793 end; 1794end; 1795 1796procedure TOICustomPropertyGrid.ValueButtonClick(Sender: TObject); 1797begin 1798 ScrollToActiveItem; 1799 DoCallEdit; 1800end; 1801 1802procedure TOICustomPropertyGrid.ValueComboBoxMeasureItem(Control: TWinControl; 1803 Index: Integer; var AHeight: Integer); 1804var 1805 CurRow: TOIPropertyGridRow; 1806begin 1807 if (FItemIndex >= 0) and (FItemIndex < FRows.Count) then 1808 begin 1809 CurRow := Rows[FItemIndex]; 1810 CurRow.Editor.ListMeasureHeight('Fj', Index, ValueComboBox.Canvas, AHeight); 1811 AHeight := Max(AHeight, ValueComboBox.ItemHeight); 1812 end; 1813end; 1814 1815procedure TOICustomPropertyGrid.SetCheckboxState(NewValue: string); 1816begin 1817 ValueCheckBox.Caption:=NewValue; 1818 if (NewValue='') or (NewValue=oisMixed) then 1819 ValueCheckBox.State:=cbGrayed 1820 else if NewValue='(True)' then 1821 ValueCheckBox.State:=cbChecked 1822 // Note: this condition can be removed when the right propedit is used always. 1823 else if NewValue='(False)' then 1824 ValueCheckBox.State:=cbUnchecked; 1825end; 1826 1827procedure TOICustomPropertyGrid.SetItemIndex(NewIndex:integer); 1828var 1829 NewRow: TOIPropertyGridRow; 1830 NewValue: string; 1831 EditorAttributes: TPropertyAttributes; 1832begin 1833 {if pgsCallingEdit in FStates then begin 1834 DumpStack; 1835 debugln(['TOICustomPropertyGrid.SetItemIndex ',DbgSName(Self),' ',dbgsname(FCurrentEdit),' ',dbgs(FStates),' GridIsUpdating=',GridIsUpdating,' FItemIndex=',FItemIndex,' NewIndex=',NewIndex]); 1836 end;} 1837 if GridIsUpdating or (FItemIndex = NewIndex) then 1838 exit; 1839 // save old edit value 1840 SetRowValue(true, false); 1841 1842 Include(FStates, pgsChangingItemIndex); 1843 if (FItemIndex >= 0) and (FItemIndex < FRows.Count) then 1844 Rows[FItemIndex].Editor.Deactivate; 1845 if CanFocus then 1846 SetCaptureControl(nil); 1847 1848 FItemIndex := NewIndex; 1849 if FCurrentEdit <> nil then 1850 begin 1851 FCurrentEdit.Visible:=false; 1852 FCurrentEdit.Enabled:=false; 1853 FCurrentEdit:=nil; 1854 end; 1855 if FCurrentButton<>nil then 1856 begin 1857 FCurrentButton.Visible:=false; 1858 FCurrentButton.Enabled:=false; 1859 FCurrentButton:=nil; 1860 end; 1861 FCurrentEditorLookupRoot:=nil; 1862 if (NewIndex >= 0) and (NewIndex < FRows.Count) then 1863 begin 1864 NewRow:=Rows[NewIndex]; 1865 ScrollToItem(NewIndex); 1866 if CanFocus then 1867 NewRow.Editor.Activate; 1868 EditorAttributes:=NewRow.Editor.GetAttributes; 1869 if paDialog in EditorAttributes then begin 1870 FCurrentButton:=ValueButton; 1871 FCurrentButton.Visible:=true; 1872 //DebugLn(['TOICustomPropertyGrid.SetItemIndex FCurrentButton.BoundsRect=',dbgs(FCurrentButton.BoundsRect)]); 1873 end; 1874 NewValue:=NewRow.Editor.GetVisualValue; 1875 if ((NewRow.Editor is TBoolPropertyEditor) or (NewRow.Editor is TSetElementPropertyEditor)) 1876 and FCheckboxForBoolean then 1877 begin 1878 FCurrentEdit:=ValueCheckBox; 1879 ValueCheckBox.Enabled:=not NewRow.IsReadOnly; 1880 SetCheckboxState(NewValue); 1881 end 1882 else if paValueList in EditorAttributes then 1883 begin 1884 FCurrentEdit:=ValueComboBox; 1885 if (paCustomDrawn in EditorAttributes) and (paPickList in EditorAttributes) then 1886 ValueComboBox.Style:=csOwnerDrawVariable 1887 else if paCustomDrawn in EditorAttributes then 1888 ValueComboBox.Style:=csOwnerDrawEditableVariable 1889 else if paPickList in EditorAttributes then 1890 ValueComboBox.Style:=csOwnerDrawFixed 1891 else 1892 ValueComboBox.Style:=csOwnerDrawEditableFixed; 1893 ValueComboBox.MaxLength:=NewRow.Editor.GetEditLimit; 1894 ValueComboBox.Sorted:=paSortList in NewRow.Editor.GetAttributes; 1895 ValueComboBox.Enabled:=not NewRow.IsReadOnly; 1896 // Do not fill the items here, because it can be very slow. 1897 // Just fill in some values and update the values before the combobox popups 1898 ValueComboBox.Items.Text:=NewValue; 1899 Exclude(FStates,pgsGetComboItemsCalled); 1900 SetIdleEvent(true); 1901 ValueComboBox.Text:=NewValue; 1902 end 1903 else begin 1904 FCurrentEdit:=ValueEdit; 1905 ValueEdit.ReadOnly:=NewRow.IsReadOnly; 1906 ValueEdit.Enabled:=true; 1907 ValueEdit.MaxLength:=NewRow.Editor.GetEditLimit; 1908 ValueEdit.Text:=NewValue; 1909 end; 1910 AlignEditComponents; 1911 if FCurrentEdit<>nil then 1912 begin 1913 if FPropertyEditorHook<>nil then 1914 FCurrentEditorLookupRoot:=FPropertyEditorHook.LookupRoot; 1915 if (FCurrentEdit=ValueComboBox) or (FCurrentEdit=ValueEdit) then 1916 begin 1917 if NewRow.Editor.AllEqual then 1918 FCurrentEdit.Color:=clWindow 1919 else 1920 FCurrentEdit.Color:=FValueDifferBackgrndColor; 1921 end; 1922 if NewRow.Editor.ValueIsStreamed then 1923 FCurrentEdit.Font:=FValueFont 1924 else 1925 FCurrentEdit.Font:=FDefaultValueFont; 1926 FCurrentEdit.Visible:=true; 1927 if (FDragging=false) and FCurrentEdit.Showing and FCurrentEdit.Enabled 1928 and (not NewRow.IsReadOnly) and CanFocus and (Column=oipgcValue) 1929 and not (pgsFocusPropertyEditorDisabled in FStates) 1930 then 1931 SetActiveControl(FCurrentEdit); 1932 end; 1933 if FCurrentButton<>nil then 1934 FCurrentButton.Enabled:=not NewRow.IsDisabled; 1935 end; 1936 //DebugLn(['TOICustomPropertyGrid.SetItemIndex Vis=',ValueComboBox.Visible,' Ena=',ValueComboBox.Enabled, 1937 // ' Items.Count=',ValueComboBox.Items.Count ,' Text=',ValueComboBox.Text]); 1938 Exclude(FStates, pgsChangingItemIndex); 1939 DoSelectionChange; 1940 Invalidate; 1941end; 1942 1943function TOICustomPropertyGrid.GetNameRowHeight: Integer; 1944begin 1945 Result := Abs(FNameFont.Height); 1946 if Result = 0 then 1947 Result := 16; 1948 Inc(Result, 2); // margin 1949end; 1950 1951function TOICustomPropertyGrid.GetRowCount:integer; 1952begin 1953 Result:=FRows.Count; 1954end; 1955 1956procedure TOICustomPropertyGrid.BuildPropertyList(OnlyIfNeeded: Boolean; 1957 FocusEditor: Boolean); 1958var 1959 a: integer; 1960 CurRow: TOIPropertyGridRow; 1961 OldSelectedRowPath: string; 1962begin 1963 if OnlyIfNeeded and (not (pgsBuildPropertyListNeeded in FStates)) then exit; 1964 Exclude(FStates,pgsBuildPropertyListNeeded); 1965 if not FocusEditor then Include(FStates, pgsFocusPropertyEditorDisabled); 1966 OldSelectedRowPath:=PropertyPath(ItemIndex); 1967 // unselect 1968 ItemIndex:=-1; 1969 // clear 1970 for a:=0 to FRows.Count-1 do Rows[a].Free; 1971 FRows.Clear; 1972 // get properties 1973 if FSelection.Count>0 then begin 1974 GetPersistentProperties(FSelection, FFilter + [tkClass], FPropertyEditorHook, 1975 @AddPropertyEditor, @EditorFilter); 1976 end; 1977 // sort 1978 FRows.Sort(@SortGridRows); 1979 for a:=0 to FRows.Count-1 do begin 1980 if a>0 then 1981 Rows[a].FPriorBrother:=Rows[a-1] 1982 else 1983 Rows[a].FPriorBrother:=nil; 1984 if a<FRows.Count-1 then 1985 Rows[a].FNextBrother:=Rows[a+1] 1986 else 1987 Rows[a].FNextBrother:=nil; 1988 end; 1989 // set indices and tops 1990 SetItemsTops; 1991 // restore expands 1992 for a:=FExpandedProperties.Count-1 downto 0 do begin 1993 CurRow:=GetRowByPath(FExpandedProperties[a]); 1994 if CurRow<>nil then 1995 ExpandRow(CurRow.Index); 1996 end; 1997 // update scrollbar 1998 FTopY:=0; 1999 UpdateScrollBar; 2000 // reselect 2001 CurRow:=GetRowByPath(OldSelectedRowPath); 2002 if CurRow<>nil then 2003 ItemIndex:=CurRow.Index; 2004 Exclude(FStates, pgsFocusPropertyEditorDisabled); 2005 // paint 2006 Invalidate; 2007end; 2008 2009procedure TOICustomPropertyGrid.AddPropertyEditor(PropEditor: TPropertyEditor); 2010var 2011 NewRow: TOIPropertyGridRow; 2012 WidgetSets: TLCLPlatforms; 2013begin 2014 WidgetSets := []; 2015 if Favorites<>nil then begin 2016 //debugln('TOICustomPropertyGrid.AddPropertyEditor A ',PropEditor.GetName); 2017 if Favorites is TOIRestrictedProperties then 2018 begin 2019 WidgetSets := TOIRestrictedProperties(Favorites).AreRestricted( 2020 Selection,PropEditor.GetName); 2021 if WidgetSets = [] then 2022 begin 2023 PropEditor.Free; 2024 Exit; 2025 end; 2026 end 2027 else 2028 if not Favorites.AreFavorites(Selection,PropEditor.GetName) then begin 2029 PropEditor.Free; 2030 exit; 2031 end; 2032 end; 2033 if PropEditor is TClassPropertyEditor then 2034 begin 2035 TClassPropertyEditor(PropEditor).SubPropsNameFilter := PropNameFilter; 2036 TClassPropertyEditor(PropEditor).SubPropsTypeFilter := FFilter; 2037 TClassPropertyEditor(PropEditor).HideClassName:=FHideClassNames; 2038 end; 2039 NewRow := TOIPropertyGridRow.Create(Self, PropEditor, nil, WidgetSets); 2040 FRows.Add(NewRow); 2041 if FRows.Count>1 then begin 2042 NewRow.FPriorBrother:=Rows[FRows.Count-2]; 2043 NewRow.FPriorBrother.FNextBrother:=NewRow; 2044 end; 2045end; 2046 2047procedure TOICustomPropertyGrid.AddStringToComboBox(const s: string); 2048begin 2049 if FNewComboBoxItems=nil then 2050 FNewComboBoxItems:=TStringListUTF8Fast.Create; 2051 FNewComboBoxItems.Add(s); 2052end; 2053 2054procedure TOICustomPropertyGrid.ExpandRow(Index:integer); 2055var 2056 a: integer; 2057 CurPath: string; 2058 AlreadyInExpandList: boolean; 2059 ActiveRow: TOIPropertyGridRow; 2060begin 2061 // Save ItemIndex 2062 if ItemIndex <> -1 then 2063 ActiveRow := Rows[ItemIndex] 2064 else 2065 ActiveRow := nil; 2066 FExpandingRow := Rows[Index]; 2067 if (FExpandingRow.Expanded) or (not CanExpandRow(FExpandingRow)) then 2068 begin 2069 FExpandingRow := nil; 2070 Exit; 2071 end; 2072 FExpandingRow.Editor.GetProperties(@AddSubEditor); 2073 SortSubEditors(FExpandingRow); 2074 SetItemsTops; 2075 FExpandingRow.FExpanded := True; 2076 a := 0; 2077 CurPath:=PropertyPath(FExpandingRow.Index); 2078 AlreadyInExpandList:=false; 2079 while a < FExpandedProperties.Count do 2080 begin 2081 if LazStartsText(FExpandedProperties[a], CurPath) then 2082 begin 2083 if Length(FExpandedProperties[a]) = Length(CurPath) then 2084 begin 2085 AlreadyInExpandList := True; 2086 inc(a); 2087 end 2088 else 2089 FExpandedProperties.Delete(a); 2090 end 2091 else 2092 inc(a); 2093 end; 2094 if not AlreadyInExpandList then 2095 FExpandedProperties.Add(CurPath); 2096 FExpandingRow := nil; 2097 // restore ItemIndex 2098 if ActiveRow <> nil then 2099 FItemIndex := ActiveRow.Index 2100 else 2101 FItemIndex := -1; 2102 UpdateScrollBar; 2103 Invalidate; 2104end; 2105 2106procedure TOICustomPropertyGrid.ShrinkRow(Index:integer); 2107var 2108 CurRow, ARow: TOIPropertyGridRow; 2109 StartIndex, EndIndex, a: integer; 2110 CurPath: string; 2111begin 2112 CurRow := Rows[Index]; 2113 if (not CurRow.Expanded) then 2114 Exit; 2115 // calculate all children (between StartIndex..EndIndex) 2116 StartIndex := CurRow.Index + 1; 2117 EndIndex := FRows.Count - 1; 2118 ARow := CurRow; 2119 while ARow <> nil do 2120 begin 2121 if ARow.NextBrother <> nil then 2122 begin 2123 EndIndex := ARow.NextBrother.Index - 1; 2124 break; 2125 end; 2126 ARow := ARow.Parent; 2127 end; 2128 if (FItemIndex >= StartIndex) and (FItemIndex <= EndIndex) then 2129 // current row delete, set new current row 2130 ItemIndex:=0 2131 else 2132 if FItemIndex > EndIndex then 2133 // adjust current index for deleted rows 2134 FItemIndex := FItemIndex - (EndIndex - StartIndex + 1); 2135 for a := EndIndex downto StartIndex do 2136 begin 2137 Rows[a].Free; 2138 FRows.Delete(a); 2139 end; 2140 SetItemsTops; 2141 CurRow.FExpanded := False; 2142 CurPath := PropertyPath(CurRow.Index); 2143 a := 0; 2144 while a < FExpandedProperties.Count do 2145 begin 2146 if LazStartsText(CurPath, FExpandedProperties[a]) then 2147 FExpandedProperties.Delete(a) 2148 else 2149 inc(a); 2150 end; 2151 if CurRow.Parent <> nil then 2152 FExpandedProperties.Add(PropertyPath(CurRow.Parent.Index)); 2153 UpdateScrollBar; 2154 Invalidate; 2155end; 2156 2157procedure TOICustomPropertyGrid.AddSubEditor(PropEditor:TPropertyEditor); 2158var 2159 NewRow:TOIPropertyGridRow; 2160 NewIndex:integer; 2161begin 2162 if not EditorFilter(PropEditor) then 2163 begin 2164 PropEditor.Free; 2165 Exit; 2166 end; 2167 2168 if PropEditor is TClassPropertyEditor then 2169 begin 2170 TClassPropertyEditor(PropEditor).SubPropsNameFilter := PropNameFilter; 2171 TClassPropertyEditor(PropEditor).SubPropsTypeFilter := FFilter; 2172 TClassPropertyEditor(PropEditor).HideClassName:=FHideClassNames; 2173 end; 2174 NewRow:=TOIPropertyGridRow.Create(Self,PropEditor,FExpandingRow, []); 2175 NewIndex:=FExpandingRow.Index+1+FExpandingRow.ChildCount; 2176 NewRow.FIndex:=NewIndex; 2177 FRows.Insert(NewIndex,NewRow); 2178 if NewIndex<FItemIndex 2179 then inc(FItemIndex); 2180 if FExpandingRow.FFirstChild=nil then 2181 FExpandingRow.FFirstChild:=NewRow; 2182 NewRow.FPriorBrother:=FExpandingRow.FLastChild; 2183 FExpandingRow.FLastChild:=NewRow; 2184 if NewRow.FPriorBrother<>nil then 2185 NewRow.FPriorBrother.FNextBrother:=NewRow; 2186 inc(FExpandingRow.FChildCount); 2187end; 2188 2189procedure TOICustomPropertyGrid.SortSubEditors(ParentRow: TOIPropertyGridRow); 2190var 2191 Item: TOIPropertyGridRow; 2192 Index: Integer; 2193 Next: TOIPropertyGridRow; 2194begin 2195 if not ParentRow.Sort(@SortGridRows) then exit; 2196 // update FRows 2197 Item:=ParentRow.FirstChild; 2198 Index:=ParentRow.Index+1; 2199 Next:=ParentRow.NextSkipChilds; 2200 while (Item<>nil) and (Item<>Next) do begin 2201 FRows[Index]:=Item; 2202 Item.FIndex:=Index; 2203 Item:=Item.Next; 2204 inc(Index); 2205 end; 2206end; 2207 2208function TOICustomPropertyGrid.CanExpandRow(Row: TOIPropertyGridRow): boolean; 2209var 2210 AnObject: TPersistent; 2211 ParentRow: TOIPropertyGridRow; 2212begin 2213 Result:=false; 2214 if (Row=nil) or (Row.Editor=nil) then exit; 2215 if (not (paSubProperties in Row.Editor.GetAttributes)) then exit; 2216 // check if circling 2217 if (Row.Editor is TPersistentPropertyEditor) then begin 2218 if (Row.Editor is TInterfacePropertyEditor) then 2219 AnObject:={%H-}TPersistent(Row.Editor.GetIntfValue) 2220 else 2221 AnObject:=TPersistent(Row.Editor.GetObjectValue); 2222 if FSelection.IndexOf(AnObject)>=0 then exit; 2223 ParentRow:=Row.Parent; 2224 while ParentRow<>nil do begin 2225 if (ParentRow.Editor is TPersistentPropertyEditor) 2226 and (ParentRow.Editor.GetObjectValue=AnObject) then 2227 exit; 2228 ParentRow:=ParentRow.Parent; 2229 end; 2230 end; 2231 Result:=true; 2232end; 2233 2234function TOICustomPropertyGrid.MouseToIndex(y: integer; MustExist: boolean): integer; 2235var l,r,m:integer; 2236begin 2237 l:=0; 2238 r:=FRows.Count-1; 2239 inc(y,FTopY); 2240 while (l<=r) do 2241 begin 2242 m:=(l+r) shr 1; 2243 if Rows[m].Top>y then 2244 r:=m-1 2245 else if Rows[m].Bottom<=y then 2246 l:=m+1 2247 else 2248 Exit(m); 2249 end; 2250 if (MustExist=false) and (FRows.Count>0) then begin 2251 if y<0 then 2252 Result:=0 2253 else 2254 Result:=FRows.Count-1; 2255 end else 2256 Result:=-1; 2257end; 2258 2259function TOICustomPropertyGrid.GetActiveRow: TOIPropertyGridRow; 2260begin 2261 if InRange(ItemIndex,0,FRows.Count-1) then 2262 Result:=Rows[ItemIndex] 2263 else 2264 Result:=nil; 2265end; 2266 2267procedure TOICustomPropertyGrid.SetCurrentRowValue(const NewValue: string); 2268begin 2269 if not CanEditRowValue(false) or Rows[FItemIndex].IsReadOnly then exit; 2270 // SetRowValue reads the value from the current edit control and writes it 2271 // to the property editor 2272 // -> set the text in the current edit control without changing FLastEditValue 2273 SetCurrentEditValue(NewValue); 2274 SetRowValue(false, true); 2275end; 2276 2277procedure TOICustomPropertyGrid.SetItemIndexAndFocus(NewItemIndex: integer; 2278 WasValueClick: Boolean); 2279begin 2280 if not InRange(NewItemIndex, 0, FRows.Count - 1) then exit; 2281 ItemIndex:=NewItemIndex; 2282 if FCurrentEdit<>nil then 2283 begin 2284 SetActiveControl(FCurrentEdit); 2285 if (FCurrentEdit is TCustomEdit) then 2286 TCustomEdit(FCurrentEdit).SelectAll 2287 {$IFnDEF UseOINormalCheckBox} 2288 else if (FCurrentEdit is TCheckBoxThemed) and WasValueClick then 2289 TCheckBoxThemed(FCurrentEdit).Checked:=not TCheckBoxThemed(FCurrentEdit).Checked; 2290 {$ELSE} 2291 else if (FCurrentEdit is TCheckBox) and WasValueClick then 2292 TCheckBox(FCurrentEdit).Checked:=not TCheckBox(FCurrentEdit).Checked; 2293 {$ENDIF} 2294 end; 2295end; 2296 2297function TOICustomPropertyGrid.CanEditRowValue(CheckFocus: boolean): boolean; 2298var 2299 FocusedControl: TWinControl; 2300begin 2301 Result:= 2302 not GridIsUpdating and IsCurrentEditorAvailable 2303 and (not (pgsCallingEdit in FStates)) 2304 and ((FCurrentEditorLookupRoot = nil) 2305 or (FPropertyEditorHook = nil) 2306 or (FPropertyEditorHook.LookupRoot = FCurrentEditorLookupRoot)); 2307 if Result and CheckFocus then begin 2308 FocusedControl:=FindOwnerControl(GetFocus); 2309 if (FocusedControl<>nil) and (FocusedControl<>Self) 2310 and (not IsParentOf(FocusedControl)) then 2311 Result:=false; 2312 end; 2313 if Result then begin 2314 {DebugLn(['TOICustomPropertyGrid.CanEditRowValue', 2315 ' pgsChangingItemIndex=',pgsChangingItemIndex in FStates, 2316 ' pgsApplyingValue=',pgsApplyingValue in FStates, 2317 ' pgsUpdatingEditControl=',pgsUpdatingEditControl in FStates, 2318 ' FCurrentEdit=',dbgsName(FCurrentEdit), 2319 ' FItemIndex=',FItemIndex, 2320 ' FCurrentEditorLookupRoot=',dbgsName(FCurrentEditorLookupRoot), 2321 ' FPropertyEditorHook.LookupRoot=',dbgsName(FPropertyEditorHook.LookupRoot) 2322 ]);} 2323 end; 2324end; 2325 2326procedure TOICustomPropertyGrid.SaveChanges; 2327begin 2328 SetRowValue(true, false); 2329end; 2330 2331function TOICustomPropertyGrid.GetHintTypeAt(RowIndex: integer; X: integer): TPropEditHint; 2332var 2333 IconX: integer; 2334begin 2335 Result := pehNone; 2336 if (RowIndex < 0) or (RowIndex >= RowCount) then 2337 Exit; 2338 if SplitterX <= X then 2339 begin 2340 if (FCurrentButton <> nil) and (FCurrentButton.Left <= X) then 2341 Result := pehEditButton 2342 else 2343 Result := pehValue; 2344 end else 2345 begin 2346 IconX := GetTreeIconX(RowIndex); 2347 if IconX + Indent > X then 2348 Result := pehTree 2349 else 2350 Result := pehName; 2351 end; 2352end; 2353 2354procedure TOICustomPropertyGrid.MouseDown(Button:TMouseButton; Shift:TShiftState; 2355 X,Y:integer); 2356var 2357 IconX,Index:integer; 2358 PointedRow:TOIpropertyGridRow; 2359 Details: TThemedElementDetails; 2360 Sz: TSize; 2361begin 2362 //ShowMessageDialog('X'+IntToStr(X)+',Y'+IntToStr(Y)); 2363 inherited MouseDown(Button,Shift,X,Y); 2364 2365 HideHint; 2366 2367 if Button=mbLeft then begin 2368 FFirstClickTime:=GetTickCount; 2369 if Cursor=crHSplit then 2370 FDragging:=true 2371 else 2372 begin 2373 Index:=MouseToIndex(Y,false); 2374 if (Index>=0) and (Index<FRows.Count) then 2375 begin 2376 PointedRow:=Rows[Index]; 2377 if CanExpandRow(PointedRow) then 2378 begin 2379 IconX:=GetTreeIconX(Index); 2380 if ((X>=IconX) and (X<=IconX+FIndent)) or (ssDouble in Shift) then 2381 begin 2382 if PointedRow.Expanded then 2383 ShrinkRow(Index) 2384 else 2385 ExpandRow(Index); 2386 end; 2387 end; 2388 // WasValueClick param is only for Boolean checkboxes, toggled if user 2389 // clicks the square. It has no effect for Boolean ComboBox editor. 2390 Details := ThemeServices.GetElementDetails(tbCheckBoxCheckedNormal); 2391 Sz := ThemeServices.GetDetailSize(Details); 2392 SetItemIndexAndFocus(Index, (X>SplitterX) and (X<=SplitterX+Sz.cx)); 2393 SetCaptureControl(Self); 2394 Column := oipgcValue; 2395 end; 2396 end; 2397 end; 2398end; 2399 2400procedure TOICustomPropertyGrid.MouseLeave; 2401begin 2402 if Assigned(FHintManager) and Assigned(FHintManager.CurHintWindow) 2403 and FHintManager.CurHintWindow.Visible 2404 and not PtInRect(ClientRect, ScreenToClient(Mouse.CursorPos)) then 2405 FHintManager.HideHint; 2406 2407 inherited MouseLeave; 2408end; 2409 2410procedure TOICustomPropertyGrid.MouseMove(Shift:TShiftState; X,Y:integer); 2411var 2412 TheHint: String; 2413 HintType: TPropEditHint; 2414 fPropRow: TOIPropertyGridRow; 2415 2416 procedure ShowShortHint(pt: TPoint); inline; 2417 //var HintFont: TFont; 2418 begin 2419 if WidgetSet.GetLCLCapability(lcTransparentWindow)=LCL_CAPABILITY_NO then 2420 Inc(pt.Y, fPropRow.Height); 2421{ By Juha : 2422 FValueFont and FDefaultValueFont are nearly unreadable. 2423 We should maybe get their negated color as the hint background is black. 2424 2425 if HintType<>pehValue then 2426 HintFont := Screen.HintFont 2427 else 2428 if fPropRow.Editor.ValueIsStreamed then 2429 HintFont:=FValueFont 2430 else 2431 HintFont:=FDefaultValueFont; } 2432 FHintManager.ShowHint(ClientToScreen(pt), TheHint, False{, HintFont}); 2433 if FHintManager.CurHintWindow<>nil then 2434 FHintManager.CurHintWindow.OnMouseLeave := @HintMouseLeave; 2435 end; 2436 2437var 2438 SplitDistance, Index, TextLeft: Integer; 2439 HintWillChange: Boolean; 2440begin 2441 inherited MouseMove(Shift,X,Y); 2442 SplitDistance := X-SplitterX; 2443 if FDragging then 2444 begin 2445 HideHint; 2446 if ssLeft in Shift then 2447 SplitterX:=SplitterX+SplitDistance 2448 else 2449 EndDragSplitter; 2450 end 2451 else begin 2452 if abs(SplitDistance) <= 2 then 2453 Cursor := crHSplit 2454 else 2455 Cursor := crDefault; 2456 if ssLeft in Shift then 2457 begin 2458 Index := MouseToIndex(Y, False); 2459 SetItemIndexAndFocus(Index); 2460 SetCaptureControl(Self); 2461 end; 2462 // The following code handler 2 kinds of hints : 2463 // 1. Property's name / value when it does not fit in the cell. 2464 // 2. Long description of a property / value, only when ShowHint option is set. 2465 Index := MouseToIndex(y,false); 2466 HintType := GetHintTypeAt(Index, x); 2467 HintWillChange := (Index<>FHintIndex) or (HintType<>FHintType); 2468 if HintWillChange then 2469 HideHint; // hide the hint of an earlier row 2470 // Don't show any more hints if the long hint is there. 2471 if FShowingLongHint or (Index = -1) then Exit; 2472 // Show the property text as a hint if it does not fit in its box. 2473 if HintWillChange or not FHintManager.HintIsVisible then 2474 begin 2475 FHintIndex := Index; 2476 FHintType := HintType; 2477 fPropRow := GetRow(Index); 2478 if HintType = pehName then 2479 begin // Mouse is over property name... 2480 TheHint := fPropRow.Name; 2481 TextLeft := BorderWidth + GetTreeIconX(Index) + Indent + 5; 2482 if (Canvas.TextWidth(TheHint) + TextLeft) >= SplitterX-2 then 2483 ShowShortHint(Point(TextLeft-3, fPropRow.Top-TopY-1)); 2484 end else 2485 if HintType in [pehValue,pehEditButton] then 2486 begin // Mouse is over property value... 2487 TheHint := fPropRow.LastPaintedValue; 2488 if length(TheHint) > 100 then 2489 TheHint := copy(TheHint, 1, 100) + '...'; 2490 TextLeft := SplitterX+2; 2491 if Canvas.TextWidth(TheHint) > (ClientWidth - BorderWidth - TextLeft) then 2492 ShowShortHint(Point(TextLeft-3, fPropRow.Top-TopY-1)); 2493 end; 2494 end; 2495 // Initialize timer for a long hint describing the property and value. 2496 if not ShowHint then Exit; 2497 if FLongHintTimer = nil then 2498 begin 2499 FHintIndex := -1; 2500 FLongHintTimer := TTimer.Create(nil); 2501 FLongHintTimer.Interval := 500; 2502 FLongHintTimer.Enabled := False; 2503 FLongHintTimer.OnTimer := @HintTimer; 2504 FHintManager.OnMouseDown := @HintMouseDown; 2505 FHintManager.WindowName := 'This_is_a_hint_window'; 2506 FHintManager.HideInterval := 4000; 2507 FHintManager.AutoHide := True; 2508 end; 2509 FLongHintTimer.Enabled := RowCount > 0; 2510 end; // not FDragging 2511end; 2512 2513procedure TOICustomPropertyGrid.MouseUp(Button:TMouseButton; Shift:TShiftState; 2514 X,Y:integer); 2515begin 2516 if FDragging then EndDragSplitter; 2517 SetCaptureControl(nil); 2518 inherited MouseUp(Button,Shift,X,Y); 2519end; 2520 2521procedure TOICustomPropertyGrid.KeyDown(var Key: Word; Shift: TShiftState); 2522begin 2523 HandleStandardKeys(Key,Shift); 2524 inherited KeyDown(Key, Shift); 2525end; 2526 2527procedure TOICustomPropertyGrid.HandleStandardKeys(var Key: Word; Shift: TShiftState); 2528var 2529 Handled: Boolean; 2530 2531 procedure FindPropertyBySearchText; 2532 var 2533 i, IIndex: Integer; 2534 begin 2535 if Column = oipgcName then 2536 begin 2537 FKeySearchText := FKeySearchText + UpCase(Chr(Key)); 2538 if ItemIndex = -1 then 2539 IIndex := 0 2540 else 2541 IIndex := ItemIndex; 2542 for i := 0 to RowCount - 1 do 2543 if (Rows[i].Lvl = Rows[IIndex].Lvl) 2544 and LazStartsText(FKeySearchText, Rows[i].Name) then 2545 begin 2546 // Set item index. To go to Value user must hit either Tab or Enter. 2547 SetItemIndex(i); 2548 exit; 2549 end; 2550 // Left part of phrase not matched, remove added char. 2551 SetLength(FKeySearchText, Length(FKeySearchText) - 1); 2552 end; 2553 Handled := false; 2554 end; 2555 2556 procedure HandleUnshifted; 2557 const 2558 Page = 20; 2559 begin 2560 Handled := true; 2561 case Key of 2562 VK_UP : SetItemIndexAndFocus(ItemIndex - 1); 2563 VK_DOWN : SetItemIndexAndFocus(ItemIndex + 1); 2564 VK_PRIOR: SetItemIndexAndFocus(Max(ItemIndex - Page, 0)); 2565 VK_NEXT : SetItemIndexAndFocus(Min(ItemIndex + Page, FRows.Count - 1)); 2566 2567 VK_TAB: DoTabKey; 2568 2569 VK_RETURN: 2570 begin 2571 if Column = oipgcName then 2572 DoTabKey 2573 else 2574 SetRowValue(false, true); 2575 if FCurrentEdit is TCustomEdit then 2576 TCustomEdit(FCurrentEdit).SelectAll; 2577 end; 2578 2579 VK_ESCAPE: 2580 begin 2581 RefreshValueEdit; 2582 FKeySearchText := ''; 2583 end; 2584 2585 VK_BACK: 2586 begin 2587 if (Column = oipgcName) then 2588 if (FKeySearchText <> '') then 2589 SetLength(FKeySearchText, Length(FKeySearchText) - 1); 2590 Handled := False; 2591 end; 2592 2593 Ord('A')..Ord('Z'): FindPropertyBySearchText; 2594 2595 else 2596 Handled := false; 2597 end; 2598 end; 2599 2600begin 2601 //writeln('TOICustomPropertyGrid.HandleStandardKeys ',Key); 2602 Handled := false; 2603 if (Shift = []) or (Shift = [ssShift]) then 2604 begin 2605 if not (FCurrentEdit is TCustomCombobox) or 2606 not TCustomCombobox(FCurrentEdit).DroppedDown then 2607 HandleUnshifted; 2608 end 2609 else 2610 if Shift = [ssCtrl] then 2611 begin 2612 case Key of 2613 VK_RETURN: 2614 begin 2615 ToggleRow; 2616 Handled := true; 2617 end; 2618 end; 2619 end 2620 else 2621 if Shift = [ssAlt] then 2622 case Key of 2623 VK_LEFT: 2624 begin 2625 Handled := (ItemIndex >= 0) and Rows[ItemIndex].Expanded; 2626 if Handled then ShrinkRow(ItemIndex); 2627 end; 2628 2629 VK_RIGHT: 2630 begin 2631 Handled := (ItemIndex >= 0) and not Rows[ItemIndex].Expanded and 2632 CanExpandRow(Rows[ItemIndex]); 2633 if Handled then ExpandRow(ItemIndex) 2634 end; 2635 end; 2636 2637 2638 if not Handled and Assigned(OnOIKeyDown) then 2639 begin 2640 OnOIKeyDown(Self, Key, Shift); 2641 Handled := Key = VK_UNKNOWN; 2642 end; 2643 2644 //writeln('TOICustomPropertyGrid.HandleStandardKeys ',Key,' Handled=',Handled); 2645 if Handled then 2646 Key := VK_UNKNOWN; 2647end; 2648 2649procedure TOICustomPropertyGrid.HandleKeyUp(var Key: Word; Shift: TShiftState); 2650begin 2651 if (Key<>VK_UNKNOWN) and Assigned(OnKeyUp) then 2652 OnKeyUp(Self,Key,Shift); 2653end; 2654 2655procedure TOICustomPropertyGrid.DoTabKey; 2656begin 2657 if Column = oipgcValue then 2658 begin 2659 Column := oipgcName; 2660 Self.SetFocus; 2661 end else 2662 begin 2663 Column := oipgcValue; 2664 if FCurrentEdit <> nil then 2665 FCurrentEdit.SetFocus; 2666 end; 2667 FKeySearchText := ''; 2668end; 2669 2670function TOICustomPropertyGrid.EditorFilter(const AEditor: TPropertyEditor): Boolean; 2671begin 2672 Result := IsInteresting(AEditor, FFilter, PropNameFilter); 2673 if Result and Assigned(OnEditorFilter) then 2674 OnEditorFilter(Self,AEditor,Result); 2675end; 2676 2677procedure TOICustomPropertyGrid.EraseBackground(DC: HDC); 2678begin 2679 // everything is painted, so erasing the background is not needed 2680end; 2681 2682procedure TOICustomPropertyGrid.DoSetBounds(ALeft, ATop, AWidth, AHeight: integer); 2683begin 2684 inherited DoSetBounds(ALeft, ATop, AWidth, AHeight); 2685 UpdateScrollBar; 2686end; 2687 2688procedure TOICustomPropertyGrid.DoSelectionChange; 2689begin 2690 if Assigned(FOnSelectionChange) then 2691 FOnSelectionChange(Self); 2692end; 2693 2694procedure TOICustomPropertyGrid.HintMouseDown(Sender: TObject; 2695 Button: TMouseButton; Shift: TShiftState; X, Y: Integer); 2696var 2697 pos: TPoint; 2698begin 2699 if FHintManager.HintIsVisible then begin 2700 pos := ScreenToClient(FHintManager.CurHintWindow.ClientToScreen(Point(X, Y))); 2701 MouseDown(Button, Shift, pos.X, pos.Y); 2702 end; 2703end; 2704 2705procedure TOICustomPropertyGrid.HintMouseLeave(Sender: TObject); 2706begin 2707 if FindLCLControl(Mouse.CursorPos)<>Self then 2708 FHintManager.HideHint; 2709end; 2710 2711procedure TOICustomPropertyGrid.EndDragSplitter; 2712begin 2713 if FDragging then begin 2714 Cursor:=crDefault; 2715 FDragging:=false; 2716 FPreferredSplitterX:=FSplitterX; 2717 if FCurrentEdit<>nil then begin 2718 SetCaptureControl(nil); 2719 if Column=oipgcValue then 2720 FCurrentEdit.SetFocus 2721 else 2722 Self.SetFocus; 2723 end; 2724 end; 2725end; 2726 2727procedure TOICustomPropertyGrid.SetReadOnlyColor(const AValue: TColor); 2728begin 2729 if FReadOnlyColor = AValue then Exit; 2730 FReadOnlyColor := AValue; 2731 Invalidate; 2732end; 2733 2734procedure TOICustomPropertyGrid.SetRowSpacing(const AValue: integer); 2735begin 2736 if FRowSpacing = AValue then exit; 2737 FRowSpacing := AValue; 2738 SetItemsTops; 2739end; 2740 2741procedure TOICustomPropertyGrid.SetShowGutter(const AValue: Boolean); 2742begin 2743 if FShowGutter=AValue then exit; 2744 FShowGutter:=AValue; 2745 invalidate; 2746end; 2747 2748procedure TOICustomPropertyGrid.SetSplitterX(const NewValue:integer); 2749var AdjustedValue:integer; 2750begin 2751 AdjustedValue:=NewValue; 2752 if AdjustedValue>ClientWidth then AdjustedValue:=ClientWidth; 2753 if AdjustedValue<1 then AdjustedValue:=1; 2754 if FSplitterX<>AdjustedValue then begin 2755 FSplitterX:=AdjustedValue; 2756 AlignEditComponents; 2757 Repaint; 2758 end; 2759end; 2760 2761procedure TOICustomPropertyGrid.SetTopY(const NewValue:integer); 2762var 2763 NewTopY, d: integer; 2764 f: UINT; 2765begin 2766 NewTopY := TopMax; 2767 if NewValue < NewTopY then 2768 NewTopY := NewValue; 2769 if NewTopY < 0 then 2770 NewTopY := 0; 2771 if FTopY<>NewTopY then begin 2772 f := SW_INVALIDATE; 2773 d := FTopY-NewTopY; 2774 // SW_SCROLLCHILDREN can only be used, if the active editor is not 2775 // "scrolling in" (i.e., partly outside the clientrect) 2776 if (FCurrentEdit = nil) or 2777 ( (d > 0) and (FCurrentEdit.Top >= 0) ) or 2778 ( (d < 0) and (FCurrentEdit.Top < Height - FCurrentEdit.Height) ) 2779 then 2780 f := f + SW_SCROLLCHILDREN; 2781 if not ScrollWindowEx(Handle,0,d,nil,nil,0,nil, f) then 2782 Invalidate; 2783 FTopY:=NewTopY; 2784 UpdateScrollBar; 2785 AlignEditComponents; 2786 end; 2787end; 2788 2789function TOICustomPropertyGrid.GetPropNameColor(ARow:TOIPropertyGridRow):TColor; 2790 2791 function HasWriter(APropInfo: PPropInfo): Boolean; inline; 2792 begin 2793 Result := Assigned(APropInfo) and Assigned(APropInfo^.SetProc); 2794 end; 2795 2796var 2797 ParentRow:TOIPropertyGridRow; 2798 IsObjectSubProperty:Boolean; 2799begin 2800 // Try to guest if ARow, or one of its parents, is a subproperty 2801 // of an object (and not an item of a set) 2802 IsObjectSubProperty:=false; 2803 ParentRow:=ARow.Parent; 2804 while Assigned(ParentRow) do 2805 begin 2806 if ParentRow.Editor is TPersistentPropertyEditor then 2807 IsObjectSubProperty:=true; 2808 ParentRow:=ParentRow.Parent; 2809 end; 2810 2811 if (ItemIndex <> -1) and (ItemIndex = ARow.Index) then 2812 Result := FHighlightFont.Color 2813 else 2814 if not HasWriter(ARow.Editor.GetPropInfo) then 2815 Result := FReadOnlyColor 2816 else 2817 if ARow.Editor is TPersistentPropertyEditor then 2818 Result := FReferencesColor 2819 else 2820 if IsObjectSubProperty then 2821 Result := FSubPropertiesColor 2822 else 2823 Result := FNameFont.Color; 2824end; 2825 2826procedure TOICustomPropertyGrid.SetBounds(aLeft,aTop,aWidth,aHeight:integer); 2827begin 2828//writeln('[TOICustomPropertyGrid.SetBounds] ',Name,' ',aLeft,',',aTop,',',aWidth,',',aHeight,' Visible=',Visible); 2829 inherited SetBounds(aLeft,aTop,aWidth,aHeight); 2830 if Visible then begin 2831 if not FDragging then begin 2832 if (SplitterX<5) and (aWidth>20) then 2833 SplitterX:=100 2834 else 2835 SplitterX:=FPreferredSplitterX; 2836 end; 2837 AlignEditComponents; 2838 end; 2839end; 2840 2841function TOICustomPropertyGrid.GetTreeIconX(Index:integer):integer; 2842begin 2843 Result:=Rows[Index].Lvl*Indent+2; 2844end; 2845 2846function TOICustomPropertyGrid.TopMax:integer; 2847begin 2848 Result:=GridHeight-ClientHeight+2*integer(BorderWidth); 2849 if Result<0 then Result:=0; 2850end; 2851 2852function TOICustomPropertyGrid.GridHeight:integer; 2853begin 2854 if FRows.Count>0 then 2855 Result:=Rows[FRows.Count-1].Bottom 2856 else 2857 Result:=0; 2858end; 2859 2860procedure TOICustomPropertyGrid.AlignEditComponents; 2861var 2862 RRect, EditCompRect, EditBtnRect: TRect; 2863begin 2864 if ItemIndex>=0 then 2865 begin 2866 RRect := RowRect(ItemIndex); 2867 InflateRect(RRect, 0, 1); 2868 EditCompRect := RRect; 2869 2870 if Layout = oilHorizontal then 2871 EditCompRect.Left := RRect.Left + SplitterX 2872 else begin 2873 EditCompRect.Top := RRect.Top + GetNameRowHeight; 2874 EditCompRect.Left := RRect.Left + GetTreeIconX(ItemIndex) + Indent; 2875 end; 2876 2877 if FCurrentButton<>nil then 2878 begin 2879 // edit dialog button 2880 with EditBtnRect do begin 2881 Top := EditCompRect.Top; 2882 Left := EditCompRect.Right - Scale96ToForm(20); 2883 Bottom := EditCompRect.Bottom - 1; 2884 Right := EditCompRect.Right; 2885 EditCompRect.Right := Left; 2886 end; 2887 if FCurrentButton.BoundsRect <> EditBtnRect then 2888 FCurrentButton.BoundsRect := EditBtnRect; 2889 //DebugLn(['TOICustomPropertyGrid.AlignEditComponents FCurrentButton.BoundsRect=',dbgs(FCurrentButton.BoundsRect),' EditBtnRect=',dbgs(EditBtnRect)]); 2890 end; 2891 if FCurrentEdit<>nil then 2892 begin 2893 // resize the edit component 2894 if (FCurrentEdit is TEdit) or (FCurrentEdit is TComboBox) then 2895 begin 2896 Dec(EditCompRect.Top); 2897 {$IFDEF UseOINormalCheckBox} 2898 end 2899 else if FCurrentEdit is TCheckBox then 2900 begin 2901 with EditCompRect do // Align "normal" CheckBox to the middle vertically 2902 Inc(Top, (Bottom - Top - ValueCheckBox.Height) div 2); 2903 {$ELSE} 2904 end 2905 else if FCurrentEdit is TCheckBoxThemed then 2906 begin // Move right as much as in TPropertyEditor.DrawCheckValue. 2907 Inc(EditCompRect.Left, CheckBoxThemedLeftOffs); 2908 {$ENDIF} 2909 end; 2910 //debugln('TOICustomPropertyGrid.AlignEditComponents A ',dbgsName(FCurrentEdit),' ',dbgs(EditCompRect)); 2911 if ( ( (FCurrentEdit.BoundsRect.Bottom >= 0) and (FCurrentEdit.BoundsRect.Top <= Height) ) or 2912 ( (EditCompRect.Bottom >= 0) and (EditCompRect.Top <= Height) ) ) and 2913 ( FCurrentEdit.BoundsRect <> EditCompRect ) 2914 then begin 2915 FCurrentEdit.BoundsRect := EditCompRect; 2916 end; 2917 end; 2918 end; 2919end; 2920 2921procedure TOICustomPropertyGrid.PaintRow(ARow: integer); 2922var 2923 FullRect, NameRect, NameTextRect, NameIconRect, ValueRect: TRect; 2924 CurRow: TOIPropertyGridRow; 2925 2926 procedure ClearBackground; 2927 var 2928 DrawValuesDiffer: Boolean; 2929 begin 2930 DrawValuesDiffer := (FValueDifferBackgrndColor<>clNone) and not CurRow.Editor.AllEqual; 2931 if FBackgroundColor <> clNone then 2932 begin 2933 Canvas.Brush.Color := FBackgroundColor; 2934 if DrawValuesDiffer then 2935 Canvas.FillRect(NameRect) 2936 else 2937 Canvas.FillRect(FullRect); 2938 end; 2939 if DrawValuesDiffer then 2940 begin 2941 // Make the background color darker than what the active edit control has. 2942 Canvas.Brush.Color := FValueDifferBackgrndColor - $282828; 2943 Canvas.FillRect(ValueRect); 2944 end; 2945 if ShowGutter and (Layout = oilHorizontal) and 2946 (FGutterColor <> FBackgroundColor) and (FGutterColor <> clNone) then 2947 begin 2948 Canvas.Brush.Color := FGutterColor; 2949 Canvas.FillRect(NameIconRect); 2950 end; 2951 end; 2952 2953 procedure DrawIcon(IconX: integer); 2954 var 2955 Details: TThemedElementDetails; 2956 sz: TSize; 2957 IconY: integer; 2958 Res: TScaledImageListResolution; 2959 begin 2960 if CurRow.Expanded then 2961 Details := ThemeServices.GetElementDetails(ttGlyphOpened) 2962 else 2963 Details := ThemeServices.GetElementDetails(ttGlyphClosed); 2964 if CanExpandRow(CurRow) then 2965 begin 2966 sz := ThemeServices.GetDetailSize(Details); 2967 IconY:=((NameRect.Bottom - NameRect.Top - sz.cy) div 2) + NameRect.Top; 2968 ThemeServices.DrawElement(Canvas.Handle, Details, 2969 Rect(IconX, IconY, IconX + sz.cx, IconY + sz.cy), nil) 2970 end else 2971 if (ARow = FItemIndex) then 2972 begin 2973 Res := FActiveRowImages.ResolutionForControl[0, Self]; 2974 2975 IconY:=((NameRect.Bottom - NameRect.Top - Res.Height) div 2) + NameRect.Top; 2976 Res.Draw(Canvas, IconX, IconY, FActiveRowImages.GetImageIndex('pg_active_row')); 2977 end; 2978 end; 2979 2980 procedure DrawName(DrawState: TPropEditDrawState); 2981 var 2982 OldFont: TFont; 2983 NameBgColor: TColor; 2984 begin 2985 if (ARow = FItemIndex) and (FHighlightColor <> clNone) then 2986 NameBgColor := FHighlightColor 2987 else 2988 NameBgColor := FBackgroundColor; 2989 OldFont:=Canvas.Font; 2990 Canvas.Font:=FNameFont; 2991 Canvas.Font.Color := GetPropNameColor(CurRow); 2992 // set bg color to highlight if needed 2993 if (NameBgColor <> FBackgroundColor) and (NameBgColor <> clNone) then 2994 begin 2995 Canvas.Brush.Color := NameBgColor; 2996 Canvas.FillRect(NameTextRect); 2997 end; 2998 CurRow.Editor.PropDrawName(Canvas, NameTextRect, DrawState); 2999 Canvas.Font := OldFont; 3000 if FBackgroundColor <> clNone then // return color back to background 3001 Canvas.Brush.Color := FBackgroundColor; 3002 end; 3003 3004 procedure DrawWidgetsets; 3005 var 3006 OldFont: TFont; 3007 X, Y: Integer; 3008 lclPlatform: TLCLPlatform; 3009 ImagesRes: TScaledImageListResolution; 3010 begin 3011 ImagesRes := IDEImages.Images_16.ResolutionForPPI[0, Font.PixelsPerInch, GetCanvasScaleFactor]; 3012 X := NameRect.Right - 2; 3013 Y := (NameRect.Top + NameRect.Bottom - ImagesRes.Height) div 2; 3014 OldFont:=Canvas.Font; 3015 Canvas.Font:=FNameFont; 3016 Canvas.Font.Color := clRed; 3017 for lclPlatform := High(TLCLPlatform) downto Low(TLCLPlatform) do 3018 begin 3019 if lclPlatform in CurRow.FWidgetSets then 3020 begin 3021 Dec(X, ImagesRes.Width); 3022 ImagesRes.Draw(Canvas, X, Y, 3023 IDEImages.LoadImage('issue_'+LCLPlatformDirNames[lclPlatform])); 3024 end; 3025 end; 3026 Canvas.Font:=OldFont; 3027 end; 3028 3029 procedure DrawValue(DrawState: TPropEditDrawState); 3030 var 3031 OldFont: TFont; 3032 begin 3033 if ARow<>ItemIndex then 3034 begin 3035 OldFont:=Canvas.Font; 3036 if CurRow.Editor.ValueIsStreamed then 3037 Canvas.Font:=FValueFont 3038 else 3039 Canvas.Font:=FDefaultValueFont; 3040 CurRow.Editor.PropDrawValue(Canvas,ValueRect,DrawState); 3041 Canvas.Font:=OldFont; 3042 end; 3043 CurRow.LastPaintedValue:=CurRow.Editor.GetVisualValue; 3044 end; 3045 3046 procedure DrawGutterToParent; 3047 var 3048 ParentRect: TRect; 3049 X: Integer; 3050 begin 3051 if ARow > 0 then 3052 begin 3053 ParentRect := RowRect(ARow - 1); 3054 X := ParentRect.Left + GetTreeIconX(ARow - 1) + Indent + 3; 3055 if X <> NameIconRect.Right then 3056 begin 3057 Canvas.MoveTo(NameIconRect.Right, NameRect.Top - 1 - FRowSpacing); 3058 Canvas.LineTo(X - 1, NameRect.Top - 1 - FRowSpacing); 3059 end; 3060 end; 3061 // to parent next sibling 3062 if ARow < FRows.Count - 1 then 3063 begin 3064 ParentRect := RowRect(ARow + 1); 3065 X := ParentRect.Left + GetTreeIconX(ARow + 1) + Indent + 3; 3066 if X <> NameIconRect.Right then 3067 begin 3068 Canvas.MoveTo(NameIconRect.Right, NameRect.Bottom - 1); 3069 Canvas.LineTo(X - 1, NameRect.Bottom - 1); 3070 end; 3071 end; 3072 end; 3073 3074var 3075 IconX: integer; 3076 DrawState: TPropEditDrawState; 3077begin 3078 CurRow := Rows[ARow]; 3079 FullRect := RowRect(ARow); 3080 if (FullRect.Bottom < FPaintRc.Top) or (FullRect.Top > FPaintRc.Bottom) then 3081 exit; 3082 NameRect := FullRect; 3083 ValueRect := FullRect; 3084 Inc(FullRect.Bottom, FRowSpacing); 3085 3086 if Layout = oilHorizontal then 3087 begin 3088 NameRect.Right:=SplitterX; 3089 ValueRect.Left:=SplitterX; 3090 end 3091 else begin 3092 NameRect.Bottom := NameRect.Top + GetNameRowHeight; 3093 ValueRect.Top := NameRect.Bottom; 3094 end; 3095 3096 IconX := GetTreeIconX(ARow); 3097 NameIconRect := NameRect; 3098 NameIconRect.Right := IconX + Indent; 3099 NameTextRect := NameRect; 3100 NameTextRect.Left := NameIconRect.Right; 3101 3102 if Layout = oilVertical then 3103 ValueRect.Left := NameTextRect.Left 3104 else 3105 begin 3106 inc(NameIconRect.Right, 2 + Ord(ShowGutter)); 3107 inc(NameTextRect.Left, 3 + Ord(ShowGutter)); 3108 end; 3109 3110 DrawState:=[]; 3111 if ARow = FItemIndex then 3112 Include(DrawState, pedsSelected); 3113 3114 ClearBackground; // clear background in one go 3115 DrawIcon(IconX); // draw icon 3116 DrawName(DrawState); // draw name 3117 DrawWidgetsets; // draw widgetsets 3118 DrawValue(DrawState); // draw value 3119 3120 with Canvas do 3121 begin 3122 if Layout = oilHorizontal then // frames 3123 begin 3124 // Row Divider 3125 if DrawHorzGridLines then 3126 begin 3127 Pen.Style := psDot; 3128 Pen.EndCap := pecFlat; 3129 Pen.Cosmetic := False; 3130 Pen.Color := cl3DShadow; 3131 if FRowSpacing <> 0 then 3132 begin 3133 MoveTo(NameTextRect.Left, NameRect.Top - 1); 3134 LineTo(ValueRect.Right, NameRect.Top - 1); 3135 end; 3136 MoveTo(NameTextRect.Left, NameRect.Bottom - 1); 3137 LineTo(ValueRect.Right, NameRect.Bottom - 1); 3138 end; 3139 3140 // Split lines between: icon and name, name and value 3141 Pen.Style := psSolid; 3142 Pen.Cosmetic := True; 3143 Pen.Color := cl3DHiLight; 3144 MoveTo(NameRect.Right - 1, NameRect.Bottom - 1); 3145 LineTo(NameRect.Right - 1, NameRect.Top - 1 - FRowSpacing); 3146 Pen.Color := cl3DShadow; 3147 MoveTo(NameRect.Right - 2, NameRect.Bottom - 1); 3148 LineTo(NameRect.Right - 2, NameRect.Top - 1 - FRowSpacing); 3149 3150 // draw gutter line 3151 if ShowGutter then 3152 begin 3153 Pen.Color := GutterEdgeColor; 3154 MoveTo(NameIconRect.Right, NameRect.Bottom - 1); 3155 LineTo(NameIconRect.Right, NameRect.Top - 1 - FRowSpacing); 3156 if CurRow.Lvl > 0 then 3157 DrawGutterToParent; 3158 end; 3159 end 3160 else begin // Layout <> oilHorizontal 3161 Pen.Style := psSolid; 3162 Pen.Color := cl3DLight; 3163 MoveTo(ValueRect.Left, ValueRect.Bottom - 1); 3164 LineTo(ValueRect.Left, NameTextRect.Top); 3165 LineTo(ValueRect.Right - 1, NameTextRect.Top); 3166 Pen.Color:=cl3DHiLight; 3167 LineTo(ValueRect.Right - 1, ValueRect.Bottom - 1); 3168 LineTo(ValueRect.Left, ValueRect.Bottom - 1); 3169 3170 MoveTo(NameTextRect.Left + 1, NametextRect.Bottom); 3171 LineTo(NameTextRect.Left + 1, NameTextRect.Top + 1); 3172 LineTo(NameTextRect.Right - 2, NameTextRect.Top + 1); 3173 Pen.Color:=cl3DLight; 3174 LineTo(NameTextRect.Right - 2, NameTextRect.Bottom - 1); 3175 LineTo(NameTextRect.Left + 2, NameTextRect.Bottom - 1); 3176 end; 3177 end; 3178end; 3179 3180procedure TOICustomPropertyGrid.DoPaint(PaintOnlyChangedValues: boolean); 3181var 3182 a: integer; 3183 SpaceRect: TRect; 3184 GutterX: Integer; 3185begin 3186 FPaintRc := Canvas.ClipRect; 3187 3188 BuildPropertyList(true); 3189 if not PaintOnlyChangedValues then 3190 begin 3191 with Canvas do 3192 begin 3193 // draw properties 3194 for a := 0 to FRows.Count - 1 do 3195 PaintRow(a); 3196 // draw unused space below rows 3197 SpaceRect := Rect(BorderWidth, BorderWidth, 3198 ClientWidth - BorderWidth + 1, ClientHeight - BorderWidth + 1); 3199 if FRows.Count > 0 then 3200 SpaceRect.Top := Rows[FRows.Count - 1].Bottom - FTopY + BorderWidth; 3201 if FBackgroundColor <> clNone then 3202 begin 3203 Brush.Color := FBackgroundColor; 3204 FillRect(SpaceRect); 3205 end; 3206 3207 // draw gutter if needed 3208 if ShowGutter and (Layout = oilHorizontal) then 3209 begin 3210 if FRows.Count > 0 then 3211 GutterX := RowRect(FRows.Count - 1).Left + GetTreeIconX(FRows.Count - 1) 3212 else 3213 GutterX := BorderWidth + 2; 3214 inc(GutterX, Indent + 3); 3215 SpaceRect.Right := GutterX; 3216 if GutterColor <> clNone then 3217 begin 3218 Brush.Color := GutterColor; 3219 FillRect(SpaceRect); 3220 end; 3221 MoveTo(GutterX, SpaceRect.Top); 3222 LineTo(GutterX, SpaceRect.Bottom); 3223 end; 3224 // don't draw border: borderstyle=bsSingle 3225 end; 3226 end else 3227 begin 3228 for a := 0 to FRows.Count-1 do 3229 begin 3230 if Rows[a].Editor.GetVisualValue <> Rows[a].LastPaintedValue then 3231 PaintRow(a); 3232 end; 3233 end; 3234end; 3235 3236procedure TOICustomPropertyGrid.Paint; 3237begin 3238 inherited Paint; 3239 DoPaint(false); 3240end; 3241 3242procedure TOICustomPropertyGrid.RefreshPropertyValues; 3243begin 3244 RefreshValueEdit; 3245 Invalidate; 3246end; 3247 3248procedure TOICustomPropertyGrid.ScrollToActiveItem; 3249begin 3250 ScrollToItem(FItemIndex); 3251end; 3252 3253procedure TOICustomPropertyGrid.ScrollToItem(NewIndex: Integer); 3254var 3255 NewRow: TOIPropertyGridRow; 3256begin 3257 if (NewIndex >= 0) and (NewIndex < FRows.Count) then 3258 begin 3259 NewRow := Rows[NewIndex]; 3260 if NewRow.Bottom >= TopY + (ClientHeight - 2*BorderWidth) then 3261 TopY := NewRow.Bottom- (ClientHeight - 2*BorderWidth) + 1 3262 else 3263 if NewRow.Top < TopY then TopY := NewRow.Top; 3264 end; 3265end; 3266 3267procedure TOICustomPropertyGrid.PropEditLookupRootChange; 3268begin 3269 // When the LookupRoot changes, no changes can be stored 3270 // -> undo the value editor changes 3271 RefreshValueEdit; 3272 if PropertyEditorHook<>nil then 3273 FCurrentEditorLookupRoot:=PropertyEditorHook.LookupRoot; 3274end; 3275 3276function TOICustomPropertyGrid.RowRect(ARow:integer):TRect; 3277const 3278 ScrollBarWidth=0; 3279begin 3280 Result.Left:=BorderWidth; 3281 Result.Top:=Rows[ARow].Top-FTopY+BorderWidth; 3282 Result.Right:=ClientWidth-ScrollBarWidth; 3283 Result.Bottom:=Rows[ARow].Bottom-FTopY+BorderWidth; 3284end; 3285 3286procedure TOICustomPropertyGrid.SetItemsTops; 3287// compute row tops from row heights 3288// set indices of all rows 3289var a:integer; 3290begin 3291 for a:=0 to FRows.Count-1 do begin 3292 Rows[a].FIndex:=a; 3293 Rows[a].MeasureHeight(Canvas); 3294 end; 3295 if FRows.Count>0 then 3296 Rows[0].Top:=0; 3297 for a:=1 to FRows.Count-1 do 3298 Rows[a].FTop:=Rows[a-1].Bottom + FRowSpacing; 3299end; 3300 3301procedure TOICustomPropertyGrid.ClearRows; 3302var i:integer; 3303begin 3304 IncreaseChangeStep; 3305 // reverse order to make sure child rows are freed before parent rows 3306 for i:=FRows.Count-1 downto 0 do begin 3307 //debugln(['TOICustomPropertyGrid.ClearRows ',i,' ',FRows.Count,' ',dbgs(frows[i])]); 3308 Rows[i].Free; 3309 FRows[i]:=nil; 3310 end; 3311 FRows.Clear; 3312end; 3313 3314function TOICustomPropertyGrid.GetCurrentEditValue: string; 3315begin 3316 if FCurrentEdit=ValueEdit then 3317 {$IFDEF LCLCarbon} 3318 Result:=StringReplace(ValueEdit.Text,LineFeedSymbolUTF8,LineEnding,[rfReplaceAll]) 3319 {$ELSE} 3320 Result:=ValueEdit.Text 3321 {$ENDIF} 3322 else if FCurrentEdit=ValueComboBox then 3323 Result:=ValueComboBox.Text 3324 else if FCurrentEdit=ValueCheckBox then 3325 Result:=ValueCheckBox.Caption 3326 else 3327 Result:=''; 3328end; 3329 3330procedure TOICustomPropertyGrid.SetActiveControl(const AControl: TWinControl); 3331var 3332 F: TCustomForm; 3333begin 3334 F := GetParentForm(Self); 3335 if F <> nil then 3336 F.ActiveControl := AControl; 3337end; 3338 3339procedure TOICustomPropertyGrid.SetColumn(const AValue: TOICustomPropertyGridColumn); 3340begin 3341 if FColumn <> AValue then 3342 begin 3343 FColumn := AValue; 3344 // TODO: indication 3345 end; 3346end; 3347 3348procedure TOICustomPropertyGrid.SetCurrentEditValue(const NewValue: string); 3349begin 3350 if FCurrentEdit=ValueEdit then 3351 {$IFDEF LCLCarbon} 3352 ValueEdit.Text:=StringReplace(StringReplace(NewValue,#13,LineEnding,[rfReplaceAll]),LineEnding,LineFeedSymbolUTF8,[rfReplaceAll]) 3353 {$ELSE} 3354 ValueEdit.Text:=NewValue 3355 {$ENDIF} 3356 else if FCurrentEdit=ValueComboBox then 3357 begin 3358 ValueComboBox.Text:=NewValue; 3359 if ValueComboBox.Style=csOwnerDrawVariable then 3360 Exclude(FStates,pgsGetComboItemsCalled); 3361 end 3362 else if FCurrentEdit=ValueCheckBox then 3363 SetCheckboxState(NewValue); 3364 3365 if (FItemIndex>=0) and (FItemIndex<RowCount) and Assigned(FCurrentEdit) then 3366 begin 3367 if Rows[FItemIndex].Editor.ValueIsStreamed then 3368 FCurrentEdit.Font:=FValueFont 3369 else 3370 FCurrentEdit.Font:=FDefaultValueFont; 3371 end; 3372end; 3373 3374procedure TOICustomPropertyGrid.SetDrawHorzGridLines(const AValue: Boolean); 3375begin 3376 if FDrawHorzGridLines = AValue then Exit; 3377 FDrawHorzGridLines := AValue; 3378 Invalidate; 3379end; 3380 3381procedure TOICustomPropertyGrid.SetFavorites( 3382 const AValue: TOIFavoriteProperties); 3383begin 3384 //debugln('TOICustomPropertyGrid.SetFavorites ',dbgsName(Self)); 3385 if FFavorites=AValue then exit; 3386 FFavorites:=AValue; 3387 BuildPropertyList; 3388end; 3389 3390procedure TOICustomPropertyGrid.SetFilter(const AValue: TTypeKinds); 3391begin 3392 if (AValue<>FFilter) then 3393 begin 3394 FFilter:=AValue; 3395 BuildPropertyList; 3396 end; 3397end; 3398 3399procedure TOICustomPropertyGrid.SetGutterColor(const AValue: TColor); 3400begin 3401 if FGutterColor=AValue then exit; 3402 FGutterColor:=AValue; 3403 invalidate; 3404end; 3405 3406procedure TOICustomPropertyGrid.SetGutterEdgeColor(const AValue: TColor); 3407begin 3408 if FGutterEdgeColor=AValue then exit; 3409 FGutterEdgeColor:=AValue; 3410 invalidate; 3411end; 3412 3413procedure TOICustomPropertyGrid.SetHighlightColor(const AValue: TColor); 3414begin 3415 if FHighlightColor=AValue then exit; 3416 FHighlightColor:=AValue; 3417 Invalidate; 3418end; 3419 3420procedure TOICustomPropertyGrid.Clear; 3421begin 3422 ClearRows; 3423end; 3424 3425function TOICustomPropertyGrid.GetRow(Index:integer):TOIPropertyGridRow; 3426begin 3427 Result:=TOIPropertyGridRow(FRows[Index]); 3428end; 3429 3430procedure TOICustomPropertyGrid.ValueComboBoxCloseUp(Sender: TObject); 3431begin 3432 SetRowValue(false, false); 3433end; 3434 3435procedure TOICustomPropertyGrid.ValueComboBoxGetItems(Sender: TObject); 3436{ This event is called whenever the widgetset updates the list. 3437 On gtk the list is updated just before the user popups the list. 3438 Other widgetsets need the list always, which is bad, as this means collecting 3439 all items even if the dropdown never happens. 3440} 3441var 3442 CurRow: TOIPropertyGridRow; 3443 MaxItemWidth, CurItemWidth, i, Cnt: integer; 3444 ItemValue, CurValue: string; 3445 NewItemIndex: LongInt; 3446 ExcludeUpdateFlag: boolean; 3447begin 3448 Include(FStates,pgsGetComboItemsCalled); 3449 if (FItemIndex>=0) and (FItemIndex<FRows.Count) then begin 3450 ExcludeUpdateFlag:=not (pgsUpdatingEditControl in FStates); 3451 Include(FStates,pgsUpdatingEditControl); 3452 ValueComboBox.Items.BeginUpdate; 3453 try 3454 CurRow:=Rows[FItemIndex]; 3455 3456 // Items 3457 if not FillComboboxItems then exit; 3458 3459 // Text and ItemIndex 3460 CurValue:=CurRow.Editor.GetVisualValue; 3461 ValueComboBox.Text:=CurValue; 3462 NewItemIndex:=ValueComboBox.Items.IndexOf(CurValue); 3463 if NewItemIndex>=0 then 3464 ValueComboBox.ItemIndex:=NewItemIndex; 3465 3466 // ItemWidth 3467 MaxItemWidth:=ValueComboBox.Width; 3468 Cnt:=ValueComboBox.Items.Count; 3469 for i:=0 to Cnt-1 do begin 3470 ItemValue:=ValueComboBox.Items[i]; 3471 CurItemWidth:=ValueComboBox.Canvas.TextWidth(ItemValue); 3472 CurRow.Editor.ListMeasureWidth(ItemValue,i,ValueComboBox.Canvas, 3473 CurItemWidth); 3474 if MaxItemWidth<CurItemWidth then 3475 MaxItemWidth:=CurItemWidth; 3476 end; 3477 ValueComboBox.ItemWidth:=MaxItemWidth; 3478 finally 3479 ValueComboBox.Items.EndUpdate; 3480 if ExcludeUpdateFlag then 3481 Exclude(FStates,pgsUpdatingEditControl); 3482 end; 3483 end; 3484end; 3485 3486procedure TOICustomPropertyGrid.ValueComboBoxDrawItem(Control: TWinControl; 3487 Index: Integer; ARect: TRect; State: TOwnerDrawState); 3488var 3489 CurRow: TOIPropertyGridRow; 3490 ItemValue: string; 3491 AState: TPropEditDrawState; 3492 FontColor: TColor; 3493begin 3494 if (FItemIndex>=0) and (FItemIndex<FRows.Count) then begin 3495 CurRow:=Rows[FItemIndex]; 3496 if (Index>=0) and (Index<ValueComboBox.Items.Count) then 3497 ItemValue:=ValueComboBox.Items[Index] 3498 else 3499 ItemValue:=''; 3500 AState:=[]; 3501 if odSelected in State then Include(AState,pedsSelected); 3502 if odFocused in State then Include(AState,pedsFocused); 3503 if odComboBoxEdit in State then 3504 Include(AState,pedsInEdit) 3505 else 3506 Include(AState,pedsInComboList); 3507 3508 if not(odBackgroundPainted in State) then 3509 ValueComboBox.Canvas.FillRect(ARect); 3510 3511 FontColor := ValueComboBox.Canvas.Font.Color; 3512 ValueComboBox.Canvas.Font.Assign(FDefaultValueFont); 3513 if odSelected in State then 3514 ValueComboBox.Canvas.Font.Color := FontColor 3515 else 3516 ValueComboBox.Canvas.Font.Color := clWindowText; 3517 if CurRow.Editor.HasDefaultValue and (ItemValue = CurRow.Editor.GetDefaultValue) then 3518 ValueComboBox.Canvas.Font.Style := ValueComboBox.Canvas.Font.Style + [fsItalic]; 3519 CurRow.Editor.ListDrawValue(ItemValue,Index,ValueComboBox.Canvas,ARect,AState); 3520 end; 3521end; 3522 3523procedure TOICustomPropertyGrid.OnIdle(Sender: TObject; var Done: Boolean); 3524begin 3525 if (not (pgsGetComboItemsCalled in FStates)) 3526 and (FCurrentEdit=ValueComboBox) 3527 and ValueComboBox.Enabled 3528 then begin 3529 ValueComboBoxGetItems(Self); 3530 end; 3531end; 3532 3533procedure TOICustomPropertyGrid.SetIdleEvent(Enable: boolean); 3534begin 3535 if (pgsIdleEnabled in FStates)=Enable then exit; 3536 if Enable then begin 3537 Application.AddOnIdleHandler(@OnIdle); 3538 Include(FStates,pgsIdleEnabled); 3539 end else begin 3540 Application.RemoveOnIdleHandler(@OnIdle); 3541 Exclude(FStates,pgsIdleEnabled); 3542 end; 3543end; 3544 3545procedure TOICustomPropertyGrid.HintTimer(Sender: TObject); 3546var 3547 PointedRow: TOIpropertyGridRow; 3548 Window: TWinControl; 3549 HintType: TPropEditHint; 3550 Position, ClientPosition: TPoint; 3551 Index: integer; 3552 AHint: String; 3553 OkToShow: Boolean; 3554begin 3555 if FLongHintTimer <> nil then 3556 FLongHintTimer.Enabled := False; 3557 Position := Mouse.CursorPos; 3558 Window := FindLCLWindow(Position); 3559 If (Window = Nil) or ((Window <> Self) and not IsParentOf(Window)) then exit; 3560 3561 ClientPosition := ScreenToClient(Position); 3562 if ((ClientPosition.X <=0) or (ClientPosition.X >= Width) or 3563 (ClientPosition.Y <= 0) or (ClientPosition.Y >= Height)) then 3564 Exit; 3565 3566 Index := MouseToIndex(ClientPosition.Y, False); 3567 // Don't show hint for the selected property. 3568 if (Index < 0) or (Index >= FRows.Count) or (Index = ItemIndex) then Exit; 3569 3570 PointedRow := Rows[Index]; 3571 if (PointedRow = Nil) or (PointedRow.Editor = Nil) then Exit; 3572 3573 // Get hint 3574 OkToShow := True; 3575 HintType := GetHintTypeAt(Index, ClientPosition.X); 3576 if (HintType = pehName) and Assigned(OnPropertyHint) then 3577 OkToShow := OnPropertyHint(Self, PointedRow, AHint) 3578 else 3579 AHint := PointedRow.Editor.GetHint(HintType, Position.X, Position.Y); 3580 // Show hint if all is well. 3581 if OkToShow and FHintManager.ShowHint(Position, AHint, True, Screen.HintFont) then 3582 begin 3583 FHintIndex := Index; 3584 FHintType := HintType; 3585 FShowingLongHint := True; 3586 end; 3587end; 3588 3589procedure TOICustomPropertyGrid.HideHint; 3590begin 3591 FHintIndex := -1; 3592 FShowingLongHint := False; 3593 FHintManager.HideHint; 3594end; 3595 3596procedure TOICustomPropertyGrid.ValueControlMouseDown(Sender : TObject; 3597 Button: TMouseButton; Shift: TShiftState; X, Y: integer); 3598begin 3599 HideHint; 3600 ScrollToActiveItem; 3601end; 3602 3603procedure TOICustomPropertyGrid.ValueControlMouseMove(Sender: TObject; 3604 Shift: TShiftState; X, Y: integer); 3605begin 3606 // when the cursor is divider change it to default 3607 if (Sender as TControl).Parent.Cursor <> crDefault then 3608 TControl(Sender).Parent.Cursor := crDefault; 3609end; 3610 3611procedure TOICustomPropertyGrid.IncreaseChangeStep; 3612begin 3613 if FChangeStep<>$7fffffff then 3614 inc(FChangeStep) 3615 else 3616 FChangeStep:=-$7fffffff; 3617end; 3618 3619function TOICustomPropertyGrid.GridIsUpdating: boolean; 3620begin 3621 Result:=(FStates*[pgsChangingItemIndex,pgsApplyingValue, 3622 pgsBuildPropertyListNeeded]<>[]) 3623end; 3624 3625procedure TOICustomPropertyGrid.ToggleRow; 3626var 3627 CurRow: TOIPropertyGridRow; 3628 TypeKind : TTypeKind; 3629 NewIndex: Integer; 3630begin 3631 if not CanEditRowValue(false) then exit; 3632 3633 if FLongHintTimer <> nil then 3634 FLongHintTimer.Enabled := False; 3635 3636 if (FCurrentEdit = ValueComboBox) then 3637 begin 3638 CurRow := Rows[FItemIndex]; 3639 TypeKind := CurRow.Editor.GetPropType^.Kind; 3640 // Integer (like TImageIndex), Enumeration, Set, Class or Boolean ComboBox 3641 if TypeKind in [tkInteger, tkEnumeration, tkSet, tkClass, tkBool] then 3642 begin 3643 if ValueComboBox.Items.Count = 0 then Exit; 3644 // Pick the next value from list 3645 if ValueComboBox.ItemIndex < (ValueComboBox.Items.Count-1) then 3646 begin 3647 NewIndex := ValueComboBox.ItemIndex + 1; 3648 // Go to first object of tkClass. Skip '(none)' which can be in different 3649 // places depending on widgetset sorting rules. 3650 if (ValueComboBox.ItemIndex = -1) // Only happen at nil value of tkClass 3651 and (ValueComboBox.Items[NewIndex] = oisNone) 3652 and (NewIndex < (ValueComboBox.Items.Count-1)) then 3653 Inc(NewIndex); 3654 end 3655 else 3656 NewIndex := 0; 3657 ValueComboBox.ItemIndex := NewIndex; 3658 SetRowValue(false, false); 3659 exit; 3660 end; 3661 end; 3662 DoCallEdit; 3663end; 3664 3665procedure TOICustomPropertyGrid.ValueEditDblClick(Sender: TObject); 3666begin 3667 FFirstClickTime:=0; 3668 ToggleRow; 3669end; 3670 3671procedure TOICustomPropertyGrid.SetBackgroundColor(const AValue: TColor); 3672begin 3673 if FBackgroundColor=AValue then exit; 3674 FBackgroundColor:=AValue; 3675 Invalidate; 3676end; 3677 3678procedure TOICustomPropertyGrid.SetReferences(const AValue: TColor); 3679begin 3680 if FReferencesColor=AValue then exit; 3681 FReferencesColor:=AValue; 3682 Invalidate; 3683end; 3684 3685procedure TOICustomPropertyGrid.SetSubPropertiesColor(const AValue: TColor); 3686begin 3687 if FSubPropertiesColor=AValue then exit; 3688 FSubPropertiesColor:=AValue; 3689 Invalidate; 3690end; 3691 3692procedure TOICustomPropertyGrid.SetValueDifferBackgrndColor(AValue: TColor); 3693begin 3694 if FValueDifferBackgrndColor=AValue then Exit; 3695 FValueDifferBackgrndColor:=AValue; 3696 Invalidate; 3697end; 3698 3699//------------------------------------------------------------------------------ 3700 3701{ TOIPropertyGridRow } 3702 3703constructor TOIPropertyGridRow.Create(PropertyTree: TOICustomPropertyGrid; 3704 PropEditor:TPropertyEditor; ParentNode:TOIPropertyGridRow; WidgetSets: TLCLPlatforms); 3705begin 3706 inherited Create; 3707 // tree pointer 3708 FTree:=PropertyTree; 3709 FParent:=ParentNode; 3710 FNextBrother:=nil; 3711 FPriorBrother:=nil; 3712 FExpanded:=false; 3713 // child nodes 3714 FChildCount:=0; 3715 FFirstChild:=nil; 3716 FLastChild:=nil; 3717 // director 3718 FEditor:=PropEditor; 3719 GetLvl; 3720 FName:=FEditor.GetName; 3721 FTop:=0; 3722 FHeight:=FTree.RealDefaultItemHeight; 3723 FIndex:=-1; 3724 LastPaintedValue:=''; 3725 FWidgetSets:=WidgetSets; 3726end; 3727 3728destructor TOIPropertyGridRow.Destroy; 3729begin 3730 //debugln(['TOIPropertyGridRow.Destroy ',fname,' ',dbgs(Pointer(Self))]); 3731 if FPriorBrother<>nil then FPriorBrother.FNextBrother:=FNextBrother; 3732 if FNextBrother<>nil then FNextBrother.FPriorBrother:=FPriorBrother; 3733 if FParent<>nil then begin 3734 if FParent.FFirstChild=Self then FParent.FFirstChild:=FNextBrother; 3735 if FParent.FLastChild=Self then FParent.FLastChild:=FPriorBrother; 3736 dec(FParent.FChildCount); 3737 end; 3738 if FEditor<>nil then FEditor.Free; 3739 inherited Destroy; 3740end; 3741 3742function TOIPropertyGridRow.ConsistencyCheck: integer; 3743var 3744 OldLvl, RealChildCount: integer; 3745 AChild: TOIPropertyGridRow; 3746begin 3747 if Top<0 then 3748 exit(-1); 3749 if Height<0 then 3750 exit(-2); 3751 if Lvl<0 then 3752 exit(-3); 3753 OldLvl:=Lvl; 3754 GetLvl; 3755 if Lvl<>OldLvl then 3756 exit(-4); 3757 if Name='' then 3758 exit(-5); 3759 if NextBrother<>nil then begin 3760 if NextBrother.PriorBrother<>Self then 3761 exit(-6); 3762 if NextBrother.Index<Index+1 then 3763 exit(-7); 3764 end; 3765 if PriorBrother<>nil then begin 3766 if PriorBrother.NextBrother<>Self then 3767 exit(-8); 3768 if PriorBrother.Index>Index-1 then 3769 Result:=-9 3770 end; 3771 if (Parent<>nil) then begin 3772 // has parent 3773 if (not Parent.HasChild(Self)) then 3774 exit(-10); 3775 end else begin 3776 // no parent 3777 end; 3778 if FirstChild<>nil then begin 3779 if Expanded then 3780 if (FirstChild.Index<>Index+1) then 3781 exit(-11); 3782 end else begin 3783 if LastChild<>nil then 3784 exit(-12); 3785 end; 3786 RealChildCount:=0; 3787 AChild:=FirstChild; 3788 while AChild<>nil do begin 3789 if AChild.Parent<>Self then 3790 exit(-13); 3791 inc(RealChildCount); 3792 AChild:=AChild.NextBrother; 3793 end; 3794 if RealChildCount<>ChildCount then 3795 exit(-14); 3796 Result:=0; 3797end; 3798 3799function TOIPropertyGridRow.HasChild(Row: TOIPropertyGridRow): boolean; 3800var 3801 ChildRow: TOIPropertyGridRow; 3802begin 3803 ChildRow:=FirstChild; 3804 while ChildRow<>nil do 3805 if ChildRow=Row then 3806 exit(true); 3807 Result:=false; 3808end; 3809 3810procedure TOIPropertyGridRow.WriteDebugReport(const Prefix: string); 3811var 3812 i: Integer; 3813 Item: TOIPropertyGridRow; 3814begin 3815 DebugLn([Prefix+'TOIPropertyGridRow.WriteDebugReport ',Name]); 3816 i:=0; 3817 Item:=FirstChild; 3818 while Item<>nil do begin 3819 DebugLn([Prefix+' ',i,' ',Item.Name]); 3820 inc(i); 3821 Item:=Item.NextBrother; 3822 end; 3823end; 3824 3825procedure TOIPropertyGridRow.GetLvl; 3826var n:TOIPropertyGridRow; 3827begin 3828 FLvl:=0; 3829 n:=FParent; 3830 while n<>nil do begin 3831 inc(FLvl); 3832 n:=n.FParent; 3833 end; 3834end; 3835 3836function TOIPropertyGridRow.GetBottom:integer; 3837begin 3838 Result:=FTop+FHeight; 3839 if FTree.Layout = oilVertical 3840 then Inc(Result, FTree.GetNameRowHeight); 3841end; 3842 3843function TOIPropertyGridRow.IsReadOnly: boolean; 3844begin 3845 Result:=Editor.IsReadOnly or IsDisabled; 3846end; 3847 3848function TOIPropertyGridRow.IsDisabled: boolean; 3849var 3850 CurRow: TOIPropertyGridRow; 3851begin 3852 CurRow:=Self; 3853 while (CurRow<>nil) do begin 3854 if paDisableSubProperties in CurRow.Editor.GetAttributes then 3855 exit(true); 3856 CurRow:=CurRow.Parent; 3857 end; 3858 Result:=false; 3859end; 3860 3861procedure TOIPropertyGridRow.MeasureHeight(ACanvas: TCanvas); 3862begin 3863 FHeight:=FTree.RealDefaultItemHeight; 3864 Editor.PropMeasureHeight(Name,ACanvas,FHeight); 3865end; 3866 3867function TOIPropertyGridRow.Sort(const Compare: TListSortCompare): boolean; 3868var 3869 List: TFPList; 3870 Item: TOIPropertyGridRow; 3871 i: Integer; 3872begin 3873 if IsSorted(Compare) then exit(false); 3874 List:=TFPList.Create; 3875 try 3876 // create a TFPList of the children 3877 List.Capacity:=ChildCount; 3878 Item:=FirstChild; 3879 while Item<>nil do begin 3880 List.Add(Item); 3881 Item:=Item.NextBrother; 3882 end; 3883 // sort the TFPList 3884 List.Sort(Compare); 3885 // sort in double linked list 3886 for i:=0 to List.Count-1 do begin 3887 Item:=TOIPropertyGridRow(List[i]); 3888 if i=0 then begin 3889 FFirstChild:=Item; 3890 Item.FPriorBrother:=nil; 3891 end else 3892 Item.FPriorBrother:=TOIPropertyGridRow(List[i-1]); 3893 if i=List.Count-1 then begin 3894 FLastChild:=Item; 3895 Item.FNextBrother:=nil; 3896 end else 3897 Item.FNextBrother:=TOIPropertyGridRow(List[i+1]); 3898 end; 3899 finally 3900 List.Free; 3901 end; 3902 Result:=true; 3903end; 3904 3905function TOIPropertyGridRow.IsSorted(const Compare: TListSortCompare): boolean; 3906var 3907 Item1: TOIPropertyGridRow; 3908 Item2: TOIPropertyGridRow; 3909begin 3910 if ChildCount<2 then exit(true); 3911 Item1:=FirstChild; 3912 while true do begin 3913 Item2:=Item1.NextBrother; 3914 if Item2=nil then break; 3915 if Compare(Item1,Item2)>0 then exit(false); 3916 Item1:=Item2; 3917 end; 3918 Result:=true; 3919end; 3920 3921function TOIPropertyGridRow.Next: TOIPropertyGridRow; 3922begin 3923 if fFirstChild<>nil then 3924 Result:=fFirstChild 3925 else 3926 Result:=NextSkipChilds; 3927end; 3928 3929function TOIPropertyGridRow.NextSkipChilds: TOIPropertyGridRow; 3930begin 3931 Result:=Self; 3932 while (Result<>nil) do begin 3933 if Result.NextBrother<>nil then begin 3934 Result:=Result.NextBrother; 3935 exit; 3936 end; 3937 Result:=Result.Parent; 3938 end; 3939end; 3940 3941//============================================================================== 3942 3943 3944{ TOIOptions } 3945 3946function TOIOptions.FPropertyGridSplitterX(Page: TObjectInspectorPage): integer; 3947begin 3948 Result:=FGridSplitterX[Page]; 3949end; 3950 3951procedure TOIOptions.FPropertyGridSplitterX(Page: TObjectInspectorPage; 3952 const AValue: integer); 3953begin 3954 FGridSplitterX[Page]:=AValue; 3955end; 3956 3957constructor TOIOptions.Create; 3958var 3959 p: TObjectInspectorPage; 3960begin 3961 inherited Create; 3962 3963 FSaveBounds:=false; 3964 FLeft:=0; 3965 FTop:=0; 3966 FWidth:=250; 3967 FHeight:=400; 3968 for p:=Low(TObjectInspectorPage) to High(TObjectInspectorPage) do 3969 FGridSplitterX[p]:=110; 3970 FDefaultItemHeight:=0; 3971 FShowComponentTree:=true; 3972 FComponentTreeHeight:=160; 3973 FInfoBoxHeight:=80; 3974 3975 FGridBackgroundColor := DefBackgroundColor; 3976 FSubPropertiesColor := DefSubPropertiesColor; 3977 FValueColor := DefValueColor; 3978 FDefaultValueColor := DefDefaultValueColor; 3979 FValueDifferBackgrndColor := DefValueDifferBackgrndColor; 3980 FReadOnlyColor := DefReadOnlyColor; 3981 FReferencesColor := DefReferencesColor; 3982 FPropertyNameColor := DefNameColor; 3983 FHighlightColor := DefHighlightColor; 3984 FHighlightFontColor := DefHighlightFontColor; 3985 FGutterColor := DefGutterColor; 3986 FGutterEdgeColor := DefGutterEdgeColor; 3987 3988 FCheckboxForBoolean := True; 3989 FBoldNonDefaultValues := True; 3990 FDrawGridLines := True; 3991 FShowPropertyFilter := True; 3992 FShowGutter := True; 3993 FShowStatusBar := True; 3994 FShowInfoBox := True; 3995end; 3996 3997function TOIOptions.Load: boolean; 3998var 3999 Path: String; 4000 FileVersion: integer; 4001 Page: TObjectInspectorPage; 4002begin 4003 Result:=False; 4004 if ConfigStore=nil then exit; 4005 try 4006 Path:='ObjectInspectorOptions/'; 4007 FileVersion:=ConfigStore.GetValue(Path+'Version/Value',0); 4008 FSaveBounds:=ConfigStore.GetValue(Path+'Bounds/Valid',False); 4009 if FSaveBounds then begin 4010 FLeft:=ConfigStore.GetValue(Path+'Bounds/Left',0); 4011 FTop:=ConfigStore.GetValue(Path+'Bounds/Top',0); 4012 FWidth:=ConfigStore.GetValue(Path+'Bounds/Width',250); 4013 FHeight:=ConfigStore.GetValue(Path+'Bounds/Height',400); 4014 end; 4015 if FileVersion>=2 then begin 4016 for Page:=Low(TObjectInspectorPage) to High(TObjectInspectorPage) do 4017 FGridSplitterX[Page]:=ConfigStore.GetValue( 4018 Path+'Bounds/'+DefaultOIPageNames[Page]+'/SplitterX',110); 4019 end else begin 4020 FGridSplitterX[oipgpProperties]:=ConfigStore.GetValue(Path+'Bounds/PropertyGridSplitterX',110); 4021 FGridSplitterX[oipgpEvents]:=ConfigStore.GetValue(Path+'Bounds/EventGridSplitterX',110); 4022 end; 4023 for Page:=Low(TObjectInspectorPage) to High(TObjectInspectorPage) do 4024 if FGridSplitterX[Page]<10 then 4025 FGridSplitterX[Page]:=10; 4026 4027 FDefaultItemHeight:=ConfigStore.GetValue(Path+'Bounds/DefaultItemHeight',0); 4028 FShowComponentTree:=ConfigStore.GetValue(Path+'ComponentTree/Show/Value',True); 4029 FComponentTreeHeight:=ConfigStore.GetValue(Path+'ComponentTree/Height/Value',160); 4030 4031 FGridBackgroundColor:=ConfigStore.GetValue(Path+'Color/GridBackground',DefBackgroundColor); 4032 FSubPropertiesColor:=ConfigStore.GetValue(Path+'Color/SubProperties',DefSubPropertiesColor); 4033 FValueColor:=ConfigStore.GetValue(Path+'Color/Value',DefValueColor); 4034 FDefaultValueColor:=ConfigStore.GetValue(Path+'Color/DefaultValue',DefDefaultValueColor); 4035 FValueDifferBackgrndColor:=ConfigStore.GetValue(Path+'Color/ValueDifferBackgrnd',DefValueDifferBackgrndColor); 4036 FReadOnlyColor:=ConfigStore.GetValue(Path+'Color/ReadOnly',DefReadOnlyColor); 4037 FReferencesColor:=ConfigStore.GetValue(Path+'Color/References',DefReferencesColor); 4038 FPropertyNameColor:=ConfigStore.GetValue(Path+'Color/PropertyName',DefNameColor); 4039 FHighlightColor:=ConfigStore.GetValue(Path+'Color/Highlight',DefHighlightColor); 4040 FHighlightFontColor:=ConfigStore.GetValue(Path+'Color/HighlightFont',DefHighlightFontColor); 4041 FGutterColor:=ConfigStore.GetValue(Path+'Color/Gutter',DefGutterColor); 4042 FGutterEdgeColor:=ConfigStore.GetValue(Path+'Color/GutterEdge',DefGutterEdgeColor); 4043 4044 FShowHints:=ConfigStore.GetValue(Path+'ShowHints',FileVersion>=3); 4045 FAutoShow := ConfigStore.GetValue(Path+'AutoShow',True); 4046 FCheckboxForBoolean := ConfigStore.GetValue(Path+'CheckboxForBoolean',True); 4047 FBoldNonDefaultValues := ConfigStore.GetValue(Path+'BoldNonDefaultValues',True); 4048 FDrawGridLines := ConfigStore.GetValue(Path+'DrawGridLines',True); 4049 FShowPropertyFilter := ConfigStore.GetValue(Path+'ShowPropertyFilter',True); 4050 FShowGutter := ConfigStore.GetValue(Path+'ShowGutter',True); 4051 FShowStatusBar := ConfigStore.GetValue(Path+'ShowStatusBar',True); 4052 FShowInfoBox := ConfigStore.GetValue(Path+'ShowInfoBox',True); 4053 FInfoBoxHeight := ConfigStore.GetValue(Path+'InfoBoxHeight',80); 4054 except 4055 on E: Exception do begin 4056 DebugLn('ERROR: TOIOptions.Load: ',E.Message); 4057 exit; 4058 end; 4059 end; 4060 Result:=True; 4061end; 4062 4063function TOIOptions.Save: boolean; 4064var 4065 Page: TObjectInspectorPage; 4066 Path: String; 4067begin 4068 Result:=False; 4069 if ConfigStore=nil then exit; 4070 try 4071 Path:='ObjectInspectorOptions/'; 4072 ConfigStore.SetValue(Path+'Version/Value',OIOptionsFileVersion); 4073 ConfigStore.SetDeleteValue(Path+'Bounds/Valid',FSaveBounds,False); 4074 if FSaveBounds then begin 4075 ConfigStore.SetValue(Path+'Bounds/Left',FLeft); 4076 ConfigStore.SetValue(Path+'Bounds/Top',FTop); 4077 ConfigStore.SetValue(Path+'Bounds/Width',FWidth); 4078 ConfigStore.SetValue(Path+'Bounds/Height',FHeight); 4079 end; 4080 for Page:=Low(TObjectInspectorPage) to High(TObjectInspectorPage) do 4081 ConfigStore.SetDeleteValue(Path+'Bounds/'+DefaultOIPageNames[Page]+'/SplitterX', 4082 FGridSplitterX[Page],110); 4083 ConfigStore.SetDeleteValue(Path+'Bounds/DefaultItemHeight',FDefaultItemHeight,0); 4084 ConfigStore.SetDeleteValue(Path+'ComponentTree/Show/Value',FShowComponentTree,True); 4085 ConfigStore.SetDeleteValue(Path+'ComponentTree/Height/Value',FComponentTreeHeight,160); 4086 4087 ConfigStore.SetDeleteValue(Path+'Color/GridBackground',FGridBackgroundColor,DefBackgroundColor); 4088 ConfigStore.SetDeleteValue(Path+'Color/SubProperties',FSubPropertiesColor,DefSubPropertiesColor); 4089 ConfigStore.SetDeleteValue(Path+'Color/Value',FValueColor,DefValueColor); 4090 ConfigStore.SetDeleteValue(Path+'Color/DefaultValue',FDefaultValueColor,DefDefaultValueColor); 4091 ConfigStore.SetDeleteValue(Path+'Color/ValueDifferBackgrnd',FValueDifferBackgrndColor,DefValueDifferBackgrndColor); 4092 ConfigStore.SetDeleteValue(Path+'Color/ReadOnly',FReadOnlyColor,DefReadOnlyColor); 4093 ConfigStore.SetDeleteValue(Path+'Color/References',FReferencesColor,DefReferencesColor); 4094 ConfigStore.SetDeleteValue(Path+'Color/PropertyName',FPropertyNameColor,DefNameColor); 4095 ConfigStore.SetDeleteValue(Path+'Color/Highlight',FHighlightColor,DefHighlightColor); 4096 ConfigStore.SetDeleteValue(Path+'Color/HighlightFont',FHighlightFontColor,DefHighlightFontColor); 4097 ConfigStore.SetDeleteValue(Path+'Color/Gutter',FGutterColor,DefGutterColor); 4098 ConfigStore.SetDeleteValue(Path+'Color/GutterEdge',FGutterEdgeColor,DefGutterEdgeColor); 4099 4100 ConfigStore.SetDeleteValue(Path+'ShowHints',FShowHints, True); 4101 ConfigStore.SetDeleteValue(Path+'AutoShow',FAutoShow, True); 4102 ConfigStore.SetDeleteValue(Path+'CheckboxForBoolean',FCheckboxForBoolean, True); 4103 ConfigStore.SetDeleteValue(Path+'BoldNonDefaultValues',FBoldNonDefaultValues, True); 4104 ConfigStore.SetDeleteValue(Path+'DrawGridLines',FDrawGridLines, True); 4105 ConfigStore.SetDeleteValue(Path+'ShowPropertyFilter',FShowPropertyFilter, True); 4106 ConfigStore.SetDeleteValue(Path+'ShowGutter',FShowGutter, True); 4107 ConfigStore.SetDeleteValue(Path+'ShowStatusBar',FShowStatusBar, True); 4108 ConfigStore.SetDeleteValue(Path+'ShowInfoBox',FShowInfoBox, True); 4109 ConfigStore.SetDeleteValue(Path+'InfoBoxHeight',FInfoBoxHeight,80); 4110 except 4111 on E: Exception do begin 4112 DebugLn('ERROR: TOIOptions.Save: ',E.Message); 4113 exit; 4114 end; 4115 end; 4116 Result:=true; 4117end; 4118 4119procedure TOIOptions.Assign(AnObjInspector: TObjectInspectorDlg); 4120var 4121 Page: TObjectInspectorPage; 4122begin 4123 FLeft:=AnObjInspector.Left; 4124 FTop:=AnObjInspector.Top; 4125 FWidth:=AnObjInspector.Width; 4126 FHeight:=AnObjInspector.Height; 4127 for Page:=Low(TObjectInspectorPage) to High(TObjectInspectorPage) do 4128 if AnObjInspector.GridControl[Page]<>nil then 4129 FGridSplitterX[Page]:=AnObjInspector.GridControl[Page].PreferredSplitterX; 4130 FDefaultItemHeight:=AnObjInspector.DefaultItemHeight; 4131 FShowComponentTree:=AnObjInspector.ShowComponentTree; 4132 FComponentTreeHeight:=AnObjInspector.ComponentPanelHeight; 4133 4134 FGridBackgroundColor:=AnObjInspector.PropertyGrid.BackgroundColor; 4135 FSubPropertiesColor:=AnObjInspector.PropertyGrid.SubPropertiesColor; 4136 FReferencesColor:=AnObjInspector.PropertyGrid.ReferencesColor; 4137 FValueColor:=AnObjInspector.PropertyGrid.ValueFont.Color; 4138 FDefaultValueColor:=AnObjInspector.PropertyGrid.DefaultValueFont.Color; 4139 FValueDifferBackgrndColor:=AnObjInspector.PropertyGrid.ValueDifferBackgrndColor; 4140 FReadOnlyColor:=AnObjInspector.PropertyGrid.ReadOnlyColor; 4141 FPropertyNameColor:=AnObjInspector.PropertyGrid.NameFont.Color; 4142 FHighlightColor:=AnObjInspector.PropertyGrid.HighlightColor; 4143 FHighlightFontColor:=AnObjInspector.PropertyGrid.HighlightFont.Color; 4144 FGutterColor:=AnObjInspector.PropertyGrid.GutterColor; 4145 FGutterEdgeColor:=AnObjInspector.PropertyGrid.GutterEdgeColor; 4146 4147 FShowHints := AnObjInspector.PropertyGrid.ShowHint; 4148 FAutoShow := AnObjInspector.AutoShow; 4149 FCheckboxForBoolean := AnObjInspector.FCheckboxForBoolean; 4150 FBoldNonDefaultValues := fsBold in AnObjInspector.PropertyGrid.ValueFont.Style; 4151 FDrawGridLines := AnObjInspector.PropertyGrid.DrawHorzGridLines; 4152 FShowPropertyFilter := AnObjInspector.ShowPropertyFilter; 4153 FShowGutter := AnObjInspector.PropertyGrid.ShowGutter; 4154 FShowStatusBar := AnObjInspector.ShowStatusBar; 4155 FShowInfoBox := AnObjInspector.ShowInfoBox; 4156 FInfoBoxHeight := AnObjInspector.InfoBoxHeight; 4157end; 4158 4159procedure TOIOptions.AssignTo(AnObjInspector: TObjectInspectorDlg); 4160var 4161 Page: TObjectInspectorPage; 4162 Grid: TOICustomPropertyGrid; 4163begin 4164 if FSaveBounds then 4165 begin 4166 AnObjInspector.SetBounds(FLeft,FTop,FWidth,FHeight); 4167 end; 4168 4169 for Page := Low(TObjectInspectorPage) to High(TObjectInspectorPage) do 4170 begin 4171 Grid := AnObjInspector.GridControl[Page]; 4172 if Grid = nil then 4173 Continue; 4174 Grid.PreferredSplitterX := FGridSplitterX[Page]; 4175 Grid.SplitterX := FGridSplitterX[Page]; 4176 AssignTo(Grid); 4177 end; 4178 AnObjInspector.DefaultItemHeight := DefaultItemHeight; 4179 AnObjInspector.AutoShow := AutoShow; 4180 AnObjInspector.FCheckboxForBoolean := FCheckboxForBoolean; 4181 AnObjInspector.ShowComponentTree := ShowComponentTree; 4182 AnObjInspector.ShowPropertyFilter := ShowPropertyFilter; 4183 AnObjInspector.ShowInfoBox := ShowInfoBox; 4184 AnObjInspector.ComponentPanelHeight := ComponentTreeHeight; 4185 AnObjInspector.InfoBoxHeight := InfoBoxHeight; 4186 AnObjInspector.ShowStatusBar := ShowStatusBar; 4187end; 4188 4189procedure TOIOptions.AssignTo(AGrid: TOICustomPropertyGrid); 4190begin 4191 AGrid.BackgroundColor := FGridBackgroundColor; 4192 AGrid.SubPropertiesColor := FSubPropertiesColor; 4193 AGrid.ReferencesColor := FReferencesColor; 4194 AGrid.ReadOnlyColor := FReadOnlyColor; 4195 AGrid.ValueDifferBackgrndColor := FValueDifferBackgrndColor; 4196 AGrid.ValueFont.Color := FValueColor; 4197 if FBoldNonDefaultValues then 4198 AGrid.ValueFont.Style := [fsBold] 4199 else 4200 AGrid.ValueFont.Style := []; 4201 AGrid.DefaultValueFont.Color := FDefaultValueColor; 4202 AGrid.NameFont.Color := FPropertyNameColor; 4203 AGrid.HighlightColor := FHighlightColor; 4204 AGrid.HighlightFont.Color := FHighlightFontColor; 4205 AGrid.GutterColor := FGutterColor; 4206 AGrid.GutterEdgeColor := FGutterEdgeColor; 4207 AGrid.ShowHint := FShowHints; 4208 AGrid.DrawHorzGridLines := FDrawGridLines; 4209 AGrid.ShowGutter := FShowGutter; 4210 AGrid.CheckboxForBoolean := FCheckboxForBoolean; 4211end; 4212 4213 4214//============================================================================== 4215 4216{ TObjectInspectorDlg } 4217 4218constructor TObjectInspectorDlg.Create(AnOwner: TComponent); 4219 4220 procedure AddPopupMenuItem(var NewMenuItem: TMenuItem; 4221 ParentMenuItem: TMenuItem; const AName, ACaption, AHint, AResourceName: string; 4222 AnOnClick: TNotifyEvent; CheckedFlag, EnabledFlag, VisibleFlag: boolean); 4223 begin 4224 NewMenuItem:=TMenuItem.Create(Self); 4225 with NewMenuItem do 4226 begin 4227 Name:=AName; 4228 Caption:=ACaption; 4229 Hint:=AHint; 4230 OnClick:=AnOnClick; 4231 Checked:=CheckedFlag; 4232 Enabled:=EnabledFlag; 4233 Visible:=VisibleFlag; 4234 if AResourceName <> '' then 4235 ImageIndex := IDEImages.LoadImage(AResourceName); 4236 end; 4237 if ParentMenuItem<>nil then 4238 ParentMenuItem.Add(NewMenuItem) 4239 else 4240 MainPopupMenu.Items.Add(NewMenuItem); 4241 end; 4242 4243 function AddSeparatorMenuItem(ParentMenuItem: TMenuItem; const AName: string; VisibleFlag: boolean): TMenuItem; 4244 begin 4245 Result := TMenuItem.Create(Self); 4246 with Result do 4247 begin 4248 Name := AName; 4249 Caption := cLineCaption; 4250 Visible := VisibleFlag; 4251 end; 4252 if ParentMenuItem <> nil then 4253 ParentMenuItem.Add(Result) 4254 else 4255 MainPopupMenu.Items.Add(Result); 4256 end; 4257 4258begin 4259 inherited Create(AnOwner); 4260 FEnableHookGetSelection := true; 4261 FPropertyEditorHook := nil; 4262 FSelection := TPersistentSelectionList.Create; 4263 FAutoShow := True; 4264 FDefaultItemHeight := 0; 4265 ComponentPanelHeight := 160; 4266 FShowComponentTree := True; 4267 FShowPropertyFilter := True; 4268 FShowFavorites := False; 4269 FShowRestricted := False; 4270 FShowStatusBar := True; 4271 FInfoBoxHeight := 80; 4272 FPropFilterUpdating := False; 4273 FShowInfoBox := True; 4274 FComponentEditor := nil; 4275 FFilter := DefaultOITypeKinds; 4276 4277 Caption := oisObjectInspector; 4278 CompFilterLabel.Caption := oisBtnComponents; 4279 MainPopupMenu.Images := IDEImages.Images_16; 4280 4281 AddPopupMenuItem(AddToFavoritesPopupMenuItem,nil,'AddToFavoritePopupMenuItem', 4282 oisAddtofavorites,'Add property to favorites properties', '', 4283 @AddToFavoritesPopupmenuItemClick,false,true,true); 4284 AddPopupMenuItem(RemoveFromFavoritesPopupMenuItem,nil, 4285 'RemoveFromFavoritesPopupMenuItem', 4286 oisRemovefromfavorites,'Remove property from favorites properties', '', 4287 @RemoveFromFavoritesPopupmenuItemClick,false,true,true); 4288 AddPopupMenuItem(ViewRestrictedPropertiesPopupMenuItem,nil, 4289 'ViewRestrictedPropertiesPopupMenuItem', 4290 oisViewRestrictedProperties,'View restricted property descriptions', '', 4291 @ViewRestrictionsPopupmenuItemClick,false,true,true); 4292 AddPopupMenuItem(UndoPropertyPopupMenuItem,nil,'UndoPropertyPopupMenuItem', 4293 oisUndo,'Set property value to last valid value', '', 4294 @UndoPopupmenuItemClick,false,true,true); 4295 AddPopupMenuItem(FindDeclarationPopupmenuItem,nil,'FindDeclarationPopupmenuItem', 4296 oisFinddeclaration,'Jump to declaration of property', '', 4297 @FindDeclarationPopupmenuItemClick,false,true,false); 4298 OptionsSeparatorMenuItem := AddSeparatorMenuItem(nil, 'OptionsSeparatorMenuItem', true); 4299 4300 AddPopupMenuItem(CutPopupMenuItem,nil,'CutPopupMenuItem', 4301 oisCutComponents,'Cut selected item', 'laz_cut', 4302 @CutPopupmenuItemClick,false,true,true); 4303 AddPopupMenuItem(CopyPopupMenuItem,nil,'CopyPopupMenuItem', 4304 oisCopyComponents,'Copy selected item', 'laz_copy', 4305 @CopyPopupmenuItemClick,false,true,true); 4306 AddPopupMenuItem(PastePopupMenuItem,nil,'PastePopupMenuItem', 4307 oisPasteComponents,'Paste selected item', 'laz_paste', 4308 @PastePopupmenuItemClick,false,true,true); 4309 AddPopupMenuItem(DeletePopupMenuItem,nil,'DeletePopupMenuItem', 4310 oisDeleteComponents,'Delete selected item', 'delete_selection', 4311 @DeletePopupmenuItemClick,false,true,true); 4312 OptionsSeparatorMenuItem2 := AddSeparatorMenuItem(nil, 'OptionsSeparatorMenuItem2', true); 4313 4314 // Change class of the component. ToDo: create a 'change_class' icon resource 4315 AddPopupMenuItem(ChangeClassPopupMenuItem,nil,'ChangeClassPopupMenuItem', 4316 oisChangeClass,'Change Class of component', '', 4317 @ChangeClassPopupmenuItemClick,false,true,true); 4318 AddPopupMenuItem(ChangeParentPopupMenuItem, nil, 'ChangeParentPopupMenuItem', 4319 oisChangeParent+' ...', 'Change Parent of component', '', 4320 @ChangeParentItemClick, False, True, True); 4321 OptionsSeparatorMenuItem3 := AddSeparatorMenuItem(nil, 'OptionsSeparatorMenuItem3', true); 4322 4323 AddPopupMenuItem(ShowComponentTreePopupMenuItem,nil 4324 ,'ShowComponentTreePopupMenuItem',oisShowComponentTree, '', '' 4325 ,@ShowComponentTreePopupMenuItemClick,FShowComponentTree,true,true); 4326 ShowComponentTreePopupMenuItem.ShowAlwaysCheckable:=true; 4327 4328 AddPopupMenuItem(ShowPropertyFilterPopupMenuItem,nil 4329 ,'ShowPropertyFilterPopupMenuItem',oisShowPropertyFilter, '', '' 4330 ,@ShowPropertyFilterPopupMenuItemClick,FShowPropertyFilter,true,true); 4331 ShowPropertyFilterPopupMenuItem.ShowAlwaysCheckable:=true; 4332 4333 AddPopupMenuItem(ShowHintsPopupMenuItem,nil 4334 ,'ShowHintPopupMenuItem',oisShowHints,'Grid hints', '' 4335 ,@ShowHintPopupMenuItemClick,false,true,true); 4336 ShowHintsPopupMenuItem.ShowAlwaysCheckable:=true; 4337 4338 AddPopupMenuItem(ShowInfoBoxPopupMenuItem,nil 4339 ,'ShowInfoBoxPopupMenuItem',oisShowInfoBox, '', '' 4340 ,@ShowInfoBoxPopupMenuItemClick,FShowInfoBox,true,true); 4341 ShowInfoBoxPopupMenuItem.ShowAlwaysCheckable:=true; 4342 4343 AddPopupMenuItem(ShowStatusBarPopupMenuItem,nil 4344 ,'ShowStatusBarPopupMenuItem',oisShowStatusBar, '', '' 4345 ,@ShowStatusBarPopupMenuItemClick,FShowStatusBar,true,true); 4346 ShowStatusBarPopupMenuItem.ShowAlwaysCheckable:=true; 4347 4348 AddPopupMenuItem(ShowOptionsPopupMenuItem,nil 4349 ,'ShowOptionsPopupMenuItem',oisOptions, '', 'oi_options' 4350 ,@ShowOptionsPopupMenuItemClick,false,true,FOnShowOptions<>nil); 4351 4352 // combobox at top (filled with available persistents) 4353 with AvailPersistentComboBox do 4354 begin 4355 Sorted := true; 4356 AutoSelect := true; 4357 AutoComplete := true; 4358 DropDownCount := 12; 4359 Visible := not FShowComponentTree; 4360 end; 4361 4362 // Component Tree at top (filled with available components) 4363 ComponentTree := TComponentTreeView.Create(Self); 4364 with ComponentTree do 4365 begin 4366 Name := 'ComponentTree'; 4367 Parent := ComponentPanel; 4368 AnchorSideTop.Control := CompFilterEdit; 4369 AnchorSideTop.Side := asrBottom; 4370 AnchorSideBottom.Control := ComponentPanel; 4371 AnchorSideBottom.Side := asrBottom; 4372 BorderSpacing.Top := 3; 4373 BorderSpacing.Bottom := 3; 4374 Left := 3; 4375 Height := ComponentPanel.Height - BorderSpacing.Top 4376 - CompFilterEdit.Top - CompFilterEdit.Height; 4377 Width := ComponentPanel.Width-6; 4378 Anchors := [akTop, akLeft, akRight, akBottom]; 4379 OnDblClick := @ComponentTreeDblClick; 4380 OnKeyDown := @ComponentTreeKeyDown; 4381 OnSelectionChanged := @ComponentTreeSelectionChanged; 4382 OnComponentGetImageIndex := @ComponentTreeGetNodeImageIndex; 4383 OnModified := @ComponentTreeModified; 4384 Scrollbars := ssAutoBoth; 4385 PopupMenu := MainPopupMenu; 4386 end; 4387 4388 // ComponentPanel encapsulates TreeFilterEdit and ComponentTree 4389 ComponentPanel.Constraints.MinHeight := 8; 4390 ComponentPanel.Visible := FShowComponentTree; 4391 CompFilterEdit.FilteredTreeview := ComponentTree; 4392 4393 InfoPanel := TPanel.Create(Self); 4394 with InfoPanel do 4395 begin 4396 Name := 'InfoPanel'; 4397 Constraints.MinHeight := 8; 4398 Caption := ''; 4399 Height := InfoBoxHeight; 4400 Parent := PnlClient; 4401 BevelOuter := bvNone; 4402 BevelInner := bvNone; 4403 Align := alBottom; 4404 PopupMenu := MainPopupMenu; 4405 Visible := FShowInfoBox; 4406 end; 4407 4408 if ShowComponentTree then 4409 CreateTopSplitter; 4410 if ShowInfoBox then 4411 CreateBottomSplitter; 4412 4413 //Create properties filter 4414 PropertyPanel := TPanel.Create(Self); 4415 with PropertyPanel do 4416 begin 4417 Name := 'PropertyPanel'; 4418 Caption := ''; 4419 Parent := PnlClient; 4420 BevelOuter := bvNone; 4421 BevelInner := bvNone; 4422 Align := alClient; 4423 Visible := True; 4424 end; 4425 4426 PropFilterPanel := TPanel.Create(Self); 4427 with PropFilterPanel do 4428 begin 4429 Name := 'PropFilterPanel'; 4430 Caption := ''; 4431 Parent := PropertyPanel; 4432 BevelOuter := bvNone; 4433 BevelInner := bvNone; 4434 AutoSize := true; 4435 Align := alTop; 4436 Visible := True; 4437 end; 4438 4439 PropFilterLabel := TLabel.Create(Self); 4440 PropFilterEdit:= TListFilterEdit.Create(Self); 4441 with PropFilterLabel do 4442 begin 4443 Parent := PropFilterPanel; 4444 BorderSpacing.Left := Scale96ToForm(5); 4445 BorderSpacing.Top := Scale96ToForm(7); 4446 Width := Scale96ToForm(53); 4447 Caption := oisBtnProperties; 4448 FocusControl := PropFilterEdit; 4449 end; 4450 4451 with PropFilterEdit do 4452 begin 4453 Parent := PropFilterPanel; 4454 AnchorSideLeft.Control := PropFilterLabel; 4455 AnchorSideLeft.Side := asrBottom; 4456 AnchorSideTop.Control := PropFilterLabel; 4457 AnchorSideTop.Side := asrCenter; 4458 Width := PropertyPanel.Width - ( Left + 3); 4459 AutoSelect := False; 4460 ButtonWidth := Scale96ToForm(23); 4461 Anchors := [akTop, akLeft, akRight]; 4462 BorderSpacing.Left := 5; 4463 OnAfterFilter := @PropFilterEditAfterFilter; 4464 end; 4465 4466 CreateNoteBook; 4467 // TabOrder has no effect. TAB key is handled by TObjectInspectorDlg.KeyDown(). 4468 CompFilterEdit.TabOrder := 0; 4469 ComponentTree.TabOrder := 1; 4470 PropFilterEdit.TabOrder := 2; 4471end; 4472 4473destructor TObjectInspectorDlg.Destroy; 4474begin 4475 FreeAndNil(FSelection); 4476 FreeAndNil(FComponentEditor); 4477 FreeAndNil(PropFilterLabel); 4478 FreeAndNil(PropFilterEdit); 4479 FreeAndNil(PropFilterPanel); 4480 FreeAndNil(PropertyPanel); 4481 inherited Destroy; 4482 FreeAndNil(FFavorites); 4483end; 4484 4485procedure TObjectInspectorDlg.PropFilterEditAfterFilter(Sender: TObject); 4486begin 4487 FPropFilterUpdating := True; 4488 GetActivePropertyGrid.PropNameFilter := PropFilterEdit.Filter; 4489 RebuildPropertyLists; 4490 FPropFilterUpdating := False; 4491end; 4492 4493procedure TObjectInspectorDlg.NoteBookPageChange(Sender: TObject); 4494begin 4495 PropFilterEditAfterFilter(Sender); 4496end; 4497 4498procedure TObjectInspectorDlg.SetPropertyEditorHook(const AValue:TPropertyEditorHook); 4499var 4500 Page: TObjectInspectorPage; 4501 OldSelection: TPersistentSelectionList; 4502begin 4503 if FPropertyEditorHook=AValue then exit; 4504 if FPropertyEditorHook<>nil then begin 4505 FPropertyEditorHook.RemoveAllHandlersForObject(Self); 4506 end; 4507 FPropertyEditorHook:=AValue; 4508 if FPropertyEditorHook<>nil then begin 4509 FPropertyEditorHook.AddHandlerChangeLookupRoot(@HookLookupRootChange); 4510 FPropertyEditorHook.AddHandlerRefreshPropertyValues(@HookRefreshPropertyValues); 4511 FPropertyEditorHook.AddHandlerSetSelection(@HookSetSelection); 4512 Selection := nil; 4513 for Page:=Low(TObjectInspectorPage) to High(TObjectInspectorPage) do 4514 if GridControl[Page]<>nil then 4515 begin 4516 if Page=oipgpProperties then // Add HookGetCheckboxForBoolean only once. 4517 FPropertyEditorHook.AddHandlerGetCheckboxForBoolean( 4518 @GridControl[Page].HookGetCheckboxForBoolean); 4519 GridControl[Page].PropertyEditorHook:=FPropertyEditorHook; 4520 end; 4521 OldSelection:=TPersistentSelectionList.Create; 4522 try 4523 FPropertyEditorHook.GetSelection(OldSelection); 4524 if EnableHookGetSelection then begin 4525 // the propertyeditorhook gets the selection from the OI 4526 if OldSelection.Count>0 then 4527 FSelection.Assign(OldSelection); // if propertyeditorhook has a selection use that 4528 FPropertyEditorHook.AddHandlerGetSelection(@HookGetSelection); 4529 if OldSelection.Count=0 then begin 4530 // select root component 4531 FSelection.Clear; 4532 if FPropertyEditorHook.LookupRoot is TComponent then 4533 FSelection.Add(TComponent(FPropertyEditorHook.LookupRoot)); 4534 end; 4535 end 4536 else 4537 Selection := OldSelection; // OI gets the selection from propertyeditorhook 4538 finally 4539 OldSelection.Free; 4540 end; 4541 ComponentTree.PropertyEditorHook:=FPropertyEditorHook; 4542 FillComponentList(True); 4543 RefreshSelection; 4544 end; 4545end; 4546 4547function TObjectInspectorDlg.PersistentToString(APersistent: TPersistent): string; 4548begin 4549 if APersistent is TComponent then 4550 Result:=TComponent(APersistent).GetNamePath+': '+APersistent.ClassName 4551 else 4552 Result:=APersistent.ClassName; 4553end; 4554 4555procedure TObjectInspectorDlg.SetComponentPanelHeight(const AValue: integer); 4556begin 4557 if ComponentPanel.Height <> AValue then 4558 ComponentPanel.Height := AValue; 4559end; 4560 4561procedure TObjectInspectorDlg.SetDefaultItemHeight(const AValue: integer); 4562var 4563 NewValue: Integer; 4564 Page: TObjectInspectorPage; 4565begin 4566 NewValue:=AValue; 4567 if NewValue<0 then 4568 NewValue:=0 4569 else if (NewValue>0) and (NewValue<10) then 4570 NewValue:=10 4571 else if NewValue>100 then NewValue:=100; 4572 if FDefaultItemHeight=NewValue then exit; 4573 FDefaultItemHeight:=NewValue; 4574 for Page:=Low(TObjectInspectorPage) to High(TObjectInspectorPage) do 4575 if GridControl[Page]<>nil then 4576 GridControl[Page].DefaultItemHeight:=FDefaultItemHeight; 4577 RebuildPropertyLists; 4578end; 4579 4580procedure TObjectInspectorDlg.SetInfoBoxHeight(const AValue: integer); 4581begin 4582 if FInfoBoxHeight <> AValue then 4583 begin 4584 FInfoBoxHeight := AValue; 4585 Assert(Assigned(InfoPanel), 'TObjectInspectorDlg.SetInfoBoxHeight: InfoPanel=nil'); 4586 InfoPanel.Height := AValue; 4587 end; 4588end; 4589 4590procedure TObjectInspectorDlg.SetRestricted(const AValue: TOIRestrictedProperties); 4591begin 4592 if FRestricted = AValue then exit; 4593 //DebugLn('TObjectInspectorDlg.SetRestricted Count: ', DbgS(AValue.Count)); 4594 FRestricted := AValue; 4595 RestrictedGrid.Favorites := FRestricted; 4596end; 4597 4598procedure TObjectInspectorDlg.SetOnShowOptions(const AValue: TNotifyEvent); 4599begin 4600 if FOnShowOptions=AValue then exit; 4601 FOnShowOptions:=AValue; 4602 ShowOptionsPopupMenuItem.Visible:=FOnShowOptions<>nil; 4603end; 4604 4605procedure TObjectInspectorDlg.AddPersistentToList(APersistent: TPersistent; 4606 List: TStrings); 4607var 4608 Allowed: boolean; 4609begin 4610 if (APersistent is TComponent) 4611 and (csDestroying in TComponent(APersistent).ComponentState) then exit; 4612 Allowed:=true; 4613 if Assigned(FOnAddAvailablePersistent) then 4614 FOnAddAvailablePersistent(APersistent,Allowed); 4615 if Allowed then 4616 List.AddObject(PersistentToString(APersistent),APersistent); 4617end; 4618 4619procedure TObjectInspectorDlg.HookLookupRootChange; 4620var 4621 Page: TObjectInspectorPage; 4622begin 4623 for Page:=Low(TObjectInspectorPage) to High(TObjectInspectorPage) do 4624 if GridControl[Page]<>nil then 4625 GridControl[Page].PropEditLookupRootChange; 4626 CompFilterEdit.Filter:=''; 4627 FillComponentList(True); 4628end; 4629 4630procedure TObjectInspectorDlg.HookRefreshPropertyValues; 4631begin 4632 RefreshPropertyValues; 4633end; 4634 4635procedure TObjectInspectorDlg.ChangeCompZOrderInList(APersistent: TPersistent; 4636 AZOrder: TZOrderDelete); 4637begin 4638 if FShowComponentTree then 4639 ComponentTree.ChangeCompZOrder(APersistent, AZOrder) 4640 else 4641 FillPersistentComboBox; 4642end; 4643 4644procedure TObjectInspectorDlg.DeleteCompFromList(APersistent: TPersistent); 4645begin 4646 if FShowComponentTree then begin 4647 if APersistent=nil then 4648 ComponentTree.BuildComponentNodes(True) 4649 else 4650 ComponentTree.DeleteComponentNode(APersistent); 4651 end 4652 else 4653 FillPersistentComboBox; 4654end; 4655 4656procedure TObjectInspectorDlg.FillComponentList(AWholeTree: Boolean); 4657begin 4658 if FShowComponentTree then 4659 ComponentTree.BuildComponentNodes(AWholeTree) 4660 else 4661 FillPersistentComboBox; 4662end; 4663 4664procedure TObjectInspectorDlg.UpdateComponentValues; 4665begin 4666 if FShowComponentTree then 4667 ComponentTree.UpdateComponentNodesValues 4668 else 4669 FillPersistentComboBox; 4670end; 4671 4672procedure TObjectInspectorDlg.FillPersistentComboBox; 4673var 4674 a: integer; 4675 Root: TComponent; 4676 OldText: AnsiString; 4677 NewList: TStringList; 4678begin 4679 Assert(not FUpdatingAvailComboBox, 4680 'TObjectInspectorDlg.FillPersistentComboBox: Updating Avail ComboBox'); 4681 //if FUpdatingAvailComboBox then exit; 4682 FUpdatingAvailComboBox:=true; 4683 NewList:=TStringList.Create; 4684 try 4685 if (FPropertyEditorHook<>nil) 4686 and (FPropertyEditorHook.LookupRoot<>nil) then begin 4687 AddPersistentToList(FPropertyEditorHook.LookupRoot,NewList); 4688 if FPropertyEditorHook.LookupRoot is TComponent then begin 4689 Root:=TComponent(FPropertyEditorHook.LookupRoot); 4690 //writeln('[TObjectInspectorDlg.FillComponentComboBox] B ',Root.Name,' ',Root.ComponentCount); 4691 for a:=0 to Root.ComponentCount-1 do 4692 AddPersistentToList(Root.Components[a],NewList); 4693 end; 4694 end; 4695 4696 if AvailPersistentComboBox.Items.Equals(NewList) then exit; 4697 4698 AvailPersistentComboBox.Items.BeginUpdate; 4699 if AvailPersistentComboBox.Items.Count=1 then 4700 OldText:=AvailPersistentComboBox.Text 4701 else 4702 OldText:=''; 4703 AvailPersistentComboBox.Items.Assign(NewList); 4704 AvailPersistentComboBox.Items.EndUpdate; 4705 a:=AvailPersistentComboBox.Items.IndexOf(OldText); 4706 if (OldText='') or (a<0) then 4707 SetAvailComboBoxText 4708 else 4709 AvailPersistentComboBox.ItemIndex:=a; 4710 4711 finally 4712 NewList.Free; 4713 FUpdatingAvailComboBox:=false; 4714 end; 4715end; 4716 4717procedure TObjectInspectorDlg.BeginUpdate; 4718begin 4719 inc(FUpdateLock); 4720end; 4721 4722procedure TObjectInspectorDlg.EndUpdate; 4723begin 4724 dec(FUpdateLock); 4725 if FUpdateLock<0 then begin 4726 DebugLn('ERROR TObjectInspectorDlg.EndUpdate'); 4727 end; 4728 if FUpdateLock=0 then begin 4729 if oifRebuildPropListsNeeded in FFLags then 4730 RebuildPropertyLists; 4731 end; 4732end; 4733 4734function TObjectInspectorDlg.GetActivePropertyGrid: TOICustomPropertyGrid; 4735begin 4736 Result:=nil; 4737 if NoteBook=nil then exit; 4738 case NoteBook.PageIndex of 4739 0: Result:=PropertyGrid; 4740 1: Result:=EventGrid; 4741 2: Result:=FavoriteGrid; 4742 3: Result:=RestrictedGrid; 4743 end; 4744end; 4745 4746function TObjectInspectorDlg.GetActivePropertyRow: TOIPropertyGridRow; 4747var 4748 CurGrid: TOICustomPropertyGrid; 4749begin 4750 Result:=nil; 4751 CurGrid:=GetActivePropertyGrid; 4752 if CurGrid=nil then exit; 4753 Result:=CurGrid.GetActiveRow; 4754end; 4755 4756function TObjectInspectorDlg.GetCurRowDefaultValue(var DefaultStr: string): Boolean; 4757var 4758 CurRow: TOIPropertyGridRow; 4759begin 4760 Result:=False; 4761 DefaultStr:=''; 4762 CurRow:=GetActivePropertyRow; 4763 if Assigned(CurRow) and (CurRow.Editor.HasDefaultValue) then 4764 begin 4765 try 4766 DefaultStr:=CurRow.Editor.GetDefaultValue; 4767 Result:=true; 4768 except 4769 DefaultStr:=''; 4770 end; 4771 end; 4772end; 4773 4774function TObjectInspectorDlg.GetParentCandidates: TFPList; 4775begin 4776 Result:=GetChangeParentCandidates(FPropertyEditorHook,Selection); 4777end; 4778 4779function TObjectInspectorDlg.HasParentCandidates: Boolean; 4780var 4781 Candidates: TFPList=nil; 4782begin 4783 try 4784 Candidates := GetParentCandidates; 4785 Result := (Candidates.Count>1); // single candidate is current parent 4786 finally 4787 Candidates.Free; 4788 end; 4789end; 4790 4791procedure TObjectInspectorDlg.ChangeParent; 4792var 4793 i: Integer; 4794 Control: TControl; 4795 NewParentName: String; 4796 NewParent: TPersistent; 4797 NewSelection: TPersistentSelectionList; 4798 Candidates: TFPList = nil; 4799 RootDesigner: TIDesigner; 4800 CompEditDsg: TComponentEditorDesigner; 4801begin 4802 if (Selection.Count < 1) then Exit; 4803 try 4804 Candidates := GetParentCandidates; 4805 if not ShowChangeParentDlg(Selection, Candidates, NewParentName) then 4806 Exit; 4807 finally 4808 Candidates.Free; 4809 end; 4810 4811 if NewParentName = TWinControl(FPropertyEditorHook.LookupRoot).Name then 4812 NewParent := FPropertyEditorHook.LookupRoot 4813 else 4814 NewParent := TWinControl(FPropertyEditorHook.LookupRoot).FindComponent(NewParentName); 4815 if not (NewParent is TWinControl) then Exit; 4816 4817 // Find designer for Undo actions. 4818 RootDesigner := FindRootDesigner(FPropertyEditorHook.LookupRoot); 4819 if (RootDesigner is TComponentEditorDesigner) then 4820 CompEditDsg := TComponentEditorDesigner(RootDesigner) //if CompEditDsg.IsUndoLocked then Exit; 4821 else 4822 CompEditDsg := nil; 4823 4824 for i := 0 to Selection.Count-1 do 4825 begin 4826 if not (Selection[i] is TControl) then Continue; 4827 Control := TControl(Selection[i]); 4828 if Control.Parent = nil then Continue; 4829 if Assigned(CompEditDsg) then 4830 CompEditDsg.AddUndoAction(Control, uopChange, i=0, 'Parent', 4831 Control.Parent.Name, NewParentName); 4832 Control.Parent := TWinControl(NewParent); 4833 end; 4834 4835 // Ensure the order of controls in the OI now reflects the new ZOrder 4836 // This code is based on ZOrderItemClick(). 4837 NewSelection := TPersistentSelectionList.Create; 4838 try 4839 NewSelection.ForceUpdate:=True; 4840 NewSelection.Add(NewParent); 4841 for i:=0 to Selection.Count-1 do 4842 NewSelection.Add(Selection.Items[i]); 4843 SetSelection(NewSelection); 4844 NewSelection.ForceUpdate:=True; 4845 NewSelection.Delete(0); 4846 SetSelection(NewSelection); 4847 finally 4848 NewSelection.Free; 4849 end; 4850 DoModified; 4851 FillComponentList(True); 4852end; 4853 4854procedure TObjectInspectorDlg.SetSelection(const ASelection: TPersistentSelectionList); 4855begin 4856 if FSettingSelectionCount > 0 then Exit; // Prevent a recursive loop. 4857 Inc(FSettingSelectionCount); 4858 try 4859 if ASelection<>nil then begin 4860 // Nothing changed or endless loop -> quit. 4861 if FSelection.IsEqual(ASelection) and not ASelection.ForceUpdate then 4862 Exit; 4863 end else begin 4864 if FSelection.Count=0 then 4865 Exit; 4866 end; 4867 if ASelection<>nil then 4868 FSelection.Assign(ASelection) 4869 else 4870 FSelection.Clear; 4871 SetAvailComboBoxText; 4872 RefreshSelection; 4873 if Assigned(FOnSelectPersistentsInOI) then 4874 FOnSelectPersistentsInOI(Self); 4875 finally 4876 Dec(FSettingSelectionCount); 4877 end; 4878end; 4879 4880procedure TObjectInspectorDlg.RefreshSelection; 4881var 4882 Page: TObjectInspectorPage; 4883begin 4884 if FRefreshingSelectionCount > 0 then Exit; // Prevent a recursive loop. 4885 Inc(FRefreshingSelectionCount); 4886 4887 if NoteBook.Page[3].Visible then 4888 begin 4889 DoUpdateRestricted; 4890 // invalidate RestrictedProps 4891 WidgetSetsRestrictedBox.Invalidate; 4892 ComponentRestrictedBox.Invalidate; 4893 end; 4894 4895 for Page := Low(TObjectInspectorPage) to High(TObjectInspectorPage) do 4896 if GridControl[Page] <> nil then 4897 GridControl[Page].Selection := FSelection; 4898 RefreshComponentTreeSelection; 4899 if (not Visible) and AutoShow and (FSelection.Count > 0) then 4900 if Assigned(OnAutoShow) then 4901 OnAutoShow(Self) 4902 else 4903 Visible := True; 4904 Dec(FRefreshingSelectionCount); 4905end; 4906 4907procedure TObjectInspectorDlg.RefreshComponentTreeSelection; 4908begin 4909 ComponentTree.Selection := FSelection; 4910 ComponentTree.MakeSelectionVisible; 4911end; 4912 4913procedure TObjectInspectorDlg.SaveChanges; 4914var 4915 Page: TObjectInspectorPage; 4916begin 4917 for Page:=Low(TObjectInspectorPage) to High(TObjectInspectorPage) do 4918 if GridControl[Page]<>nil then 4919 GridControl[Page].SaveChanges; 4920end; 4921 4922procedure TObjectInspectorDlg.RefreshPropertyValues; 4923var 4924 Page: TObjectInspectorPage; 4925begin 4926 for Page:=Low(TObjectInspectorPage) to High(TObjectInspectorPage) do 4927 if GridControl[Page]<>nil then 4928 GridControl[Page].RefreshPropertyValues; 4929end; 4930 4931procedure TObjectInspectorDlg.RebuildPropertyLists; 4932var 4933 Page: TObjectInspectorPage; 4934begin 4935 if FUpdateLock>0 then 4936 Include(FFLags,oifRebuildPropListsNeeded) 4937 else begin 4938 Exclude(FFLags,oifRebuildPropListsNeeded); 4939 for Page:=Low(TObjectInspectorPage) to High(TObjectInspectorPage) do 4940 if GridControl[Page]<>nil then 4941 GridControl[Page].BuildPropertyList(False, not FPropFilterUpdating); 4942 end; 4943end; 4944 4945procedure TObjectInspectorDlg.AvailComboBoxCloseUp(Sender:TObject); 4946var 4947 NewComponent,Root:TComponent; 4948 a:integer; 4949 4950 procedure SetSelectedPersistent(c:TPersistent); 4951 begin 4952 if (FSelection.Count=1) and (FSelection[0]=c) then exit; 4953 FSelection.Clear; 4954 FSelection.Add(c); 4955 RefreshSelection; 4956 if Assigned(FOnSelectPersistentsInOI) then 4957 FOnSelectPersistentsInOI(Self); 4958 end; 4959 4960begin 4961 if FUpdatingAvailComboBox then exit; 4962 if (FPropertyEditorHook=nil) or (FPropertyEditorHook.LookupRoot=nil) then 4963 exit; 4964 if not (FPropertyEditorHook.LookupRoot is TComponent) then begin 4965 // not a TComponent => no children => select always only the root 4966 SetSelectedPersistent(FPropertyEditorHook.LookupRoot); 4967 exit; 4968 end; 4969 Root:=TComponent(FPropertyEditorHook.LookupRoot); 4970 if (AvailPersistentComboBox.Text=PersistentToString(Root)) then begin 4971 SetSelectedPersistent(Root); 4972 end else begin 4973 for a:=0 to Root.ComponentCount-1 do begin 4974 NewComponent:=Root.Components[a]; 4975 if AvailPersistentComboBox.Text=PersistentToString(NewComponent) then 4976 begin 4977 SetSelectedPersistent(NewComponent); 4978 break; 4979 end; 4980 end; 4981 end; 4982end; 4983 4984function TObjectInspectorDlg.GetComponentEditorForSelection: TBaseComponentEditor; 4985var 4986 APersistent: TPersistent; 4987 AComponent: TComponent absolute APersistent; 4988 ADesigner: TIDesigner; 4989begin 4990 APersistent := GetSelectedPersistent; 4991 if not (APersistent is TComponent) then 4992 Exit(nil); 4993 ADesigner := FindRootDesigner(AComponent); 4994 if not (ADesigner is TComponentEditorDesigner) then 4995 Exit(nil); 4996 Result := GetComponentEditor(AComponent, TComponentEditorDesigner(ADesigner)); 4997end; 4998 4999procedure TObjectInspectorDlg.ComponentTreeDblClick(Sender: TObject); 5000var 5001 CompEditor: TBaseComponentEditor; 5002begin 5003 if (PropertyEditorHook = nil) or (PropertyEditorHook.LookupRoot = nil) then 5004 Exit; 5005 if not FSelection.IsEqual(ComponentTree.Selection) then 5006 ComponentTreeSelectionChanged(Sender); 5007 CompEditor := GetComponentEditorForSelection; 5008 if Assigned(CompEditor) then 5009 begin 5010 try 5011 CompEditor.Edit; 5012 finally 5013 CompEditor.Free; 5014 end; 5015 end; 5016end; 5017 5018function TObjectInspectorDlg.CanDeleteSelection: Boolean; 5019var 5020 persistent: TPersistent; 5021 intf: IObjInspInterface; 5022 i: Integer; 5023begin 5024 Result := true; 5025 for i:=0 to ComponentTree.Selection.Count - 1 do begin 5026 persistent := ComponentTree.Selection[i]; 5027 if persistent.GetInterface(GUID_ObjInspInterface, intf) and not intf.AllowDelete then 5028 exit(false); 5029 end; 5030end; 5031 5032procedure TObjectInspectorDlg.ComponentTreeKeyDown(Sender: TObject; 5033 var Key: Word; Shift: TShiftState); 5034begin 5035 if (Shift = []) and (Key = VK_DELETE) and 5036 (Selection.Count > 0) and CanDeleteSelection and 5037 (MessageDlg(oiscDelete, mtConfirmation,[mbYes, mbNo],0) = mrYes) then 5038 begin 5039 DeletePopupmenuItemClick(nil); 5040 end; 5041end; 5042 5043procedure TObjectInspectorDlg.ComponentTreeSelectionChanged(Sender: TObject); 5044begin 5045 if (PropertyEditorHook=nil) or (PropertyEditorHook.LookupRoot=nil) then exit; 5046 if FSelection.IsEqual(ComponentTree.Selection) then exit; 5047 FSelection.Assign(ComponentTree.Selection); 5048 RefreshSelection; 5049 DefSelectionVisibleInDesigner; 5050 if Assigned(FOnSelectPersistentsInOI) then 5051 FOnSelectPersistentsInOI(Self); 5052end; 5053 5054procedure TObjectInspectorDlg.MainPopupMenuClose(Sender: TObject); 5055begin 5056 if FStateOfHintsOnMainPopupMenu then ShowHintPopupMenuItemClick(nil); 5057end; 5058 5059procedure TObjectInspectorDlg.FormResize(Sender: TObject); 5060begin 5061 ComponentPanel.Constraints.MaxHeight := Height-50; 5062end; 5063 5064procedure TObjectInspectorDlg.GridKeyDown(Sender: TObject; var Key: Word; 5065 Shift: TShiftState); 5066var 5067 Handled: Boolean; 5068begin 5069 Handled := false; 5070 5071 //CTRL-[Shift]-TAB will select next or previous notebook tab 5072 if (Key=VK_TAB) and (ssCtrl in Shift) then 5073 begin 5074 Handled := true; 5075 if ssShift in Shift then 5076 ShowNextPage(-1) 5077 else 5078 ShowNextPage(1); 5079 end; 5080 5081 //CTRL-ArrowDown will dropdown the component combobox 5082 if (not Handled) and ((Key=VK_DOWN) or (Key=VK_UP)) and (ssCtrl in Shift) then 5083 begin 5084 Handled := true; 5085 if AvailPersistentComboBox.Canfocus then 5086 AvailPersistentComboBox.SetFocus; 5087 AvailPersistentComboBox.DroppedDown := true; 5088 end; 5089 5090 if not Handled then 5091 begin 5092 if Assigned(OnOIKeyDown) then 5093 OnOIKeyDown(Self,Key,Shift); 5094 if (Key<>VK_UNKNOWN) and Assigned(OnRemainingKeyDown) then 5095 OnRemainingKeyDown(Self,Key,Shift); 5096 end 5097 else 5098 Key := VK_UNKNOWN; 5099end; 5100 5101procedure TObjectInspectorDlg.GridKeyUp(Sender: TObject; var Key: Word; 5102 Shift: TShiftState); 5103begin 5104 if Assigned(OnRemainingKeyUp) then OnRemainingKeyUp(Self,Key,Shift); 5105end; 5106 5107procedure TObjectInspectorDlg.GridDblClick(Sender: TObject); 5108begin 5109 // 5110end; 5111 5112procedure TObjectInspectorDlg.PropEditPopupClick(Sender: TObject); 5113var 5114 CurGrid: TOICustomPropertyGrid; 5115 CurRow: TOIPropertyGridRow; 5116 s: String; 5117begin 5118 CurGrid:=GetActivePropertyGrid; 5119 CurRow := GetActivePropertyRow; 5120 CurRow.Editor.ExecuteVerb((Sender as TMenuItem).Tag); 5121 s := CurRow.Editor.GetVisualValue; 5122 CurGrid.CurrentEditValue := s; 5123 RefreshPropertyValues; 5124 Invalidate; 5125 DebugLn(['Executed verb number ', (Sender as TMenuItem).Tag, ', VisualValue: ', s, ', CurRow: ', CurRow]); 5126end; 5127 5128procedure TObjectInspectorDlg.AddToFavoritesPopupmenuItemClick(Sender: TObject); 5129begin 5130 //debugln('TObjectInspectorDlg.OnAddToFavoritePopupmenuItemClick'); 5131 if Assigned(OnAddToFavorites) then OnAddToFavorites(Self); 5132end; 5133 5134procedure TObjectInspectorDlg.RemoveFromFavoritesPopupmenuItemClick(Sender: TObject); 5135begin 5136 if Assigned(OnRemoveFromFavorites) then OnRemoveFromFavorites(Self); 5137end; 5138 5139procedure TObjectInspectorDlg.ViewRestrictionsPopupmenuItemClick(Sender: TObject); 5140begin 5141 DoViewRestricted; 5142end; 5143 5144procedure TObjectInspectorDlg.UndoPopupmenuItemClick(Sender: TObject); 5145var 5146 CurGrid: TOICustomPropertyGrid; 5147 CurRow: TOIPropertyGridRow; 5148begin 5149 CurGrid:=GetActivePropertyGrid; 5150 CurRow:=GetActivePropertyRow; 5151 if CurRow=nil then exit; 5152 CurGrid.CurrentEditValue:=CurRow.Editor.GetVisualValue; 5153end; 5154 5155procedure TObjectInspectorDlg.FindDeclarationPopupmenuItemClick(Sender: TObject); 5156begin 5157 if Assigned(OnFindDeclarationOfProperty) then 5158 OnFindDeclarationOfProperty(Self); 5159end; 5160 5161procedure TObjectInspectorDlg.CutPopupmenuItemClick(Sender: TObject); 5162var 5163 ADesigner: TIDesigner; 5164begin 5165 if (Selection.Count > 0) and (Selection[0] is TComponent) then 5166 begin 5167 ADesigner := FindRootDesigner(Selection[0]); 5168 if ADesigner is TComponentEditorDesigner then 5169 TComponentEditorDesigner(ADesigner).CutSelection; 5170 end; 5171end; 5172 5173procedure TObjectInspectorDlg.CopyPopupmenuItemClick(Sender: TObject); 5174var 5175 ADesigner: TIDesigner; 5176begin 5177 if (Selection.Count > 0) and (Selection[0] is TComponent) then 5178 begin 5179 ADesigner := FindRootDesigner(Selection[0]); 5180 if ADesigner is TComponentEditorDesigner then 5181 TComponentEditorDesigner(ADesigner).CopySelection; 5182 end; 5183end; 5184 5185procedure TObjectInspectorDlg.PastePopupmenuItemClick(Sender: TObject); 5186var 5187 ADesigner: TIDesigner; 5188begin 5189 if Selection.Count > 0 then 5190 begin 5191 ADesigner := FindRootDesigner(Selection[0]); 5192 if ADesigner is TComponentEditorDesigner then 5193 TComponentEditorDesigner(ADesigner).PasteSelection([]); 5194 end; 5195end; 5196 5197procedure TObjectInspectorDlg.DeletePopupmenuItemClick(Sender: TObject); 5198var 5199 ADesigner: TIDesigner; 5200 ACollection: TCollection; 5201 i: integer; 5202begin 5203 if (Selection.Count > 0) then 5204 begin 5205 ADesigner := FindRootDesigner(Selection[0]); 5206 if ADesigner is TComponentEditorDesigner then 5207 begin 5208 if Selection[0] is TCollection then 5209 begin 5210 ACollection := TCollection(Selection[0]); 5211 Selection.BeginUpdate; 5212 Selection.Clear; 5213 for i := 0 to ACollection.Count - 1 do 5214 Selection.Add(ACollection.Items[i]); 5215 Selection.EndUpdate; 5216 if Assigned(FOnSelectPersistentsInOI) then 5217 FOnSelectPersistentsInOI(Self); 5218 end; 5219 TComponentEditorDesigner(ADesigner).DeleteSelection; 5220 end; 5221 end; 5222end; 5223 5224procedure TObjectInspectorDlg.ChangeClassPopupmenuItemClick(Sender: TObject); 5225var 5226 ADesigner: TIDesigner; 5227begin 5228 if (Selection.Count = 1) then 5229 begin 5230 ADesigner := FindRootDesigner(Selection[0]); 5231 if ADesigner is TComponentEditorDesigner then 5232 TComponentEditorDesigner(ADesigner).ChangeClass; 5233 end; 5234end; 5235 5236procedure TObjectInspectorDlg.GridModified(Sender: TObject); 5237begin 5238 DoModified; 5239end; 5240 5241procedure TObjectInspectorDlg.GridSelectionChange(Sender: TObject); 5242var 5243 Row: TOIPropertyGridRow; 5244begin 5245 Row := GetActivePropertyRow; 5246 if Assigned(Row) then 5247 FLastActiveRowName := Row.Name; 5248 if Assigned(FOnSelectionChange) then 5249 FOnSelectionChange(Self); 5250end; 5251 5252function TObjectInspectorDlg.GridPropertyHint(Sender: TObject; 5253 PointedRow: TOIPropertyGridRow; out AHint: string): boolean; 5254begin 5255 Result := False; 5256 if Assigned(FOnPropertyHint) then 5257 Result := FOnPropertyHint(Sender, PointedRow, AHint); 5258end; 5259 5260procedure TObjectInspectorDlg.SetAvailComboBoxText; 5261begin 5262 case FSelection.Count of 5263 0: // none selected 5264 AvailPersistentComboBox.Text:=''; 5265 1: // single selection 5266 AvailPersistentComboBox.Text:=PersistentToString(FSelection[0]); 5267 else 5268 // multi selection 5269 AvailPersistentComboBox.Text:=Format(oisItemsSelected, [FSelection.Count]); 5270 end; 5271end; 5272 5273procedure TObjectInspectorDlg.HookGetSelection(const ASelection: TPersistentSelectionList); 5274begin 5275 if ASelection=nil then exit; 5276 ASelection.Assign(FSelection); 5277end; 5278 5279procedure TObjectInspectorDlg.HookSetSelection(const ASelection: TPersistentSelectionList); 5280begin 5281 Selection := ASelection; 5282end; 5283 5284procedure TObjectInspectorDlg.SetShowComponentTree(const AValue: boolean); 5285begin 5286 if FShowComponentTree = AValue then Exit; 5287 FShowComponentTree := AValue; 5288 BeginUpdate; 5289 try 5290 ShowComponentTreePopupMenuItem.Checked := FShowComponentTree; 5291 // hide / show / rebuild controls 5292 AvailPersistentComboBox.Visible := not FShowComponentTree; 5293 ComponentPanel.Visible := FShowComponentTree; 5294 if FShowComponentTree then 5295 CreateTopSplitter 5296 else 5297 FreeAndNil(Splitter1); 5298 FillComponentList(True); 5299 finally 5300 EndUpdate; 5301 end; 5302end; 5303 5304procedure TObjectInspectorDlg.SetShowPropertyFilter(const AValue: Boolean); 5305begin 5306 if FShowPropertyFilter = AValue then exit; 5307 FShowPropertyFilter := AValue; 5308 PropFilterPanel.Visible := AValue; 5309 ShowPropertyFilterPopupMenuItem.Checked := AValue; 5310end; 5311 5312procedure TObjectInspectorDlg.SetShowInfoBox(const AValue: Boolean); 5313begin 5314 if FShowInfoBox = AValue then exit; 5315 FShowInfoBox := AValue; 5316 ShowInfoBoxPopupMenuItem.Checked := AValue; 5317 InfoPanel.Visible := AValue; 5318 if AValue then begin 5319 CreateBottomSplitter; 5320 if Assigned(FOnSelectionChange) then 5321 FOnSelectionChange(Self); 5322 end 5323 else 5324 FreeAndNil(Splitter2); 5325end; 5326 5327procedure TObjectInspectorDlg.SetShowStatusBar(const AValue: Boolean); 5328begin 5329 if FShowStatusBar = AValue then exit; 5330 FShowStatusBar := AValue; 5331 StatusBar.Visible := AValue; 5332 ShowStatusBarPopupMenuItem.Checked := AValue; 5333 if ShowInfoBox then // make sure StatusBar goes below InfoPanel. 5334 StatusBar.Top := InfoPanel.Top + InfoPanel.Height + 1; 5335end; 5336 5337procedure TObjectInspectorDlg.SetShowFavorites(const AValue: Boolean); 5338begin 5339 if FShowFavorites = AValue then exit; 5340 FShowFavorites := AValue; 5341 NoteBook.Page[2].TabVisible := AValue; 5342end; 5343 5344procedure TObjectInspectorDlg.SetShowRestricted(const AValue: Boolean); 5345begin 5346 if FShowRestricted = AValue then exit; 5347 FShowRestricted := AValue; 5348 NoteBook.Page[3].TabVisible := AValue; 5349end; 5350 5351procedure TObjectInspectorDlg.ShowNextPage(Delta: integer); 5352var 5353 NewPageIndex: Integer; 5354begin 5355 NewPageIndex := NoteBook.PageIndex; 5356 repeat 5357 NewPageIndex := NewPageIndex + Delta; 5358 if NewPageIndex >= NoteBook.PageCount then 5359 NewPageIndex := 0; 5360 if NewPageIndex < 0 then 5361 NewPageIndex := NoteBook.PageCount - 1; 5362 if NoteBook.Page[NewPageIndex].TabVisible then 5363 begin 5364 NoteBook.PageIndex := NewPageIndex; 5365 break; 5366 end; 5367 until NewPageIndex = NoteBook.PageIndex; 5368end; 5369 5370procedure TObjectInspectorDlg.RestrictedPageShow(Sender: TObject); 5371begin 5372 //DebugLn('RestrictedPageShow'); 5373 DoUpdateRestricted; 5374end; 5375 5376procedure TObjectInspectorDlg.RestrictedPaint( 5377 ABox: TPaintBox; const ARestrictions: TWidgetSetRestrictionsArray); 5378 5379 function OutVertCentered(AX: Integer; const AStr: String): TSize; 5380 begin 5381 Result := ABox.Canvas.TextExtent(AStr); 5382 ABox.Canvas.TextOut(AX, (ABox.Height - Result.CY) div 2, AStr); 5383 end; 5384 5385var 5386 X, Y: Integer; 5387 lclPlatform: TLCLPlatform; 5388 None: Boolean; 5389 OldStyle: TBrushStyle; 5390 ImagesRes: TScaledImageListResolution; 5391 dist: Integer; 5392begin 5393 ImagesRes := IDEImages.Images_16.ResolutionForPPI[0, Font.PixelsPerInch, GetCanvasScaleFactor]; 5394 dist := Scale96ToForm(4); 5395 X := 0; 5396 Y := (ABox.Height - ImagesRes.Height) div 2; 5397 OldStyle := ABox.Canvas.Brush.Style; 5398 try 5399 ABox.Canvas.Brush.Style := bsClear; 5400 None := True; 5401 for lclPlatform := Low(TLCLPlatform) to High(TLCLPlatform) do 5402 begin 5403 if ARestrictions[lclPlatform] = 0 then continue; 5404 None := False; 5405 ImagesRes.Draw( 5406 ABox.Canvas, X, Y, 5407 IDEImages.LoadImage('issue_'+LCLPlatformDirNames[lclPlatform])); 5408 Inc(X, ImagesRes.Width); 5409 Inc(X, Scale96ToForm(OutVertCentered(X, IntToStr(ARestrictions[lclPlatform])).CX)); 5410 Inc(X, dist); 5411 end; 5412 5413 if None then 5414 OutVertCentered(4, oisNone); 5415 finally 5416 ABox.Canvas.Brush.Style := OldStyle; 5417 end; 5418end; 5419 5420procedure TObjectInspectorDlg.WidgetSetRestrictedPaint(Sender: TObject); 5421begin 5422 if RestrictedProps <> nil then 5423 RestrictedPaint(WidgetSetsRestrictedBox, RestrictedProps.WidgetSetRestrictions); 5424end; 5425 5426procedure TObjectInspectorDlg.ComponentRestrictedPaint(Sender: TObject); 5427var 5428 I, J: Integer; 5429 WSRestrictions: TWidgetSetRestrictionsArray; 5430 RestrProp: TOIRestrictedProperty; 5431begin 5432 if (RestrictedProps = nil) or (Selection = nil) then exit; 5433 5434 FillChar(WSRestrictions{%H-}, SizeOf(WSRestrictions), 0); 5435 for I := 0 to RestrictedProps.Count - 1 do 5436 begin 5437 if not (RestrictedProps.Items[I] is TOIRestrictedProperty) then continue; 5438 RestrProp:=TOIRestrictedProperty(RestrictedProps.Items[I]); 5439 for J := 0 to Selection.Count - 1 do 5440 with RestrProp do 5441 CheckRestrictions(Selection[J].ClassType, WSRestrictions); 5442 end; 5443 5444 RestrictedPaint(ComponentRestrictedBox, WSRestrictions); 5445end; 5446 5447procedure TObjectInspectorDlg.TopSplitterMoved(Sender: TObject); 5448begin 5449 Assert(Assigned(ComponentTree)); 5450 ComponentTree.Invalidate; // Update Scrollbars. 5451end; 5452 5453procedure TObjectInspectorDlg.CreateTopSplitter; 5454// vertical splitter between component tree and notebook 5455begin 5456 Splitter1 := TSplitter.Create(Self); 5457 with Splitter1 do 5458 begin 5459 Name := 'Splitter1'; 5460 Parent := PnlClient; 5461 Align := alTop; 5462 Top := ComponentPanelHeight; 5463 Height := 5; 5464 OnMoved := @TopSplitterMoved; 5465 end; 5466end; 5467 5468procedure TObjectInspectorDlg.DefSelectionVisibleInDesigner; 5469 procedure ShowPage(const aPage: TTabSheet); 5470 begin 5471 if aPage.Parent is TPageControl then 5472 TPageControl(aPage.Parent).PageIndex := aPage.PageIndex; 5473 end; 5474 procedure ShowPage(const aPage: TPage); 5475 begin 5476 if aPage.Parent is TNotebook then 5477 TNotebook(aPage.Parent).PageIndex := aPage.PageIndex; 5478 end; 5479var 5480 Cnt: TControl; 5481begin 5482 if (Selection.Count = 0) or (Selection[0] = nil) or not(Selection[0] is TControl) then 5483 Exit; 5484 5485 Cnt := TControl(Selection[0]); 5486 while Cnt<>nil do 5487 begin 5488 if Cnt is TTabSheet then 5489 ShowPage(TTabSheet(Cnt)) 5490 else 5491 if Cnt is TPage then 5492 ShowPage(TPage(Cnt)); 5493 5494 Cnt := Cnt.Parent; 5495 end; 5496end; 5497 5498procedure TObjectInspectorDlg.CreateBottomSplitter; 5499// vertical splitter between notebook and info panel 5500begin 5501 Splitter2 := TSplitter.Create(Self); 5502 with Splitter2 do 5503 begin 5504 Name := 'Splitter2'; 5505 Parent := PnlClient; 5506 Align := alBottom; 5507 Top := InfoPanel.Top - 1; 5508 Height := 5; 5509 end; 5510end; 5511 5512procedure TObjectInspectorDlg.DestroyNoteBook; 5513begin 5514 if NoteBook<>nil then 5515 NoteBook.Visible:=false; 5516 FreeAndNil(PropertyGrid); 5517 FreeAndNil(EventGrid); 5518 FreeAndNil(FavoriteGrid); 5519 FreeAndNil(RestrictedGrid); 5520 FreeAndNil(NoteBook); 5521end; 5522 5523procedure TObjectInspectorDlg.CreateNoteBook; 5524 5525 function CreateGrid( 5526 ATypeFilter: TTypeKinds; AOIPage: TObjectInspectorPage; 5527 ANotebookPage: Integer): TOICustomPropertyGrid; 5528 begin 5529 Result:=TOICustomPropertyGrid.CreateWithParams( 5530 Self, PropertyEditorHook, ATypeFilter, FDefaultItemHeight); 5531 with Result do 5532 begin 5533 Name := DefaultOIGridNames[AOIPage]; 5534 Selection := Self.FSelection; 5535 Align := alClient; 5536 PopupMenu := MainPopupMenu; 5537 OnModified := @GridModified; 5538 OnSelectionChange := @GridSelectionChange; 5539 OnPropertyHint := @GridPropertyHint; 5540 OnOIKeyDown := @GridKeyDown; 5541 OnKeyUp := @GridKeyUp; 5542 OnDblClick := @GridDblClick; 5543 OnMouseWheel := @OnGridMouseWheel; 5544 5545 Parent := NoteBook.Page[ANotebookPage]; 5546 end; 5547 end; 5548 5549 function AddPage(PageName, TabCaption: string): TTabSheet; 5550 begin 5551 Result:=TTabSheet.Create(Self); 5552 Result.Name:=PageName; 5553 Result.Caption:=TabCaption; 5554 Result.Parent:=NoteBook; 5555 end; 5556var 5557 APage: TTabSheet; 5558begin 5559 DestroyNoteBook; 5560 5561 // NoteBook 5562 NoteBook:=TPageControl.Create(Self); 5563 with NoteBook do 5564 begin 5565 Name := 'NoteBook'; 5566 Parent := PropertyPanel; 5567 Align := alClient; 5568 PopupMenu := MainPopupMenu; 5569 OnChange := @NoteBookPageChange; 5570 BorderSpacing.Top := 2; 5571 end; 5572 5573 AddPage(DefaultOIPageNames[oipgpProperties],oisProperties); 5574 5575 AddPage(DefaultOIPageNames[oipgpEvents],oisEvents); 5576 5577 APage:=AddPage(DefaultOIPageNames[oipgpFavorite],oisFavorites); 5578 APage.TabVisible := ShowFavorites; 5579 5580 APage:=AddPage(DefaultOIPageNames[oipgpRestricted],oisRestricted); 5581 APage.TabVisible := ShowRestricted; 5582 APage.OnShow := @RestrictedPageShow; 5583 5584 NoteBook.PageIndex:=0; 5585 5586 PropertyGrid := CreateGrid(Filter - [tkMethod], oipgpProperties, 0); 5587 EventGrid := CreateGrid([tkMethod], oipgpEvents, 1); 5588 FavoriteGrid := CreateGrid(Filter + [tkMethod], oipgpFavorite, 2); 5589 FavoriteGrid.Favorites := FFavorites; 5590 RestrictedGrid := CreateGrid(Filter + [tkMethod], oipgpRestricted, 3); 5591 5592 RestrictedPanel := TPanel.Create(Self); 5593 with RestrictedPanel do 5594 begin 5595 Align := alTop; 5596 BevelOuter := bvNone; 5597 Parent := NoteBook.Page[3]; 5598 end; 5599 5600 RestrictedInnerPanel := TPanel.Create(Self); 5601 with RestrictedInnerPanel do 5602 begin 5603 BevelOuter := bvNone; 5604 BorderSpacing.Around := 6; 5605 Parent := RestrictedPanel; 5606 end; 5607 5608 WidgetSetsRestrictedLabel := TLabel.Create(Self); 5609 with WidgetSetsRestrictedLabel do 5610 begin 5611 Caption := oisWidgetSetRestrictions; 5612 Top := 1; 5613 Align := alTop; 5614 AutoSize := True; 5615 Parent := RestrictedInnerPanel; 5616 end; 5617 5618 WidgetSetsRestrictedBox := TPaintBox.Create(Self); 5619 with WidgetSetsRestrictedBox do 5620 begin 5621 Top := 2; 5622 Align := alTop; 5623 Height := 24; 5624 OnPaint := @WidgetSetRestrictedPaint; 5625 Parent := RestrictedInnerPanel; 5626 end; 5627 5628 ComponentRestrictedLabel := TLabel.Create(Self); 5629 with ComponentRestrictedLabel do 5630 begin 5631 Caption := oisComponentRestrictions; 5632 Top := 3; 5633 Align := alTop; 5634 AutoSize := True; 5635 Parent := RestrictedInnerPanel; 5636 end; 5637 5638 ComponentRestrictedBox := TPaintBox.Create(Self); 5639 with ComponentRestrictedBox do 5640 begin 5641 Top := 4; 5642 Align := alTop; 5643 Height := 24; 5644 OnPaint := @ComponentRestrictedPaint; 5645 Parent := RestrictedInnerPanel; 5646 end; 5647 5648 RestrictedInnerPanel.AutoSize := True; 5649 RestrictedPanel.AutoSize := True; 5650end; 5651 5652procedure TObjectInspectorDlg.KeyDown(var Key: Word; Shift: TShiftState); 5653var 5654 CurGrid: TOICustomPropertyGrid; 5655begin 5656 // ToDo: Allow TAB key to FilterEdit, TreeView and Grid. Now the Grid gets seleted always. 5657 //DebugLn(['TObjectInspectorDlg.KeyDown: Key=', Key, ', ActiveControl=', ActiveControl]); 5658 //Do not disturb the combobox navigation while it has focus 5659 if not AvailPersistentComboBox.DroppedDown then begin 5660 CurGrid:=GetActivePropertyGrid; 5661 if CurGrid<>nil then begin 5662 CurGrid.HandleStandardKeys(Key,Shift); 5663 if Key=VK_UNKNOWN then exit; 5664 end; 5665 end; 5666 inherited KeyDown(Key, Shift); 5667 if (Key<>VK_UNKNOWN) and Assigned(OnRemainingKeyDown) then 5668 OnRemainingKeyDown(Self,Key,Shift); 5669end; 5670 5671procedure TObjectInspectorDlg.KeyUp(var Key: Word; Shift: TShiftState); 5672begin 5673 inherited KeyUp(Key, Shift); 5674 if (Key<>VK_UNKNOWN) and Assigned(OnRemainingKeyUp) then 5675 OnRemainingKeyUp(Self,Key,Shift); 5676end; 5677 5678procedure TObjectInspectorDlg.Resize; 5679begin 5680 inherited Resize; 5681 // BUG: resize gets called, even if nothing changed 5682 if Assigned(ComponentTree) and (FLastTreeSize <> ComponentTree.BoundsRect) then begin 5683 ComponentTree.Invalidate; // Update Scrollbars. 5684 FLastTreeSize := ComponentTree.BoundsRect; 5685 end; 5686end; 5687 5688procedure TObjectInspectorDlg.ComponentTreeModified(Sender: TObject); 5689begin 5690 DoModified; 5691end; 5692 5693function TObjectInspectorDlg.GetSelectedPersistent: TPersistent; 5694begin 5695 if ComponentTree.Selection.Count = 1 then 5696 Result := ComponentTree.Selection[0] 5697 else 5698 Result := nil; 5699end; 5700 5701procedure TObjectInspectorDlg.ShowComponentTreePopupMenuItemClick(Sender: TObject); 5702begin 5703 ShowComponentTree:=not ShowComponentTree; 5704end; 5705 5706procedure TObjectInspectorDlg.ShowPropertyFilterPopupMenuItemClick(Sender: TObject); 5707begin 5708 ShowPropertyFilter := not ShowPropertyFilter; 5709end; 5710 5711procedure TObjectInspectorDlg.ShowHintPopupMenuItemClick(Sender : TObject); 5712var 5713 Page: TObjectInspectorPage; 5714begin 5715 for Page := Low(TObjectInspectorPage) to High(TObjectInspectorPage) do 5716 if GridControl[Page] <> nil then 5717 GridControl[Page].ShowHint := not GridControl[Page].ShowHint; 5718end; 5719 5720procedure TObjectInspectorDlg.ShowInfoBoxPopupMenuItemClick(Sender: TObject); 5721begin 5722 ShowInfoBox:=not ShowInfoBox; 5723end; 5724 5725procedure TObjectInspectorDlg.ShowStatusBarPopupMenuItemClick(Sender: TObject); 5726begin 5727 ShowStatusBar:=not ShowStatusBar; 5728end; 5729 5730procedure TObjectInspectorDlg.ShowOptionsPopupMenuItemClick(Sender: TObject); 5731begin 5732 if Assigned(FOnShowOptions) then FOnShowOptions(Sender); 5733end; 5734// --- 5735 5736procedure TObjectInspectorDlg.MainPopupMenuPopup(Sender: TObject); 5737const 5738 PropertyEditorMIPrefix = 'PropertyEditorVerbMenuItem'; 5739 ComponentEditorMIPrefix = 'ComponentEditorVerbMenuItem'; 5740var 5741 ComponentEditorVerbSeparator: TMenuItem; 5742 PropertyEditorVerbSeparator: TMenuItem; 5743 5744 procedure RemovePropertyEditorMenuItems; 5745 var 5746 I: Integer; 5747 begin 5748 PropertyEditorVerbSeparator := nil; 5749 for I := MainPopupMenu.Items.Count - 1 downto 0 do 5750 if Pos(PropertyEditorMIPrefix, MainPopupMenu.Items[I].Name) = 1 then 5751 MainPopupMenu.Items[I].Free; 5752 end; 5753 5754 procedure AddPropertyEditorMenuItems(Editor: TPropertyEditor); 5755 var 5756 I, VerbCount: Integer; 5757 Item: TMenuItem; 5758 begin 5759 VerbCount := Editor.GetVerbCount; 5760 for I := 0 to VerbCount - 1 do 5761 begin 5762 Item := NewItem(Editor.GetVerb(I), 0, False, True, 5763 @PropEditPopupClick, 0, PropertyEditorMIPrefix + IntToStr(i)); 5764 Editor.PrepareItem(I, Item); 5765 Item.Tag:=I; 5766 MainPopupMenu.Items.Insert(I, Item); 5767 end; 5768 // insert the separator 5769 if VerbCount > 0 then 5770 begin 5771 PropertyEditorVerbSeparator := Menus.NewLine; 5772 PropertyEditorVerbSeparator.Name := PropertyEditorMIPrefix + IntToStr(VerbCount); 5773 MainPopupMenu.Items.Insert(VerbCount, PropertyEditorVerbSeparator); 5774 end; 5775 end; 5776 5777 procedure RemoveComponentEditorMenuItems; 5778 var 5779 I: Integer; 5780 begin 5781 ComponentEditorVerbSeparator:=nil; 5782 for I := MainPopupMenu.Items.Count - 1 downto 0 do 5783 if Pos(ComponentEditorMIPrefix, MainPopupMenu.Items[I].Name) = 1 then 5784 MainPopupMenu.Items[I].Free; 5785 end; 5786 5787 procedure AddComponentEditorMenuItems; 5788 var 5789 I, VerbCount: Integer; 5790 Item: TMenuItem; 5791 begin 5792 VerbCount := ComponentEditor.GetVerbCount; 5793 for I := 0 to VerbCount - 1 do 5794 begin 5795 Item := NewItem(ComponentEditor.GetVerb(I), 0, False, True, 5796 @ComponentEditorVerbMenuItemClick, 0, ComponentEditorMIPrefix + IntToStr(i)); 5797 ComponentEditor.PrepareItem(I, Item); 5798 Item.Tag:=I; 5799 MainPopupMenu.Items.Insert(I, Item); 5800 end; 5801 // insert the separator 5802 if VerbCount > 0 then 5803 begin 5804 ComponentEditorVerbSeparator := Menus.NewLine; 5805 ComponentEditorVerbSeparator.Name := ComponentEditorMIPrefix + IntToStr(VerbCount); 5806 MainPopupMenu.Items.Insert(VerbCount, ComponentEditorVerbSeparator); 5807 end; 5808 end; 5809 5810 procedure AddCollectionEditorMenuItems({%H-}ACollection: TCollection); 5811 var 5812 Item: TMenuItem; 5813 intf: IObjInspInterface; 5814 begin 5815 if ACollection.GetInterface(GUID_ObjInspInterface, intf) and not intf.AllowAdd then 5816 exit; 5817 5818 Item := NewItem(oisAddCollectionItem, 0, False, True, 5819 @CollectionAddItem, 0, ComponentEditorMIPrefix+'0'); 5820 MainPopupMenu.Items.Insert(0, Item); 5821 ComponentEditorVerbSeparator := NewLine; 5822 ComponentEditorVerbSeparator.Name := ComponentEditorMIPrefix+'1'; 5823 MainPopupMenu.Items.Insert(1, ComponentEditorVerbSeparator); 5824 end; 5825 5826 procedure AddZOrderMenuItems; 5827 var 5828 ZItem, Item: TMenuItem; 5829 begin 5830 ZItem := NewSubMenu(oisZOrder, 0, ComponentEditorMIPrefix+'ZOrder', [], True); 5831 Item := NewItem(oisOrderMoveToFront, 0, False, True, @ZOrderItemClick, 0, ''); 5832 Item.ImageIndex := IDEImages.LoadImage('Order_move_front'); 5833 Item.Tag := 0; 5834 ZItem.Add(Item); 5835 Item := NewItem(oisOrderMoveToBack, 0, False, True, @ZOrderItemClick, 0, ''); 5836 Item.ImageIndex := IDEImages.LoadImage('Order_move_back'); 5837 Item.Tag := 1; 5838 ZItem.Add(Item); 5839 Item := NewItem(oisOrderForwardOne, 0, False, True, @ZOrderItemClick, 0, ''); 5840 Item.ImageIndex := IDEImages.LoadImage('Order_forward_one'); 5841 Item.Tag := 2; 5842 ZItem.Add(Item); 5843 Item := NewItem(oisOrderBackOne, 0, False, True, @ZOrderItemClick, 0, ''); 5844 Item.ImageIndex := IDEImages.LoadImage('Order_back_one'); 5845 Item.Tag := 3; 5846 ZItem.Add(Item); 5847 if ComponentEditorVerbSeparator <> nil then 5848 MainPopupMenu.Items.Insert(ComponentEditorVerbSeparator.MenuIndex + 1, ZItem) 5849 else 5850 MainPopupMenu.Items.Insert(0, ZItem); 5851 Item := NewLine; 5852 Item.Name := ComponentEditorMIPrefix+'ZOrderSeparator'; 5853 MainPopupMenu.Items.Insert(ZItem.MenuIndex + 1, Item); 5854 end; 5855 5856var 5857 b, CanBeCopyPasted, CanBeDeleted, CanChangeClass, HasParentCand: Boolean; 5858 i: Integer; 5859 CurRow: TOIPropertyGridRow; 5860 Persistent: TPersistent; 5861 Page: TObjectInspectorPage; 5862begin 5863 RemovePropertyEditorMenuItems; 5864 RemoveComponentEditorMenuItems; 5865 ShowHintsPopupMenuItem.Checked := PropertyGrid.ShowHint; 5866 FStateOfHintsOnMainPopupMenu:=PropertyGrid.ShowHint; 5867 for Page := Low(TObjectInspectorPage) to High(TObjectInspectorPage) do 5868 if GridControl[Page] <> nil then 5869 GridControl[Page].ShowHint := False; 5870 Persistent := GetSelectedPersistent; 5871 CanBeCopyPasted := False; 5872 CanBeDeleted := False; 5873 CanChangeClass := False; 5874 HasParentCand := False; 5875 // show component editors only for component treeview 5876 if MainPopupMenu.PopupComponent = ComponentTree then 5877 begin 5878 ComponentEditor := GetComponentEditorForSelection; 5879 if ComponentEditor <> nil then 5880 AddComponentEditorMenuItems 5881 else 5882 begin 5883 // check if it is a TCollection 5884 if Persistent is TCollection then 5885 AddCollectionEditorMenuItems(TCollection(Persistent)) 5886 else if Persistent is TCollectionItem then 5887 AddCollectionEditorMenuItems(TCollectionItem(Persistent).Collection); 5888 end; 5889 for i:=0 to Selection.Count-1 do 5890 if Selection[i] is TComponent then 5891 begin 5892 CanBeDeleted := True; 5893 // ToDo: Figure out why TMenuItem or TAction cannot be copy / pasted in OI, 5894 if not (Selection[i] is TMenuItem) and 5895 not (Selection[i] is TAction) then // then fix it. 5896 CanBeCopyPasted := True; 5897 end; 5898 CanChangeClass := (Selection.Count = 1) and (Selection[0] is TComponent) 5899 and (Selection[0] <> FPropertyEditorHook.LookupRoot); 5900 // add Z-Order menu 5901 if (Selection.Count = 1) and (Selection[0] is TControl) then 5902 AddZOrderMenuItems; 5903 // check existing of Change Parent candidates 5904 if CanBeCopyPasted then 5905 HasParentCand := HasParentCandidates; 5906 end; 5907 CutPopupMenuItem.Visible := CanBeCopyPasted; 5908 CopyPopupMenuItem.Visible := CanBeCopyPasted; 5909 PastePopupMenuItem.Visible := CanBeCopyPasted; 5910 DeletePopupMenuItem.Visible := CanBeDeleted; 5911 OptionsSeparatorMenuItem2.Visible := CanBeCopyPasted or CanBeDeleted; 5912 ChangeClassPopupmenuItem.Visible := CanChangeClass; 5913 ChangeParentPopupmenuItem.Visible := HasParentCand; 5914 OptionsSeparatorMenuItem3.Visible := CanChangeClass or HasParentCand; 5915 5916 // The editors can do menu actions, for example set defaults and constraints 5917 CurRow := GetActivePropertyRow; 5918 if (MainPopupMenu.PopupComponent is TOICustomPropertyGrid) then 5919 begin 5920 // popup menu of property grid 5921 if CurRow<>nil then 5922 AddPropertyEditorMenuItems(CurRow.Editor); 5923 5924 b := (Favorites <> nil) and ShowFavorites and (GetActivePropertyRow <> nil); 5925 AddToFavoritesPopupMenuItem.Visible := b and 5926 (GetActivePropertyGrid <> FavoriteGrid) and Assigned(OnAddToFavorites); 5927 RemoveFromFavoritesPopupMenuItem.Visible := b and 5928 (GetActivePropertyGrid = FavoriteGrid) and Assigned(OnRemoveFromFavorites); 5929 5930 UndoPropertyPopupMenuItem.Visible := True; 5931 UndoPropertyPopupMenuItem.Enabled := (CurRow<>nil) 5932 and (CurRow.Editor.GetVisualValue <> GetActivePropertyGrid.CurrentEditValue); 5933 if CurRow=nil then begin 5934 FindDeclarationPopupmenuItem.Visible := False; 5935 end 5936 else begin 5937 FindDeclarationPopupmenuItem.Visible := true; 5938 FindDeclarationPopupmenuItem.Caption := Format(oisJumpToDeclarationOf, [CurRow.Name]); 5939 FindDeclarationPopupmenuItem.Hint := Format(oisJumpToDeclarationOf, 5940 [CurRow.Editor.GetPropertyPath(0)]); 5941 end; 5942 ViewRestrictedPropertiesPopupMenuItem.Visible := True; 5943 OptionsSeparatorMenuItem.Visible := True; 5944 end 5945 else 5946 begin 5947 // default popup menu 5948 AddToFavoritesPopupMenuItem.Visible := False; 5949 RemoveFromFavoritesPopupMenuItem.Visible := False; 5950 UndoPropertyPopupMenuItem.Visible := False; 5951 FindDeclarationPopupmenuItem.Visible := False; 5952 ViewRestrictedPropertiesPopupMenuItem.Visible := False; 5953 OptionsSeparatorMenuItem.Visible := False; 5954 end; 5955 //debugln(['TObjectInspectorDlg.OnMainPopupMenuPopup ',FindDeclarationPopupmenuItem.Visible]); 5956end; 5957 5958procedure TObjectInspectorDlg.DoModified; 5959begin 5960 if Assigned(FOnModified) then FOnModified(Self); 5961end; 5962 5963procedure TObjectInspectorDlg.DoUpdateRestricted; 5964begin 5965 if Assigned(FOnUpdateRestricted) then FOnUpdateRestricted(Self); 5966end; 5967 5968procedure TObjectInspectorDlg.DoViewRestricted; 5969begin 5970 if Assigned(FOnViewRestricted) then FOnViewRestricted(Self); 5971end; 5972 5973procedure TObjectInspectorDlg.ChangeParentItemClick(Sender: TObject); 5974begin 5975 if Selection.Count > 0 then 5976 ChangeParent; 5977end; 5978 5979procedure TObjectInspectorDlg.ComponentEditorVerbMenuItemClick(Sender: TObject); 5980var 5981 Verb: integer; 5982 AMenuItem: TMenuItem; 5983begin 5984 if Sender is TMenuItem then 5985 AMenuItem := TMenuItem(Sender) 5986 else 5987 Exit; 5988 Verb := AMenuItem.Tag; 5989 ComponentEditor.ExecuteVerb(Verb); 5990end; 5991 5992procedure TObjectInspectorDlg.CollectionAddItem(Sender: TObject); 5993var 5994 Persistent: TPersistent; 5995 Collection: TCollection absolute Persistent; 5996 ci: TCollectionItem; 5997begin 5998 Persistent := GetSelectedPersistent; 5999 if Persistent = nil then 6000 Exit; 6001 if Persistent is TCollectionItem then 6002 Persistent := TCollectionItem(Persistent).Collection; 6003 if not (Persistent is TCollection) then 6004 Exit; 6005 ci:=Collection.Add; 6006 GlobalDesignHook.PersistentAdded(ci,false); 6007 DoModified; 6008 Selection.ForceUpdate := True; 6009 try 6010 SetSelection(Selection); 6011 finally 6012 Selection.ForceUpdate := False; 6013 end; 6014end; 6015 6016procedure TObjectInspectorDlg.ZOrderItemClick(Sender: TObject); 6017var 6018 Control: TControl; 6019 ZOrder: TZOrderDelete; 6020 NewSelection: TPersistentSelectionList; 6021begin 6022 if not (Sender is TMenuItem) then Exit; 6023 if (Selection.Count <> 1) or not (Selection[0] is TControl) then Exit; 6024 Control := TControl(Selection[0]); 6025 if Control.Parent = nil then Exit; 6026 // The enum matches with the Tag numbers. 6027 ZOrder := TZOrderDelete(TMenuItem(Sender).Tag); 6028 case ZOrder of 6029 zoToFront: Control.BringToFront; 6030 zoToBack: Control.SendToBack; 6031 zoForward: Control.Parent.SetControlIndex(Control, Control.Parent.GetControlIndex(Control) + 1); 6032 zoBackward:Control.Parent.SetControlIndex(Control, Control.Parent.GetControlIndex(Control) - 1); 6033 end; 6034 6035 // Ensure controls that belong to a container are rearranged if required. 6036 Control.Parent.ReAlign; 6037 6038 // Ensure the order of controls in the OI now reflects the new ZOrder 6039 NewSelection := TPersistentSelectionList.Create; 6040 try 6041 NewSelection.ForceUpdate:=True; 6042 NewSelection.Add(Control.Parent); 6043 SetSelection(NewSelection); 6044 NewSelection.Clear; 6045 NewSelection.ForceUpdate:=True; 6046 NewSelection.Add(Control); 6047 SetSelection(NewSelection); 6048 finally 6049 NewSelection.Free; 6050 end; 6051 DoModified; 6052 ChangeCompZOrderInList(Control, ZOrder); 6053end; 6054 6055function TObjectInspectorDlg.GetComponentPanelHeight: integer; 6056begin 6057 Result := ComponentPanel.Height; 6058end; 6059 6060function TObjectInspectorDlg.GetInfoBoxHeight: integer; 6061begin 6062 Result := InfoPanel.Height; 6063end; 6064 6065procedure TObjectInspectorDlg.SetEnableHookGetSelection(AValue: boolean); 6066begin 6067 if FEnableHookGetSelection=AValue then Exit; 6068 FEnableHookGetSelection:=AValue; 6069 if PropertyEditorHook<>nil then 6070 if EnableHookGetSelection then 6071 FPropertyEditorHook.AddHandlerGetSelection(@HookGetSelection) 6072 else 6073 FPropertyEditorHook.RemoveHandlerGetSelection(@HookGetSelection) 6074end; 6075 6076procedure TObjectInspectorDlg.SetFilter(const AValue: TTypeKinds); 6077begin 6078 if FFilter=AValue then Exit; 6079 FFilter:=AValue; 6080 PropertyGrid.Filter := Filter - [tkMethod]; 6081 FavoriteGrid.Filter := Filter + [tkMethod]; 6082 RestrictedGrid.Filter := Filter + [tkMethod]; 6083end; 6084 6085procedure TObjectInspectorDlg.ActivateGrid(Grid: TOICustomPropertyGrid); 6086begin 6087 if Grid=PropertyGrid then NoteBook.PageIndex:=0 6088 else if Grid=EventGrid then NoteBook.PageIndex:=1 6089 else if Grid=FavoriteGrid then NoteBook.PageIndex:=2 6090 else if Grid=RestrictedGrid then NoteBook.PageIndex:=3; 6091end; 6092 6093procedure TObjectInspectorDlg.FocusGrid(Grid: TOICustomPropertyGrid); 6094var 6095 Index: Integer; 6096begin 6097 if Grid=nil then 6098 Grid := GetActivePropertyGrid 6099 else 6100 ActivateGrid(Grid); 6101 if Grid <> nil then 6102 begin 6103 Index := Grid.ItemIndex; 6104 if Index < 0 then 6105 Index := 0; 6106 Grid.SetItemIndexAndFocus(Index); 6107 end; 6108end; 6109 6110function TObjectInspectorDlg.GetGridControl(Page: TObjectInspectorPage 6111 ): TOICustomPropertyGrid; 6112begin 6113 case Page of 6114 oipgpFavorite: Result:=FavoriteGrid; 6115 oipgpEvents: Result:=EventGrid; 6116 oipgpRestricted: Result:=RestrictedGrid; 6117 else Result:=PropertyGrid; 6118 end; 6119end; 6120 6121procedure TObjectInspectorDlg.SetComponentEditor(const AValue: TBaseComponentEditor); 6122begin 6123 if FComponentEditor <> AValue then 6124 begin 6125 FComponentEditor.Free; 6126 FComponentEditor := AValue; 6127 end; 6128end; 6129 6130procedure TObjectInspectorDlg.SetFavorites(const AValue: TOIFavoriteProperties); 6131begin 6132 //debugln('TObjectInspectorDlg.SetFavorites ',dbgsName(Self)); 6133 if FFavorites=AValue then exit; 6134 FFavorites:=AValue; 6135 FavoriteGrid.Favorites:=FFavorites; 6136end; 6137 6138procedure TObjectInspectorDlg.ComponentTreeGetNodeImageIndex( 6139 APersistent: TPersistent; var AIndex: integer); 6140begin 6141 //ask TMediator 6142 if assigned(FOnNodeGetImageIndex) then 6143 FOnNodeGetImageIndex(APersistent, AIndex); 6144end; 6145 6146{ TCustomPropertiesGrid } 6147 6148function TCustomPropertiesGrid.GetTIObject: TPersistent; 6149begin 6150 if PropertyEditorHook<>nil then 6151 Result:=PropertyEditorHook.LookupRoot 6152 else 6153 Result:=Nil; 6154end; 6155 6156procedure TCustomPropertiesGrid.SetAutoFreeHook(const AValue: boolean); 6157begin 6158 if FAutoFreeHook=AValue then exit; 6159 FAutoFreeHook:=AValue; 6160end; 6161 6162procedure TCustomPropertiesGrid.SetTIObject(const AValue: TPersistent); 6163var 6164 NewSelection: TPersistentSelectionList; 6165begin 6166 if (TIObject=AValue) then begin 6167 if ((AValue<>nil) and (Selection.Count=1) and (Selection[0]=AValue)) 6168 or (AValue=nil) then 6169 exit; 6170 end; 6171 if SaveOnChangeTIObject then 6172 SaveChanges; 6173 if PropertyEditorHook=nil then 6174 begin 6175 fAutoFreeHook:=true; 6176 PropertyEditorHook:=TPropertyEditorHook.Create(Self); 6177 end; 6178 PropertyEditorHook.LookupRoot:=AValue; 6179 if (AValue=nil) or (Selection.Count<>1) or (Selection[0]<>AValue) then 6180 begin 6181 NewSelection:=TPersistentSelectionList.Create; 6182 try 6183 if AValue<>nil then 6184 NewSelection.Add(AValue); 6185 Selection:=NewSelection; 6186 finally 6187 NewSelection.Free; 6188 end; 6189 end; 6190end; 6191 6192constructor TCustomPropertiesGrid.Create(TheOwner: TComponent); 6193var 6194 Hook: TPropertyEditorHook; 6195begin 6196 Hook:=TPropertyEditorHook.Create(Self); 6197 FAutoFreeHook:=true; 6198 FSaveOnChangeTIObject:=true; 6199 CreateWithParams(TheOwner,Hook,AllTypeKinds,0); 6200end; 6201 6202destructor TCustomPropertiesGrid.Destroy; 6203begin 6204 if FAutoFreeHook then 6205 FreeAndNil(FPropertyEditorHook); 6206 inherited Destroy; 6207end; 6208 6209end. 6210 6211