init
This commit is contained in:
commit
8e6ad52ee4
44 files changed
+6842
No files matched your search
@@ -0,0 +1,211 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Cthangover.Tools.Services;
|
||||
using Godot;
|
||||
|
||||
namespace Cthangover.Core.UI.Tool.ScenarioEditor
|
||||
{
|
||||
public partial class ScenarioGraphView : HSplitContainer
|
||||
{
|
||||
private GraphEdit _graph;
|
||||
private RichTextLabel _infoLabel;
|
||||
private Dictionary<string, GraphNode> _nodes;
|
||||
private Dictionary<string, SceneGraphNode> _lookup;
|
||||
|
||||
public event Action<string> ScenarioFileRequested;
|
||||
|
||||
public ScenarioGraphView()
|
||||
{
|
||||
SizeFlagsHorizontal = SizeFlags.ExpandFill;
|
||||
SizeFlagsVertical = SizeFlags.ExpandFill;
|
||||
|
||||
_graph = new GraphEdit
|
||||
{
|
||||
SizeFlagsHorizontal = SizeFlags.ExpandFill,
|
||||
SizeFlagsVertical = SizeFlags.ExpandFill,
|
||||
RightDisconnects = false,
|
||||
ConnectionLinesThickness = 2f,
|
||||
ConnectionLinesAntialiased = true,
|
||||
MinimapEnabled = true,
|
||||
ShowGrid = true,
|
||||
SnappingEnabled = true,
|
||||
SnappingDistance = 20
|
||||
};
|
||||
_graph.ConnectionRequest += OnConnectionRequest;
|
||||
_graph.DisconnectionRequest += OnDisconnectionRequest;
|
||||
_graph.NodeSelected += OnNodeSelected;
|
||||
_graph.NodeDeselected += OnNodeDeselected;
|
||||
AddChild(_graph);
|
||||
|
||||
var panel = new VBoxContainer { CustomMinimumSize = new Vector2(250, 0) };
|
||||
panel.SizeFlagsVertical = SizeFlags.ExpandFill;
|
||||
AddChild(panel);
|
||||
|
||||
panel.AddChild(new Label
|
||||
{
|
||||
Text = TranslationServer.Translate("tools/scenario_editor/graph_select_node"),
|
||||
AutowrapMode = TextServer.AutowrapMode.WordSmart
|
||||
});
|
||||
|
||||
_infoLabel = new RichTextLabel
|
||||
{
|
||||
BbcodeEnabled = true,
|
||||
FitContent = true,
|
||||
ScrollFollowing = true,
|
||||
SizeFlagsVertical = SizeFlags.ExpandFill
|
||||
};
|
||||
_infoLabel.MetaClicked += OnLinkClicked;
|
||||
panel.AddChild(_infoLabel);
|
||||
}
|
||||
|
||||
public void Populate(SceneGraphData data)
|
||||
{
|
||||
var savedPositions = SaveNodePositions();
|
||||
ClearGraph();
|
||||
|
||||
_nodes = new Dictionary<string, GraphNode>();
|
||||
_lookup = new Dictionary<string, SceneGraphNode>();
|
||||
|
||||
int x = 40, y = 40;
|
||||
foreach (var pos in savedPositions.Values)
|
||||
{
|
||||
int bottom = (int)pos.Y + 160 + 20;
|
||||
if (bottom > y)
|
||||
y = bottom;
|
||||
}
|
||||
|
||||
foreach (var nodeData in data.Nodes)
|
||||
{
|
||||
var key = nodeData.SceneName.ToLowerInvariant();
|
||||
if (_nodes.ContainsKey(key))
|
||||
continue;
|
||||
|
||||
var bgCount = nodeData.Backgrounds?.Count ?? 0;
|
||||
var firstBg = bgCount > 0 ? nodeData.Backgrounds[0] : "";
|
||||
|
||||
var position = savedPositions.TryGetValue(key, out var saved)
|
||||
? saved
|
||||
: new Vector2(x, y);
|
||||
|
||||
var gn = new GraphNode
|
||||
{
|
||||
Title = nodeData.SceneName,
|
||||
Size = new Vector2(240, 90),
|
||||
PositionOffset = position
|
||||
};
|
||||
|
||||
gn.AddChild(new Label
|
||||
{
|
||||
Text = $"Mod: {nodeData.ModId}\nScenarios: {nodeData.ScenarioCount}" +
|
||||
(bgCount > 0 ? $"\nBg: {firstBg}" +
|
||||
(bgCount > 1 ? $" +{bgCount - 1}" : "") : "")
|
||||
});
|
||||
|
||||
var color = Colors.White;
|
||||
if (nodeData.IsStartScene)
|
||||
{
|
||||
color = new Color(0.3f, 1f, 0.3f);
|
||||
gn.AddThemeStyleboxOverride("titlebar", CreateTitlebarStyle(new Color(0.2f, 0.5f, 0.15f)));
|
||||
}
|
||||
else if (nodeData.HasErrors)
|
||||
{
|
||||
color = new Color(1f, 0.3f, 0.3f);
|
||||
gn.AddThemeStyleboxOverride("titlebar", CreateTitlebarStyle(new Color(0.5f, 0.1f, 0.1f)));
|
||||
}
|
||||
gn.SetSlot(0, true, 0, Colors.White, true, 0, color);
|
||||
|
||||
_graph.AddChild(gn);
|
||||
_nodes[key] = gn;
|
||||
_lookup[key] = nodeData;
|
||||
|
||||
if (!savedPositions.ContainsKey(key))
|
||||
{
|
||||
x += 280;
|
||||
if (x > 1000) { x = 40; y += 160; }
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var edge in data.Edges)
|
||||
{
|
||||
var srcK = edge.FromScene.ToLowerInvariant();
|
||||
var dstK = edge.ToScene.ToLowerInvariant();
|
||||
if (!_nodes.ContainsKey(srcK) || !_nodes.ContainsKey(dstK))
|
||||
continue;
|
||||
_graph.ConnectNode(_nodes[srcK].Name, 0, _nodes[dstK].Name, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private Dictionary<string, Vector2> SaveNodePositions()
|
||||
{
|
||||
var positions = new Dictionary<string, Vector2>();
|
||||
if (_nodes == null)
|
||||
return positions;
|
||||
foreach (var kv in _nodes)
|
||||
positions[kv.Key] = kv.Value.PositionOffset;
|
||||
return positions;
|
||||
}
|
||||
|
||||
private static StyleBoxFlat CreateTitlebarStyle(Color bgColor)
|
||||
{
|
||||
return new StyleBoxFlat
|
||||
{
|
||||
BgColor = bgColor,
|
||||
CornerRadiusTopLeft = 6,
|
||||
CornerRadiusTopRight = 6,
|
||||
CornerRadiusBottomLeft = 0,
|
||||
CornerRadiusBottomRight = 0
|
||||
};
|
||||
}
|
||||
|
||||
private void ClearGraph()
|
||||
{
|
||||
foreach (var c in _graph.GetChildren())
|
||||
if (c is GraphNode gn)
|
||||
gn.QueueFree();
|
||||
_infoLabel.Text = "";
|
||||
_nodes?.Clear();
|
||||
_lookup?.Clear();
|
||||
}
|
||||
|
||||
private void OnConnectionRequest(StringName fromNode, long fromPort, StringName toNode, long toPort) { }
|
||||
|
||||
private void OnDisconnectionRequest(StringName fromNode, long fromPort, StringName toNode, long toPort) { }
|
||||
|
||||
private void OnNodeSelected(Node n)
|
||||
{
|
||||
if (n is not GraphNode gn)
|
||||
return;
|
||||
var key = gn.Title.ToString().ToLowerInvariant();
|
||||
if (!_lookup.TryGetValue(key, out var nodeData))
|
||||
return;
|
||||
|
||||
var sb = new System.Text.StringBuilder();
|
||||
sb.AppendLine($"Scene: [b]{nodeData.SceneName}[/b]");
|
||||
sb.AppendLine($"Mod: {nodeData.ModId}");
|
||||
if (nodeData.Backgrounds.Count > 0)
|
||||
sb.AppendLine($"Backgrounds: {string.Join(", ", nodeData.Backgrounds)}");
|
||||
sb.AppendLine();
|
||||
sb.AppendLine($"Scenarios ({nodeData.Scenarios.Count}):");
|
||||
|
||||
foreach (var sc in nodeData.Scenarios.OrderBy(s => s.Priority))
|
||||
{
|
||||
var url = Uri.EscapeDataString(sc.FilePath);
|
||||
sb.AppendLine($" [{sc.Priority}] [url={url}]{sc.Name}[/url]");
|
||||
}
|
||||
|
||||
_infoLabel.Text = sb.ToString();
|
||||
}
|
||||
|
||||
private void OnNodeDeselected(Node n)
|
||||
{
|
||||
_infoLabel.Text = "";
|
||||
}
|
||||
|
||||
private void OnLinkClicked(Variant meta)
|
||||
{
|
||||
var path = Uri.UnescapeDataString(meta.AsString());
|
||||
ScenarioFileRequested?.Invoke(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user