fix: .gitignore + add 44 language JSON files
This commit is contained in:
1 parent
e8fd68e27b
commit
8de545dd2c
227 files changed
+22603
No files matched your search
@@ -0,0 +1,369 @@
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace Lity3DEditor;
|
||||
|
||||
public class MainForm : Form
|
||||
{
|
||||
private List<SceneNode> _nodes = new();
|
||||
private string? _currentPath;
|
||||
private bool _modified;
|
||||
|
||||
private TreeView _tree = null!;
|
||||
private PropertyGrid _propertyGrid = null!;
|
||||
private StatusStrip _status = null!;
|
||||
private ToolStripButton _btnSave = null!;
|
||||
|
||||
public MainForm()
|
||||
{
|
||||
Text = "Lity3D Engine Scene Editor";
|
||||
Size = new Size(1280, 800);
|
||||
StartPosition = FormStartPosition.CenterScreen;
|
||||
BackColor = Color.FromArgb(30, 30, 38);
|
||||
Font = new Font("Microsoft YaHei UI", 9F, FontStyle.Regular, GraphicsUnit.Point);
|
||||
|
||||
BuildMenu();
|
||||
BuildToolbar();
|
||||
BuildPanels();
|
||||
BuildStatus();
|
||||
|
||||
Load += (_, _) =>
|
||||
{
|
||||
foreach (var c in Controls.OfType<SplitContainer>())
|
||||
{
|
||||
if (c.Orientation == Orientation.Vertical)
|
||||
{
|
||||
c.Panel1MinSize = 180;
|
||||
c.Panel2MinSize = 300;
|
||||
c.SplitterDistance = 260;
|
||||
}
|
||||
else
|
||||
{
|
||||
c.Panel1MinSize = 200;
|
||||
c.Panel2MinSize = 120;
|
||||
c.SplitterDistance = c.Height - 220;
|
||||
}
|
||||
}
|
||||
TryOpenScene(Path.Combine(Application.StartupPath, "scene.txt"));
|
||||
};
|
||||
FormClosing += (_, e) => { if (!PromptSave()) e.Cancel = true; };
|
||||
}
|
||||
|
||||
private void BuildMenu()
|
||||
{
|
||||
var menu = new MenuStrip();
|
||||
var file = new ToolStripMenuItem("文件(&F)");
|
||||
file.DropDownItems.Add(new ToolStripMenuItem("打开...", null, (_, _) => OpenScene()) { ShortcutKeys = Keys.Control | Keys.O });
|
||||
file.DropDownItems.Add(new ToolStripMenuItem("保存", null, (_, _) => SaveScene()) { ShortcutKeys = Keys.Control | Keys.S });
|
||||
file.DropDownItems.Add(new ToolStripMenuItem("另存为...", null, (_, _) => SaveSceneAs()));
|
||||
file.DropDownItems.Add(new ToolStripSeparator());
|
||||
file.DropDownItems.Add(new ToolStripMenuItem("退出", null, (_, _) => Close()) { ShortcutKeys = Keys.Alt | Keys.F4 });
|
||||
menu.Items.Add(file);
|
||||
|
||||
var edit = new ToolStripMenuItem("编辑(&E)");
|
||||
edit.DropDownItems.Add(new ToolStripMenuItem("添加立方体", null, (_, _) => AddNode(MeshType.CUBE, "cube")));
|
||||
edit.DropDownItems.Add(new ToolStripMenuItem("添加球体", null, (_, _) => AddNode(MeshType.SPHERE, "sphere")));
|
||||
edit.DropDownItems.Add(new ToolStripMenuItem("添加平面", null, (_, _) => AddNode(MeshType.PLANE, "plane")));
|
||||
edit.DropDownItems.Add(new ToolStripSeparator());
|
||||
edit.DropDownItems.Add(new ToolStripMenuItem("删除选中", null, (_, _) => DeleteSelected()) { ShortcutKeys = Keys.Delete });
|
||||
menu.Items.Add(edit);
|
||||
|
||||
MainMenuStrip = menu;
|
||||
Controls.Add(menu);
|
||||
}
|
||||
|
||||
private void BuildToolbar()
|
||||
{
|
||||
var tool = new ToolStrip();
|
||||
tool.GripStyle = ToolStripGripStyle.Hidden;
|
||||
tool.BackColor = Color.FromArgb(40, 40, 50);
|
||||
tool.ForeColor = Color.White;
|
||||
tool.Renderer = new DarkToolStripRenderer();
|
||||
|
||||
_btnSave = new ToolStripButton("保存", null, (_, _) => SaveScene()) { Enabled = false };
|
||||
tool.Items.Add(_btnSave);
|
||||
tool.Items.Add(new ToolStripSeparator());
|
||||
tool.Items.Add(new ToolStripButton("添加立方体", null, (_, _) => AddNode(MeshType.CUBE, "cube")));
|
||||
tool.Items.Add(new ToolStripButton("添加球体", null, (_, _) => AddNode(MeshType.SPHERE, "sphere")));
|
||||
tool.Items.Add(new ToolStripButton("添加平面", null, (_, _) => AddNode(MeshType.PLANE, "plane")));
|
||||
tool.Items.Add(new ToolStripSeparator());
|
||||
tool.Items.Add(new ToolStripButton("删除", null, (_, _) => DeleteSelected()));
|
||||
|
||||
tool.Dock = DockStyle.Top;
|
||||
Controls.Add(tool);
|
||||
}
|
||||
|
||||
private void BuildPanels()
|
||||
{
|
||||
var split = new SplitContainer
|
||||
{
|
||||
Dock = DockStyle.Fill,
|
||||
BackColor = Color.FromArgb(30, 30, 38)
|
||||
};
|
||||
split.Panel1.BackColor = Color.FromArgb(35, 35, 45);
|
||||
split.Panel2.BackColor = Color.FromArgb(35, 35, 45);
|
||||
|
||||
_tree = new TreeView
|
||||
{
|
||||
Dock = DockStyle.Fill,
|
||||
BackColor = Color.FromArgb(35, 35, 45),
|
||||
ForeColor = Color.White,
|
||||
BorderStyle = BorderStyle.None,
|
||||
FullRowSelect = true,
|
||||
HideSelection = false,
|
||||
ShowLines = true,
|
||||
ShowPlusMinus = true,
|
||||
LineColor = Color.FromArgb(100, 120, 160)
|
||||
};
|
||||
_tree.AfterSelect += (_, _) => OnNodeSelected();
|
||||
split.Panel1.Controls.Add(_tree);
|
||||
|
||||
var rightSplit = new SplitContainer
|
||||
{
|
||||
Dock = DockStyle.Fill,
|
||||
Orientation = Orientation.Horizontal,
|
||||
BackColor = Color.FromArgb(30, 30, 38)
|
||||
};
|
||||
rightSplit.Panel1.BackColor = Color.FromArgb(35, 35, 45);
|
||||
rightSplit.Panel2.BackColor = Color.FromArgb(28, 28, 36);
|
||||
|
||||
_propertyGrid = new PropertyGrid
|
||||
{
|
||||
Dock = DockStyle.Fill,
|
||||
BackColor = Color.FromArgb(35, 35, 45),
|
||||
ForeColor = Color.White,
|
||||
CategoryForeColor = Color.FromArgb(180, 180, 200),
|
||||
CommandsBackColor = Color.FromArgb(35, 35, 45),
|
||||
CommandsForeColor = Color.White,
|
||||
DisabledItemForeColor = Color.Gray,
|
||||
HelpBackColor = Color.FromArgb(28, 28, 36),
|
||||
HelpForeColor = Color.White,
|
||||
ViewBackColor = Color.FromArgb(35, 35, 45),
|
||||
ViewForeColor = Color.White,
|
||||
LineColor = Color.FromArgb(60, 60, 80),
|
||||
ToolbarVisible = false,
|
||||
PropertySort = PropertySort.Categorized
|
||||
};
|
||||
_propertyGrid.PropertyValueChanged += (_, _) => OnPropertyChanged();
|
||||
rightSplit.Panel1.Controls.Add(_propertyGrid);
|
||||
|
||||
var previewLabel = new Label
|
||||
{
|
||||
Dock = DockStyle.Fill,
|
||||
Text = "3D 预览区\n(由 Lity3D Engine 运行时渲染)",
|
||||
ForeColor = Color.FromArgb(120, 120, 140),
|
||||
BackColor = Color.FromArgb(28, 28, 36),
|
||||
TextAlign = ContentAlignment.MiddleCenter,
|
||||
Font = new Font(Font.FontFamily, 11f, FontStyle.Regular)
|
||||
};
|
||||
rightSplit.Panel2.Controls.Add(previewLabel);
|
||||
|
||||
split.Panel2.Controls.Add(rightSplit);
|
||||
|
||||
Controls.Add(split);
|
||||
}
|
||||
|
||||
private void BuildStatus()
|
||||
{
|
||||
_status = new StatusStrip();
|
||||
_status.BackColor = Color.FromArgb(40, 40, 50);
|
||||
_status.ForeColor = Color.White;
|
||||
_status.Items.Add(new ToolStripStatusLabel("就绪"));
|
||||
Controls.Add(_status);
|
||||
}
|
||||
|
||||
private void TryOpenScene(string path)
|
||||
{
|
||||
if (!File.Exists(path)) return;
|
||||
try
|
||||
{
|
||||
_nodes = SceneIO.Load(path);
|
||||
_currentPath = path;
|
||||
RebuildTree();
|
||||
SetModified(false);
|
||||
SetStatus($"已打开 {path}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(this, ex.Message, "打开失败", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private void OpenScene()
|
||||
{
|
||||
if (!PromptSave()) return;
|
||||
using var dlg = new OpenFileDialog
|
||||
{
|
||||
Filter = "Lity3D 场景|*.txt|所有文件|*.*",
|
||||
Title = "打开场景"
|
||||
};
|
||||
if (dlg.ShowDialog(this) == DialogResult.OK)
|
||||
TryOpenScene(dlg.FileName);
|
||||
}
|
||||
|
||||
private bool SaveScene()
|
||||
{
|
||||
if (string.IsNullOrEmpty(_currentPath))
|
||||
return SaveSceneAs();
|
||||
try
|
||||
{
|
||||
SceneIO.Save(_currentPath, _nodes);
|
||||
SetModified(false);
|
||||
SetStatus($"已保存 {_currentPath}");
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(this, ex.Message, "保存失败", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private bool SaveSceneAs()
|
||||
{
|
||||
using var dlg = new SaveFileDialog
|
||||
{
|
||||
Filter = "Lity3D 场景|*.txt|所有文件|*.*",
|
||||
Title = "另存为"
|
||||
};
|
||||
if (dlg.ShowDialog(this) != DialogResult.OK) return false;
|
||||
_currentPath = dlg.FileName;
|
||||
return SaveScene();
|
||||
}
|
||||
|
||||
private bool PromptSave()
|
||||
{
|
||||
if (!_modified) return true;
|
||||
var r = MessageBox.Show(this, "场景已修改,是否保存?", "保存确认",
|
||||
MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
|
||||
if (r == DialogResult.Cancel) return false;
|
||||
if (r == DialogResult.Yes) return SaveScene();
|
||||
return true;
|
||||
}
|
||||
|
||||
private void AddNode(MeshType type, string baseName)
|
||||
{
|
||||
int idx = 1;
|
||||
string name = baseName;
|
||||
while (_nodes.Any(n => n.Name == name))
|
||||
name = $"{baseName}_{idx++}";
|
||||
|
||||
var parentIdx = -1;
|
||||
if (_tree.SelectedNode?.Tag is SceneNode sel && sel.Name != "root")
|
||||
parentIdx = _nodes.IndexOf(sel);
|
||||
else if (_nodes.Count > 0)
|
||||
parentIdx = 0; // root
|
||||
|
||||
var node = new SceneNode
|
||||
{
|
||||
Name = name,
|
||||
ParentIndex = parentIdx,
|
||||
Mesh = type,
|
||||
PosY = type == MeshType.PLANE ? -1.0f : 0.0f
|
||||
};
|
||||
_nodes.Add(node);
|
||||
RebuildTree();
|
||||
SelectNode(node);
|
||||
SetModified(true);
|
||||
SetStatus($"添加 {name}");
|
||||
}
|
||||
|
||||
private void DeleteSelected()
|
||||
{
|
||||
if (_tree.SelectedNode?.Tag is not SceneNode node || node.Name == "root")
|
||||
{
|
||||
MessageBox.Show(this, "不能删除根节点", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
return;
|
||||
}
|
||||
_nodes.Remove(node);
|
||||
RebuildTree();
|
||||
SetModified(true);
|
||||
SetStatus($"删除 {node.Name}");
|
||||
}
|
||||
|
||||
private void RebuildTree()
|
||||
{
|
||||
_tree.Nodes.Clear();
|
||||
var treeMap = new Dictionary<int, TreeNode>();
|
||||
for (int i = 0; i < _nodes.Count; i++)
|
||||
{
|
||||
var n = _nodes[i];
|
||||
var tn = new TreeNode(n.Name) { Tag = n, ForeColor = Color.White };
|
||||
treeMap[i] = tn;
|
||||
if (n.ParentIndex >= 0 && treeMap.TryGetValue(n.ParentIndex, out var parent))
|
||||
parent.Nodes.Add(tn);
|
||||
else
|
||||
_tree.Nodes.Add(tn);
|
||||
}
|
||||
_tree.ExpandAll();
|
||||
}
|
||||
|
||||
private void SelectNode(SceneNode node)
|
||||
{
|
||||
foreach (TreeNode root in _tree.Nodes)
|
||||
{
|
||||
var found = FindNode(root, node);
|
||||
if (found != null)
|
||||
{
|
||||
_tree.SelectedNode = found;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static TreeNode? FindNode(TreeNode parent, SceneNode node)
|
||||
{
|
||||
if (parent.Tag == node) return parent;
|
||||
foreach (TreeNode c in parent.Nodes)
|
||||
{
|
||||
var r = FindNode(c, node);
|
||||
if (r != null) return r;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void OnNodeSelected()
|
||||
{
|
||||
_propertyGrid.SelectedObject = _tree.SelectedNode?.Tag;
|
||||
if (_tree.SelectedNode?.Tag is SceneNode n)
|
||||
SetStatus(n.Name);
|
||||
}
|
||||
|
||||
private void OnPropertyChanged()
|
||||
{
|
||||
SetModified(true);
|
||||
_tree.Refresh();
|
||||
}
|
||||
|
||||
private void SetModified(bool modified)
|
||||
{
|
||||
_modified = modified;
|
||||
_btnSave.Enabled = modified;
|
||||
Text = "Lity3D Engine Scene Editor" + (modified ? " *" : "") + (string.IsNullOrEmpty(_currentPath) ? "" : $" - {_currentPath}");
|
||||
}
|
||||
|
||||
private void SetStatus(string msg)
|
||||
{
|
||||
if (_status.Items[0] is ToolStripStatusLabel lbl)
|
||||
lbl.Text = msg;
|
||||
}
|
||||
}
|
||||
|
||||
public class DarkToolStripRenderer : ToolStripProfessionalRenderer
|
||||
{
|
||||
public DarkToolStripRenderer() : base(new DarkColorTable()) { }
|
||||
}
|
||||
|
||||
public class DarkColorTable : ProfessionalColorTable
|
||||
{
|
||||
public override Color ToolStripBorder => Color.FromArgb(60, 60, 80);
|
||||
public override Color ToolStripGradientBegin => Color.FromArgb(40, 40, 50);
|
||||
public override Color ToolStripGradientEnd => Color.FromArgb(40, 40, 50);
|
||||
public override Color ToolStripGradientMiddle => Color.FromArgb(45, 45, 55);
|
||||
public override Color ButtonSelectedHighlight => Color.FromArgb(70, 70, 90);
|
||||
public override Color ButtonSelectedBorder => Color.FromArgb(100, 120, 160);
|
||||
public override Color ButtonPressedHighlight => Color.FromArgb(60, 80, 120);
|
||||
public override Color ButtonCheckedHighlight => Color.FromArgb(60, 80, 120);
|
||||
public override Color MenuBorder => Color.FromArgb(60, 60, 80);
|
||||
public override Color MenuItemSelected => Color.FromArgb(70, 70, 90);
|
||||
public override Color MenuItemBorder => Color.FromArgb(100, 120, 160);
|
||||
}
|
||||
Reference in new issue
Block a user