mirror of https://gitlab.com/basile.b/dexed.git
342 lines
8.9 KiB
Plaintext
342 lines
8.9 KiB
Plaintext
unit u_optionseditor;
|
|
|
|
{$I u_defines.inc}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils, FileUtil, RTTIGrids, Forms, Controls, Graphics, ExtCtrls,
|
|
Menus, ComCtrls, Buttons, PropEdits, ObjectInspector, u_sharedres,
|
|
u_common, u_widget, u_interfaces, u_observer, u_dialogs;
|
|
|
|
type
|
|
|
|
// store the information about the obsever
|
|
// exposing some editable options.
|
|
PCategoryData = ^TCategoryData;
|
|
TCategoryData = record
|
|
kind: TOptionEditorKind;
|
|
container: TPersistent;
|
|
observer: IEditableOptions;
|
|
end;
|
|
|
|
{ TOptionEditorWidget }
|
|
|
|
TOptionEditorWidget = class(TDexedWidget, IOptionsEditor)
|
|
btnCancel: TSpeedButton;
|
|
btnAccept: TSpeedButton;
|
|
pnlEd: TPanel;
|
|
pnlBody: TPanel;
|
|
pnlFooter: TPanel;
|
|
Splitter1: TSplitter;
|
|
inspector: TTIPropertyGrid;
|
|
selCat: TTreeView;
|
|
procedure btnAcceptClick(Sender: TObject);
|
|
procedure btnCancelClick(Sender: TObject);
|
|
procedure FormCloseQuery(Sender: TObject; var CanClose: boolean);
|
|
procedure inspectorEditorFilter(Sender: TObject; aEditor: TPropertyEditor;
|
|
var aShow: boolean);
|
|
procedure inspectorModified(Sender: TObject);
|
|
procedure selCatChanging(Sender: TObject; Node: TTreeNode;
|
|
var AllowChange: Boolean);
|
|
procedure selCatDeletion(Sender: TObject; Node: TTreeNode);
|
|
procedure selCatSelectionChanged(Sender: TObject);
|
|
protected
|
|
procedure UpdateShowing; override;
|
|
private
|
|
fUpdatingCat: boolean;
|
|
fCatChanged: boolean;
|
|
fEdOptsSubj: TEditableOptionsSubject;
|
|
procedure updateCategories;
|
|
function allowCategoryChange: boolean;
|
|
function sortCategories(Cat1, Cat2: TTreeNode): integer;
|
|
procedure showOptionEditor(observer: IEditableOptions = nil);
|
|
function singleServiceName: string;
|
|
public
|
|
constructor create(aOwner: TComponent); override;
|
|
destructor destroy; override;
|
|
end;
|
|
|
|
implementation
|
|
{$R *.lfm}
|
|
|
|
const
|
|
msg_mod = 'The current category modifications are not validated, discard them and continue ?';
|
|
|
|
{$REGION Standard Comp/Obj------------------------------------------------------}
|
|
constructor TOptionEditorWidget.create(aOwner: TComponent);
|
|
begin
|
|
inherited;
|
|
toolbarVisible:=false;
|
|
fIsDockable := false;
|
|
fIsModal:= true;
|
|
fEdOptsSubj := TEditableOptionsSubject.create;
|
|
inspector.CheckboxForBoolean := true;
|
|
inspector.PropertyEditorHook.AddHandlerModified(@inspectorModified);
|
|
inspector.DefaultItemHeight := scaleY(22, 96);
|
|
selCat.Width := ScaleX(180, 96);
|
|
width := ScaleX(600, 96);
|
|
|
|
case GetIconScaledSize of
|
|
iss16:
|
|
begin
|
|
AssignPng(btnCancel, 'CANCEL');
|
|
AssignPng(btnAccept, 'ACCEPT');
|
|
end;
|
|
iss24:
|
|
begin
|
|
AssignPng(btnCancel, 'CANCEL24');
|
|
AssignPng(btnAccept, 'ACCEPT24');
|
|
end;
|
|
iss32:
|
|
begin
|
|
AssignPng(btnCancel, 'CANCEL32');
|
|
AssignPng(btnAccept, 'ACCEPT32');
|
|
end;
|
|
end;
|
|
|
|
EntitiesConnector.addSingleService(self);
|
|
end;
|
|
|
|
destructor TOptionEditorWidget.destroy;
|
|
begin
|
|
fCatChanged := false;
|
|
fEdOptsSubj.Free;
|
|
inherited;
|
|
end;
|
|
|
|
procedure TOptionEditorWidget.UpdateShowing;
|
|
begin
|
|
inherited;
|
|
if Visible then
|
|
begin
|
|
updateCategories;
|
|
inspector.SplitterX := inspector.width div 2;
|
|
inspector.PreferredSplitterX := inspector.SplitterX;
|
|
end;
|
|
end;
|
|
{$ENDREGION}
|
|
|
|
{$REGION Option editor things --------------------------------------------------}
|
|
procedure TOptionEditorWidget.showOptionEditor(observer: IEditableOptions = nil);
|
|
var
|
|
n: TTreeNode;
|
|
begin
|
|
if assigned(observer) then
|
|
begin
|
|
if selCat.Items.Count = 0 then
|
|
updateCategories;
|
|
n := selCat.Items.FindNodeWithText(observer.optionedWantCategory());
|
|
if n.isNotNil then
|
|
selCat.Selected := n;
|
|
end;
|
|
showWidget;
|
|
end;
|
|
|
|
function TOptionEditorWidget.singleServiceName: string;
|
|
begin
|
|
exit('IOptionsEditor');
|
|
end;
|
|
|
|
procedure TOptionEditorWidget.updateCategories;
|
|
var
|
|
i: Integer;
|
|
dt: PCategoryData;
|
|
ed: IEditableOptions;
|
|
sel: string = '';
|
|
begin
|
|
if selCat.Selected.isNotNil then
|
|
sel := selCat.Selected.Text;
|
|
fUpdatingCat := true;
|
|
inspector.TIObject := nil;
|
|
selCat.BeginUpdate;
|
|
selCat.Items.Clear;
|
|
for i:= 0 to fEdOptsSubj.observersCount-1 do
|
|
begin
|
|
dt := new(PCategoryData);
|
|
ed := fEdOptsSubj.observers[i] as IEditableOptions;
|
|
selCat.Items.AddObject(nil, ed.optionedWantCategory, dt);
|
|
dt^.container := ed.optionedWantContainer;
|
|
dt^.kind := ed.optionedWantEditorKind;
|
|
dt^.observer := ed;
|
|
end;
|
|
selCat.Items.SortTopLevelNodes(@sortCategories);
|
|
for i := 0 to selCat.Items.Count-1 do
|
|
if SelCat.Items.Item[i].Text = sel then
|
|
SelCat.Selected := SelCat.Items.Item[i];
|
|
selCat.EndUpdate;
|
|
fUpdatingCat := false;
|
|
end;
|
|
|
|
function TOptionEditorWidget.sortCategories(Cat1, Cat2: TTreeNode): integer;
|
|
begin
|
|
result := CompareText(Cat1.Text, Cat2.Text);
|
|
end;
|
|
|
|
procedure TOptionEditorWidget.selCatDeletion(Sender: TObject; Node: TTreeNode);
|
|
begin
|
|
if node.Data.isNotNil then
|
|
Dispose(PCategoryData(node.Data));
|
|
end;
|
|
|
|
function TOptionEditorWidget.allowCategoryChange: boolean;
|
|
var
|
|
dt: PCategoryData;
|
|
begin
|
|
result := true;
|
|
if fUpdatingCat then
|
|
exit;
|
|
if csDestroying in ComponentState then
|
|
exit;
|
|
if selCat.Selected.isNil then
|
|
exit;
|
|
if selCat.Selected.Data.isNil then
|
|
exit;
|
|
// accept/cancel is relative to a single category
|
|
dt := PCategoryData(selCat.Selected.Data);
|
|
// generic editor, changes are tracked directly here
|
|
if dt^.kind = oekGeneric then
|
|
begin
|
|
if fCatChanged then
|
|
begin
|
|
result := dlgYesNo(msg_mod) = mrYes;
|
|
fCatChanged := not result;
|
|
if result then
|
|
btnCancelClick(nil);
|
|
end;
|
|
// custom editor, changes are notified by optionedOptionsModified()
|
|
end else
|
|
begin
|
|
dt := PCategoryData(selCat.Selected.Data);
|
|
if dt^.container.isNil or (dt^.observer = nil) then
|
|
exit;
|
|
if dt^.observer.optionedOptionsModified() then
|
|
begin
|
|
result := dlgYesNo(msg_mod) = mrYes;
|
|
if result then
|
|
btnCancelClick(nil);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TOptionEditorWidget.selCatChanging(Sender: TObject;Node: TTreeNode;
|
|
var AllowChange: Boolean);
|
|
begin
|
|
AllowChange := allowCategoryChange;
|
|
end;
|
|
|
|
procedure TOptionEditorWidget.selCatSelectionChanged(Sender: TObject);
|
|
var
|
|
dt: PCategoryData;
|
|
begin
|
|
// remove either the control, the form or the inspector used as editor.
|
|
inspector.TIObject := nil;
|
|
if pnlEd.ControlCount > 0 then
|
|
begin
|
|
pnlEd.Controls[0].Visible:=false;
|
|
pnlEd.Controls[0].Parent := nil;
|
|
end;
|
|
|
|
if selCat.Selected.isNil or selcat.Selected.Data.isNil then
|
|
exit;
|
|
|
|
dt := PCategoryData(selCat.Selected.Data);
|
|
if dt^.container.isNil then
|
|
exit;
|
|
case dt^.kind of
|
|
oekControl:
|
|
begin
|
|
TWinControl(dt^.container).Parent := pnlEd;
|
|
TWinControl(dt^.container).Align := alClient;
|
|
TWinControl(dt^.container).Visible:=true;
|
|
end;
|
|
oekForm:
|
|
begin
|
|
TCustomForm(dt^.container).ShowInTaskBar:= TShowInTaskbar.stNever;
|
|
TCustomForm(dt^.container).Parent := pnlEd;
|
|
TCustomForm(dt^.container).Align := alClient;
|
|
TCustomForm(dt^.container).BorderIcons:= [];
|
|
TCustomForm(dt^.container).BorderStyle:= bsNone;
|
|
TCustomForm(dt^.container).Show;
|
|
TCustomForm(dt^.container).Visible:=true;
|
|
end;
|
|
oekGeneric:
|
|
begin
|
|
inspector.Parent := pnlEd;
|
|
inspector.Align := alClient;
|
|
inspector.TIObject := dt^.container;
|
|
inspector.Visible:=true;
|
|
end;
|
|
end;
|
|
|
|
PCategoryData(selCat.Selected.Data)^
|
|
.observer
|
|
.optionedEvent(oeeSelectCat);
|
|
end;
|
|
|
|
procedure TOptionEditorWidget.inspectorModified(Sender: TObject);
|
|
begin
|
|
if selCat.Selected.isNil or selcat.Selected.Data.isNil then
|
|
exit;
|
|
|
|
fCatChanged := true;
|
|
PCategoryData(selCat.Selected.Data)^
|
|
.observer
|
|
.optionedEvent(oeeChange);
|
|
end;
|
|
|
|
procedure TOptionEditorWidget.btnCancelClick(Sender: TObject);
|
|
begin
|
|
if selCat.Selected.isNil or selcat.Selected.Data.isNil then
|
|
exit;
|
|
|
|
fCatChanged := false;
|
|
if inspector.Parent.isNotNil then
|
|
inspector.ItemIndex := -1;
|
|
PCategoryData(selCat.Selected.Data)^
|
|
.observer
|
|
.optionedEvent(oeeCancel);
|
|
end;
|
|
|
|
procedure TOptionEditorWidget.FormCloseQuery(Sender: TObject;
|
|
var CanClose: boolean);
|
|
begin
|
|
canClose := allowCategoryChange;
|
|
end;
|
|
|
|
procedure TOptionEditorWidget.inspectorEditorFilter(Sender: TObject;aEditor:
|
|
TPropertyEditor; var aShow: boolean);
|
|
var
|
|
nme: string;
|
|
len: integer;
|
|
begin
|
|
if aEditor.GetComponent(0) is TComponent then
|
|
begin
|
|
nme := aEditor.GetPropInfo^.Name;
|
|
len := nme.length;
|
|
if (len > 2) and (nme[len - 2 .. len] = 'Tag') then
|
|
aShow := false
|
|
else if nme = 'Name' then
|
|
aShow := false
|
|
else if aEditor.GetPropInfo^.PropType = TypeInfo(TCollection) then
|
|
aShow := false;
|
|
end;
|
|
end;
|
|
|
|
procedure TOptionEditorWidget.btnAcceptClick(Sender: TObject);
|
|
begin
|
|
if selCat.Selected.isNil or selcat.Selected.Data.isNil then
|
|
exit;
|
|
|
|
fCatChanged := false;
|
|
if inspector.Parent.isNotNil then
|
|
inspector.ItemIndex := -1;
|
|
PCategoryData(selCat.Selected.Data)^
|
|
.observer
|
|
.optionedEvent(oeeAccept);
|
|
end;
|
|
{$ENDREGION}
|
|
|
|
end.
|
|
|