InspectorBar controls : Using custom inplace editors

TInspectorBar

The InspectorBars provide a similar functionality as TAdvStringGrid to use any TWinControl descendent component as inplace editor for the InspectorBar. This is done through a TInspectorEditLink that handles the communication between the InspectorBar and the TWinControl based inplace editor. To start using a custom inplace editor, it is then sufficient to :

1) Drop the TInspectorEditLink component for the custom editor on the form
2) Set the EditLink property for the item that needs to be edited with this custom inplace editor to the InspectorEditLink component
3) Set the PropertyType to ptCustom

The InspectorBar has also the capability to draw an always visible dropdown button, spin up/down buttons and ellipsis button when the inplace editor is not visible.
This is done with the event : OnCustomEditButton. This event queries the button type that must be drawn for the custom editor. In case no button must be drawn, set the parameter AEditButton to ebNone. If drawing the button is not sufficient, but the value part of the property editor must be fully custom drawn, the OnCustomEditDraw event can be used. This allows drawing the value part during the time the inplace editor is not visible. A typical use for this custom drawing is showing a color as a color preview box instead of text only.

Before covering more in depth the creation of InspectorEditLink components, this is a brief look at how these are used. There are 2 categories of custom inplace editors possible. Either the inplace editor is shown in the inspector value rectangle or is shown as a popup. This is controlled by the EditStyle which can be esInplace or esPopup. When the esPopup style is choosen, the PopupWidth and PopupHeight control the size of the popup window at edit time.

The AEInspectorEditLink component enables the use of TAdvEdit in the InspectorBar. It exposes several properties such as EditColor, EditType, ModifiedColor, Prefix, Suffix etc.. These properties are applied to the TAdvEdit control when the edit control needs to be activated. Additional properties can be set from the OnSetProperties event. The ColComboInspectorEditLink makes using the TColumnComboBox component possible in the Inspector. The ColComboInspectorEditLink creates the ColumnComboBox and exposes this as ColComboInspectorEditLink.ColumnCombobox. This ColumnCombobox can as such be configured for its use in the Inspector from the OnSetProperties event. This example shows how it is done :
procedure TForm1.ColComboInspectorEditLink1SetProperties(Sender: TObject;
  R: TRect; Item: TInspectorItem);

begin
  with ColComboInspectorEditLink1.ColumnComboBox do
  begin
    // Configure the columns
    Columns.Clear;
    with Columns.Add do
    begin
      Width := 50;
      Font.Name := 'Tahoma'; 
    end;
    with Columns.Add do
    begin
      Width := 150;
      Font.Color := clBlue;
      Font.Style := [fsItalic];
      Font.Name := 'Tahoma';
    end;
    ComboItems.Clear;

    // Add the items in 2 columns
    with ComboItems.Add.Strings do
    begin
      Add('BMW');
      Add('3 series');
    end;
    with ComboItems.Add.Strings do
    begin
      Add('Porsche');
      Add('Boxster Roadster series');
    end;
    with ComboItems.Add.Strings do
    begin
      Add('Mercedes');
      Add('SL Grand Tourismo series');
    end;
    with ComboItems.Add.Strings do
    begin
      Add('Audi');
      Add('TT roadster series');
    end;

    // Use the Item's IntValue to preselect the correct combobox entry

    ItemIndex := Item.IntValue;
  end;
end;

Creation of TInspectorEditLink descendent components :

This is the base class for a TInspectorEditLink. All descendent components will at least override a few methods of the base class to support a custom inplace editor.
TInspectorEditLink = class(TComponent)
  public
    function GetEditor: TWinControl; virtual;
    procedure CreateEditor(AParent:TWinControl); virtual;
    procedure DestroyEditor; virtual;
    procedure SetProperties(R: TRect; Item: TInspectorItem); virtual;
    procedure StartEdit(Item: TInspectorItem); virtual;
    procedure StopEdit(Item: TInspectorItem); virtual;
    function GetEditorValue: string; virtual;
    procedure SetEditorValue(s: string); virtual;
    procedure SetOriginalValue; virtual;
    property Inspector: TInspectorBar;
  published
    property EditStyle: TInspectorEditStyle;
    property PopupWidth: Integer;
    property PopupHeight: Integer;
    property WantKeyLeftRight: Boolean;
    property WantKeyUpDown: Boolean;
    property WantKeyHomeEnd: Boolean;
    property WantKeyPriorNext: Boolean;
    property WantKeyReturn: Boolean;
    property WantKeyEscape: Boolean;
    property Tag: Integer;
    property OnSetProperties: TInspSetPropertiesEvent;
  end;
