mirror of https://github.com/x64dbg/zydis
1823 lines
54 KiB
Plaintext
1823 lines
54 KiB
Plaintext
|
unit formMain;
|
||
|
|
||
|
interface
|
||
|
|
||
|
uses
|
||
|
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, System.UITypes,
|
||
|
System.ImageList, System.Generics.Collections, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
|
||
|
Vcl.ImgList, Vcl.StdCtrls, Vcl.ExtCtrls, dxSkinsCore, dxSkinBlue, dxSkinSeven, dxDockPanel, cxOI,
|
||
|
dxSkinsdxBarPainter, cxGraphics, cxControls, cxLookAndFeels, cxLookAndFeelPainters,cxVGrid,
|
||
|
dxRibbonCustomizationForm, dxRibbonSkins, cxStyles, cxEdit, cxInplaceContainer, dxSkinsForm,
|
||
|
dxStatusBar, dxRibbonStatusBar, cxClasses, dxRibbon, dxBar, dxRibbonForm, cxSplitter, cxPC,
|
||
|
dxBarExtItems, dxSkinsdxDockControlPainter, dxDockControl, dxSkinsdxRibbonPainter,
|
||
|
dxGDIPlusClasses, VirtualTrees, untInstructionEditor;
|
||
|
|
||
|
// TODO: Add support for multi node selection and allow copy / paste / cut / delete of mutiple
|
||
|
// definitions
|
||
|
// http://www.delphipraxis.net/136601-virtual-treeview-multiselect-onchange-event-problem.html
|
||
|
|
||
|
// TODO: Update inspector after inspected object changed
|
||
|
|
||
|
type
|
||
|
TfrmMain = class(TdxRibbonForm)
|
||
|
BarManager: TdxBarManager;
|
||
|
RibbonTab1: TdxRibbonTab;
|
||
|
Ribbon: TdxRibbon;
|
||
|
StatusBar: TdxRibbonStatusBar;
|
||
|
SkinController: TdxSkinController;
|
||
|
barMainManu: TdxBar;
|
||
|
barEditor: TdxBar;
|
||
|
lbLoadDatabase: TdxBarLargeButton;
|
||
|
lbSaveDatabase: TdxBarLargeButton;
|
||
|
imgIcons16: TcxImageList;
|
||
|
imgIcons32: TcxImageList;
|
||
|
lbCreateDefinition: TdxBarLargeButton;
|
||
|
barStatusBarProgress: TdxBar;
|
||
|
piStatusBarProgress: TdxBarProgressItem;
|
||
|
barView: TdxBar;
|
||
|
Splitter: TcxSplitter;
|
||
|
bbDuplicateDefinition: TdxBarButton;
|
||
|
bbDeleteDefinition: TdxBarButton;
|
||
|
barGenerator: TdxBar;
|
||
|
lbGenerate: TdxBarLargeButton;
|
||
|
pnlInspector: TPanel;
|
||
|
DockingManager: TdxDockingManager;
|
||
|
imgMisc: TcxImageList;
|
||
|
DockSite: TdxDockSite;
|
||
|
LayoutDockSite: TdxLayoutDockSite;
|
||
|
pnlPropertyInspector: TdxDockPanel;
|
||
|
Inspector: TcxRTTIInspector;
|
||
|
pnlPropertyInformation: TdxDockPanel;
|
||
|
VertContainerDockSite: TdxVertContainerDockSite;
|
||
|
lblPropertyInfo: TLabel;
|
||
|
popupEditor: TdxRibbonPopupMenu;
|
||
|
dxBarSeparator1: TdxBarSeparator;
|
||
|
dxBarSeparator2: TdxBarSeparator;
|
||
|
dxBarSeparator3: TdxBarSeparator;
|
||
|
bbClipboardCopy: TdxBarButton;
|
||
|
barClipboard: TdxBar;
|
||
|
lbClipboardPaste: TdxBarLargeButton;
|
||
|
bbClipboardCut: TdxBarButton;
|
||
|
lbMnemonicFilter: TdxBarLargeButton;
|
||
|
bbExpandNodes: TdxBarButton;
|
||
|
bbCollapseNodes: TdxBarButton;
|
||
|
barMnemonicFilter: TdxBar;
|
||
|
edtMnemonicFilter: TdxBarEdit;
|
||
|
bbExactMatch: TdxBarButton;
|
||
|
EditorTree: TVirtualStringTree;
|
||
|
imgTreeView: TcxImageList;
|
||
|
dxBarSeparator4: TdxBarSeparator;
|
||
|
bbExpandLeaf: TdxBarButton;
|
||
|
bbCollapseLeaf: TdxBarButton;
|
||
|
Button1: TButton;
|
||
|
Button2: TButton;
|
||
|
procedure FormCreate(Sender: TObject);
|
||
|
procedure FormResize(Sender: TObject);
|
||
|
procedure FormDestroy(Sender: TObject);
|
||
|
procedure lbLoadDatabaseClick(Sender: TObject);
|
||
|
procedure lbSaveDatabaseClick(Sender: TObject);
|
||
|
procedure EditorTreeGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex;
|
||
|
TextType: TVSTTextType; var CellText: string);
|
||
|
procedure EditorTreeChange(Sender: TBaseVirtualTree; Node: PVirtualNode);
|
||
|
procedure EditorTreeCompareNodes(Sender: TBaseVirtualTree; Node1, Node2: PVirtualNode;
|
||
|
Column: TColumnIndex; var Result: Integer);
|
||
|
procedure EditorTreeCollapsing(Sender: TBaseVirtualTree; Node: PVirtualNode;
|
||
|
var Allowed: Boolean);
|
||
|
procedure EditorTreePaintText(Sender: TBaseVirtualTree; const TargetCanvas: TCanvas;
|
||
|
Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType);
|
||
|
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
|
||
|
procedure lbCreateDefinitionClick(Sender: TObject);
|
||
|
procedure lbGenerateClick(Sender: TObject);
|
||
|
procedure bbDeleteDefinitionClick(Sender: TObject);
|
||
|
procedure InspectorItemChanged(Sender: TObject; AOldRow: TcxCustomRow; AOldCellIndex: Integer);
|
||
|
procedure bbDuplicateDefinitionClick(Sender: TObject);
|
||
|
procedure EditorTreeKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
|
||
|
procedure bbClipboardCopyClick(Sender: TObject);
|
||
|
procedure lbClipboardPasteClick(Sender: TObject);
|
||
|
procedure bbExpandNodesClick(Sender: TObject);
|
||
|
procedure bbCollapseNodesClick(Sender: TObject);
|
||
|
procedure bbClipboardCutClick(Sender: TObject);
|
||
|
procedure lbMnemonicFilterClick(Sender: TObject);
|
||
|
procedure edtMnemonicFilterCurChange(Sender: TObject);
|
||
|
procedure bbExactMatchClick(Sender: TObject);
|
||
|
procedure EditorTreeMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X,
|
||
|
Y: Integer);
|
||
|
procedure bbExpandLeafClick(Sender: TObject);
|
||
|
procedure bbCollapseLeafClick(Sender: TObject);
|
||
|
procedure Button1Click(Sender: TObject);
|
||
|
procedure Button2Click(Sender: TObject);
|
||
|
procedure EditorTreeGetImageIndex(Sender: TBaseVirtualTree;
|
||
|
Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex;
|
||
|
var Ghosted: Boolean; var ImageIndex: TImageIndex);
|
||
|
strict private
|
||
|
FEditor: TInstructionEditor;
|
||
|
FUpdating: Boolean;
|
||
|
FHasUnsavedChanges: Boolean;
|
||
|
FExpandedFilterProperties: TList<String>;
|
||
|
FExpandedDefinitionProperties: TList<String>;
|
||
|
FInspectorActiveFilterRow: String;
|
||
|
FInspectorActiveDefinitionRow: String;
|
||
|
FEditing: Boolean;
|
||
|
FEditedNode: PVirtualNode;
|
||
|
strict private
|
||
|
procedure EditorWorkStart(Sender: TObject; MinWorkCount, MaxWorkCount: Integer);
|
||
|
procedure EditorWork(Sender: TObject; WorkCount: Integer);
|
||
|
procedure EditorWorkEnd(Sender: TObject);
|
||
|
procedure EditorBeginUpdate(Sender: TObject);
|
||
|
procedure EditorEndUpdate(Sender: TObject);
|
||
|
procedure EditorFilterCreated(Sender: TObject; Filter: TInstructionFilter);
|
||
|
procedure EditorFilterInserted(Sender: TObject; Filter: TInstructionFilter);
|
||
|
procedure EditorFilterChanged(Sender: TObject; Filter: TInstructionFilter);
|
||
|
procedure EditorFilterRemoved(Sender: TObject; Filter: TInstructionFilter);
|
||
|
procedure EditorFilterDestroyed(Sender: TObject; Filter: TInstructionFilter);
|
||
|
procedure EditorDefinitionCreated(Sender: TObject; Definition: TInstructionDefinition);
|
||
|
procedure EditorDefinitionInserted(Sender: TObject; Definition: TInstructionDefinition);
|
||
|
procedure EditorDefinitionChanged(Sender: TObject; Definition: TInstructionDefinition);
|
||
|
procedure EditorDefinitionRemoved(Sender: TObject; Definition: TInstructionDefinition);
|
||
|
procedure EditorDefinitionDestroyed(Sender: TObject; Definition: TInstructionDefinition);
|
||
|
strict private
|
||
|
function GetTreeNode(const Definition: TInstructionDefinition): PVirtualNode; overload;
|
||
|
function GetTreeNode(const Filter: TInstructionFilter): PVirtualNode; overload;
|
||
|
strict private
|
||
|
procedure SetDefaultWindowPosition; inline;
|
||
|
procedure LoadGUIConfiguration;
|
||
|
procedure SaveGUIConfiguration;
|
||
|
procedure UpdateExpandedProperties;
|
||
|
strict private
|
||
|
procedure UpdateControls;
|
||
|
procedure UpdateStatistic;
|
||
|
strict private
|
||
|
procedure ClipboardPaste(Node: PVirtualNode);
|
||
|
procedure ClipboardCopy(Node: PVirtualNode);
|
||
|
procedure ClipboardCut(Node: PVirtualNode);
|
||
|
procedure DefinitionCreate;
|
||
|
procedure DefinitionDuplicate(Node: PVirtualNode);
|
||
|
procedure DefinitionDelete(Node: PVirtualNode);
|
||
|
procedure ExpandAllNodes(Expanded: Boolean);
|
||
|
procedure ExpandLeaf(Node: PVirtualNode; Expanded: Boolean);
|
||
|
procedure SetMnemonicFilter(const Filter: String; ExactMatch: Boolean);
|
||
|
public
|
||
|
{ Public-Deklarationen }
|
||
|
end;
|
||
|
|
||
|
var
|
||
|
frmMain: TfrmMain;
|
||
|
|
||
|
implementation
|
||
|
|
||
|
uses
|
||
|
System.IniFiles, Vcl.Clipbrd, SynCrossPlatformJSON, formCreateDefinition, formGenerator,
|
||
|
untHelperClasses, untPropertyHints,
|
||
|
|
||
|
System.Math;
|
||
|
|
||
|
{$R *.dfm}
|
||
|
|
||
|
type
|
||
|
TEditorNodeType = (ntFilterTable, ntInstructionDefinition);
|
||
|
|
||
|
PEditorNodeData = ^TEditorNodeData;
|
||
|
TEditorNodeData = record
|
||
|
public
|
||
|
NodeType: TEditorNodeType;
|
||
|
case Integer of
|
||
|
0: (DataClass: TPersistent);
|
||
|
1: (Filter: TInstructionFilter);
|
||
|
2: (Definition: TInstructionDefinition);
|
||
|
end;
|
||
|
|
||
|
{$REGION 'Code: TreeView related methods'}
|
||
|
function TfrmMain.GetTreeNode(const Definition: TInstructionDefinition): PVirtualNode;
|
||
|
begin
|
||
|
// We are using the "data" property to store the corresponding node pointer
|
||
|
Assert(Assigned(Definition.Data));
|
||
|
Result := Definition.Data;
|
||
|
end;
|
||
|
|
||
|
function TfrmMain.GetTreeNode(const Filter: TInstructionFilter): PVirtualNode;
|
||
|
begin
|
||
|
// We are using the "data" property to store the corresponding node pointer
|
||
|
Assert(Assigned(Filter.Data));
|
||
|
Result := Filter.Data;
|
||
|
end;
|
||
|
{$ENDREGION}
|
||
|
|
||
|
{$REGION 'Code: TreeView related operations'}
|
||
|
procedure TfrmMain.ClipboardCopy(Node: PVirtualNode);
|
||
|
|
||
|
procedure SaveToJSON(Filter: TInstructionFilter; JSONArray: PJSONVariantData);
|
||
|
var
|
||
|
I: Integer;
|
||
|
JSONObject: TJSONVariantData;
|
||
|
begin
|
||
|
if (Filter.IsDefinitionContainer) then
|
||
|
begin
|
||
|
for I := 0 to (Filter as TDefinitionContainer).DefinitionCount - 1 do
|
||
|
begin
|
||
|
JSONObject.Init;
|
||
|
(Filter as TDefinitionContainer).Definitions[I].SaveToJSON(@JSONObject);
|
||
|
JSONArray^.AddValue(Variant(JSONObject));
|
||
|
end;
|
||
|
end else
|
||
|
begin
|
||
|
for I := 0 to Filter.Capacity - 1 do
|
||
|
begin
|
||
|
if (Assigned(Filter.Items[I])) then
|
||
|
begin
|
||
|
SaveToJSON(Filter.Items[I], JSONArray);
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
var
|
||
|
NodeData: PEditorNodeData;
|
||
|
JSON,
|
||
|
JSONArray,
|
||
|
JSONObject: TJSONVariantData;
|
||
|
begin
|
||
|
NodeData := EditorTree.GetNodeData(Node);
|
||
|
if (Assigned(NodeData)) then
|
||
|
begin
|
||
|
JSONArray.Init;
|
||
|
if (NodeData^.NodeType = ntInstructionDefinition) then
|
||
|
begin
|
||
|
JSONObject.Init;
|
||
|
NodeData^.Definition.SaveToJSON(@JSONObject);
|
||
|
JSONArray.AddValue(Variant(JSONObject));
|
||
|
end else
|
||
|
begin
|
||
|
if (Application.MessageBox(
|
||
|
'You are trying to copy multiple definitions to clipboard. Do you want to continue?',
|
||
|
'Question', MB_ICONQUESTION or MB_YESNO) <> IdYes) then
|
||
|
begin
|
||
|
Exit;
|
||
|
end;
|
||
|
SaveToJSON(NodeData^.Filter, @JSONArray);
|
||
|
end;
|
||
|
JSON.Init;
|
||
|
JSON.AddNameValue('definitions', Variant(JSONArray));
|
||
|
Clipboard.AsText := TJSONHelper.JSONToString(@JSON);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrmMain.ClipboardCut(Node: PVirtualNode);
|
||
|
begin
|
||
|
ClipboardCopy(Node);
|
||
|
DefinitionDelete(Node);
|
||
|
end;
|
||
|
|
||
|
procedure TfrmMain.ClipboardPaste(Node: PVirtualNode);
|
||
|
var
|
||
|
JSON: TJSONVariantData;
|
||
|
JSONArray: PJSONVariantData;
|
||
|
I: Integer;
|
||
|
D: TInstructionDefinition;
|
||
|
begin
|
||
|
JSON.Init;
|
||
|
if (JSON.FromJSON(Clipboard.AsText) and (JSON.Kind = jvObject)) then
|
||
|
begin
|
||
|
JSONArray := JSON.Data('definitions');
|
||
|
if (Assigned(JSONArray) and (JSONArray^.Kind = jvArray)) then
|
||
|
begin
|
||
|
if (JSONArray^.Count > 1) then
|
||
|
begin
|
||
|
if (Application.MessageBox(
|
||
|
'You are trying to paste multiple definitions from clipboard. Do you want to continue?',
|
||
|
'Question', MB_ICONQUESTION or MB_YESNO) <> IdYes) then
|
||
|
begin
|
||
|
Exit;
|
||
|
end;
|
||
|
end;
|
||
|
FEditor.BeginUpdate;
|
||
|
try
|
||
|
for I := 0 to JSONArray^.Count - 1 do
|
||
|
begin
|
||
|
D := FEditor.CreateDefinition('unnamed');
|
||
|
try
|
||
|
D.BeginUpdate;
|
||
|
try
|
||
|
D.Update;
|
||
|
D.LoadFromJSON(JSONVariantDataSafe(JSONArray^.Item[I], jvObject));
|
||
|
finally
|
||
|
D.EndUpdate;
|
||
|
end;
|
||
|
except
|
||
|
on E: Exception do
|
||
|
begin
|
||
|
D.Free;
|
||
|
Application.MessageBox(PChar(E.Message), 'Error', MB_ICONERROR);
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
finally
|
||
|
FEditor.EndUpdate;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrmMain.DefinitionCreate;
|
||
|
var
|
||
|
frmCreateDefinition: TfrmCreateDefinition;
|
||
|
D: TInstructionDefinition;
|
||
|
begin
|
||
|
frmCreateDefinition := TfrmCreateDefinition.Create(Application);
|
||
|
try
|
||
|
D := FEditor.CreateDefinition('unnamed');
|
||
|
D.BeginUpdate;
|
||
|
try
|
||
|
// Force initial position update to cause OnDefinitionInserted for new definitions with
|
||
|
// unchanged (position-relevant) properties.
|
||
|
D.Update;
|
||
|
frmCreateDefinition.Inspector.InspectedObject := D;
|
||
|
frmCreateDefinition.ShowModal;
|
||
|
finally
|
||
|
if (not frmCreateDefinition.Canceled) then D.EndUpdate;
|
||
|
end;
|
||
|
if (frmCreateDefinition.Canceled) then
|
||
|
begin
|
||
|
D.Free;
|
||
|
end;
|
||
|
finally
|
||
|
frmCreateDefinition.Free;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrmMain.DefinitionDelete(Node: PVirtualNode);
|
||
|
var
|
||
|
NextNode: PVirtualNode;
|
||
|
NodeData: PEditorNodeData;
|
||
|
begin
|
||
|
NodeData := EditorTree.GetNodeData(Node);
|
||
|
if Assigned(NodeData) and (NodeData^.NodeType = ntInstructionDefinition) then
|
||
|
begin
|
||
|
NextNode := EditorTree.GetNextSibling(Node);
|
||
|
if (not Assigned(NextNode)) then
|
||
|
begin
|
||
|
NextNode := EditorTree.GetPreviousSibling(Node);
|
||
|
end;
|
||
|
NodeData^.Definition.Free;
|
||
|
if (Assigned(NextNode)) then
|
||
|
begin
|
||
|
EditorTree.FocusedNode := NextNode;
|
||
|
EditorTree.Selected[NextNode] := true;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrmMain.DefinitionDuplicate(Node: PVirtualNode);
|
||
|
var
|
||
|
frmCreateDefinition: TfrmCreateDefinition;
|
||
|
D: TInstructionDefinition;
|
||
|
NodeData: PEditorNodeData;
|
||
|
begin
|
||
|
NodeData := EditorTree.GetNodeData(Node);
|
||
|
if (Assigned(NodeData) and (NodeData^.NodeType = ntInstructionDefinition)) then
|
||
|
begin
|
||
|
frmCreateDefinition := TfrmCreateDefinition.Create(Application);
|
||
|
try
|
||
|
D := FEditor.CreateDefinition('unnamed');
|
||
|
D.BeginUpdate;
|
||
|
try
|
||
|
// Force initial position update to cause OnDefinitionInserted for new definitions with
|
||
|
// unchanged (position-relevant) properties.
|
||
|
D.Update;
|
||
|
D.Assign(NodeData^.Definition);
|
||
|
frmCreateDefinition.Inspector.InspectedObject := D;
|
||
|
frmCreateDefinition.ShowModal;
|
||
|
finally
|
||
|
if (not frmCreateDefinition.Canceled) then D.EndUpdate;
|
||
|
end;
|
||
|
if (frmCreateDefinition.Canceled) then
|
||
|
begin
|
||
|
D.Free;
|
||
|
end;
|
||
|
finally
|
||
|
frmCreateDefinition.Free;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrmMain.ExpandAllNodes(Expanded: Boolean);
|
||
|
var
|
||
|
Node: PVirtualNode;
|
||
|
NodeData: PEditorNodeData;
|
||
|
begin
|
||
|
EditorTree.BeginUpdate;
|
||
|
try
|
||
|
Node := EditorTree.GetFirst;
|
||
|
while (Assigned(Node)) do
|
||
|
begin
|
||
|
NodeData := EditorTree.GetNodeData(Node);
|
||
|
if (Assigned(NodeData) and (NodeData^.NodeType = ntFilterTable) and
|
||
|
(Assigned(NodeData^.Filter)) and
|
||
|
(not (iffIsRootTable in NodeData^.Filter.FilterFlags))) then
|
||
|
begin
|
||
|
EditorTree.Expanded[Node] := Expanded;
|
||
|
end;
|
||
|
Node := EditorTree.GetNext(Node);
|
||
|
end;
|
||
|
finally
|
||
|
EditorTree.EndUpdate;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrmMain.ExpandLeaf(Node: PVirtualNode; Expanded: Boolean);
|
||
|
begin
|
||
|
// TODO:
|
||
|
end;
|
||
|
{$ENDREGION}
|
||
|
|
||
|
{$REGION 'Events: Form'}
|
||
|
procedure TfrmMain.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
|
||
|
var
|
||
|
ID: Integer;
|
||
|
begin
|
||
|
CanClose := true;
|
||
|
if (FHasUnsavedChanges) then
|
||
|
begin
|
||
|
ID := Application.MessageBox('The current database have unsaved changes. Do you'
|
||
|
+ ' really want to exit?', 'Question', MB_ICONWARNING or MB_YESNO or MB_DEFBUTTON2);
|
||
|
CanClose := (ID = IdYes);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrmMain.FormCreate(Sender: TObject);
|
||
|
begin
|
||
|
EditorTree.NodeDataSize := SizeOf(TEditorNodeData);
|
||
|
|
||
|
FExpandedFilterProperties := TList<String>.Create;
|
||
|
FExpandedDefinitionProperties := TList<String>.Create;
|
||
|
|
||
|
SetDefaultWindowPosition;
|
||
|
LoadGUIConfiguration;
|
||
|
|
||
|
StatusBar.Panels[1].Visible := false;
|
||
|
|
||
|
FEditor := TInstructionEditor.Create;
|
||
|
FEditor.OnWorkStart := EditorWorkStart;
|
||
|
FEditor.OnWork := EditorWork;
|
||
|
FEditor.OnWorkEnd := EditorWorkEnd;
|
||
|
FEditor.OnBeginUpdate := EditorBeginUpdate;
|
||
|
FEditor.OnEndUpdate := EditorEndUpdate;
|
||
|
FEditor.OnFilterCreated := EditorFilterCreated;
|
||
|
FEditor.OnFilterInserted := EditorFilterInserted;
|
||
|
FEditor.OnFilterChanged := EditorFilterChanged;
|
||
|
FEditor.OnFilterRemoved := EditorFilterRemoved;
|
||
|
FEditor.OnFilterDestroyed := EditorFilterDestroyed;
|
||
|
FEditor.OnDefinitionCreated := EditorDefinitionCreated;
|
||
|
FEditor.OnDefinitionInserted := EditorDefinitionInserted;
|
||
|
FEditor.OnDefinitionChanged := EditorDefinitionChanged;
|
||
|
FEditor.OnDefinitionRemoved := EditorDefinitionRemoved;
|
||
|
FEditor.OnDefinitionDestroyed := EditorDefinitionDestroyed;
|
||
|
|
||
|
FEditing := false;
|
||
|
FEditor.Reset;
|
||
|
FEditing := true;
|
||
|
ExpandAllNodes(true);
|
||
|
end;
|
||
|
|
||
|
procedure TfrmMain.FormDestroy(Sender: TObject);
|
||
|
begin
|
||
|
FEditing := false;
|
||
|
SaveGUIConfiguration;
|
||
|
ExpandAllNodes(false);
|
||
|
if (Assigned(FEditor)) then
|
||
|
begin
|
||
|
FEditor.Free;
|
||
|
end;
|
||
|
if (Assigned(FExpandedFilterProperties)) then
|
||
|
begin
|
||
|
FExpandedFilterProperties.Free;
|
||
|
end;
|
||
|
if (Assigned(FExpandedDefinitionProperties)) then
|
||
|
begin
|
||
|
FExpandedDefinitionProperties.Free;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrmMain.FormResize(Sender: TObject);
|
||
|
begin
|
||
|
piStatusBarProgress.Width := barStatusBarProgress.Control.ClientWidth;
|
||
|
end;
|
||
|
{$ENDREGION}
|
||
|
|
||
|
{$REGION 'Events: InstructionEditor'}
|
||
|
procedure TfrmMain.EditorBeginUpdate(Sender: TObject);
|
||
|
begin
|
||
|
EditorTree.BeginUpdate;
|
||
|
FUpdating := true;
|
||
|
end;
|
||
|
|
||
|
procedure TfrmMain.EditorDefinitionChanged(Sender: TObject; Definition: TInstructionDefinition);
|
||
|
begin
|
||
|
EditorTree.RepaintNode(GetTreeNode(Definition));
|
||
|
UpdateStatistic;
|
||
|
if (FEditing) then
|
||
|
begin
|
||
|
if (not (csDestroying in ComponentState)) and (lbMnemonicFilter.Down) then
|
||
|
begin
|
||
|
SetMnemonicFilter(edtMnemonicFilter.Text, bbExactMatch.Down);
|
||
|
end;
|
||
|
FHasUnsavedChanges := true;
|
||
|
UpdateControls;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrmMain.EditorDefinitionCreated(Sender: TObject; Definition: TInstructionDefinition);
|
||
|
var
|
||
|
Node: PVirtualNode;
|
||
|
NodeData: PEditorNodeData;
|
||
|
begin
|
||
|
Node := EditorTree.AddChild(nil);
|
||
|
Definition.Data := Node;
|
||
|
EditorTree.IsVisible[Node] := false;
|
||
|
NodeData := EditorTree.GetNodeData(Node);
|
||
|
NodeData^.NodeType := ntInstructionDefinition;
|
||
|
NodeData^.Definition := Definition;
|
||
|
UpdateStatistic;
|
||
|
end;
|
||
|
|
||
|
procedure TfrmMain.EditorDefinitionDestroyed(Sender: TObject; Definition: TInstructionDefinition);
|
||
|
begin
|
||
|
EditorTree.DeleteNode(GetTreeNode(Definition));
|
||
|
if (Inspector.InspectedObject = Definition) then
|
||
|
begin
|
||
|
Inspector.InspectedObject := nil;
|
||
|
end;
|
||
|
UpdateStatistic;
|
||
|
end;
|
||
|
|
||
|
procedure TfrmMain.EditorDefinitionInserted(Sender: TObject; Definition: TInstructionDefinition);
|
||
|
var
|
||
|
Node: PVirtualNode;
|
||
|
begin
|
||
|
Assert(Assigned(Definition.Parent));
|
||
|
Node := GetTreeNode(Definition);
|
||
|
EditorTree.IsVisible[Node] := true;
|
||
|
EditorTree.MoveTo(Node, GetTreeNode(Definition.Parent), amAddChildLast, false);
|
||
|
if (FEditing) then
|
||
|
begin
|
||
|
FEditedNode := Node;
|
||
|
FHasUnsavedChanges := true;
|
||
|
UpdateControls;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrmMain.EditorDefinitionRemoved(Sender: TObject; Definition: TInstructionDefinition);
|
||
|
var
|
||
|
Node: PVirtualNode;
|
||
|
begin
|
||
|
Node := GetTreeNode(Definition);
|
||
|
EditorTree.IsVisible[Node] := false;
|
||
|
EditorTree.MoveTo(Node, nil, amInsertAfter, false);
|
||
|
if (FEditing) then
|
||
|
begin
|
||
|
if (EditorTree.FocusedNode = Node) then
|
||
|
begin
|
||
|
EditorTree.FocusedNode := nil;
|
||
|
EditorTree.Selected[Node] := false;
|
||
|
end;
|
||
|
FHasUnsavedChanges := true;
|
||
|
UpdateControls;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrmMain.EditorEndUpdate(Sender: TObject);
|
||
|
begin
|
||
|
EditorTree.EndUpdate;
|
||
|
FUpdating := false;
|
||
|
if (FEditing) and Assigned(FEditedNode) then
|
||
|
begin
|
||
|
EditorTree.FocusedNode := FEditedNode;
|
||
|
EditorTree.Selected[FEditedNode] := true;
|
||
|
EditorTree.ScrollIntoView(FEditedNode, true);
|
||
|
FEditedNode := nil;
|
||
|
end;
|
||
|
UpdateStatistic;
|
||
|
end;
|
||
|
|
||
|
procedure TfrmMain.EditorFilterChanged(Sender: TObject; Filter: TInstructionFilter);
|
||
|
begin
|
||
|
EditorTree.RepaintNode(GetTreeNode(Filter));
|
||
|
end;
|
||
|
|
||
|
procedure TfrmMain.EditorFilterCreated(Sender: TObject; Filter: TInstructionFilter);
|
||
|
var
|
||
|
Node: PVirtualNode;
|
||
|
NodeData: PEditorNodeData;
|
||
|
begin
|
||
|
Node := EditorTree.AddChild(nil);
|
||
|
Filter.Data := Node;
|
||
|
if (not (iffIsRootTable in Filter.FilterFlags)) then
|
||
|
begin
|
||
|
EditorTree.IsVisible[Node] := false;
|
||
|
end;
|
||
|
NodeData := EditorTree.GetNodeData(Node);
|
||
|
NodeData^.NodeType := ntFilterTable;
|
||
|
NodeData^.Filter := Filter;
|
||
|
UpdateStatistic;
|
||
|
end;
|
||
|
|
||
|
procedure TfrmMain.EditorFilterDestroyed(Sender: TObject; Filter: TInstructionFilter);
|
||
|
begin
|
||
|
EditorTree.DeleteNode(GetTreeNode(Filter));
|
||
|
if (Inspector.InspectedObject = Filter) then
|
||
|
begin
|
||
|
Inspector.InspectedObject := nil;
|
||
|
end;
|
||
|
UpdateStatistic;
|
||
|
end;
|
||
|
|
||
|
procedure TfrmMain.EditorFilterInserted(Sender: TObject; Filter: TInstructionFilter);
|
||
|
var
|
||
|
Node, ParentNode: PVirtualNode;
|
||
|
begin
|
||
|
Assert(Assigned(Filter.Parent));
|
||
|
Node := GetTreeNode(Filter);
|
||
|
ParentNode := GetTreeNode(Filter.Parent);
|
||
|
EditorTree.MoveTo(Node, ParentNode, amAddChildLast, false);
|
||
|
EditorTree.IsVisible[Node] := true;
|
||
|
// Expand root table after first filter insertion
|
||
|
if (iffIsRootTable in Filter.Parent.FilterFlags) and (Filter.Parent.ItemCount = 1) then
|
||
|
begin
|
||
|
EditorTree.Expanded[ParentNode] := true;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrmMain.EditorFilterRemoved(Sender: TObject; Filter: TInstructionFilter);
|
||
|
var
|
||
|
Node: PVirtualNode;
|
||
|
begin
|
||
|
Node := GetTreeNode(Filter);
|
||
|
EditorTree.IsVisible[Node] := false;
|
||
|
EditorTree.MoveTo(Node, nil, amInsertAfter, false);
|
||
|
if (FEditing) then
|
||
|
begin
|
||
|
if (EditorTree.FocusedNode = Node) then
|
||
|
begin
|
||
|
EditorTree.FocusedNode := nil;
|
||
|
EditorTree.Selected[Node] := false;
|
||
|
end;
|
||
|
UpdateControls;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrmMain.EditorWork(Sender: TObject; WorkCount: Integer);
|
||
|
begin
|
||
|
piStatusBarProgress.Position := WorkCount;
|
||
|
if ((WorkCount mod piStatusBarProgress.Tag) = 0) then
|
||
|
begin
|
||
|
Application.ProcessMessages;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrmMain.EditorWorkEnd(Sender: TObject);
|
||
|
begin
|
||
|
piStatusBarProgress.Visible := ivNever;
|
||
|
end;
|
||
|
|
||
|
procedure TfrmMain.EditorWorkStart(Sender: TObject; MinWorkCount, MaxWorkCount: Integer);
|
||
|
begin
|
||
|
piStatusBarProgress.Min := MinWorkCount;
|
||
|
piStatusBarProgress.Max := MaxWorkCount;
|
||
|
piStatusBarProgress.Tag := Round((MaxWorkCount - MinWorkCount) / 100) + 1;
|
||
|
piStatusBarProgress.Position := 0;
|
||
|
piStatusBarProgress.Visible := ivAlways;
|
||
|
end;
|
||
|
{$ENDREGION}
|
||
|
|
||
|
{$REGION 'Events: TreeView'}
|
||
|
procedure TfrmMain.EditorTreeChange(Sender: TBaseVirtualTree; Node: PVirtualNode);
|
||
|
var
|
||
|
NodeData: PEditorNodeData;
|
||
|
I: Integer;
|
||
|
begin
|
||
|
UpdateExpandedProperties;
|
||
|
Inspector.BeginUpdate;
|
||
|
try
|
||
|
if (Assigned(Inspector.FocusedRow)) then
|
||
|
begin
|
||
|
if (Inspector.InspectedObject is TInstructionFilter) then
|
||
|
begin
|
||
|
FInspectorActiveFilterRow :=
|
||
|
(Inspector.FocusedRow as TcxPropertyRow).PropertyEditor.GetName;
|
||
|
end else if (Inspector.InspectedObject is TInstructionDefinition) then
|
||
|
begin
|
||
|
FInspectorActiveDefinitionRow :=
|
||
|
(Inspector.FocusedRow as TcxPropertyRow).PropertyEditor.GetName;
|
||
|
end;
|
||
|
end;
|
||
|
Inspector.InspectedObject := nil;
|
||
|
NodeData := Sender.GetNodeData(Node);
|
||
|
if Assigned(NodeData) then
|
||
|
begin
|
||
|
Inspector.InspectedObject := NodeData^.DataClass;
|
||
|
for I := 0 to Inspector.Rows.Count - 1 do
|
||
|
begin
|
||
|
if ((NodeData^.NodeType = ntFilterTable) and FExpandedFilterProperties.Contains(
|
||
|
(Inspector.Rows[I] as TcxPropertyRow).PropertyEditor.GetName)) or
|
||
|
((NodeData^.NodeType = ntInstructionDefinition) and
|
||
|
FExpandedDefinitionProperties.Contains(
|
||
|
(Inspector.Rows[I] as TcxPropertyRow).PropertyEditor.GetName)) then
|
||
|
begin
|
||
|
Inspector.Rows[I].Expanded := true;
|
||
|
end;
|
||
|
if ((NodeData^.NodeType = ntFilterTable) and (FInspectorActiveFilterRow =
|
||
|
(Inspector.Rows[I] as TcxPropertyRow).PropertyEditor.GetName)) or
|
||
|
((NodeData^.NodeType = ntInstructionDefinition) and
|
||
|
(FInspectorActiveDefinitionRow =
|
||
|
(Inspector.Rows[I] as TcxPropertyRow).PropertyEditor.GetName)) then
|
||
|
begin
|
||
|
Inspector.FocusedRow := Inspector.Rows[I];
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
finally
|
||
|
Inspector.EndUpdate;
|
||
|
end;
|
||
|
UpdateControls;
|
||
|
end;
|
||
|
|
||
|
procedure TfrmMain.EditorTreeCollapsing(Sender: TBaseVirtualTree; Node: PVirtualNode;
|
||
|
var Allowed: Boolean);
|
||
|
var
|
||
|
NodeData: PEditorNodeData;
|
||
|
begin
|
||
|
NodeData := Sender.GetNodeData(Node);
|
||
|
if (Assigned(NodeData) and (NodeData^.NodeType = ntFilterTable) and
|
||
|
Assigned(NodeData^.Filter) and (iffIsRootTable in NodeData^.Filter.FilterFlags)) then
|
||
|
begin
|
||
|
Allowed := false;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrmMain.EditorTreeCompareNodes(Sender: TBaseVirtualTree; Node1, Node2: PVirtualNode;
|
||
|
Column: TColumnIndex; var Result: Integer);
|
||
|
var
|
||
|
NodeDataA,
|
||
|
NodeDataB: PEditorNodeData;
|
||
|
begin
|
||
|
NodeDataA := Sender.GetNodeData(Node1);
|
||
|
NodeDataB := Sender.GetNodeData(Node2);
|
||
|
if (NodeDataA^.NodeType <> NodeDataB^.NodeType) then Exit;
|
||
|
if (Assigned(NodeDataA) and Assigned(NodeDataB) and
|
||
|
Assigned(NodeDataA^.DataClass) and Assigned(NodeDataB^.DataClass)) then
|
||
|
begin
|
||
|
case NodeDataA^.NodeType of
|
||
|
ntFilterTable:
|
||
|
begin
|
||
|
Assert(NodeDataB^.NodeType = ntFilterTable);
|
||
|
if (Assigned(NodeDataA^.Filter.Parent)) then
|
||
|
begin
|
||
|
Assert(Assigned(NodeDataB^.Filter.Parent));
|
||
|
Assert(NodeDataA^.Filter.Parent = NodeDataB^.Filter.Parent);
|
||
|
Result := NodeDataA^.Filter.Parent.IndexOf(NodeDataA^.Filter) -
|
||
|
NodeDataB^.Filter.Parent.IndexOf(NodeDataB^.Filter);
|
||
|
end;
|
||
|
end;
|
||
|
ntInstructionDefinition:
|
||
|
begin
|
||
|
Assert(NodeDataB^.NodeType = ntInstructionDefinition);
|
||
|
Result := CompareStr(NodeDataA^.Definition.Mnemonic, NodeDataB^.Definition.Mnemonic);
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrmMain.EditorTreeGetImageIndex(Sender: TBaseVirtualTree;
|
||
|
Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex;
|
||
|
var Ghosted: Boolean; var ImageIndex: TImageIndex);
|
||
|
var
|
||
|
NodeData: PEditorNodeData;
|
||
|
begin
|
||
|
if (Column <> 0) or (Kind = ikOverlay) then
|
||
|
begin
|
||
|
Exit;
|
||
|
end;
|
||
|
NodeData := Sender.GetNodeData(Node);
|
||
|
if Assigned(NodeData) then
|
||
|
begin
|
||
|
case NodeData^.NodeType of
|
||
|
ntFilterTable:
|
||
|
begin
|
||
|
ImageIndex := 0;
|
||
|
if (NodeData^.Filter is TDefinitionContainer) then
|
||
|
begin
|
||
|
ImageIndex := 1;
|
||
|
end;
|
||
|
end;
|
||
|
ntInstructionDefinition:
|
||
|
begin
|
||
|
ImageIndex := 2;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrmMain.EditorTreeGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
|
||
|
Column: TColumnIndex; TextType: TVSTTextType; var CellText: string);
|
||
|
var
|
||
|
NodeData: PEditorNodeData;
|
||
|
S: String;
|
||
|
begin
|
||
|
CellText := '';
|
||
|
NodeData := Sender.GetNodeData(Node);
|
||
|
if (Assigned(NodeData) and Assigned(NodeData^.DataClass)) then
|
||
|
begin
|
||
|
case (NodeData^.NodeType) of
|
||
|
ntFilterTable:
|
||
|
begin
|
||
|
if (TextType <> ttNormal) and (not (Column in [0])) then Exit;
|
||
|
case Column of
|
||
|
0:
|
||
|
begin
|
||
|
case TextType of
|
||
|
ttNormal:
|
||
|
begin
|
||
|
if (not Assigned(NodeData^.Filter.Parent)) then
|
||
|
begin
|
||
|
CellText := 'Root';
|
||
|
end else
|
||
|
begin
|
||
|
CellText := IntToHex(NodeData^.Filter.Parent.IndexOf(NodeData^.Filter), 2);
|
||
|
end;
|
||
|
end;
|
||
|
ttStatic:
|
||
|
begin
|
||
|
if (Assigned(NodeData^.Filter.Parent)) then
|
||
|
begin
|
||
|
S := NodeData^.Filter.Parent.GetItemDescription(
|
||
|
NodeData^.Filter.Parent.IndexOf(NodeData^.Filter));
|
||
|
if (S <> '') then
|
||
|
begin
|
||
|
CellText := '(' + S + ')';
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
ntInstructionDefinition:
|
||
|
begin
|
||
|
if (TextType <> ttNormal) and (not (Column in [0, 1])) then Exit;
|
||
|
case Column of
|
||
|
0:
|
||
|
begin
|
||
|
case TextType of
|
||
|
ttNormal: CellText := IntToHex(Node.Index, 2);
|
||
|
ttStatic: CellText := 'Definition';
|
||
|
end;
|
||
|
end;
|
||
|
1:
|
||
|
begin
|
||
|
case TextType of
|
||
|
ttNormal:
|
||
|
begin
|
||
|
CellText := IntToHex(NodeData^.Definition.Opcode, 2);
|
||
|
end;
|
||
|
ttStatic:
|
||
|
begin
|
||
|
CellText := ''; // TODO:
|
||
|
end
|
||
|
end;
|
||
|
end;
|
||
|
2: CellText := NodeData^.Definition.Mnemonic;
|
||
|
3: CellText := NodeData^.Definition.Operands.OperandA.GetDescription(true);
|
||
|
4: CellText := NodeData^.Definition.Operands.OperandB.GetDescription(true);
|
||
|
5: CellText := NodeData^.Definition.Operands.OperandC.GetDescription(true);
|
||
|
6: CellText := NodeData^.Definition.Operands.OperandD.GetDescription(true);
|
||
|
7: CellText := NodeData^.Definition.Comment;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrmMain.EditorTreeKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
|
||
|
|
||
|
procedure CopyOperands;
|
||
|
var
|
||
|
NodeData: PEditorNodeData;
|
||
|
I: Integer;
|
||
|
S: String;
|
||
|
O: TInstructionOperand;
|
||
|
begin
|
||
|
NodeData := EditorTree.GetNodeData(EditorTree.FocusedNode);
|
||
|
if (Assigned(NodeData) and (NodeData^.NodeType = ntInstructionDefinition)) then
|
||
|
begin
|
||
|
S := '';
|
||
|
for I := 0 to 3 do
|
||
|
begin
|
||
|
O := nil;
|
||
|
case I of
|
||
|
0: O := NodeData^.Definition.Operands.OperandA;
|
||
|
1: O := NodeData^.Definition.Operands.OperandB;
|
||
|
2: O := NodeData^.Definition.Operands.OperandC;
|
||
|
3: O := NodeData^.Definition.Operands.OperandD;
|
||
|
end;
|
||
|
S := S + IntToStr(Integer(O.OperandType)) + ',' + IntToStr(Integer(O.Encoding)) + ',' +
|
||
|
IntToStr(Integer(O.AccessMode)) + ',';
|
||
|
end;
|
||
|
Clipboard.AsText := S;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure PasteOperands;
|
||
|
var
|
||
|
NodeData: PEditorNodeData;
|
||
|
A: TArray<String>;
|
||
|
I, J: Integer;
|
||
|
O: TInstructionOperand;
|
||
|
begin
|
||
|
NodeData := EditorTree.GetNodeData(EditorTree.FocusedNode);
|
||
|
if (Assigned(NodeData) and (NodeData^.NodeType = ntInstructionDefinition)) then
|
||
|
begin
|
||
|
A := Clipboard.AsText.Split([',']);
|
||
|
if (Length(A) >= 12) then
|
||
|
begin
|
||
|
I := 0;
|
||
|
J := 0;
|
||
|
while (J < 4) do
|
||
|
begin
|
||
|
O := nil;
|
||
|
case J of
|
||
|
0: O := NodeData^.Definition.Operands.OperandA;
|
||
|
1: O := NodeData^.Definition.Operands.OperandB;
|
||
|
2: O := NodeData^.Definition.Operands.OperandC;
|
||
|
3: O := NodeData^.Definition.Operands.OperandD;
|
||
|
end;
|
||
|
O.OperandType := TOperandType(StrToInt(A[I]));
|
||
|
O.Encoding := TOperandEncoding(StrToInt(A[I + 1]));
|
||
|
O.AccessMode := TOperandAccessMode(StrToInt(A[I + 2]));
|
||
|
Inc(I, 3);
|
||
|
Inc(J);
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
begin
|
||
|
if (ssCtrl in Shift) then
|
||
|
begin
|
||
|
case Key of
|
||
|
Ord('V'):
|
||
|
lbClipboardPaste.Click;
|
||
|
Ord('C'):
|
||
|
bbClipboardCopy.Click;
|
||
|
Ord('X'):
|
||
|
bbClipboardCut.Click;
|
||
|
Ord('F'):
|
||
|
lbMnemonicFilter.Click;
|
||
|
Ord('E'):
|
||
|
CopyOperands;
|
||
|
Ord('R'):
|
||
|
PasteOperands;
|
||
|
end;
|
||
|
end else if (Shift = []) then
|
||
|
begin
|
||
|
case Key of
|
||
|
VK_DELETE:
|
||
|
bbDeleteDefinition.Click;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrmMain.EditorTreeMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X,
|
||
|
Y: Integer);
|
||
|
begin
|
||
|
if (Button = mbRight) then
|
||
|
begin
|
||
|
popupEditor.PopupFromCursorPos;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrmMain.EditorTreePaintText(Sender: TBaseVirtualTree; const TargetCanvas: TCanvas;
|
||
|
Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType);
|
||
|
var
|
||
|
NodeData: PEditorNodeData;
|
||
|
begin
|
||
|
NodeData := Sender.GetNodeData(Node);
|
||
|
if (Assigned(NodeData) and Assigned(NodeData^.DataClass)) then
|
||
|
begin
|
||
|
case NodeData^.NodeType of
|
||
|
ntFilterTable:
|
||
|
begin
|
||
|
if (NodeData^.Filter.HasConflicts) then
|
||
|
begin
|
||
|
TargetCanvas.Font.Color := clRed;
|
||
|
Exit;
|
||
|
end;
|
||
|
end;
|
||
|
ntInstructionDefinition:
|
||
|
begin
|
||
|
if (NodeData^.Definition.HasConflicts) then
|
||
|
begin
|
||
|
TargetCanvas.Font.Color := clRed;
|
||
|
Exit;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
case Column of
|
||
|
0:
|
||
|
begin
|
||
|
case TextType of
|
||
|
ttNormal: ;
|
||
|
ttStatic: TargetCanvas.Font.Color := clGray;
|
||
|
end;
|
||
|
end;
|
||
|
1:
|
||
|
begin
|
||
|
case TextType of
|
||
|
ttNormal: ;
|
||
|
ttStatic: TargetCanvas.Font.Color := clGray;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
{$ENDREGION}
|
||
|
|
||
|
procedure TfrmMain.bbClipboardCopyClick(Sender: TObject);
|
||
|
begin
|
||
|
ClipboardCopy(EditorTree.FocusedNode);
|
||
|
end;
|
||
|
|
||
|
procedure TfrmMain.bbClipboardCutClick(Sender: TObject);
|
||
|
begin
|
||
|
ClipboardCut(EditorTree.FocusedNode);
|
||
|
end;
|
||
|
|
||
|
procedure TfrmMain.bbDuplicateDefinitionClick(Sender: TObject);
|
||
|
begin
|
||
|
DefinitionDuplicate(EditorTree.FocusedNode);
|
||
|
end;
|
||
|
|
||
|
procedure TfrmMain.bbExactMatchClick(Sender: TObject);
|
||
|
begin
|
||
|
SetMnemonicFilter(edtMnemonicFilter.Text, bbExactMatch.Down);
|
||
|
end;
|
||
|
|
||
|
procedure TfrmMain.bbExpandLeafClick(Sender: TObject);
|
||
|
begin
|
||
|
ExpandLeaf(EditorTree.FocusedNode, true);
|
||
|
end;
|
||
|
|
||
|
procedure TfrmMain.bbExpandNodesClick(Sender: TObject);
|
||
|
begin
|
||
|
ExpandAllNodes(true);
|
||
|
end;
|
||
|
|
||
|
procedure TfrmMain.Button1Click(Sender: TObject);
|
||
|
|
||
|
procedure DeleteDuplicates(T: TInstructionFilter);
|
||
|
var
|
||
|
L: TList<TInstructionDefinition>;
|
||
|
D: TInstructionDefinition;
|
||
|
I, J: Integer;
|
||
|
B: Boolean;
|
||
|
begin
|
||
|
if (T is TDefinitionContainer) then
|
||
|
begin
|
||
|
L := TList<TInstructionDefinition>.Create;
|
||
|
try
|
||
|
for I := (T as TDefinitionContainer).DefinitionCount - 1 downto 0 do
|
||
|
begin
|
||
|
D := (T as TDefinitionContainer).Definitions[I];
|
||
|
B := true;
|
||
|
for J := 0 to L.Count - 1 do
|
||
|
begin
|
||
|
if ((D.Mnemonic = L[J].Mnemonic) and D.Operands.Equals(L[J].Operands) and
|
||
|
D.CPUID.Equals(L[J].CPUID) and (D.EVEXCD8Scale = L[J].EVEXCD8Scale)) then
|
||
|
begin
|
||
|
L[J].Flags := L[J].Flags + D.Flags;
|
||
|
D.Free;
|
||
|
B := false;
|
||
|
Break;
|
||
|
end;
|
||
|
end;
|
||
|
if (B) then L.Add(D);
|
||
|
end;
|
||
|
finally
|
||
|
L.Free;
|
||
|
end;
|
||
|
end else
|
||
|
begin
|
||
|
for I := 0 to T.Capacity - 1 do
|
||
|
begin
|
||
|
if Assigned(T.Items[I]) then
|
||
|
begin
|
||
|
DeleteDuplicates(T.Items[I]);
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
var
|
||
|
I, J, K, RegCount, MemIndex: Integer;
|
||
|
S: String;
|
||
|
A: TArray<String>;
|
||
|
D: TInstructionDefinition;
|
||
|
O: TInstructionOperand;
|
||
|
begin
|
||
|
FEditor.BeginUpdate;
|
||
|
|
||
|
for I := 0 to FEditor.DefinitionCount - 1 do
|
||
|
begin
|
||
|
D := FEditor.Definitions[I];
|
||
|
if (D.Encoding <> ieEVEX) then Continue;
|
||
|
S := D.Comment;
|
||
|
J := 1;
|
||
|
while (J < Length(S)) and (S[J] <> ' ') do Inc(J);
|
||
|
Delete(S, 1, J);
|
||
|
A := S.Split([',']);
|
||
|
for J := Low(A) to High(A) do
|
||
|
begin
|
||
|
A[J] := Trim(A[J]);
|
||
|
end;
|
||
|
S := A[High(A)];
|
||
|
J := 1;
|
||
|
while (J < Length(S)) and (S[J] <> ' ') do Inc(J);
|
||
|
Delete(S, J, Length(S));
|
||
|
A[High(A)] := S;
|
||
|
if (A[High(A)][1] = '(') then SetLength(A, Length(A) - 1);
|
||
|
|
||
|
RegCount := 0;
|
||
|
MemIndex := -1;
|
||
|
D.BeginUpdate;
|
||
|
for J := Low(A) to High(A) do
|
||
|
begin
|
||
|
O := nil;
|
||
|
case J of
|
||
|
0: O := D.Operands.OperandA;
|
||
|
1: O := D.Operands.OperandB;
|
||
|
2: O := D.Operands.OperandC;
|
||
|
3: O := D.Operands.OperandD;
|
||
|
end;
|
||
|
|
||
|
if (Pos('{1to', A[J]) > 0) then D.Flags := D.Flags + [ifHasEVEXBC];
|
||
|
if (Pos('{sae}', A[J]) > 0) then D.Flags := D.Flags + [ifHasEVEXSAE];
|
||
|
|
||
|
if (Pos('VK1', A[J]) > 0) then O.OperandType := optMSKR;
|
||
|
if (Pos('VK2', A[J]) > 0) then O.OperandType := optMSKR;
|
||
|
if (Pos('VK4', A[J]) > 0) then O.OperandType := optMSKR;
|
||
|
if (Pos('VK8', A[J]) > 0) then O.OperandType := optMSKR;
|
||
|
if (Pos('VK16', A[J]) > 0) then O.OperandType := optMSKR;
|
||
|
if (Pos('VK32', A[J]) > 0) then O.OperandType := optMSKR;
|
||
|
if (Pos('VK64', A[J]) > 0) then O.OperandType := optMSKR;
|
||
|
|
||
|
if (Pos('GR8', A[J]) > 0) then O.OperandType := optGPR8;
|
||
|
if (Pos('GR16', A[J]) > 0) then O.OperandType := optGPR16;
|
||
|
if (Pos('GR32', A[J]) > 0) then O.OperandType := optGPR32;
|
||
|
if (Pos('GR64', A[J]) > 0) then O.OperandType := optGPR64;
|
||
|
if (Pos('8mem', A[J]) > 0) then O.OperandType := optMem8;
|
||
|
if (Pos('16mem', A[J]) > 0) then O.OperandType := optMem16;
|
||
|
if (Pos('32mem', A[J]) > 0) then
|
||
|
begin
|
||
|
if (Pos('{1to2}', A[J]) > 0) then O.OperandType := optMem32Bcst2 else
|
||
|
if (Pos('{1to4}', A[J]) > 0) then O.OperandType := optMem32Bcst4 else
|
||
|
if (Pos('{1to8}', A[J]) > 0) then O.OperandType := optMem32Bcst8 else
|
||
|
if (Pos('{1to16}', A[J]) > 0) then O.OperandType := optMem32Bcst16 else
|
||
|
O.OperandType := optMem32;
|
||
|
end;
|
||
|
if (Pos('64mem', A[J]) > 0) then
|
||
|
begin
|
||
|
if (Pos('{1to2}', A[J]) > 0) then O.OperandType := optMem64Bcst2 else
|
||
|
if (Pos('{1to4}', A[J]) > 0) then O.OperandType := optMem64Bcst4 else
|
||
|
if (Pos('{1to8}', A[J]) > 0) then O.OperandType := optMem64Bcst8 else
|
||
|
if (Pos('{1to16}', A[J]) > 0) then O.OperandType := optMem64Bcst16 else
|
||
|
O.OperandType := optMem64;
|
||
|
end;
|
||
|
|
||
|
if (Pos('VR128', A[J]) > 0) then O.OperandType := optVR128;
|
||
|
if (Pos('VR256', A[J]) > 0) then O.OperandType := optVR256;
|
||
|
if (Pos('VR512', A[J]) > 0) then O.OperandType := optVR512;
|
||
|
if (Pos('128mem', A[J]) > 0) then O.OperandType := optMem128;
|
||
|
if (Pos('256mem', A[J]) > 0) then O.OperandType := optMem256;
|
||
|
if (Pos('512mem', A[J]) > 0) then O.OperandType := optMem512;
|
||
|
|
||
|
if (Pos('vx32', A[J]) > 0) then O.Encoding := opeNone;
|
||
|
if (Pos('vx64', A[J]) > 0) then O.Encoding := opeNone;
|
||
|
if (Pos('vx128', A[J]) > 0) then O.Encoding := opeNone;
|
||
|
if (Pos('vx256', A[J]) > 0) then O.Encoding := opeNone;
|
||
|
if (Pos('vx512', A[J]) > 0) then O.Encoding := opeNone;
|
||
|
if (Pos('vy32', A[J]) > 0) then O.Encoding := opeNone;
|
||
|
if (Pos('vy64', A[J]) > 0) then O.Encoding := opeNone;
|
||
|
if (Pos('vy128', A[J]) > 0) then O.Encoding := opeNone;
|
||
|
if (Pos('vy256', A[J]) > 0) then O.Encoding := opeNone;
|
||
|
if (Pos('vy512', A[J]) > 0) then O.Encoding := opeNone;
|
||
|
if (Pos('vz32', A[J]) > 0) then O.Encoding := opeNone;
|
||
|
if (Pos('vz64', A[J]) > 0) then O.Encoding := opeNone;
|
||
|
if (Pos('vz128', A[J]) > 0) then O.Encoding := opeNone;
|
||
|
if (Pos('vz256', A[J]) > 0) then O.Encoding := opeNone;
|
||
|
if (Pos('vz512', A[J]) > 0) then O.Encoding := opeNone;
|
||
|
|
||
|
if (Pos('imm8', A[J]) > 0) then O.OperandType := optImm8;
|
||
|
if (Pos('imm8u', A[J]) > 0) then O.OperandType := optImm8U;
|
||
|
if (Pos('u8imm', A[J]) > 0) then O.OperandType := optImm8U;
|
||
|
|
||
|
if (O.Encoding = opeModrmRm) then
|
||
|
begin
|
||
|
MemIndex := J;
|
||
|
if (D.EVEXCD8Scale <> 0) then
|
||
|
begin
|
||
|
case D.EvexCD8Scale of
|
||
|
1: O.Encoding := opeModrmRmCD1;
|
||
|
2: O.Encoding := opeModrmRmCD2;
|
||
|
4: O.Encoding := opeModrmRmCD4;
|
||
|
8: O.Encoding := opeModrmRmCD8;
|
||
|
16: O.Encoding := opeModrmRmCD16;
|
||
|
32: O.Encoding := opeModrmRmCD32;
|
||
|
64: O.Encoding := opeModrmRmCD64;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
if (O.Encoding = opeModrmReg) then Inc(RegCount);
|
||
|
end;
|
||
|
D.Operands.OperandA.AccessMode := opaWrite;
|
||
|
if (RegCount = 3) or ((RegCount = 2) and (MemIndex > -1) and (MemIndex <> 1)) then
|
||
|
begin
|
||
|
D.Operands.OperandB.Encoding := opeVexVVVV;
|
||
|
end;
|
||
|
D.EndUpdate;
|
||
|
|
||
|
end;
|
||
|
DeleteDuplicates(FEditor.RootTable.Items[$62]);
|
||
|
FEditor.EndUpdate;
|
||
|
end;
|
||
|
|
||
|
procedure TfrmMain.Button2Click(Sender: TObject);
|
||
|
|
||
|
function BitsNeeded(N: Integer): Integer;
|
||
|
begin
|
||
|
Result := Floor(log2(n) + 1);
|
||
|
end;
|
||
|
|
||
|
var
|
||
|
Mnemonics: TDictionary<String, Boolean>;
|
||
|
Node: PVirtualNode;
|
||
|
NodeData: PEditorNodeData;
|
||
|
LOPS: TList<TPair<TInstructionOperands, Integer>>;
|
||
|
LCPUID: TList<TPair<TCPUIDFeatureFlagSet, Integer>>;
|
||
|
LEFLAGS: TList<TPair<TX86Flags, Integer>>;
|
||
|
LREGS: TList<TPair<TX86RegisterSet, Integer>>;
|
||
|
I, J, Bits: Integer;
|
||
|
B: Boolean;
|
||
|
POPS: TPair<TInstructionOperands, Integer>;
|
||
|
PCPUID: TPair<TCPUIDFeatureFlagSet, Integer>;
|
||
|
PEFLAGS: TPair<TX86Flags, Integer>;
|
||
|
PREGS: TPair<TX86RegisterSet, Integer>;
|
||
|
begin
|
||
|
Bits := 4; // EVEX Info
|
||
|
|
||
|
Mnemonics := TDictionary<String, Boolean>.Create;
|
||
|
try
|
||
|
Node := EditorTree.GetFirst;
|
||
|
while Assigned(Node) do
|
||
|
begin
|
||
|
NodeData := EditorTree.GetNodeData(Node);
|
||
|
if (NodeData^.NodeType = ntInstructionDefinition) then
|
||
|
begin
|
||
|
if (not Mnemonics.ContainsKey(NodeData^.Definition.Mnemonic)) then
|
||
|
begin
|
||
|
Mnemonics.Add(NodeData^.Definition.Mnemonic, true);
|
||
|
end;
|
||
|
end;
|
||
|
Node := EditorTree.GetNext(Node);
|
||
|
end;
|
||
|
ShowMessage('Mnemonics: ' + IntToStr(Mnemonics.Count) + ' (' + IntToStr(BitsNeeded(Mnemonics.Count)) + ' bit)');
|
||
|
Inc(Bits, BitsNeeded(Mnemonics.Count));
|
||
|
finally
|
||
|
Mnemonics.Free;
|
||
|
end;
|
||
|
|
||
|
LOPS := TList<TPair<TInstructionOperands, Integer>>.Create;
|
||
|
for I := 0 to FEditor.DefinitionCount - 1 do
|
||
|
begin
|
||
|
B := false;
|
||
|
for J := 0 to LOPS.Count - 1 do
|
||
|
begin
|
||
|
if (LOPS[J].Key.Equals(FEditor.Definitions[I].Operands)) then
|
||
|
begin
|
||
|
POPS := LOPS[J];
|
||
|
Inc(POPS.Value);
|
||
|
LOPS[J] := POPS;
|
||
|
B := true;
|
||
|
Break;
|
||
|
end;
|
||
|
end;
|
||
|
if (not B) then
|
||
|
begin
|
||
|
POPS.Key := FEditor.Definitions[I].Operands;
|
||
|
POPS.Value := 1;
|
||
|
LOPS.Add(POPS);
|
||
|
end;
|
||
|
end;
|
||
|
ShowMessage('OPS: ' + IntToStr(LOPS.Count) + ' (' + IntToStr(BitsNeeded(LOPS.Count)) + ' bit)');
|
||
|
Inc(Bits, BitsNeeded(LOPS.Count));
|
||
|
LOPS.Free;
|
||
|
|
||
|
LCPUID := TList<TPair<TCPUIDFeatureFlagSet, Integer>>.Create;
|
||
|
for I := 0 to FEditor.DefinitionCount - 1 do
|
||
|
begin
|
||
|
B := false;
|
||
|
for J := 0 to LOPS.Count - 1 do
|
||
|
begin
|
||
|
if (LCPUID[J].Key = FEditor.Definitions[I].CPUID.FeatureFlags) then
|
||
|
begin
|
||
|
PCPUID := LCPUID[J];
|
||
|
Inc(PCPUID.Value);
|
||
|
LCPUID[J] := PCPUID;
|
||
|
B := true;
|
||
|
Break;
|
||
|
end;
|
||
|
end;
|
||
|
if (not B) then
|
||
|
begin
|
||
|
PCPUID.Key := FEditor.Definitions[I].CPUID.FeatureFlags;
|
||
|
PCPUID.Value := 1;
|
||
|
LCPUID.Add(PCPUID);
|
||
|
end;
|
||
|
end;
|
||
|
ShowMessage('CPUID: ' + IntToStr(LCPUID.Count) + ' (' + IntToStr(BitsNeeded(LCPUID.Count)) + ' bit)');
|
||
|
Inc(Bits, BitsNeeded(LCPUID.Count));
|
||
|
LCPUID.Free;
|
||
|
|
||
|
LEFLAGS := TList<TPair<TX86Flags, Integer>>.Create;
|
||
|
for I := 0 to FEditor.DefinitionCount - 1 do
|
||
|
begin
|
||
|
B := false;
|
||
|
for J := 0 to LOPS.Count - 1 do
|
||
|
begin
|
||
|
if (LEFLAGS[J].Key.Equals(FEditor.Definitions[I].X86Flags)) then
|
||
|
begin
|
||
|
PEFLAGS := LEFLAGS[J];
|
||
|
Inc(PEFLAGS.Value);
|
||
|
LEFLAGS[J] := PEFLAGS;
|
||
|
B := true;
|
||
|
Break;
|
||
|
end;
|
||
|
end;
|
||
|
if (not B) then
|
||
|
begin
|
||
|
PEFLAGS.Key := FEditor.Definitions[I].X86Flags;
|
||
|
PEFLAGS.Value := 1;
|
||
|
LEFLAGS.Add(PEFLAGS);
|
||
|
end;
|
||
|
end;
|
||
|
ShowMessage('EFLAGS: ' + IntToStr(LEFLAGS.Count) + ' (' + IntToStr(BitsNeeded(LEFLAGS.Count)) + ' bit)');
|
||
|
Inc(Bits, BitsNeeded(LEFLAGS.Count));
|
||
|
LEFLAGS.Free;
|
||
|
|
||
|
LREGS := TList<TPair<TX86RegisterSet, Integer>>.Create;
|
||
|
for I := 0 to FEditor.DefinitionCount - 1 do
|
||
|
begin
|
||
|
B := false;
|
||
|
for J := 0 to LOPS.Count - 1 do
|
||
|
begin
|
||
|
if (LREGS[J].Key = FEditor.Definitions[I].ImplicitRead.Registers) then
|
||
|
begin
|
||
|
PREGS := LREGS[J];
|
||
|
Inc(PREGS.Value);
|
||
|
LREGS[J] := PREGS;
|
||
|
B := true;
|
||
|
Break;
|
||
|
end;
|
||
|
end;
|
||
|
if (not B) then
|
||
|
begin
|
||
|
PREGS.Key := FEditor.Definitions[I].ImplicitRead.Registers;
|
||
|
PREGS.Value := 1;
|
||
|
LREGS.Add(PREGS);
|
||
|
end;
|
||
|
B := false;
|
||
|
for J := 0 to LOPS.Count - 1 do
|
||
|
begin
|
||
|
if (LREGS[J].Key = FEditor.Definitions[I].ImplicitWrite.Registers) then
|
||
|
begin
|
||
|
PREGS := LREGS[J];
|
||
|
Inc(PREGS.Value);
|
||
|
LREGS[J] := PREGS;
|
||
|
B := true;
|
||
|
Break;
|
||
|
end;
|
||
|
end;
|
||
|
if (not B) then
|
||
|
begin
|
||
|
PREGS.Key := FEditor.Definitions[I].ImplicitWrite.Registers;
|
||
|
PREGS.Value := 1;
|
||
|
LREGS.Add(PREGS);
|
||
|
end;
|
||
|
end;
|
||
|
ShowMessage('REGS: ' + IntToStr(LREGS.Count) + ' (' + IntToStr(BitsNeeded(LREGS.Count)) + ' bit)');
|
||
|
Inc(Bits, BitsNeeded(LREGS.Count));
|
||
|
LEFLAGS.Free;
|
||
|
|
||
|
ShowMessage('BytesNeeded: ' + IntToStr(Ceil(Bits / 8)) + ' (' + IntToStr(Bits) + ' bits)');
|
||
|
end;
|
||
|
|
||
|
procedure TfrmMain.bbCollapseLeafClick(Sender: TObject);
|
||
|
begin
|
||
|
ExpandLeaf(EditorTree.FocusedNode, false);
|
||
|
end;
|
||
|
|
||
|
procedure TfrmMain.bbCollapseNodesClick(Sender: TObject);
|
||
|
begin
|
||
|
ExpandAllNodes(false);
|
||
|
end;
|
||
|
|
||
|
procedure TfrmMain.bbDeleteDefinitionClick(Sender: TObject);
|
||
|
begin
|
||
|
DefinitionDelete(EditorTree.FocusedNode);
|
||
|
end;
|
||
|
|
||
|
procedure TfrmMain.edtMnemonicFilterCurChange(Sender: TObject);
|
||
|
begin
|
||
|
// TODO: Filter is offsync, if the user leaves the edit by pressing ESC or focusing an other
|
||
|
// control
|
||
|
SetMnemonicFilter(edtMnemonicFilter.CurText, bbExactMatch.Down);
|
||
|
end;
|
||
|
|
||
|
procedure TfrmMain.lbClipboardPasteClick(Sender: TObject);
|
||
|
begin
|
||
|
ClipboardPaste(EditorTree.FocusedNode);
|
||
|
end;
|
||
|
|
||
|
procedure TfrmMain.lbCreateDefinitionClick(Sender: TObject);
|
||
|
begin
|
||
|
DefinitionCreate;
|
||
|
end;
|
||
|
|
||
|
procedure TfrmMain.lbGenerateClick(Sender: TObject);
|
||
|
|
||
|
procedure DeleteDuplicates(T: TInstructionFilter);
|
||
|
var
|
||
|
L: TList<TInstructionDefinition>;
|
||
|
D: TInstructionDefinition;
|
||
|
I, J: Integer;
|
||
|
B: Boolean;
|
||
|
begin
|
||
|
if (T is TDefinitionContainer) then
|
||
|
begin
|
||
|
L := TList<TInstructionDefinition>.Create;
|
||
|
try
|
||
|
for I := (T as TDefinitionContainer).DefinitionCount - 1 downto 0 do
|
||
|
begin
|
||
|
D := (T as TDefinitionContainer).Definitions[I];
|
||
|
B := true;
|
||
|
for J := 0 to L.Count - 1 do
|
||
|
begin
|
||
|
if (D.Equals(L[J])) then
|
||
|
begin
|
||
|
D.Free;
|
||
|
B := false;
|
||
|
Break;
|
||
|
end;
|
||
|
end;
|
||
|
if (B) then L.Add(D);
|
||
|
end;
|
||
|
finally
|
||
|
L.Free;
|
||
|
end;
|
||
|
end else
|
||
|
begin
|
||
|
for I := 0 to T.Capacity - 1 do
|
||
|
begin
|
||
|
if Assigned(T.Items[I]) then
|
||
|
begin
|
||
|
DeleteDuplicates(T.Items[I]);
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
var
|
||
|
frmGenerator: TfrmGenerator;
|
||
|
begin
|
||
|
frmGenerator := TfrmGenerator.Create(Application);
|
||
|
try
|
||
|
frmGenerator.Editor := FEditor;
|
||
|
frmGenerator.ShowModal;
|
||
|
finally
|
||
|
frmGenerator.Free;
|
||
|
end;
|
||
|
|
||
|
Exit;
|
||
|
FEditor.BeginUpdate;
|
||
|
DeleteDuplicates(FEditor.RootTable);
|
||
|
FEditor.EndUpdate;
|
||
|
end;
|
||
|
|
||
|
procedure TfrmMain.lbLoadDatabaseClick(Sender: TObject);
|
||
|
var
|
||
|
ID: Integer;
|
||
|
begin
|
||
|
if (FHasUnsavedChanges) then
|
||
|
begin
|
||
|
ID := Application.MessageBox('Reloading the database will revert all unsaved changes. Do you'
|
||
|
+ ' really want to continue?', 'Question', MB_ICONWARNING or MB_YESNO or MB_DEFBUTTON2);
|
||
|
if (ID <> IdYes) then
|
||
|
begin
|
||
|
Exit;
|
||
|
end;
|
||
|
end;
|
||
|
FEditing := false;
|
||
|
try
|
||
|
ExpandAllNodes(false);
|
||
|
FEditor.LoadFromFile(ExtractFilePath(ParamStr(0)) + 'instructions.json');
|
||
|
if (lbMnemonicFilter.Down) then
|
||
|
begin
|
||
|
SetMnemonicFilter(edtMnemonicFilter.Text, bbExactMatch.Down);
|
||
|
end;
|
||
|
except
|
||
|
on E: Exception do
|
||
|
begin
|
||
|
Application.MessageBox(PChar(E.Message), 'Error', MB_ICONERROR);
|
||
|
end;
|
||
|
end;
|
||
|
FEditing := true;
|
||
|
FHasUnsavedChanges := false;
|
||
|
UpdateControls;
|
||
|
end;
|
||
|
|
||
|
procedure TfrmMain.lbMnemonicFilterClick(Sender: TObject);
|
||
|
begin
|
||
|
StatusBar.Panels[1].Visible := lbMnemonicFilter.Down;
|
||
|
piStatusBarProgress.Width := barStatusBarProgress.Control.ClientWidth;
|
||
|
if (lbMnemonicFilter.Down) then
|
||
|
begin
|
||
|
SetMnemonicFilter(edtMnemonicFilter.Text, bbExactMatch.Down);
|
||
|
edtMnemonicFilter.SetFocus;
|
||
|
end else
|
||
|
begin
|
||
|
SetMnemonicFilter('', false);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrmMain.lbSaveDatabaseClick(Sender: TObject);
|
||
|
begin
|
||
|
FEditor.SaveToFile(ExtractFilePath(ParamStr(0)) + 'instructions.json');
|
||
|
FHasUnsavedChanges := false;
|
||
|
UpdateControls;
|
||
|
end;
|
||
|
|
||
|
procedure TfrmMain.LoadGUIConfiguration;
|
||
|
var
|
||
|
Ini: TIniFile;
|
||
|
I: Integer;
|
||
|
A: TArray<String>;
|
||
|
begin
|
||
|
DockingManager.LoadLayoutFromIniFile(ChangeFileExt(ParamStr(0), 'Layout.ini'));
|
||
|
Ini := TIniFile.Create(ChangeFileExt(ParamStr(0), '.ini'));
|
||
|
try
|
||
|
for I := 0 to EditorTree.Header.Columns.Count - 1 do
|
||
|
begin
|
||
|
EditorTree.Header.Columns[I].Width := Ini.ReadInteger('Editor',
|
||
|
Format('Col_%.2d_Width', [I]), EditorTree.Header.Columns[I].Width);
|
||
|
end;
|
||
|
A := Ini.ReadString('Inspector', 'ExpandedFilterProperties', '').Split([',']);
|
||
|
for I := Low(A) to High(A) do
|
||
|
begin
|
||
|
FExpandedFilterProperties.Add(A[I]);
|
||
|
end;
|
||
|
A := Ini.ReadString('Inspector', 'ExpandedDefinitionProperties', '').Split([',']);
|
||
|
for I := Low(A) to High(A) do
|
||
|
begin
|
||
|
FExpandedDefinitionProperties.Add(A[I]);
|
||
|
end;
|
||
|
pnlInspector.Width := Ini.ReadInteger('Inspector', 'Width', 364);
|
||
|
Inspector.OptionsView.RowHeaderWidth := Ini.ReadInteger('Inspector', 'RowHeaderWidth', 170);
|
||
|
finally
|
||
|
Ini.Free;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrmMain.SaveGUIConfiguration;
|
||
|
var
|
||
|
Ini: TIniFile;
|
||
|
I: Integer;
|
||
|
S: String;
|
||
|
begin
|
||
|
DockingManager.SaveLayoutToIniFile(ChangeFileExt(ParamStr(0), 'Layout.ini'));
|
||
|
Ini := TIniFile.Create(ChangeFileExt(ParamStr(0), '.ini'));
|
||
|
try
|
||
|
for I := 0 to EditorTree.Header.Columns.Count - 1 do
|
||
|
begin
|
||
|
Ini.WriteInteger('Editor', Format('Col_%.2d_Width', [I]), EditorTree.Header.Columns[I].Width);
|
||
|
end;
|
||
|
UpdateExpandedProperties;
|
||
|
S := '';
|
||
|
for I := 0 to FExpandedFilterProperties.Count - 1 do
|
||
|
begin
|
||
|
S := S + FExpandedFilterProperties[I];
|
||
|
if (I < FExpandedFilterProperties.Count - 1) then
|
||
|
begin
|
||
|
S := S + ',';
|
||
|
end;
|
||
|
end;
|
||
|
Ini.WriteString('Inspector', 'ExpandedFilterProperties', S);
|
||
|
S := '';
|
||
|
for I := 0 to FExpandedDefinitionProperties.Count - 1 do
|
||
|
begin
|
||
|
S := S + FExpandedDefinitionProperties[I];
|
||
|
if (I < FExpandedDefinitionProperties.Count - 1) then
|
||
|
begin
|
||
|
S := S + ',';
|
||
|
end;
|
||
|
end;
|
||
|
Ini.WriteString('Inspector', 'ExpandedDefinitionProperties', S);
|
||
|
Ini.WriteInteger('Inspector', 'Width', pnlInspector.Width);
|
||
|
Ini.WriteInteger('Inspector', 'RowHeaderWidth', Inspector.OptionsView.RowHeaderWidth);
|
||
|
finally
|
||
|
Ini.Free;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrmMain.SetDefaultWindowPosition;
|
||
|
var
|
||
|
R: TRect;
|
||
|
begin
|
||
|
R := Screen.MonitorFromPoint(Mouse.CursorPos).WorkareaRect;
|
||
|
SetBounds(R.Left + 50, R.Top + 50, R.Width - 100, R.Height - 100);
|
||
|
end;
|
||
|
|
||
|
procedure TfrmMain.SetMnemonicFilter(const Filter: String; ExactMatch: Boolean);
|
||
|
|
||
|
procedure ApplyMnemonicFilter(Filter: TInstructionFilter; out IsVisible: Boolean;
|
||
|
const FilterText: String; FilterLength: Integer);
|
||
|
var
|
||
|
D: TInstructionDefinition;
|
||
|
C: TDefinitionContainer;
|
||
|
I: Integer;
|
||
|
B: Boolean;
|
||
|
begin
|
||
|
IsVisible := (FilterLength = 0);
|
||
|
if (iffIsDefinitionContainer in Filter.FilterFlags) then
|
||
|
begin
|
||
|
C := (Filter as TDefinitionContainer);
|
||
|
for I := 0 to C.DefinitionCount - 1 do
|
||
|
begin
|
||
|
B := IsVisible;
|
||
|
D := C.Definitions[I];
|
||
|
if (not IsVisible) then
|
||
|
begin
|
||
|
if (Length(D.Mnemonic) >= FilterLength) then
|
||
|
begin
|
||
|
if (ExactMatch) then
|
||
|
begin
|
||
|
B := (CompareStr(FilterText, LowerCase(D.Mnemonic)) = 0);
|
||
|
end else
|
||
|
begin
|
||
|
B := (CompareStr(FilterText, AnsiLowerCase(Copy(D.Mnemonic, 1, FilterLength))) = 0);
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
EditorTree.IsVisible[GetTreeNode(D)] := B;
|
||
|
IsVisible := IsVisible or B;
|
||
|
end;
|
||
|
end else
|
||
|
begin
|
||
|
for I := 0 to Filter.Capacity - 1 do
|
||
|
begin
|
||
|
if (not Assigned(Filter.Items[I])) then Continue;
|
||
|
ApplyMnemonicFilter(Filter.Items[I], B, FilterText, FilterLength);
|
||
|
EditorTree.IsVisible[GetTreeNode(Filter.Items[I])] := B;
|
||
|
IsVisible := IsVisible or B;
|
||
|
end;
|
||
|
EditorTree.IsVisible[GetTreeNode(Filter)] := IsVisible;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
var
|
||
|
FilterText: String;
|
||
|
FilterLength: Integer;
|
||
|
IsVisible: Boolean;
|
||
|
begin
|
||
|
EditorTree.BeginUpdate;
|
||
|
try
|
||
|
FilterText := AnsiLowerCase(Filter);
|
||
|
FilterLength := Length(Filter);
|
||
|
ApplyMnemonicFilter(FEditor.RootTable, IsVisible, FilterText, FilterLength);
|
||
|
finally
|
||
|
EditorTree.EndUpdate;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrmMain.UpdateControls;
|
||
|
var
|
||
|
NodeData: PEditorNodeData;
|
||
|
begin
|
||
|
lbSaveDatabase.Enabled := FHasUnsavedChanges;
|
||
|
|
||
|
NodeData := EditorTree.GetNodeData(EditorTree.FocusedNode);
|
||
|
bbDuplicateDefinition.Enabled :=
|
||
|
Assigned(NodeData) and (NodeData^.NodeType = ntInstructionDefinition);
|
||
|
bbDeleteDefinition.Enabled :=
|
||
|
Assigned(NodeData) and (NodeData^.NodeType = ntInstructionDefinition);
|
||
|
bbClipboardCopy.Enabled :=
|
||
|
Assigned(NodeData) {and (NodeData^.NodeType = ntInstructionDefinition)};
|
||
|
bbClipboardCut.Enabled :=
|
||
|
Assigned(NodeData) and (NodeData^.NodeType = ntInstructionDefinition);
|
||
|
bbExpandLeaf.Enabled :=
|
||
|
Assigned(NodeData) and (NodeData^.NodeType <> ntInstructionDefinition);
|
||
|
bbCollapseLeaf.Enabled :=
|
||
|
Assigned(NodeData) and (NodeData^.NodeType <> ntInstructionDefinition);
|
||
|
end;
|
||
|
|
||
|
procedure TfrmMain.UpdateExpandedProperties;
|
||
|
var
|
||
|
I: Integer;
|
||
|
begin
|
||
|
if (Assigned(Inspector.InspectedObject)) then
|
||
|
begin
|
||
|
if (Inspector.InspectedObject is TInstructionFilter) then
|
||
|
begin
|
||
|
FExpandedFilterProperties.Clear;
|
||
|
end;
|
||
|
if (Inspector.InspectedObject is TInstructionDefinition) then
|
||
|
begin
|
||
|
FExpandedDefinitionProperties.Clear;
|
||
|
end;
|
||
|
for I := 0 to Inspector.Rows.Count - 1 do
|
||
|
begin
|
||
|
if (Inspector.Rows[I].Expanded) then
|
||
|
begin
|
||
|
if (Inspector.InspectedObject is TInstructionFilter) then
|
||
|
begin
|
||
|
FExpandedFilterProperties.Add(
|
||
|
(Inspector.Rows[I] as TcxPropertyRow).PropertyEditor.GetName);
|
||
|
end;
|
||
|
if (Inspector.InspectedObject is TInstructionDefinition) then
|
||
|
begin
|
||
|
FExpandedDefinitionProperties.Add(
|
||
|
(Inspector.Rows[I] as TcxPropertyRow).PropertyEditor.GetName);
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrmMain.UpdateStatistic;
|
||
|
var
|
||
|
Mnemonics: TDictionary<String, Boolean>;
|
||
|
Node: PVirtualNode;
|
||
|
NodeData: PEditorNodeData;
|
||
|
begin
|
||
|
if (not FUpdating) then
|
||
|
begin
|
||
|
Mnemonics := TDictionary<String, Boolean>.Create;
|
||
|
try
|
||
|
Node := EditorTree.GetFirst;
|
||
|
while Assigned(Node) do
|
||
|
begin
|
||
|
NodeData := EditorTree.GetNodeData(Node);
|
||
|
if (NodeData^.NodeType = ntInstructionDefinition) then
|
||
|
begin
|
||
|
if (not Mnemonics.ContainsKey(NodeData^.Definition.Mnemonic)) then
|
||
|
begin
|
||
|
Mnemonics.Add(NodeData^.Definition.Mnemonic, true);
|
||
|
end;
|
||
|
end;
|
||
|
Node := EditorTree.GetNext(Node);
|
||
|
end;
|
||
|
StatusBar.Panels[2].Text := 'Mnemonics: ' + IntToStr(Mnemonics.Count);
|
||
|
finally
|
||
|
Mnemonics.Free;
|
||
|
end;
|
||
|
StatusBar.Panels[3].Text := 'Definitions: ' + IntToStr(FEditor.DefinitionCount);
|
||
|
StatusBar.Panels[4].Text := 'Filters: ' + IntToStr(FEditor.FilterCount);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrmMain.InspectorItemChanged(Sender: TObject; AOldRow: TcxCustomRow;
|
||
|
AOldCellIndex: Integer);
|
||
|
var
|
||
|
Row: TcxPropertyRow;
|
||
|
S: String;
|
||
|
begin
|
||
|
lblPropertyInfo.Caption := 'No info text available';
|
||
|
Row := (Inspector.FocusedRow as TcxPropertyRow);
|
||
|
if Assigned(Row) and Assigned(Row.PropertyEditor) then
|
||
|
begin
|
||
|
S := Row.PropertyEditor.GetName;
|
||
|
while (Assigned(Row.Parent)) do
|
||
|
begin
|
||
|
Row := (Row.Parent as TcxPropertyRow);
|
||
|
S := Row.PropertyEditor.GetName + '.' + S;
|
||
|
end;
|
||
|
if (Inspector.InspectedObject is TInstructionFilter) then
|
||
|
begin
|
||
|
S := 'Filter.' + S;
|
||
|
end else if (Inspector.InspectedObject is TInstructionDefinition) then
|
||
|
begin
|
||
|
S := 'Definition.' + S;
|
||
|
end;
|
||
|
lblPropertyInfo.Caption := GetPropertyHint(S);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
end.
|