This commit is contained in:
backuppc
2026-02-12 09:58:01 +09:00
parent 2b3a9b3d1d
commit d6aed58516
17 changed files with 914 additions and 402 deletions

View File

@@ -115,6 +115,7 @@ namespace AGVMapEditor.Forms
_mapCanvas.NodesSelected += OnNodesSelected; // 다중 선택 이벤트
_mapCanvas.NodeMoved += OnNodeMoved;
_mapCanvas.NodeDeleted += OnNodeDeleted;
_mapCanvas.ConnectionCreated += OnConnectionCreated;
_mapCanvas.ConnectionDeleted += OnConnectionDeleted;
_mapCanvas.ImageDoubleClicked += OnImageDoubleClicked;
_mapCanvas.MapChanged += OnMapChanged;
@@ -144,9 +145,8 @@ namespace AGVMapEditor.Forms
btnAddLabel.Click += (s, e) => _mapCanvas.CurrentEditMode = UnifiedAGVCanvas.EditMode.AddLabel;
btnAddImage.Click += (s, e) => _mapCanvas.CurrentEditMode = UnifiedAGVCanvas.EditMode.AddImage;
btnConnect.Click += (s, e) => _mapCanvas.CurrentEditMode = UnifiedAGVCanvas.EditMode.Connect;
btnConnNode.Click += (s, e) => _mapCanvas.CurrentEditMode = UnifiedAGVCanvas.EditMode.Connect;
btnDelete.Click += (s, e) => _mapCanvas.CurrentEditMode = UnifiedAGVCanvas.EditMode.Delete;
btnDeleteConnection.Click += (s, e) => _mapCanvas.CurrentEditMode = UnifiedAGVCanvas.EditMode.DeleteConnection;
// 그리드 토글 버튼
btnToggleGrid.Click += (s, e) => _mapCanvas.ShowGrid = !_mapCanvas.ShowGrid;
@@ -182,6 +182,7 @@ namespace AGVMapEditor.Forms
_hasChanges = true;
UpdateTitle();
RefreshNodeList();
RefreshMagnetList(); // 추가
// RFID 자동 할당
}
@@ -215,6 +216,20 @@ namespace AGVMapEditor.Forms
{
// 단일 선택은 기존 방식 사용
_selectedNode = nodes[0];
// Sync with lstMagnet
if (_selectedNode is MapMagnet magnet)
{
lstMagnet.SelectedItem = magnet;
}
else
{
lstMagnet.SelectedItem = null;
}
//this._mapCanvas.SelectedNode = nodes;
//this._mapCanvas.Invalidate();
UpdateNodeProperties();
UpdateImageEditButton();
}
@@ -242,17 +257,20 @@ namespace AGVMapEditor.Forms
_hasChanges = true;
UpdateTitle();
RefreshNodeList();
RefreshMagnetList(); // 추가
ClearNodeProperties();
// RFID 자동 할당
}
private void OnConnectionCreated(object sender, (MapNode From, MapNode To) connection)
{
_hasChanges = true;
UpdateTitle();
RefreshNodeConnectionList();
UpdateNodeProperties(); // 연결 정보 업데이트
}
private void OnConnectionDeleted(object sender, (MapNode From, MapNode To) connection)
{
_hasChanges = true;
@@ -261,6 +279,8 @@ namespace AGVMapEditor.Forms
UpdateNodeProperties(); // 연결 정보 업데이트
}
private void OnImageDoubleClicked(object sender, MapImage image)
{
// 이미지 노드 더블클릭 시 이미지 편집창 표시
@@ -280,6 +300,7 @@ namespace AGVMapEditor.Forms
{
_hasChanges = true;
UpdateTitle();
RefreshMagnetDirectionList(); // 방향 정보 업데이트
}
private void OnBackgroundClicked(object sender, Point location)
@@ -621,7 +642,7 @@ namespace AGVMapEditor.Forms
private void LoadMapFromFile(string filePath)
{
var result = MapLoader.LoadMapFromFile(filePath);
sbFile.Text = filePath;
if (result.Success)
{
// 맵 캔버스에 데이터 설정
@@ -637,6 +658,7 @@ namespace AGVMapEditor.Forms
UpdateTitle();
UpdateNodeList();
RefreshNodeConnectionList();
RefreshMagnetList(); // 추가
@@ -767,6 +789,7 @@ namespace AGVMapEditor.Forms
{
RefreshNodeList();
RefreshNodeConnectionList();
RefreshMagnetList(); // 추가
RefreshMapCanvas();
ClearNodeProperties();
}
@@ -829,7 +852,7 @@ namespace AGVMapEditor.Forms
var item = node as MapNode;
if (item.StationType == StationType.Normal)
foreColor = Color.DimGray;
else if (item.StationType == StationType.Charger1 || item.StationType == StationType.Charger2)
else if (item.StationType == StationType.Charger)
foreColor = Color.Red;
else
foreColor = Color.DarkGreen;
@@ -945,13 +968,21 @@ namespace AGVMapEditor.Forms
_mapCanvas?.HighlightConnection(connectionInfo.FromNodeId, connectionInfo.ToNodeId);
// 연결된 노드들을 맵에서 하이라이트 표시 (선택적)
var fromNode = this._mapCanvas.Nodes.FirstOrDefault(n => n.Id == connectionInfo.FromNodeId);
if (fromNode != null)
{
_selectedNode = fromNode;
UpdateNodeProperties();
_mapCanvas?.Invalidate();
}
//var fromNode = this._mapCanvas.Nodes.FirstOrDefault(n => n.Id == connectionInfo.FromNodeId);
//if (fromNode != null)
//{
// if (_selectedNode != fromNode)
// {
// _selectedNode = fromNode;
// _mapCanvas.SelectedNode = fromNode; // 캔버스 선택 상태 동기화
// // 속성창 업데이트 (리스트 리프레시 포함)
// // 주의: RefreshMagnetDirectionList()가 호출되어도 lstNodeConnection에는 영향이 없으므로 안전함
// UpdateNodeProperties();
// _mapCanvas?.Invalidate();
// }
//}
}
else
{
@@ -1303,9 +1334,9 @@ namespace AGVMapEditor.Forms
{
foreach (var node in this._mapCanvas.Nodes)
{
node.CanTurnLeft = true;
node.CanTurnRight = true;
node.DisableCross = false;
node.CanTurnLeft = false;
node.CanTurnRight = false;
node.DisableCross = true;
node.ModifiedDate = DateTime.Now;
}
@@ -1367,6 +1398,9 @@ namespace AGVMapEditor.Forms
private void RefreshMagnetDirectionList()
{
// 이벤트 임시 제거 (DataSource 변경 시 불필요한 이벤트 발생 방지)
lstMagnetDirection.SelectedIndexChanged -= LstMagnetDirection_SelectedIndexChanged;
// 현재 선택된 항목 기억
int selectedIndex = lstMagnetDirection.SelectedIndex;
@@ -1374,7 +1408,12 @@ namespace AGVMapEditor.Forms
lstMagnetDirection.DataSource = null;
lstMagnetDirection.Items.Clear();
if (this._mapCanvas.Nodes == null) return;
if (this._mapCanvas.Nodes == null)
{
// 이벤트 다시 연결 (빠른 리턴 시에도 연결 필요)
lstMagnetDirection.SelectedIndexChanged += LstMagnetDirection_SelectedIndexChanged;
return;
}
var directions = new List<MagnetDirectionInfo>();
@@ -1410,8 +1449,7 @@ namespace AGVMapEditor.Forms
lstMagnetDirection.DataSource = directions;
}
// 이벤트 연결
lstMagnetDirection.SelectedIndexChanged -= LstMagnetDirection_SelectedIndexChanged;
// 이벤트 다시 연결
lstMagnetDirection.SelectedIndexChanged += LstMagnetDirection_SelectedIndexChanged;
lstMagnetDirection.DoubleClick -= LstMagnetDirection_DoubleClick;
@@ -1420,7 +1458,15 @@ namespace AGVMapEditor.Forms
// 선택 항목 복원 (가능한 경우) -> 선택된 객체가 다르게 생성되므로 인덱스로 복원 시도
if (selectedIndex >= 0 && selectedIndex < lstMagnetDirection.Items.Count)
{
lstMagnetDirection.SelectedIndex = selectedIndex;
try
{
lstMagnetDirection.SelectedIndex = selectedIndex;
}
catch (Exception ex)
{
}
}
}
@@ -1430,6 +1476,44 @@ namespace AGVMapEditor.Forms
{
// 버튼 상태 업데이트
UpdateDirectionButtons(info);
// 캔버스에서 해당 연결선 강조 표시
if (info.FromNode != null && info.ToNode != null)
{
_mapCanvas.HighlightConnection(info.FromNode.Id, info.ToNode.Id);
// FromNode 선택 (속성창 갱신 루프 방지 위해 _propertyGrid 직접 설정 고려)
// 하지만 _selectedNode 변경 시 RefreshMagnetDirectionList()가 호출되어 리스트가 재생성되면 선택이 풀릴 수 있음
// 따라서 여기서는 캔버스 상의 선택 표시만 변경하고, 전체 속성 업데이트(리스트 리프레시 포함)는 건너뛰거나
// 리스트 리프레시 로직에서 선택 상태 유지를 보완해야 함.
// 일단 _selectedNode를 변경하되, RefreshMagnetDirectionList에서 선택 인덱스 복원을 하므로 괜찮을 것으로 예상됨.
// 만약 깜빡임이나 끊김이 심하면 UpdateNodeProperties 내의 RefreshMagnetDirectionList 호출을 조건부로 변경해야 함.
if (_selectedNode != info.FromNode)
{
var prevSelected = _selectedNode;
_selectedNode = info.FromNode;
// _mapCanvas.SelectedNode 설정 (이것만으로는 PropertyGrid 갱신 안됨)
_mapCanvas.SelectedNode = info.FromNode;
// PropertyGrid 갱신 (리스트 리프레시 포함)
// 주의: 여기서 UpdateNodeProperties()를 부르면 리스트가 다시 그려지면서 선택 이벤트가 다시 발생할 수 있음.
// 하지만 인덱스 복원 로직이 있으므로 무한루프는 아닐 수 있으나, 비효율적임.
// 해결책: 리스트 리프레시 없이 속성창만 갱신
_propertyGrid.SelectedObject = _selectedNode;
UpdateImageEditButton();
// 캔버스 다시 그리기
_mapCanvas.Invalidate();
}
}
}
else
{
_mapCanvas.ClearHighlightedConnection();
}
}
@@ -1670,8 +1754,8 @@ namespace AGVMapEditor.Forms
}
}
// 현재 선택된 노드의 속성창 및 리스트 갱신
UpdateNodeProperties();
// 현재 선택된 노드의 속성창 및 리스트 갱신
UpdateNodeProperties();
}
private void btAddMagnet_Click(object sender, EventArgs e)
@@ -1695,11 +1779,11 @@ namespace AGVMapEditor.Forms
string id = _mapCanvas.GenerateUniqueNodeId();
var magnet = new MapMagnet { Id = id };
// 점 생성 시 정규화(Snap) 처리
int cx = (int)worldCX;
int cy = (int)worldCY;
magnet.StartPoint = new Point(cx - 50, cy);
magnet.EndPoint = new Point(cx + 50, cy);
@@ -1711,14 +1795,118 @@ namespace AGVMapEditor.Forms
// 캔버스에 추가
_mapCanvas.Magnets.Add(magnet);
_hasChanges = true;
UpdateTitle();
RefreshMapCanvas();
RefreshNodeList();
RefreshMagnetList(); // 추가
// 추가된 마그넷 선택
//_mapCanvas.SelectedNode = magnet;
UpdateNodeProperties();
}
private void btDelMagnet_Click(object sender, EventArgs e)
{
//선택한 마그넷라인을 삭제 (삭제 후 맵에 바로 반영되도록 업데이트필요)
if (lstMagnet.SelectedItem is MapMagnet magnet)
{
_mapCanvas.RemoveMagnet(magnet);
RefreshMagnetList();
}
}
private void RefreshMagnetList()
{
lstMagnet.DataSource = null;
lstMagnet.Items.Clear();
if (_mapCanvas.Magnets != null && _mapCanvas.Magnets.Count > 0)
{
lstMagnet.DataSource = _mapCanvas.Magnets;
}
// 이벤트 연결
lstMagnet.SelectedIndexChanged -= LstMagnet_SelectedIndexChanged;
lstMagnet.SelectedIndexChanged += LstMagnet_SelectedIndexChanged;
lstMagnet.DoubleClick -= LstMagnet_DoubleClick;
lstMagnet.DoubleClick += LstMagnet_DoubleClick;
lstMagnet.DrawMode = DrawMode.OwnerDrawFixed;
lstMagnet.DrawItem -= LstMagnet_DrawItem;
lstMagnet.DrawItem += LstMagnet_DrawItem;
}
private void LstMagnet_DrawItem(object sender, DrawItemEventArgs e)
{
e.DrawBackground();
if (e.Index >= 0 && e.Index < lstMagnet.Items.Count)
{
var magnet = lstMagnet.Items[e.Index] as MapMagnet;
if (magnet != null)
{
Brush brush = Brushes.Black;
if (magnet.ControlPoint != null) // Curve
{
brush = Brushes.Blue; // Curve는 파란색
}
// 선택된 항목은 흰색 글씨 (배경이 파란색이므로)
if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
{
brush = Brushes.White;
}
e.Graphics.DrawString(magnet.ToString(), e.Font, brush, e.Bounds);
}
}
e.DrawFocusRectangle();
}
private void LstMagnet_SelectedIndexChanged(object sender, EventArgs e)
{
if (lstMagnet.SelectedItem is MapMagnet magnet)
{
_mapCanvas.SelectedNode = magnet;
//UpdateNodeProperties(); // SelectedNode setter에서 Invalidate 호출됨
}
}
private void LstMagnet_DoubleClick(object sender, EventArgs e)
{
if (lstMagnet.SelectedItem is MapMagnet magnet)
{
_mapCanvas.PanTo(magnet.Position);
}
}
private void btnAddNode_ButtonClick(object sender, EventArgs e)
{
}
private void btnAddNode_BackColorChanged(object sender, EventArgs e)
{
}
private void btnDeleteConnection_Click(object sender, EventArgs e)
{
_mapCanvas.CurrentEditMode = UnifiedAGVCanvas.EditMode.DeleteConnection;
}
private void btnConnDir_Click(object sender, EventArgs e)
{
//방향연결(노드연결과 유사), 두 노드간의 방향을 생성한다 기본값 straight
_mapCanvas.CurrentEditMode = UnifiedAGVCanvas.EditMode.ConnectDirection;
}
private void toolStripButton3_Click_1(object sender, EventArgs e)
{
RefreshMagnetList();
}
}
}