Virtual methods:
The first function that will always have to be used is GetEditor. Use this function to return the custom inplace editor as a TWinControl. The CreateEditor method is called when the inplace editor needs to be activated. Either this method can be used to create an instance of the inplace editor or the TInspectorEditLink constructor. The DestroyEditor is called when the inplace editor editing ends. Either in this method, the inplace editor can be destroyed or in the TInspectorEditLink's destructor. The StartEdit method is called just before making the editor visible. It allows setting some inplace editor values dependent on the item being edited. The StopEdit method allows to set some values in the item being edited after editing is done. 2 methods are used to get and set the item's value as a text : SetEditorValue & GetEditorValue. Finally, the method SetOriginalValue is called when the value needs to be restored when the users pressed ESC.

Properties:
The base class properties WantKeyXXXX are used to set which keystrokes the inplace editor will handle itself and which ones are handled automatically by the Inspector. The EditStyle determines whether the inplace editor is a displayed in the text value rectangle (esInplace style) or uses a popup (esPopup style) In the esPopup style, the PopupWidth / PopupHeight determine the size of the popup.

Applying this to create an InspectorEditLink for TAdvEdit results in following code:
{ TAEInspectorEditLink }


constructor TAEInspectorEditLink.Create(AOwner: TComponent);

begin
  inherited;
  // Initialize default properties
  FAdvEdit := nil;
  FEditColor := clWhite;
  FModifiedColor := clRed;

end;


procedure TAEInspectorEditLink.CreateEditor(AParent: TWinControl);

begin
  inherited;
  // Create an instance of TAdvEdit
  if not Assigned(FAdvEdit) then
    FAdvEdit := TAdvEdit.Create(AParent);
  // Make sure it is not visible yet
  FAdvEdit.Width := 0;
  FAdvEdit.Height := 0;
  FAdvEdit.Parent := AParent;
  FAdvEdit.Visible := False;
  // Use the Inspectors keyboard handling
  FAdvEdit.OnKeyDown := EditKeyDown;

end;


destructor TAEInspectorEditLink.Destroy;

begin
  // Make sure the TAdvEdit instance is destroyed in all circumstances
  if Assigned(FAdvEdit) then
    FAdvEdit.Free;
  FAdvEdit := nil;
  inherited;

end;


procedure TAEInspectorEditLink.DestroyEditor;

begin
  // Destroy the TAdvEdit instance
  if Assigned(FAdvEdit) then
    FAdvEdit.Free;
  FAdvEdit := nil;
  inherited;

end;


function TAEInspectorEditLink.GetEditor: TWinControl;

begin
  // Returns the inplace edit control as TWinControl
  Result := FAdvEdit;

end;


procedure TAEInspectorEditLink.SetOriginalValue;

begin
  inherited;
  // Restore original value when ESC is pressed
  FAdvEdit.Text := FOrigValue;

end;


procedure TAEInspectorEditLink.SetProperties(R: TRect; Item: TInspectorItem);

begin
  // Method called just before display of the inplace editor, allows to set
  // all properties here

  inherited;
  InflateRect(R,-2,-1);
  R.Right := R.Right - 20;
  
  FAdvEdit.Left := R.Left;
  FAdvEdit.Top := R.Top;
  FAdvEdit.Width := R.Right - R.Left;
  FAdvEdit.Height := R.Bottom - R.Top;
  FAdvEdit.BorderStyle := bsNone;
  FAdvEdit.Font.Assign(Item.InspectorPanel.Font);
  FAdvEdit.Color := FEditColor;
  FAdvEdit.FocusColor := FEditColor;
  FAdvEdit.EditType := FEditType;
  FAdvEdit.EditAlign := FEditAlign;
  FAdvEdit.ModifiedColor := FModifiedColor;
  FAdvEdit.Prefix := FPrefix;
  FAdvEdit.Suffix := FSuffix;
  FAdvEdit.ShowModified := FShowModified;
  FAdvEdit.Precision := FPrecision;

end;


procedure TAEInspectorEditLink.StartEdit(Item: TInspectorItem);

begin
  inherited;
  // Save current value to be able to restore when ESC is pressed & set initial value
  FOrigValue := Item.TextValue;
  FAdvEdit.Text := Item.TextValue;
  FAdvEdit.Visible := True;
  FAdvEdit.SetFocus;

end;


procedure TAEInspectorEditLink.StopEdit(Item: TInspectorItem);

begin
  // Update item with edited value
  inherited;
  Item.TextValue := FAdvEdit.Text;
  FAdvEdit.Visible := False;

end;

The INSPLINKS.PAS code is included in the distribution for TInspectorBar and can be used in Delphi & C++Builder