feat: Add AGV Map Editor and Simulator tools
- Add AGVMapEditor: Visual map editing with drag-and-drop node placement * RFID mapping separation (physical ID ↔ logical node mapping) * A* pathfinding algorithm with AGV directional constraints * JSON map data persistence with structured format * Interactive map canvas with zoom/pan functionality - Add AGVSimulator: Real-time AGV movement simulation * Virtual AGV with state machine (Idle, Moving, Rotating, Docking, Charging, Error) * Path execution and visualization from calculated routes * Real-time position tracking and battery simulation * Integration with map editor data format - Update solution structure and build configuration - Add comprehensive documentation in CLAUDE.md - Implement AGV-specific constraints (forward/backward docking, rotation limits) 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
422
Cs_HMI/AGVMapEditor/Forms/MainForm.Designer.cs
generated
Normal file
422
Cs_HMI/AGVMapEditor/Forms/MainForm.Designer.cs
generated
Normal file
@@ -0,0 +1,422 @@
|
||||
namespace AGVMapEditor.Forms
|
||||
{
|
||||
partial class MainForm
|
||||
{
|
||||
/// <summary>
|
||||
/// 필수 디자이너 변수입니다.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// 사용 중인 모든 리소스를 정리합니다.
|
||||
/// </summary>
|
||||
/// <param name="disposing">관리되는 리소스를 삭제해야 하면 true이고, 그렇지 않으면 false입니다.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form 디자이너에서 생성한 코드
|
||||
|
||||
/// <summary>
|
||||
/// 디자이너 지원에 필요한 메서드입니다.
|
||||
/// 이 메서드의 내용을 코드 편집기로 수정하지 마세요.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.menuStrip1 = new System.Windows.Forms.MenuStrip();
|
||||
this.fileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.newToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.openToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.saveToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.saveAsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.exitToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.statusStrip1 = new System.Windows.Forms.StatusStrip();
|
||||
this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel();
|
||||
this.splitContainer1 = new System.Windows.Forms.SplitContainer();
|
||||
this.tabControl1 = new System.Windows.Forms.TabControl();
|
||||
this.tabPageNodes = new System.Windows.Forms.TabPage();
|
||||
this.btnRemoveConnection = new System.Windows.Forms.Button();
|
||||
this.btnAddConnection = new System.Windows.Forms.Button();
|
||||
this.btnDeleteNode = new System.Windows.Forms.Button();
|
||||
this.btnAddNode = new System.Windows.Forms.Button();
|
||||
this.listBoxNodes = new System.Windows.Forms.ListBox();
|
||||
this.label1 = new System.Windows.Forms.Label();
|
||||
this.tabPageRfid = new System.Windows.Forms.TabPage();
|
||||
this.btnDeleteRfidMapping = new System.Windows.Forms.Button();
|
||||
this.btnAddRfidMapping = new System.Windows.Forms.Button();
|
||||
this.listBoxRfidMappings = new System.Windows.Forms.ListBox();
|
||||
this.label2 = new System.Windows.Forms.Label();
|
||||
this.tabPageProperties = new System.Windows.Forms.TabPage();
|
||||
this.labelSelectedNode = new System.Windows.Forms.Label();
|
||||
this.label3 = new System.Windows.Forms.Label();
|
||||
this.menuStrip1.SuspendLayout();
|
||||
this.statusStrip1.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit();
|
||||
this.splitContainer1.Panel1.SuspendLayout();
|
||||
this.splitContainer1.SuspendLayout();
|
||||
this.tabControl1.SuspendLayout();
|
||||
this.tabPageNodes.SuspendLayout();
|
||||
this.tabPageRfid.SuspendLayout();
|
||||
this.tabPageProperties.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// menuStrip1
|
||||
//
|
||||
this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.fileToolStripMenuItem});
|
||||
this.menuStrip1.Location = new System.Drawing.Point(0, 0);
|
||||
this.menuStrip1.Name = "menuStrip1";
|
||||
this.menuStrip1.Size = new System.Drawing.Size(1200, 24);
|
||||
this.menuStrip1.TabIndex = 0;
|
||||
this.menuStrip1.Text = "menuStrip1";
|
||||
//
|
||||
// fileToolStripMenuItem
|
||||
//
|
||||
this.fileToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.newToolStripMenuItem,
|
||||
this.openToolStripMenuItem,
|
||||
this.toolStripSeparator1,
|
||||
this.saveToolStripMenuItem,
|
||||
this.saveAsToolStripMenuItem,
|
||||
this.toolStripSeparator2,
|
||||
this.exitToolStripMenuItem});
|
||||
this.fileToolStripMenuItem.Name = "fileToolStripMenuItem";
|
||||
this.fileToolStripMenuItem.Size = new System.Drawing.Size(57, 20);
|
||||
this.fileToolStripMenuItem.Text = "파일(&F)";
|
||||
//
|
||||
// newToolStripMenuItem
|
||||
//
|
||||
this.newToolStripMenuItem.Name = "newToolStripMenuItem";
|
||||
this.newToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.N)));
|
||||
this.newToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
|
||||
this.newToolStripMenuItem.Text = "새로 만들기(&N)";
|
||||
this.newToolStripMenuItem.Click += new System.EventHandler(this.newToolStripMenuItem_Click);
|
||||
//
|
||||
// openToolStripMenuItem
|
||||
//
|
||||
this.openToolStripMenuItem.Name = "openToolStripMenuItem";
|
||||
this.openToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.O)));
|
||||
this.openToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
|
||||
this.openToolStripMenuItem.Text = "열기(&O)";
|
||||
this.openToolStripMenuItem.Click += new System.EventHandler(this.openToolStripMenuItem_Click);
|
||||
//
|
||||
// toolStripSeparator1
|
||||
//
|
||||
this.toolStripSeparator1.Name = "toolStripSeparator1";
|
||||
this.toolStripSeparator1.Size = new System.Drawing.Size(177, 6);
|
||||
//
|
||||
// saveToolStripMenuItem
|
||||
//
|
||||
this.saveToolStripMenuItem.Name = "saveToolStripMenuItem";
|
||||
this.saveToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.S)));
|
||||
this.saveToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
|
||||
this.saveToolStripMenuItem.Text = "저장(&S)";
|
||||
this.saveToolStripMenuItem.Click += new System.EventHandler(this.saveToolStripMenuItem_Click);
|
||||
//
|
||||
// saveAsToolStripMenuItem
|
||||
//
|
||||
this.saveAsToolStripMenuItem.Name = "saveAsToolStripMenuItem";
|
||||
this.saveAsToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
|
||||
this.saveAsToolStripMenuItem.Text = "다른 이름으로 저장(&A)";
|
||||
this.saveAsToolStripMenuItem.Click += new System.EventHandler(this.saveAsToolStripMenuItem_Click);
|
||||
//
|
||||
// toolStripSeparator2
|
||||
//
|
||||
this.toolStripSeparator2.Name = "toolStripSeparator2";
|
||||
this.toolStripSeparator2.Size = new System.Drawing.Size(177, 6);
|
||||
//
|
||||
// exitToolStripMenuItem
|
||||
//
|
||||
this.exitToolStripMenuItem.Name = "exitToolStripMenuItem";
|
||||
this.exitToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
|
||||
this.exitToolStripMenuItem.Text = "종료(&X)";
|
||||
this.exitToolStripMenuItem.Click += new System.EventHandler(this.exitToolStripMenuItem_Click);
|
||||
//
|
||||
// statusStrip1
|
||||
//
|
||||
this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.toolStripStatusLabel1});
|
||||
this.statusStrip1.Location = new System.Drawing.Point(0, 751);
|
||||
this.statusStrip1.Name = "statusStrip1";
|
||||
this.statusStrip1.Size = new System.Drawing.Size(1200, 22);
|
||||
this.statusStrip1.TabIndex = 1;
|
||||
this.statusStrip1.Text = "statusStrip1";
|
||||
//
|
||||
// toolStripStatusLabel1
|
||||
//
|
||||
this.toolStripStatusLabel1.Name = "toolStripStatusLabel1";
|
||||
this.toolStripStatusLabel1.Size = new System.Drawing.Size(39, 17);
|
||||
this.toolStripStatusLabel1.Text = "Ready";
|
||||
//
|
||||
// splitContainer1
|
||||
//
|
||||
this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.splitContainer1.Location = new System.Drawing.Point(0, 24);
|
||||
this.splitContainer1.Name = "splitContainer1";
|
||||
//
|
||||
// splitContainer1.Panel1
|
||||
//
|
||||
this.splitContainer1.Panel1.Controls.Add(this.tabControl1);
|
||||
this.splitContainer1.Panel1MinSize = 300;
|
||||
this.splitContainer1.Size = new System.Drawing.Size(1200, 727);
|
||||
this.splitContainer1.SplitterDistance = 300;
|
||||
this.splitContainer1.TabIndex = 2;
|
||||
//
|
||||
// tabControl1
|
||||
//
|
||||
this.tabControl1.Controls.Add(this.tabPageNodes);
|
||||
this.tabControl1.Controls.Add(this.tabPageRfid);
|
||||
this.tabControl1.Controls.Add(this.tabPageProperties);
|
||||
this.tabControl1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.tabControl1.Location = new System.Drawing.Point(0, 0);
|
||||
this.tabControl1.Name = "tabControl1";
|
||||
this.tabControl1.SelectedIndex = 0;
|
||||
this.tabControl1.Size = new System.Drawing.Size(300, 727);
|
||||
this.tabControl1.TabIndex = 0;
|
||||
//
|
||||
// tabPageNodes
|
||||
//
|
||||
this.tabPageNodes.Controls.Add(this.btnRemoveConnection);
|
||||
this.tabPageNodes.Controls.Add(this.btnAddConnection);
|
||||
this.tabPageNodes.Controls.Add(this.btnDeleteNode);
|
||||
this.tabPageNodes.Controls.Add(this.btnAddNode);
|
||||
this.tabPageNodes.Controls.Add(this.listBoxNodes);
|
||||
this.tabPageNodes.Controls.Add(this.label1);
|
||||
this.tabPageNodes.Location = new System.Drawing.Point(4, 22);
|
||||
this.tabPageNodes.Name = "tabPageNodes";
|
||||
this.tabPageNodes.Padding = new System.Windows.Forms.Padding(3);
|
||||
this.tabPageNodes.Size = new System.Drawing.Size(292, 701);
|
||||
this.tabPageNodes.TabIndex = 0;
|
||||
this.tabPageNodes.Text = "노드 관리";
|
||||
this.tabPageNodes.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// btnRemoveConnection
|
||||
//
|
||||
this.btnRemoveConnection.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btnRemoveConnection.Location = new System.Drawing.Point(6, 637);
|
||||
this.btnRemoveConnection.Name = "btnRemoveConnection";
|
||||
this.btnRemoveConnection.Size = new System.Drawing.Size(280, 25);
|
||||
this.btnRemoveConnection.TabIndex = 5;
|
||||
this.btnRemoveConnection.Text = "연결 제거";
|
||||
this.btnRemoveConnection.UseVisualStyleBackColor = true;
|
||||
this.btnRemoveConnection.Click += new System.EventHandler(this.btnRemoveConnection_Click);
|
||||
//
|
||||
// btnAddConnection
|
||||
//
|
||||
this.btnAddConnection.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btnAddConnection.Location = new System.Drawing.Point(6, 606);
|
||||
this.btnAddConnection.Name = "btnAddConnection";
|
||||
this.btnAddConnection.Size = new System.Drawing.Size(280, 25);
|
||||
this.btnAddConnection.TabIndex = 4;
|
||||
this.btnAddConnection.Text = "연결 추가";
|
||||
this.btnAddConnection.UseVisualStyleBackColor = true;
|
||||
this.btnAddConnection.Click += new System.EventHandler(this.btnAddConnection_Click);
|
||||
//
|
||||
// btnDeleteNode
|
||||
//
|
||||
this.btnDeleteNode.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btnDeleteNode.Location = new System.Drawing.Point(148, 670);
|
||||
this.btnDeleteNode.Name = "btnDeleteNode";
|
||||
this.btnDeleteNode.Size = new System.Drawing.Size(138, 25);
|
||||
this.btnDeleteNode.TabIndex = 3;
|
||||
this.btnDeleteNode.Text = "노드 삭제";
|
||||
this.btnDeleteNode.UseVisualStyleBackColor = true;
|
||||
this.btnDeleteNode.Click += new System.EventHandler(this.btnDeleteNode_Click);
|
||||
//
|
||||
// btnAddNode
|
||||
//
|
||||
this.btnAddNode.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btnAddNode.Location = new System.Drawing.Point(6, 670);
|
||||
this.btnAddNode.Name = "btnAddNode";
|
||||
this.btnAddNode.Size = new System.Drawing.Size(138, 25);
|
||||
this.btnAddNode.TabIndex = 2;
|
||||
this.btnAddNode.Text = "노드 추가";
|
||||
this.btnAddNode.UseVisualStyleBackColor = true;
|
||||
this.btnAddNode.Click += new System.EventHandler(this.btnAddNode_Click);
|
||||
//
|
||||
// listBoxNodes
|
||||
//
|
||||
this.listBoxNodes.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.listBoxNodes.FormattingEnabled = true;
|
||||
this.listBoxNodes.ItemHeight = 12;
|
||||
this.listBoxNodes.Location = new System.Drawing.Point(6, 25);
|
||||
this.listBoxNodes.Name = "listBoxNodes";
|
||||
this.listBoxNodes.Size = new System.Drawing.Size(280, 568);
|
||||
this.listBoxNodes.TabIndex = 1;
|
||||
//
|
||||
// label1
|
||||
//
|
||||
this.label1.AutoSize = true;
|
||||
this.label1.Location = new System.Drawing.Point(6, 6);
|
||||
this.label1.Name = "label1";
|
||||
this.label1.Size = new System.Drawing.Size(53, 12);
|
||||
this.label1.TabIndex = 0;
|
||||
this.label1.Text = "노드 목록";
|
||||
//
|
||||
// tabPageRfid
|
||||
//
|
||||
this.tabPageRfid.Controls.Add(this.btnDeleteRfidMapping);
|
||||
this.tabPageRfid.Controls.Add(this.btnAddRfidMapping);
|
||||
this.tabPageRfid.Controls.Add(this.listBoxRfidMappings);
|
||||
this.tabPageRfid.Controls.Add(this.label2);
|
||||
this.tabPageRfid.Location = new System.Drawing.Point(4, 22);
|
||||
this.tabPageRfid.Name = "tabPageRfid";
|
||||
this.tabPageRfid.Padding = new System.Windows.Forms.Padding(3);
|
||||
this.tabPageRfid.Size = new System.Drawing.Size(292, 701);
|
||||
this.tabPageRfid.TabIndex = 1;
|
||||
this.tabPageRfid.Text = "RFID 매핑";
|
||||
this.tabPageRfid.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// btnDeleteRfidMapping
|
||||
//
|
||||
this.btnDeleteRfidMapping.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btnDeleteRfidMapping.Location = new System.Drawing.Point(148, 670);
|
||||
this.btnDeleteRfidMapping.Name = "btnDeleteRfidMapping";
|
||||
this.btnDeleteRfidMapping.Size = new System.Drawing.Size(138, 25);
|
||||
this.btnDeleteRfidMapping.TabIndex = 3;
|
||||
this.btnDeleteRfidMapping.Text = "매핑 삭제";
|
||||
this.btnDeleteRfidMapping.UseVisualStyleBackColor = true;
|
||||
this.btnDeleteRfidMapping.Click += new System.EventHandler(this.btnDeleteRfidMapping_Click);
|
||||
//
|
||||
// btnAddRfidMapping
|
||||
//
|
||||
this.btnAddRfidMapping.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btnAddRfidMapping.Location = new System.Drawing.Point(6, 670);
|
||||
this.btnAddRfidMapping.Name = "btnAddRfidMapping";
|
||||
this.btnAddRfidMapping.Size = new System.Drawing.Size(138, 25);
|
||||
this.btnAddRfidMapping.TabIndex = 2;
|
||||
this.btnAddRfidMapping.Text = "매핑 추가";
|
||||
this.btnAddRfidMapping.UseVisualStyleBackColor = true;
|
||||
this.btnAddRfidMapping.Click += new System.EventHandler(this.btnAddRfidMapping_Click);
|
||||
//
|
||||
// listBoxRfidMappings
|
||||
//
|
||||
this.listBoxRfidMappings.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.listBoxRfidMappings.FormattingEnabled = true;
|
||||
this.listBoxRfidMappings.ItemHeight = 12;
|
||||
this.listBoxRfidMappings.Location = new System.Drawing.Point(6, 25);
|
||||
this.listBoxRfidMappings.Name = "listBoxRfidMappings";
|
||||
this.listBoxRfidMappings.Size = new System.Drawing.Size(280, 628);
|
||||
this.listBoxRfidMappings.TabIndex = 1;
|
||||
//
|
||||
// label2
|
||||
//
|
||||
this.label2.AutoSize = true;
|
||||
this.label2.Location = new System.Drawing.Point(6, 6);
|
||||
this.label2.Name = "label2";
|
||||
this.label2.Size = new System.Drawing.Size(77, 12);
|
||||
this.label2.TabIndex = 0;
|
||||
this.label2.Text = "RFID 매핑 목록";
|
||||
//
|
||||
// tabPageProperties
|
||||
//
|
||||
this.tabPageProperties.Controls.Add(this.labelSelectedNode);
|
||||
this.tabPageProperties.Controls.Add(this.label3);
|
||||
this.tabPageProperties.Location = new System.Drawing.Point(4, 22);
|
||||
this.tabPageProperties.Name = "tabPageProperties";
|
||||
this.tabPageProperties.Size = new System.Drawing.Size(292, 701);
|
||||
this.tabPageProperties.TabIndex = 2;
|
||||
this.tabPageProperties.Text = "속성";
|
||||
this.tabPageProperties.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// labelSelectedNode
|
||||
//
|
||||
this.labelSelectedNode.AutoSize = true;
|
||||
this.labelSelectedNode.Location = new System.Drawing.Point(8, 35);
|
||||
this.labelSelectedNode.Name = "labelSelectedNode";
|
||||
this.labelSelectedNode.Size = new System.Drawing.Size(93, 12);
|
||||
this.labelSelectedNode.TabIndex = 1;
|
||||
this.labelSelectedNode.Text = "선택된 노드: 없음";
|
||||
//
|
||||
// label3
|
||||
//
|
||||
this.label3.AutoSize = true;
|
||||
this.label3.Location = new System.Drawing.Point(8, 12);
|
||||
this.label3.Name = "label3";
|
||||
this.label3.Size = new System.Drawing.Size(53, 12);
|
||||
this.label3.TabIndex = 0;
|
||||
this.label3.Text = "노드 속성";
|
||||
//
|
||||
// MainForm
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 12F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(1200, 773);
|
||||
this.Controls.Add(this.splitContainer1);
|
||||
this.Controls.Add(this.statusStrip1);
|
||||
this.Controls.Add(this.menuStrip1);
|
||||
this.MainMenuStrip = this.menuStrip1;
|
||||
this.Name = "MainForm";
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
|
||||
this.Text = "AGV Map Editor";
|
||||
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.MainForm_FormClosing);
|
||||
this.Load += new System.EventHandler(this.MainForm_Load);
|
||||
this.menuStrip1.ResumeLayout(false);
|
||||
this.menuStrip1.PerformLayout();
|
||||
this.statusStrip1.ResumeLayout(false);
|
||||
this.statusStrip1.PerformLayout();
|
||||
this.splitContainer1.Panel1.ResumeLayout(false);
|
||||
((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit();
|
||||
this.splitContainer1.ResumeLayout(false);
|
||||
this.tabControl1.ResumeLayout(false);
|
||||
this.tabPageNodes.ResumeLayout(false);
|
||||
this.tabPageNodes.PerformLayout();
|
||||
this.tabPageRfid.ResumeLayout(false);
|
||||
this.tabPageRfid.ResumeLayout(false);
|
||||
this.tabPageRfid.PerformLayout();
|
||||
this.tabPageProperties.ResumeLayout(false);
|
||||
this.tabPageProperties.PerformLayout();
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.MenuStrip menuStrip1;
|
||||
private System.Windows.Forms.ToolStripMenuItem fileToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem newToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem openToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripSeparator toolStripSeparator1;
|
||||
private System.Windows.Forms.ToolStripMenuItem saveToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem saveAsToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripSeparator toolStripSeparator2;
|
||||
private System.Windows.Forms.ToolStripMenuItem exitToolStripMenuItem;
|
||||
private System.Windows.Forms.StatusStrip statusStrip1;
|
||||
private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabel1;
|
||||
private System.Windows.Forms.SplitContainer splitContainer1;
|
||||
private System.Windows.Forms.TabControl tabControl1;
|
||||
private System.Windows.Forms.TabPage tabPageNodes;
|
||||
private System.Windows.Forms.TabPage tabPageRfid;
|
||||
private System.Windows.Forms.Button btnDeleteNode;
|
||||
private System.Windows.Forms.Button btnAddNode;
|
||||
private System.Windows.Forms.ListBox listBoxNodes;
|
||||
private System.Windows.Forms.Label label1;
|
||||
private System.Windows.Forms.Button btnDeleteRfidMapping;
|
||||
private System.Windows.Forms.Button btnAddRfidMapping;
|
||||
private System.Windows.Forms.ListBox listBoxRfidMappings;
|
||||
private System.Windows.Forms.Label label2;
|
||||
private System.Windows.Forms.TabPage tabPageProperties;
|
||||
private System.Windows.Forms.Label labelSelectedNode;
|
||||
private System.Windows.Forms.Label label3;
|
||||
private System.Windows.Forms.Button btnRemoveConnection;
|
||||
private System.Windows.Forms.Button btnAddConnection;
|
||||
}
|
||||
}
|
||||
586
Cs_HMI/AGVMapEditor/Forms/MainForm.cs
Normal file
586
Cs_HMI/AGVMapEditor/Forms/MainForm.cs
Normal file
@@ -0,0 +1,586 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
using AGVMapEditor.Models;
|
||||
using AGVMapEditor.Controls;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace AGVMapEditor.Forms
|
||||
{
|
||||
/// <summary>
|
||||
/// AGV 맵 에디터 메인 폼
|
||||
/// </summary>
|
||||
public partial class MainForm : Form
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private NodeResolver _nodeResolver;
|
||||
private List<MapNode> _mapNodes;
|
||||
private List<RfidMapping> _rfidMappings;
|
||||
private MapCanvas _mapCanvas;
|
||||
|
||||
// 현재 선택된 노드
|
||||
private MapNode _selectedNode;
|
||||
|
||||
// 파일 경로
|
||||
private string _currentMapFile = string.Empty;
|
||||
private bool _hasChanges = false;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
|
||||
public MainForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
InitializeData();
|
||||
InitializeMapCanvas();
|
||||
UpdateTitle();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Initialization
|
||||
|
||||
private void InitializeData()
|
||||
{
|
||||
_mapNodes = new List<MapNode>();
|
||||
_rfidMappings = new List<RfidMapping>();
|
||||
_nodeResolver = new NodeResolver(_rfidMappings, _mapNodes);
|
||||
}
|
||||
|
||||
private void InitializeMapCanvas()
|
||||
{
|
||||
_mapCanvas = new MapCanvas(_mapNodes);
|
||||
_mapCanvas.Dock = DockStyle.Fill;
|
||||
_mapCanvas.NodeSelected += OnNodeSelected;
|
||||
_mapCanvas.NodeMoved += OnNodeMoved;
|
||||
_mapCanvas.BackgroundClicked += OnBackgroundClicked;
|
||||
|
||||
// 스플리터 패널에 맵 캔버스 추가
|
||||
splitContainer1.Panel2.Controls.Add(_mapCanvas);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Event Handlers
|
||||
|
||||
private void MainForm_Load(object sender, EventArgs e)
|
||||
{
|
||||
RefreshNodeList();
|
||||
RefreshRfidMappingList();
|
||||
}
|
||||
|
||||
private void OnNodeSelected(object sender, MapNode node)
|
||||
{
|
||||
_selectedNode = node;
|
||||
UpdateNodeProperties();
|
||||
}
|
||||
|
||||
private void OnNodeMoved(object sender, MapNode node)
|
||||
{
|
||||
_hasChanges = true;
|
||||
UpdateTitle();
|
||||
RefreshNodeList();
|
||||
}
|
||||
|
||||
private void OnBackgroundClicked(object sender, Point location)
|
||||
{
|
||||
_selectedNode = null;
|
||||
ClearNodeProperties();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Menu Event Handlers
|
||||
|
||||
private void newToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (CheckSaveChanges())
|
||||
{
|
||||
NewMap();
|
||||
}
|
||||
}
|
||||
|
||||
private void openToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (CheckSaveChanges())
|
||||
{
|
||||
OpenMap();
|
||||
}
|
||||
}
|
||||
|
||||
private void saveToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
SaveMap();
|
||||
}
|
||||
|
||||
private void saveAsToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
SaveAsMap();
|
||||
}
|
||||
|
||||
private void exitToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
this.Close();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Button Event Handlers
|
||||
|
||||
private void btnAddNode_Click(object sender, EventArgs e)
|
||||
{
|
||||
AddNewNode();
|
||||
}
|
||||
|
||||
private void btnDeleteNode_Click(object sender, EventArgs e)
|
||||
{
|
||||
DeleteSelectedNode();
|
||||
}
|
||||
|
||||
private void btnAddConnection_Click(object sender, EventArgs e)
|
||||
{
|
||||
AddConnectionToSelectedNode();
|
||||
}
|
||||
|
||||
private void btnRemoveConnection_Click(object sender, EventArgs e)
|
||||
{
|
||||
RemoveConnectionFromSelectedNode();
|
||||
}
|
||||
|
||||
private void btnAddRfidMapping_Click(object sender, EventArgs e)
|
||||
{
|
||||
AddNewRfidMapping();
|
||||
}
|
||||
|
||||
private void btnDeleteRfidMapping_Click(object sender, EventArgs e)
|
||||
{
|
||||
DeleteSelectedRfidMapping();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Node Management
|
||||
|
||||
private void AddNewNode()
|
||||
{
|
||||
var nodeId = GenerateNodeId();
|
||||
var nodeName = $"노드{_mapNodes.Count + 1}";
|
||||
var position = new Point(100 + _mapNodes.Count * 50, 100 + _mapNodes.Count * 50);
|
||||
|
||||
var node = new MapNode(nodeId, nodeName, position, NodeType.Normal);
|
||||
|
||||
_mapNodes.Add(node);
|
||||
_hasChanges = true;
|
||||
|
||||
RefreshNodeList();
|
||||
RefreshMapCanvas();
|
||||
UpdateTitle();
|
||||
}
|
||||
|
||||
private void DeleteSelectedNode()
|
||||
{
|
||||
if (_selectedNode == null)
|
||||
{
|
||||
MessageBox.Show("삭제할 노드를 선택하세요.", "알림", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
return;
|
||||
}
|
||||
|
||||
var result = MessageBox.Show($"노드 '{_selectedNode.Name}'를 삭제하시겠습니까?\n연결된 RFID 매핑도 함께 삭제됩니다.",
|
||||
"삭제 확인", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
|
||||
|
||||
if (result == DialogResult.Yes)
|
||||
{
|
||||
_nodeResolver.RemoveMapNode(_selectedNode.NodeId);
|
||||
_selectedNode = null;
|
||||
_hasChanges = true;
|
||||
|
||||
RefreshNodeList();
|
||||
RefreshRfidMappingList();
|
||||
RefreshMapCanvas();
|
||||
ClearNodeProperties();
|
||||
UpdateTitle();
|
||||
}
|
||||
}
|
||||
|
||||
private void AddConnectionToSelectedNode()
|
||||
{
|
||||
if (_selectedNode == null)
|
||||
{
|
||||
MessageBox.Show("연결을 추가할 노드를 선택하세요.", "알림", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
return;
|
||||
}
|
||||
|
||||
// 다른 노드들 중에서 선택
|
||||
var availableNodes = _mapNodes.Where(n => n.NodeId != _selectedNode.NodeId &&
|
||||
!_selectedNode.ConnectedNodes.Contains(n.NodeId)).ToList();
|
||||
|
||||
if (availableNodes.Count == 0)
|
||||
{
|
||||
MessageBox.Show("연결 가능한 노드가 없습니다.", "알림", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
return;
|
||||
}
|
||||
|
||||
// 간단한 선택 다이얼로그 (실제로는 별도 폼을 만들어야 함)
|
||||
var nodeNames = availableNodes.Select(n => $"{n.NodeId}: {n.Name}").ToArray();
|
||||
var input = Microsoft.VisualBasic.Interaction.InputBox("연결할 노드를 선택하세요:", "노드 연결", nodeNames[0]);
|
||||
|
||||
var targetNode = availableNodes.FirstOrDefault(n => input.StartsWith(n.NodeId));
|
||||
if (targetNode != null)
|
||||
{
|
||||
_selectedNode.AddConnection(targetNode.NodeId);
|
||||
_hasChanges = true;
|
||||
RefreshMapCanvas();
|
||||
UpdateNodeProperties();
|
||||
UpdateTitle();
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveConnectionFromSelectedNode()
|
||||
{
|
||||
if (_selectedNode == null || _selectedNode.ConnectedNodes.Count == 0)
|
||||
{
|
||||
MessageBox.Show("연결을 제거할 노드를 선택하거나 연결된 노드가 없습니다.", "알림", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
return;
|
||||
}
|
||||
|
||||
// 연결된 노드들 중에서 선택
|
||||
var connectedNodeNames = _selectedNode.ConnectedNodes.Select(connectedNodeId =>
|
||||
{
|
||||
var node = _mapNodes.FirstOrDefault(n => n.NodeId == connectedNodeId);
|
||||
return node != null ? $"{node.NodeId}: {node.Name}" : connectedNodeId;
|
||||
}).ToArray();
|
||||
|
||||
var input = Microsoft.VisualBasic.Interaction.InputBox("제거할 연결을 선택하세요:", "연결 제거", connectedNodeNames[0]);
|
||||
|
||||
var targetNodeId = input.Split(':')[0];
|
||||
if (_selectedNode.ConnectedNodes.Contains(targetNodeId))
|
||||
{
|
||||
_selectedNode.RemoveConnection(targetNodeId);
|
||||
_hasChanges = true;
|
||||
RefreshMapCanvas();
|
||||
UpdateNodeProperties();
|
||||
UpdateTitle();
|
||||
}
|
||||
}
|
||||
|
||||
private string GenerateNodeId()
|
||||
{
|
||||
int counter = 1;
|
||||
string nodeId;
|
||||
|
||||
do
|
||||
{
|
||||
nodeId = $"N{counter:D3}";
|
||||
counter++;
|
||||
} while (_mapNodes.Any(n => n.NodeId == nodeId));
|
||||
|
||||
return nodeId;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region RFID Mapping Management
|
||||
|
||||
private void AddNewRfidMapping()
|
||||
{
|
||||
if (_mapNodes.Count == 0)
|
||||
{
|
||||
MessageBox.Show("매핑할 노드가 없습니다. 먼저 노드를 추가하세요.", "알림", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
return;
|
||||
}
|
||||
|
||||
var unmappedNodes = _nodeResolver.GetUnmappedNodes();
|
||||
if (unmappedNodes.Count == 0)
|
||||
{
|
||||
MessageBox.Show("모든 노드가 이미 RFID에 매핑되어 있습니다.", "알림", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
return;
|
||||
}
|
||||
|
||||
// RFID 값 입력
|
||||
var rfidValue = Microsoft.VisualBasic.Interaction.InputBox("RFID 값을 입력하세요:", "RFID 매핑 추가");
|
||||
if (string.IsNullOrEmpty(rfidValue))
|
||||
return;
|
||||
|
||||
// 노드 선택
|
||||
var nodeNames = unmappedNodes.Select(n => $"{n.NodeId}: {n.Name}").ToArray();
|
||||
var selectedNode = Microsoft.VisualBasic.Interaction.InputBox("매핑할 노드를 선택하세요:", "노드 선택", nodeNames[0]);
|
||||
|
||||
var nodeId = selectedNode.Split(':')[0];
|
||||
var description = Microsoft.VisualBasic.Interaction.InputBox("설명을 입력하세요 (선택사항):", "설명");
|
||||
|
||||
if (_nodeResolver.AddRfidMapping(rfidValue, nodeId, description))
|
||||
{
|
||||
_hasChanges = true;
|
||||
RefreshRfidMappingList();
|
||||
UpdateTitle();
|
||||
MessageBox.Show("RFID 매핑이 추가되었습니다.", "성공", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show("RFID 매핑 추가에 실패했습니다. 중복된 RFID이거나 노드가 존재하지 않습니다.", "오류", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private void DeleteSelectedRfidMapping()
|
||||
{
|
||||
if (listBoxRfidMappings.SelectedItem == null)
|
||||
{
|
||||
MessageBox.Show("삭제할 RFID 매핑을 선택하세요.", "알림", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
return;
|
||||
}
|
||||
|
||||
var mapping = listBoxRfidMappings.SelectedItem as RfidMapping;
|
||||
var result = MessageBox.Show($"RFID 매핑 '{mapping.RfidId} → {mapping.LogicalNodeId}'를 삭제하시겠습니까?",
|
||||
"삭제 확인", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
|
||||
|
||||
if (result == DialogResult.Yes)
|
||||
{
|
||||
if (_nodeResolver.RemoveRfidMapping(mapping.RfidId))
|
||||
{
|
||||
_hasChanges = true;
|
||||
RefreshRfidMappingList();
|
||||
UpdateTitle();
|
||||
MessageBox.Show("RFID 매핑이 삭제되었습니다.", "성공", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show("RFID 매핑 삭제에 실패했습니다.", "오류", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region File Operations
|
||||
|
||||
private void NewMap()
|
||||
{
|
||||
_mapNodes.Clear();
|
||||
_rfidMappings.Clear();
|
||||
_nodeResolver = new NodeResolver(_rfidMappings, _mapNodes);
|
||||
_selectedNode = null;
|
||||
_currentMapFile = string.Empty;
|
||||
_hasChanges = false;
|
||||
|
||||
RefreshAll();
|
||||
UpdateTitle();
|
||||
}
|
||||
|
||||
private void OpenMap()
|
||||
{
|
||||
var openFileDialog = new OpenFileDialog
|
||||
{
|
||||
Filter = "AGV Map Files (*.agvmap)|*.agvmap|JSON Files (*.json)|*.json|All Files (*.*)|*.*",
|
||||
DefaultExt = "agvmap"
|
||||
};
|
||||
|
||||
if (openFileDialog.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
try
|
||||
{
|
||||
LoadMapFromFile(openFileDialog.FileName);
|
||||
_currentMapFile = openFileDialog.FileName;
|
||||
_hasChanges = false;
|
||||
RefreshAll();
|
||||
UpdateTitle();
|
||||
MessageBox.Show("맵이 성공적으로 로드되었습니다.", "성공", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show($"맵 로드 중 오류가 발생했습니다: {ex.Message}", "오류", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SaveMap()
|
||||
{
|
||||
if (string.IsNullOrEmpty(_currentMapFile))
|
||||
{
|
||||
SaveAsMap();
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
SaveMapToFile(_currentMapFile);
|
||||
_hasChanges = false;
|
||||
UpdateTitle();
|
||||
MessageBox.Show("맵이 성공적으로 저장되었습니다.", "성공", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show($"맵 저장 중 오류가 발생했습니다: {ex.Message}", "오류", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SaveAsMap()
|
||||
{
|
||||
var saveFileDialog = new SaveFileDialog
|
||||
{
|
||||
Filter = "AGV Map Files (*.agvmap)|*.agvmap|JSON Files (*.json)|*.json",
|
||||
DefaultExt = "agvmap",
|
||||
FileName = "NewMap.agvmap"
|
||||
};
|
||||
|
||||
if (saveFileDialog.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
try
|
||||
{
|
||||
SaveMapToFile(saveFileDialog.FileName);
|
||||
_currentMapFile = saveFileDialog.FileName;
|
||||
_hasChanges = false;
|
||||
UpdateTitle();
|
||||
MessageBox.Show("맵이 성공적으로 저장되었습니다.", "성공", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show($"맵 저장 중 오류가 발생했습니다: {ex.Message}", "오류", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadMapFromFile(string filePath)
|
||||
{
|
||||
var json = File.ReadAllText(filePath);
|
||||
var mapData = JsonConvert.DeserializeObject<MapData>(json);
|
||||
|
||||
_mapNodes = mapData.Nodes ?? new List<MapNode>();
|
||||
_rfidMappings = mapData.RfidMappings ?? new List<RfidMapping>();
|
||||
_nodeResolver = new NodeResolver(_rfidMappings, _mapNodes);
|
||||
}
|
||||
|
||||
private void SaveMapToFile(string filePath)
|
||||
{
|
||||
var mapData = new MapData
|
||||
{
|
||||
Nodes = _mapNodes,
|
||||
RfidMappings = _rfidMappings,
|
||||
CreatedDate = DateTime.Now,
|
||||
Version = "1.0"
|
||||
};
|
||||
|
||||
var json = JsonConvert.SerializeObject(mapData, Formatting.Indented);
|
||||
File.WriteAllText(filePath, json);
|
||||
}
|
||||
|
||||
private bool CheckSaveChanges()
|
||||
{
|
||||
if (_hasChanges)
|
||||
{
|
||||
var result = MessageBox.Show("변경사항이 있습니다. 저장하시겠습니까?", "변경사항 저장",
|
||||
MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
|
||||
|
||||
if (result == DialogResult.Yes)
|
||||
{
|
||||
SaveMap();
|
||||
return !_hasChanges; // 저장이 성공했으면 true
|
||||
}
|
||||
else if (result == DialogResult.Cancel)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region UI Updates
|
||||
|
||||
private void RefreshAll()
|
||||
{
|
||||
RefreshNodeList();
|
||||
RefreshRfidMappingList();
|
||||
RefreshMapCanvas();
|
||||
ClearNodeProperties();
|
||||
}
|
||||
|
||||
private void RefreshNodeList()
|
||||
{
|
||||
listBoxNodes.DataSource = null;
|
||||
listBoxNodes.DataSource = _mapNodes;
|
||||
listBoxNodes.DisplayMember = "Name";
|
||||
listBoxNodes.ValueMember = "NodeId";
|
||||
}
|
||||
|
||||
private void RefreshRfidMappingList()
|
||||
{
|
||||
listBoxRfidMappings.DataSource = null;
|
||||
listBoxRfidMappings.DataSource = _rfidMappings;
|
||||
listBoxRfidMappings.DisplayMember = "ToString";
|
||||
}
|
||||
|
||||
private void RefreshMapCanvas()
|
||||
{
|
||||
_mapCanvas?.Invalidate();
|
||||
}
|
||||
|
||||
private void UpdateNodeProperties()
|
||||
{
|
||||
if (_selectedNode == null)
|
||||
{
|
||||
ClearNodeProperties();
|
||||
return;
|
||||
}
|
||||
|
||||
// 선택된 노드의 속성을 프로퍼티 패널에 표시
|
||||
// (실제로는 PropertyGrid나 별도 컨트롤 사용)
|
||||
labelSelectedNode.Text = $"선택된 노드: {_selectedNode.Name} ({_selectedNode.NodeId})";
|
||||
}
|
||||
|
||||
private void ClearNodeProperties()
|
||||
{
|
||||
labelSelectedNode.Text = "선택된 노드: 없음";
|
||||
}
|
||||
|
||||
private void UpdateTitle()
|
||||
{
|
||||
var title = "AGV Map Editor";
|
||||
|
||||
if (!string.IsNullOrEmpty(_currentMapFile))
|
||||
{
|
||||
title += $" - {Path.GetFileName(_currentMapFile)}";
|
||||
}
|
||||
|
||||
if (_hasChanges)
|
||||
{
|
||||
title += " *";
|
||||
}
|
||||
|
||||
this.Text = title;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Form Events
|
||||
|
||||
private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
|
||||
{
|
||||
if (!CheckSaveChanges())
|
||||
{
|
||||
e.Cancel = true;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Data Model for Serialization
|
||||
|
||||
private class MapData
|
||||
{
|
||||
public List<MapNode> Nodes { get; set; } = new List<MapNode>();
|
||||
public List<RfidMapping> RfidMappings { get; set; } = new List<RfidMapping>();
|
||||
public DateTime CreatedDate { get; set; }
|
||||
public string Version { get; set; } = "1.0";
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
67
Cs_HMI/AGVMapEditor/Forms/MainForm.resx
Normal file
67
Cs_HMI/AGVMapEditor/Forms/MainForm.resx
Normal file
@@ -0,0 +1,67 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<metadata name="menuStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
<metadata name="statusStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>132, 17</value>
|
||||
</metadata>
|
||||
</root>
|
||||
Reference in New Issue
Block a user