diff --git a/G940LEDControl/Forms/ButtonFunctionFrm.dfm b/G940LEDControl/Forms/ButtonFunctionFrm.dfm
index a4a0057..6e8825f 100644
--- a/G940LEDControl/Forms/ButtonFunctionFrm.dfm
+++ b/G940LEDControl/Forms/ButtonFunctionFrm.dfm
@@ -72,10 +72,13 @@ object ButtonFunctionForm: TButtonFunctionForm
Header.Options = [hoAutoResize, hoColumnResize, hoDrag, hoShowSortGlyphs, hoVisible]
TabOrder = 1
TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoSort, toAutoTristateTracking, toAutoDeleteMovedNodes]
+ TreeOptions.MiscOptions = [toAcceptOLEDrop, toFullRepaintOnResize, toInitOnSave, toWheelPanning, toEditOnClick]
TreeOptions.PaintOptions = [toShowButtons, toShowDropmark, toShowTreeLines, toThemeAware, toUseBlendedImages]
TreeOptions.SelectionOptions = [toFullRowSelect]
+ OnFocusChanged = vstFunctionsFocusChanged
OnGetText = vstFunctionsGetText
OnPaintText = vstFunctionsPaintText
+ ExplicitTop = 5
Columns = <
item
Position = 0
@@ -98,9 +101,9 @@ object ButtonFunctionForm: TButtonFunctionForm
TabOrder = 2
object vstStates: TVirtualStringTree
Left = 0
- Top = 113
+ Top = 81
Width = 411
- Height = 239
+ Height = 271
Align = alClient
Header.AutoSizeIndex = 0
Header.Font.Charset = DEFAULT_CHARSET
@@ -108,8 +111,16 @@ object ButtonFunctionForm: TButtonFunctionForm
Header.Font.Height = -11
Header.Font.Name = 'Tahoma'
Header.Font.Style = []
+ Header.MainColumn = 1
Header.Options = [hoAutoResize, hoColumnResize, hoDrag, hoShowSortGlyphs, hoVisible]
TabOrder = 0
+ TreeOptions.MiscOptions = [toAcceptOLEDrop, toEditable, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning]
+ TreeOptions.PaintOptions = [toShowButtons, toShowDropmark, toThemeAware, toUseBlendedImages]
+ TreeOptions.SelectionOptions = [toExtendedFocus, toFullRowSelect]
+ OnChange = vstStatesChange
+ OnCreateEditor = vstStatesCreateEditor
+ OnEditing = vstStatesEditing
+ OnGetText = vstStatesGetText
Columns = <
item
Position = 0
@@ -119,20 +130,20 @@ object ButtonFunctionForm: TButtonFunctionForm
item
Position = 1
Width = 200
- WideText = 'Color'
+ WideText = 'Colour'
end>
end
object pnlName: TPanel
Left = 0
Top = 0
Width = 411
- Height = 113
+ Height = 81
Align = alTop
BevelOuter = bvNone
TabOrder = 1
DesignSize = (
411
- 113)
+ 81)
object lblFunctionName: TLabel
Left = 0
Top = 19
@@ -157,11 +168,17 @@ object ButtonFunctionForm: TButtonFunctionForm
Anchors = [akLeft, akTop, akRight]
AutoSize = False
Caption = 'runtime: category'
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clGrayText
+ Font.Height = -11
+ Font.Name = 'Tahoma'
+ Font.Style = []
+ ParentFont = False
ExplicitWidth = 401
end
object lblHasStates: TLabel
Left = 0
- Top = 74
+ Top = 47
Width = 401
Height = 31
AutoSize = False
@@ -173,7 +190,7 @@ object ButtonFunctionForm: TButtonFunctionForm
end
object lblNoStates: TLabel
Left = 0
- Top = 55
+ Top = 47
Width = 195
Height = 13
Caption = 'This function has no configurable states.'
diff --git a/G940LEDControl/Forms/ButtonFunctionFrm.pas b/G940LEDControl/Forms/ButtonFunctionFrm.pas
index 6c1c5b4..cb1b237 100644
--- a/G940LEDControl/Forms/ButtonFunctionFrm.pas
+++ b/G940LEDControl/Forms/ButtonFunctionFrm.pas
@@ -8,12 +8,18 @@ uses
Vcl.Forms,
Vcl.Graphics,
Vcl.StdCtrls,
+ Winapi.Messages,
VirtualTrees,
+ LEDFunctionIntf,
Profile;
+const
+ WM_STARTEDITING = WM_USER + 1;
+
+
type
TButtonFunctionForm = class(TForm)
pnlButtons: TPanel;
@@ -32,11 +38,22 @@ type
procedure FormDestroy(Sender: TObject);
procedure vstFunctionsGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: string);
procedure vstFunctionsPaintText(Sender: TBaseVirtualTree; const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType);
+ procedure vstFunctionsFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex);
+ procedure vstStatesGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: string);
+ procedure vstStatesChange(Sender: TBaseVirtualTree; Node: PVirtualNode);
+ procedure vstStatesCreateEditor(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; out EditLink: IVTEditLink);
+ procedure vstStatesEditing(Sender: TBaseVirtualTree;
+ Node: PVirtualNode; Column: TColumnIndex; var Allowed: Boolean);
private
FButtonIndex: Integer;
FProfile: TProfile;
+ protected
+ procedure WMStartEditing(var Msg: TMessage); message WM_STARTEDITING;
protected
procedure LoadFunctions;
+ procedure SetFunction(AProvider: ILEDFunctionProvider; AFunction: ILEDFunction);
+
+ procedure LoadStates(AFunction: ILEDMultiStateFunction);
property ButtonIndex: Integer read FButtonIndex write FButtonIndex;
property Profile: TProfile read FProfile write FProfile;
@@ -47,22 +64,36 @@ type
implementation
uses
- System.SysUtils,
Generics.Collections,
+ System.SysUtils,
+ Winapi.Windows,
- LEDFunctionIntf,
- LEDFunctionRegistry;
+ ColourEditor,
+ LEDFunctionRegistry,
+ LEDStateIntf;
type
- TNodeType = (ntCategory, ntFunction);
- TNodeData = record
- NodeType: TNodeType;
+ TFunctionNodeType = (ntCategory, ntFunction);
+ TFunctionNodeData = record
+ NodeType: TFunctionNodeType;
Provider: ILEDFunctionProvider;
LEDFunction: ILEDFunction;
end;
- PNodeData = ^TNodeData;
+ PFunctionNodeData = ^TFunctionNodeData;
+
+
+ TStateNodeData = record
+ State: ILEDState;
+ end;
+
+ PStateNodeData = ^TStateNodeData;
+
+
+const
+ ColumnState = 0;
+ ColumnColour = 1;
{$R *.dfm}
@@ -84,9 +115,8 @@ end;
procedure TButtonFunctionForm.FormCreate(Sender: TObject);
begin
- vstFunctions.NodeDataSize := SizeOf(TNodeData);
-
- lblNoStates.Top := lblHasStates.Top;
+ vstFunctions.NodeDataSize := SizeOf(TFunctionNodeData);
+ vstStates.NodeDataSize := SizeOf(TStateNodeData);
lblCategoryName.Caption := '';
lblFunctionName.Caption := '';
@@ -108,7 +138,7 @@ var
function GetCategoryNode(AProvider: ILEDFunctionProvider; AFunction: ILEDFunction): PVirtualNode;
var
category: string;
- nodeData: PNodeData;
+ nodeData: PFunctionNodeData;
begin
category := AFunction.GetCategoryName;
@@ -130,7 +160,7 @@ var
var
node: PVirtualNode;
- nodeData: PNodeData;
+ nodeData: PFunctionNodeData;
provider: ILEDFunctionProvider;
ledFunction: ILEDFunction;
@@ -162,10 +192,88 @@ begin
end;
+procedure TButtonFunctionForm.SetFunction(AProvider: ILEDFunctionProvider; AFunction: ILEDFunction);
+var
+ multiStateFunction: ILEDMultiStateFunction;
+
+begin
+ lblCategoryName.Caption := AFunction.GetCategoryName;
+ lblFunctionName.Caption := AFunction.GetDisplayName;
+
+ if Supports(AFunction, ILEDMultiStateFunction, multiStateFunction) then
+ begin
+ lblNoStates.Visible := False;
+ lblHasStates.Visible := True;
+
+ LoadStates(multiStateFunction);
+ vstStates.Visible := True;
+ end else
+ begin
+ lblNoStates.Visible := True;
+ lblHasStates.Visible := False;
+
+ vstStates.Visible := False;
+ vstStates.Clear;
+ end;
+end;
+
+
+procedure TButtonFunctionForm.LoadStates(AFunction: ILEDMultiStateFunction);
+var
+ node: PVirtualNode;
+ nodeData: PStateNodeData;
+ state: ILEDState;
+
+begin
+ vstStates.BeginUpdate;
+ try
+ vstStates.Clear;
+
+ for state in AFunction do
+ begin
+ node := vstStates.AddChild(nil);
+ nodeData := vstStates.GetNodeData(node);
+ nodeData^.State := state;
+ end;
+ finally
+ vstStates.EndUpdate;
+ end;
+end;
+
+
+procedure TButtonFunctionForm.vstFunctionsFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex);
+var
+ nodeData: PFunctionNodeData;
+ functionNode: PVirtualNode;
+
+begin
+ if Assigned(Node) then
+ begin
+ nodeData := Sender.GetNodeData(Node);
+
+ case nodeData^.NodeType of
+ ntCategory:
+ begin
+ { Select first child (function) node instead }
+ functionNode := Sender.GetFirstChild(Node);
+ if not Assigned(functionNode) then
+ exit;
+
+ Sender.FocusedNode := functionNode;
+ Sender.Selected[functionNode] := True;
+ end;
+
+ ntFunction:
+ SetFunction(nodeData^.Provider, nodeData^.LEDFunction);
+ end;
+ end;
+end;
+
+
procedure TButtonFunctionForm.vstFunctionsGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex;
TextType: TVSTTextType; var CellText: string);
var
- nodeData: PNodeData;
+ nodeData: PFunctionNodeData;
begin
nodeData := Sender.GetNodeData(Node);
@@ -180,7 +288,7 @@ end;
procedure TButtonFunctionForm.vstFunctionsPaintText(Sender: TBaseVirtualTree; const TargetCanvas: TCanvas;
Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType);
var
- nodeData: PNodeData;
+ nodeData: PFunctionNodeData;
begin
nodeData := Sender.GetNodeData(Node);
@@ -191,4 +299,49 @@ begin
TargetCanvas.Font.Style := [];
end;
+
+procedure TButtonFunctionForm.vstStatesGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex;
+ TextType: TVSTTextType; var CellText: string);
+var
+ nodeData: PStateNodeData;
+
+begin
+ nodeData := Sender.GetNodeData(Node);
+
+ case Column of
+ ColumnState: CellText := nodeData^.State.GetDisplayName;
+ ColumnColour: CellText := 'Red';
+ end;
+end;
+
+
+procedure TButtonFunctionForm.vstStatesChange(Sender: TBaseVirtualTree; Node: PVirtualNode);
+begin
+ if Assigned(Node) and not (tsIncrementalSearching in Sender.TreeStates) then
+ PostMessage(Self.Handle, WM_STARTEDITING, WPARAM(Node), 0);
+end;
+
+
+procedure TButtonFunctionForm.vstStatesCreateEditor(Sender: TBaseVirtualTree; Node: PVirtualNode;
+ Column: TColumnIndex; out EditLink: IVTEditLink);
+begin
+ EditLink := TVTColourEditor.Create;
+end;
+
+
+procedure TButtonFunctionForm.vstStatesEditing(Sender: TBaseVirtualTree;
+ Node: PVirtualNode; Column: TColumnIndex; var Allowed: Boolean);
+begin
+ Allowed := True;
+end;
+
+procedure TButtonFunctionForm.WMStartEditing(var Msg: TMessage);
+var
+ node: PVirtualNode;
+
+begin
+ node := Pointer(Msg.WParam);
+ vstStates.EditNode(Node, 1);
+end;
+
end.
diff --git a/G940LEDControl/G940LEDControl.dpr b/G940LEDControl/G940LEDControl.dpr
index da5f91d..0bba2da 100644
--- a/G940LEDControl/G940LEDControl.dpr
+++ b/G940LEDControl/G940LEDControl.dpr
@@ -29,7 +29,8 @@ uses
FSXLEDFunction in 'Units\FSXLEDFunction.pas',
StaticResources in 'Units\StaticResources.pas',
FSXResources in 'Units\FSXResources.pas',
- FSXSimConnectClient in 'Units\FSXSimConnectClient.pas';
+ FSXSimConnectClient in 'Units\FSXSimConnectClient.pas',
+ ColourEditor in 'Units\ColourEditor.pas';
{$R *.res}
diff --git a/G940LEDControl/G940LEDControl.dproj b/G940LEDControl/G940LEDControl.dproj
index 5638f7d..4c8b157 100644
--- a/G940LEDControl/G940LEDControl.dproj
+++ b/G940LEDControl/G940LEDControl.dproj
@@ -195,6 +195,7 @@
+
Cfg_2
Base
diff --git a/G940LEDControl/Units/ColourEditor.pas b/G940LEDControl/Units/ColourEditor.pas
new file mode 100644
index 0000000..2daf26d
--- /dev/null
+++ b/G940LEDControl/Units/ColourEditor.pas
@@ -0,0 +1,141 @@
+unit ColourEditor;
+
+interface
+uses
+ System.Types,
+ System.Classes,
+ Vcl.StdCtrls,
+ Winapi.Messages,
+
+ VirtualTrees;
+
+
+type
+ TVTColourEditor = class(TInterfacedObject, IVTEditLink)
+ private
+ FEdit: TComboBox;
+ FTree: TBaseVirtualTree;
+ FColumn: TColumnIndex;
+ protected
+ procedure EditKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
+ protected
+ { IVTEditLink }
+ function BeginEdit: Boolean; stdcall;
+ function CancelEdit: Boolean; stdcall;
+ function EndEdit: Boolean; stdcall;
+
+ function PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean; stdcall;
+ procedure ProcessMessage(var Message: TMessage); stdcall;
+
+ function GetBounds: TRect; stdcall;
+ procedure SetBounds(R: TRect); stdcall;
+ public
+ destructor Destroy; override;
+ end;
+
+implementation
+uses
+ System.SysUtils,
+ Winapi.Windows;
+
+
+{ TVTColourEditor }
+destructor TVTColourEditor.Destroy;
+begin
+ FreeAndNil(FEdit);
+
+ inherited;
+end;
+
+
+function TVTColourEditor.BeginEdit: Boolean;
+begin
+ Result := True;
+ FEdit.Show;
+ FEdit.SetFocus;
+end;
+
+
+function TVTColourEditor.CancelEdit: Boolean;
+begin
+ Result := True;
+ FEdit.Hide;
+end;
+
+
+function TVTColourEditor.EndEdit: Boolean;
+begin
+ Result := True;
+ // TODO update node data
+end;
+
+
+function TVTColourEditor.PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean;
+begin
+ Result := True;
+
+ FTree := Tree;
+// FNode := Node;
+ FColumn := Column;
+
+ FreeAndNil(FEdit);
+
+ FEdit := TComboBox.Create(nil);
+ FEdit.Visible := False;
+ FEdit.Parent := Tree;
+
+// FEdit.Text := Data.Value;
+// FEdit.Items.Add();
+
+ FEdit.OnKeyDown := EditKeyDown;
+end;
+
+
+procedure TVTColourEditor.ProcessMessage(var Message: TMessage);
+begin
+ FEdit.WindowProc(Message);
+end;
+
+
+function TVTColourEditor.GetBounds: TRect;
+begin
+ Result := FEdit.BoundsRect;
+end;
+
+
+procedure TVTColourEditor.SetBounds(R: TRect);
+var
+ dummy: Integer;
+
+begin
+ (FTree as TVirtualStringTree).Header.Columns.GetColumnBounds(FColumn, dummy, R.Right);
+ FEdit.BoundsRect := R;
+end;
+
+
+procedure TVTColourEditor.EditKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
+begin
+ case Key of
+ VK_ESCAPE:
+ begin
+ FTree.CancelEditNode;
+ Key := 0;
+ end;
+
+ VK_RETURN:
+ begin
+ FTree.EndEditNode;
+ Key := 0;
+ end;
+
+ VK_UP,
+ VK_DOWN:
+ if (Shift = []) and (not FEdit.DroppedDown) then
+ begin
+ PostMessage(FTree.Handle, WM_KEYDOWN, Key, 0);
+ Key := 0;
+ end;
+ end;
+end;
+
+end.