UI refactoring
This commit is contained in:
@@ -29,15 +29,10 @@ const
|
|||||||
type
|
type
|
||||||
TAstViewNode = class; // Forward declaration
|
TAstViewNode = class; // Forward declaration
|
||||||
|
|
||||||
// This aggregate interface encapsulates all node-specific logic.
|
|
||||||
IAstViewNodeHandler = interface
|
IAstViewNodeHandler = interface
|
||||||
// Gets the original logical AST node
|
|
||||||
function GetAstNode: IAstNode;
|
function GetAstNode: IAstNode;
|
||||||
// Creates the specific FMX UI for this node
|
|
||||||
procedure BuildUI(OwnerNode: TAstViewNode);
|
procedure BuildUI(OwnerNode: TAstViewNode);
|
||||||
// Reconstructs the logical AST node from the FMX UI state
|
|
||||||
function ReconstructAst(OwnerNode: TAstViewNode): IAstNode;
|
function ReconstructAst(OwnerNode: TAstViewNode): IAstNode;
|
||||||
// The original logical AST node
|
|
||||||
property Node: IAstNode read GetAstNode;
|
property Node: IAstNode read GetAstNode;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@@ -56,19 +51,15 @@ type
|
|||||||
property Workspace: TAstWorkspace read GetWorkspace;
|
property Workspace: TAstWorkspace read GetWorkspace;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// Defines the layout direction for children within TAutoFitControl
|
|
||||||
TLayoutOrientation = (loVertical, loHorizontal);
|
TLayoutOrientation = (loVertical, loHorizontal);
|
||||||
|
|
||||||
// Defines the alignment of children on the cross-axis
|
|
||||||
TLayoutAlignment = (laCenter, laFlush);
|
TLayoutAlignment = (laCenter, laFlush);
|
||||||
|
|
||||||
// A styled control that automatically adjusts its size to fit its children, including padding.
|
|
||||||
TAutoFitControl = class(TStyledControl)
|
TAutoFitControl = class(TStyledControl)
|
||||||
private
|
private
|
||||||
FUpdatingOwnSize: Boolean; // Recursion guard
|
FUpdatingOwnSize: Boolean;
|
||||||
FNeedRecalcSize: Boolean; // Flag for EndUpdate
|
FNeedRecalcSize: Boolean;
|
||||||
FOrientation: TLayoutOrientation; // Storage for Orientation
|
FOrientation: TLayoutOrientation;
|
||||||
FAlignment: TLayoutAlignment; // Storage for Alignment
|
FAlignment: TLayoutAlignment;
|
||||||
procedure RecalcOwnSize;
|
procedure RecalcOwnSize;
|
||||||
procedure SetOrientation(const Value: TLayoutOrientation);
|
procedure SetOrientation(const Value: TLayoutOrientation);
|
||||||
procedure SetAlignment(const Value: TLayoutAlignment);
|
procedure SetAlignment(const Value: TLayoutAlignment);
|
||||||
@@ -87,12 +78,9 @@ type
|
|||||||
property Alignment: TLayoutAlignment read FAlignment write SetAlignment default TLayoutAlignment.laCenter;
|
property Alignment: TLayoutAlignment read FAlignment write SetAlignment default TLayoutAlignment.laCenter;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// A movable panel with a custom-painted border. Content (like title) is added externally.
|
|
||||||
TAstViewNode = class(TAutoFitControl)
|
TAstViewNode = class(TAutoFitControl)
|
||||||
private
|
private
|
||||||
FBackgroundColor: TAlphaColor;
|
FBackgroundColor: TAlphaColor;
|
||||||
FIsDragging: Boolean;
|
|
||||||
FDownPos: TPointF;
|
|
||||||
FBorderColor: TAlphaColor;
|
FBorderColor: TAlphaColor;
|
||||||
FBorderWidth: Single;
|
FBorderWidth: Single;
|
||||||
FBorderRadius: Single;
|
FBorderRadius: Single;
|
||||||
@@ -100,7 +88,6 @@ type
|
|||||||
FVisualizer: IAstVisualizer;
|
FVisualizer: IAstVisualizer;
|
||||||
FHandler: IAstViewNodeHandler;
|
FHandler: IAstViewNodeHandler;
|
||||||
|
|
||||||
// --- Visual State Fields ---
|
|
||||||
FErrorMessage: string;
|
FErrorMessage: string;
|
||||||
FTypeInfoText: string;
|
FTypeInfoText: string;
|
||||||
|
|
||||||
@@ -111,17 +98,20 @@ type
|
|||||||
procedure SetFrameless(const Value: Boolean);
|
procedure SetFrameless(const Value: Boolean);
|
||||||
function GetNode: IAstNode;
|
function GetNode: IAstNode;
|
||||||
|
|
||||||
// New Setters
|
|
||||||
procedure SetErrorMessage(const Value: string);
|
procedure SetErrorMessage(const Value: string);
|
||||||
procedure SetTypeInfoText(const Value: string);
|
procedure SetTypeInfoText(const Value: string);
|
||||||
procedure UpdateVisualState;
|
procedure UpdateVisualState;
|
||||||
|
|
||||||
protected
|
protected
|
||||||
procedure Paint; override;
|
procedure Paint; override;
|
||||||
|
procedure SetupNode;
|
||||||
|
|
||||||
|
// Overrides for interaction
|
||||||
|
procedure DoMouseEnter; override;
|
||||||
|
procedure DoMouseLeave; override;
|
||||||
procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Single); override;
|
procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Single); override;
|
||||||
procedure MouseMove(Shift: TShiftState; X, Y: Single); override;
|
procedure MouseMove(Shift: TShiftState; X, Y: Single); override;
|
||||||
procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Single); override;
|
procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Single); override;
|
||||||
procedure SetupNode;
|
|
||||||
|
|
||||||
public
|
public
|
||||||
constructor Create(const AVisualizer: IAstVisualizer; const AHandler: IAstViewNodeHandler); reintroduce;
|
constructor Create(const AVisualizer: IAstVisualizer; const AHandler: IAstViewNodeHandler); reintroduce;
|
||||||
@@ -138,7 +128,6 @@ type
|
|||||||
property Visualizer: IAstVisualizer read FVisualizer;
|
property Visualizer: IAstVisualizer read FVisualizer;
|
||||||
property Node: IAstNode read GetNode;
|
property Node: IAstNode read GetNode;
|
||||||
|
|
||||||
// --- Visual State Properties ---
|
|
||||||
property ErrorMessage: string read FErrorMessage write SetErrorMessage;
|
property ErrorMessage: string read FErrorMessage write SetErrorMessage;
|
||||||
property TypeInfoText: string read FTypeInfoText write SetTypeInfoText;
|
property TypeInfoText: string read FTypeInfoText write SetTypeInfoText;
|
||||||
|
|
||||||
@@ -180,7 +169,6 @@ type
|
|||||||
property OnMouseLeave;
|
property OnMouseLeave;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// Helper base class to reduce boilerplate in specific handlers
|
|
||||||
TBaseNodeHandler<T: IAstNode> = class(TInterfacedObject, IAstViewNodeHandler)
|
TBaseNodeHandler<T: IAstNode> = class(TInterfacedObject, IAstViewNodeHandler)
|
||||||
protected
|
protected
|
||||||
FNode: T;
|
FNode: T;
|
||||||
@@ -394,8 +382,6 @@ begin
|
|||||||
FVisualizer := AVisualizer.Clone(Self, AVisualizer.ExprDepth);
|
FVisualizer := AVisualizer.Clone(Self, AVisualizer.ExprDepth);
|
||||||
FHandler := AHandler;
|
FHandler := AHandler;
|
||||||
|
|
||||||
FIsDragging := False;
|
|
||||||
|
|
||||||
FBorderColor := TAlphaColors.Gray;
|
FBorderColor := TAlphaColors.Gray;
|
||||||
FBorderWidth := 1;
|
FBorderWidth := 1;
|
||||||
FBorderRadius := 9;
|
FBorderRadius := 9;
|
||||||
@@ -406,6 +392,7 @@ begin
|
|||||||
Width := cMinNodeWidth;
|
Width := cMinNodeWidth;
|
||||||
Height := cMinNodeHeight;
|
Height := cMinNodeHeight;
|
||||||
|
|
||||||
|
// HitTest muss True sein für Hover-Effekte (IsMouseOver)
|
||||||
HitTest := True;
|
HitTest := True;
|
||||||
ClipChildren := True;
|
ClipChildren := True;
|
||||||
|
|
||||||
@@ -429,6 +416,60 @@ begin
|
|||||||
inherited;
|
inherited;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TAstViewNode.DoMouseEnter;
|
||||||
|
begin
|
||||||
|
inherited;
|
||||||
|
// Wir müssen neu zeichnen, da sich IsMouseOver geändert hat,
|
||||||
|
// FMX triggert Paint nicht automatisch bei Hover.
|
||||||
|
Repaint;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TAstViewNode.DoMouseLeave;
|
||||||
|
begin
|
||||||
|
inherited;
|
||||||
|
Repaint;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TAstViewNode.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Single);
|
||||||
|
var
|
||||||
|
pt: TPointF;
|
||||||
|
begin
|
||||||
|
inherited;
|
||||||
|
// Panning-Weiterleitung an den Workspace
|
||||||
|
if Assigned(FVisualizer.Workspace) then
|
||||||
|
begin
|
||||||
|
pt := LocalToAbsolute(TPointF.Create(X, Y));
|
||||||
|
pt := FVisualizer.Workspace.AbsoluteToLocal(pt);
|
||||||
|
FVisualizer.Workspace.ExternalMouseDown(Button, Shift, pt.X, pt.Y);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TAstViewNode.MouseMove(Shift: TShiftState; X, Y: Single);
|
||||||
|
var
|
||||||
|
pt: TPointF;
|
||||||
|
begin
|
||||||
|
inherited;
|
||||||
|
if Assigned(FVisualizer.Workspace) then
|
||||||
|
begin
|
||||||
|
pt := LocalToAbsolute(TPointF.Create(X, Y));
|
||||||
|
pt := FVisualizer.Workspace.AbsoluteToLocal(pt);
|
||||||
|
FVisualizer.Workspace.ExternalMouseMove(Shift, pt.X, pt.Y);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TAstViewNode.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Single);
|
||||||
|
var
|
||||||
|
pt: TPointF;
|
||||||
|
begin
|
||||||
|
inherited;
|
||||||
|
if Assigned(FVisualizer.Workspace) then
|
||||||
|
begin
|
||||||
|
pt := LocalToAbsolute(TPointF.Create(X, Y));
|
||||||
|
pt := FVisualizer.Workspace.AbsoluteToLocal(pt);
|
||||||
|
FVisualizer.Workspace.ExternalMouseUp(Button, Shift, pt.X, pt.Y);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
function TAstViewNode.AddContainer(Parent: TControl; Orientation: TLayoutOrientation; Alignment: TLayoutAlignment): TAutoFitControl;
|
function TAstViewNode.AddContainer(Parent: TControl; Orientation: TLayoutOrientation; Alignment: TLayoutAlignment): TAutoFitControl;
|
||||||
begin
|
begin
|
||||||
Result := TAutoFitControl.Create(Self);
|
Result := TAutoFitControl.Create(Self);
|
||||||
@@ -535,57 +576,88 @@ var
|
|||||||
effBorderColor: TAlphaColor;
|
effBorderColor: TAlphaColor;
|
||||||
effBorderWidth: Single;
|
effBorderWidth: Single;
|
||||||
effDash: TStrokeDash;
|
effDash: TStrokeDash;
|
||||||
|
isHovering: Boolean;
|
||||||
|
isBlock: Boolean;
|
||||||
begin
|
begin
|
||||||
inherited;
|
inherited;
|
||||||
|
|
||||||
Canvas.Fill.Kind := TBrushKind.None;
|
// Check if this is a block node (blocks should not highlight on hover)
|
||||||
|
isBlock := Assigned(Node) and (Node.Kind = TAstNodeKind.akBlockExpression);
|
||||||
|
|
||||||
// Determine styles based on state (Error > Standard)
|
// Determine hover state: active only if mouse is over AND it is not a block
|
||||||
if FErrorMessage <> '' then
|
isHovering := IsMouseOver and (not isBlock);
|
||||||
|
|
||||||
|
// 1. Set base values
|
||||||
|
if FFrameless then
|
||||||
begin
|
begin
|
||||||
effBorderColor := TAlphaColors.Red;
|
effBorderColor := FBorderColor;
|
||||||
effBorderWidth := 2.0;
|
effBorderWidth := FBorderWidth;
|
||||||
effDash := TStrokeDash.Solid;
|
effDash := TStrokeDash.Dot;
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
effBorderColor := FBorderColor;
|
effBorderColor := FBorderColor;
|
||||||
effBorderWidth := FBorderWidth;
|
effBorderWidth := FBorderWidth;
|
||||||
if FFrameless then
|
effDash := TStrokeDash.Solid;
|
||||||
effDash := TStrokeDash.Dot
|
|
||||||
else
|
|
||||||
effDash := TStrokeDash.Solid;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
if FFrameless and (FErrorMessage = '') then
|
// 2. Hover state (overrides base, makes frameless nodes visible)
|
||||||
|
if isHovering then
|
||||||
begin
|
begin
|
||||||
// Standard frameless drawing (only if no error)
|
// Bright white for strong contrast against dark background
|
||||||
Canvas.Fill.Kind := TBrushKind.Solid;
|
effBorderColor := TAlphaColors.White;
|
||||||
Canvas.Fill.Color := FBackgroundColor;
|
|
||||||
Canvas.Stroke.Kind := TBrushKind.None;
|
// Make border slightly thicker for a "pop" effect
|
||||||
|
effBorderWidth := Max(2.0, FBorderWidth + 1.0);
|
||||||
|
|
||||||
|
// Always solid line when hovering, even if originally frameless
|
||||||
|
effDash := TStrokeDash.Solid;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// 3. Error state (dominates everything)
|
||||||
|
if FErrorMessage <> '' then
|
||||||
|
begin
|
||||||
|
effBorderColor := TAlphaColors.Red;
|
||||||
|
effBorderWidth := 2.0;
|
||||||
|
effDash := TStrokeDash.Solid;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// --- Drawing ---
|
||||||
|
|
||||||
|
// Fill background
|
||||||
|
Canvas.Fill.Kind := TBrushKind.Solid;
|
||||||
|
Canvas.Fill.Color := FBackgroundColor;
|
||||||
|
|
||||||
|
if FFrameless and (FErrorMessage = '') and (not isHovering) then
|
||||||
|
begin
|
||||||
|
// Special case: Inactive, frameless node (e.g., simple constant)
|
||||||
|
// Draw only background, no border
|
||||||
Canvas.FillRect(TRectF.Create(0, 0, Width, Height), 0, 0, [], 1.0);
|
Canvas.FillRect(TRectF.Create(0, 0, Width, Height), 0, 0, [], 1.0);
|
||||||
Canvas.Stroke.Kind := TBrushKind.Solid;
|
|
||||||
Canvas.Stroke.Color := effBorderColor;
|
// Draw border only if explicit width is set (e.g. debugging)
|
||||||
Canvas.Stroke.Thickness := effBorderWidth;
|
if FBorderWidth > 0 then
|
||||||
Canvas.Stroke.Dash := effDash;
|
begin
|
||||||
Canvas.DrawRect(TRectF.Create(0, 0, Width, Height), 0, 0, [], 1.0);
|
Canvas.Stroke.Kind := TBrushKind.Solid;
|
||||||
|
Canvas.Stroke.Color := effBorderColor;
|
||||||
|
Canvas.Stroke.Thickness := effBorderWidth;
|
||||||
|
Canvas.Stroke.Dash := effDash;
|
||||||
|
Canvas.DrawRect(TRectF.Create(0, 0, Width, Height), 0, 0, [], 1.0);
|
||||||
|
end;
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
// Draw background fill first
|
// Standard case: Node with border (or hovered frameless node)
|
||||||
Canvas.Fill.Kind := TBrushKind.Solid;
|
|
||||||
Canvas.Fill.Color := FBackgroundColor;
|
|
||||||
rect := TRectF.Create(0, 0, Width, Height);
|
rect := TRectF.Create(0, 0, Width, Height);
|
||||||
|
// Adjust to avoid clipping the border
|
||||||
if (effBorderWidth > 0) then
|
if (effBorderWidth > 0) then
|
||||||
rect.Inflate(-effBorderWidth / 2, -effBorderWidth / 2);
|
rect.Inflate(-effBorderWidth / 2, -effBorderWidth / 2);
|
||||||
|
|
||||||
Canvas.FillRect(rect, FBorderRadius, FBorderRadius, AllCorners, 1.0, TCornerType.Round);
|
Canvas.FillRect(rect, FBorderRadius, FBorderRadius, AllCorners, 1.0, TCornerType.Round);
|
||||||
|
|
||||||
// Draw border (Custom or Error)
|
// Draw border
|
||||||
if (effBorderWidth > 0) and (effBorderColor <> TAlphaColors.Null) then
|
if (effBorderWidth > 0) and (effBorderColor <> TAlphaColors.Null) then
|
||||||
begin
|
begin
|
||||||
rect := TRectF.Create(0, 0, Width, Height);
|
|
||||||
rect.Inflate(-effBorderWidth / 2, -effBorderWidth / 2);
|
|
||||||
|
|
||||||
Canvas.Stroke.Kind := TBrushKind.Solid;
|
Canvas.Stroke.Kind := TBrushKind.Solid;
|
||||||
Canvas.Stroke.Color := effBorderColor;
|
Canvas.Stroke.Color := effBorderColor;
|
||||||
Canvas.Stroke.Thickness := effBorderWidth;
|
Canvas.Stroke.Thickness := effBorderWidth;
|
||||||
@@ -631,53 +703,6 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TAstViewNode.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Single);
|
|
||||||
begin
|
|
||||||
inherited;
|
|
||||||
if Button = TMouseButton.mbLeft then
|
|
||||||
begin
|
|
||||||
var lControl := ObjectAtPoint(LocalToScreen(TPointF.Create(X, Y)));
|
|
||||||
if Assigned(lControl) and (lControl.GetObject = Self) then
|
|
||||||
begin
|
|
||||||
FIsDragging := True;
|
|
||||||
FDownPos := TPointF.Create(X, Y);
|
|
||||||
Capture;
|
|
||||||
BringToFront;
|
|
||||||
end
|
|
||||||
else
|
|
||||||
FIsDragging := False;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure TAstViewNode.MouseMove(Shift: TShiftState; X, Y: Single);
|
|
||||||
begin
|
|
||||||
inherited;
|
|
||||||
|
|
||||||
if FIsDragging then
|
|
||||||
begin
|
|
||||||
var deltaX := X - FDownPos.X;
|
|
||||||
var deltaY := Y - FDownPos.Y;
|
|
||||||
|
|
||||||
Position.X := Position.X + deltaX;
|
|
||||||
Position.Y := Position.Y + deltaY;
|
|
||||||
|
|
||||||
if ParentControl <> nil then
|
|
||||||
ParentControl.Repaint;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure TAstViewNode.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Single);
|
|
||||||
begin
|
|
||||||
inherited;
|
|
||||||
if (Button = TMouseButton.mbLeft) and (FIsDragging) then
|
|
||||||
begin
|
|
||||||
ReleaseCapture;
|
|
||||||
FIsDragging := False;
|
|
||||||
if ParentControl <> nil then
|
|
||||||
ParentControl.Repaint;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure TAstViewNode.SetBackgroundColor(const Value: TAlphaColor);
|
procedure TAstViewNode.SetBackgroundColor(const Value: TAlphaColor);
|
||||||
begin
|
begin
|
||||||
FBackgroundColor := Value;
|
FBackgroundColor := Value;
|
||||||
|
|||||||
@@ -47,6 +47,11 @@ type
|
|||||||
function GetChildrenMatrix(var Matrix: TMatrix; var Simple: Boolean): Boolean; override;
|
function GetChildrenMatrix(var Matrix: TMatrix; var Simple: Boolean): Boolean; override;
|
||||||
function Zoom(Factor: Single): Boolean;
|
function Zoom(Factor: Single): Boolean;
|
||||||
|
|
||||||
|
// Neue Public Methoden, damit Nodes das Panning steuern können
|
||||||
|
procedure ExternalMouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Single);
|
||||||
|
procedure ExternalMouseMove(Shift: TShiftState; X, Y: Single);
|
||||||
|
procedure ExternalMouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Single);
|
||||||
|
|
||||||
published
|
published
|
||||||
property Align;
|
property Align;
|
||||||
property Anchors;
|
property Anchors;
|
||||||
@@ -88,8 +93,8 @@ implementation
|
|||||||
uses
|
uses
|
||||||
System.Math,
|
System.Math,
|
||||||
FMX.Platform,
|
FMX.Platform,
|
||||||
Myc.Fmx.AstEditor.Core, // Enthält TAstViewNode Interfaces
|
Myc.Fmx.AstEditor.Core,
|
||||||
Myc.Fmx.AstEditor.Visualizer; // Enthält TAstVisualizer
|
Myc.Fmx.AstEditor.Visualizer;
|
||||||
|
|
||||||
{ TPinConnection }
|
{ TPinConnection }
|
||||||
|
|
||||||
@@ -112,7 +117,6 @@ var
|
|||||||
visu: IAstVisualizer;
|
visu: IAstVisualizer;
|
||||||
node: TAstViewNode;
|
node: TAstViewNode;
|
||||||
begin
|
begin
|
||||||
// Erstelle den Visualizer mit diesem Workspace als Kontext
|
|
||||||
visu := TAstVisualizer.Create(Self, Self, 0);
|
visu := TAstVisualizer.Create(Self, Self, 0);
|
||||||
node := visu.CallAccept(RootNode);
|
node := visu.CallAccept(RootNode);
|
||||||
if Assigned(node) then
|
if Assigned(node) then
|
||||||
@@ -132,23 +136,43 @@ begin
|
|||||||
Result := True;
|
Result := True;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
// --- Interne Event Handler ---
|
||||||
|
|
||||||
procedure TAstWorkspace.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Single);
|
procedure TAstWorkspace.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Single);
|
||||||
begin
|
begin
|
||||||
inherited;
|
inherited;
|
||||||
if (Button = TMouseButton.mbLeft) and (ObjectAtPoint(LocalToScreen(TPointF.Create(X, Y))) = Self as IControl) then
|
ExternalMouseDown(Button, Shift, X, Y);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TAstWorkspace.MouseMove(Shift: TShiftState; X, Y: Single);
|
||||||
|
begin
|
||||||
|
inherited;
|
||||||
|
ExternalMouseMove(Shift, X, Y);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TAstWorkspace.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Single);
|
||||||
|
begin
|
||||||
|
inherited;
|
||||||
|
ExternalMouseUp(Button, Shift, X, Y);
|
||||||
|
end;
|
||||||
|
|
||||||
|
// --- Externe Steuerung für Nodes ---
|
||||||
|
|
||||||
|
procedure TAstWorkspace.ExternalMouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Single);
|
||||||
|
begin
|
||||||
|
if (Button = TMouseButton.mbLeft) then
|
||||||
begin
|
begin
|
||||||
|
Capture;
|
||||||
FIsPanning := True;
|
FIsPanning := True;
|
||||||
FLastPanPos := TPointF.Create(X, Y);
|
FLastPanPos := TPointF.Create(X, Y);
|
||||||
Cursor := crHandPoint;
|
Cursor := crHandPoint;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TAstWorkspace.MouseMove(Shift: TShiftState; X, Y: Single);
|
procedure TAstWorkspace.ExternalMouseMove(Shift: TShiftState; X, Y: Single);
|
||||||
var
|
var
|
||||||
delta: TPointF;
|
delta: TPointF;
|
||||||
begin
|
begin
|
||||||
inherited;
|
|
||||||
|
|
||||||
if FIsPanning then
|
if FIsPanning then
|
||||||
begin
|
begin
|
||||||
delta := TPointF.Create(X - FLastPanPos.X, Y - FLastPanPos.Y);
|
delta := TPointF.Create(X - FLastPanPos.X, Y - FLastPanPos.Y);
|
||||||
@@ -161,11 +185,11 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TAstWorkspace.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Single);
|
procedure TAstWorkspace.ExternalMouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Single);
|
||||||
begin
|
begin
|
||||||
inherited;
|
|
||||||
if (Button = TMouseButton.mbLeft) and (FIsPanning) then
|
if (Button = TMouseButton.mbLeft) and (FIsPanning) then
|
||||||
begin
|
begin
|
||||||
|
ReleaseCapture;
|
||||||
FIsPanning := False;
|
FIsPanning := False;
|
||||||
Cursor := crDefault;
|
Cursor := crDefault;
|
||||||
end;
|
end;
|
||||||
@@ -200,26 +224,21 @@ begin
|
|||||||
|
|
||||||
for connection in FConnections do
|
for connection in FConnections do
|
||||||
begin
|
begin
|
||||||
// Output Pin Calculation
|
|
||||||
pinCenter := TPointF.Create(connection.OutputPin.Width / 2, connection.OutputPin.Height / 2);
|
pinCenter := TPointF.Create(connection.OutputPin.Width / 2, connection.OutputPin.Height / 2);
|
||||||
absoluteStart := connection.OutputPin.LocalToAbsolute(pinCenter);
|
absoluteStart := connection.OutputPin.LocalToAbsolute(pinCenter);
|
||||||
|
|
||||||
// Input Pin Calculation
|
|
||||||
pinCenter := TPointF.Create(connection.InputPin.Width / 2, connection.InputPin.Height / 2);
|
pinCenter := TPointF.Create(connection.InputPin.Width / 2, connection.InputPin.Height / 2);
|
||||||
absoluteEnd := connection.InputPin.LocalToAbsolute(pinCenter);
|
absoluteEnd := connection.InputPin.LocalToAbsolute(pinCenter);
|
||||||
|
|
||||||
// Convert to Workspace Local Coordinates
|
|
||||||
startPoint := AbsoluteToLocal(absoluteStart);
|
startPoint := AbsoluteToLocal(absoluteStart);
|
||||||
endPoint := AbsoluteToLocal(absoluteEnd);
|
endPoint := AbsoluteToLocal(absoluteEnd);
|
||||||
|
|
||||||
// Determine Color based on TagString (naive check)
|
|
||||||
str := connection.InputPin.TagString;
|
str := connection.InputPin.TagString;
|
||||||
if Pos('data', str) = 0 then
|
if Pos('data', str) = 0 then
|
||||||
Canvas.Stroke.Color := cExecPinColor
|
Canvas.Stroke.Color := cExecPinColor
|
||||||
else
|
else
|
||||||
Canvas.Stroke.Color := cDataPinColor;
|
Canvas.Stroke.Color := cDataPinColor;
|
||||||
|
|
||||||
// Draw Curve
|
|
||||||
path := TPathData.Create;
|
path := TPathData.Create;
|
||||||
try
|
try
|
||||||
controlOffset := Max(25, 0.5 * endPoint.Distance(startPoint));
|
controlOffset := Max(25, 0.5 * endPoint.Distance(startPoint));
|
||||||
|
|||||||
Reference in New Issue
Block a user