using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Design;
using AGVNavigationCore.Models;
using AGVNavigationCore.Controls;
namespace AGVMapEditor.Models
{
///
/// 노드 타입에 따른 PropertyWrapper 팩토리
///
public static class NodePropertyWrapperFactory
{
public static object CreateWrapper(MapNode node, List mapNodes)
{
switch (node.Type)
{
case NodeType.Label:
return new LabelNodePropertyWrapper(node, mapNodes);
case NodeType.Image:
return new ImageNodePropertyWrapper(node, mapNodes);
default:
return new NodePropertyWrapper(node, mapNodes);
}
}
}
///
/// 라벨 노드 전용 PropertyWrapper
///
public class LabelNodePropertyWrapper
{
private MapNode _node;
private List _mapNodes;
public LabelNodePropertyWrapper(MapNode node, List mapNodes)
{
_node = node;
_mapNodes = mapNodes;
}
///
/// 래핑된 MapNode 인스턴스 접근
///
public MapNode WrappedNode => _node;
[Category("기본 정보")]
[DisplayName("노드 ID")]
[Description("노드의 고유 식별자")]
[ReadOnly(true)]
public string NodeId
{
get => _node.NodeId;
}
[Category("기본 정보")]
[DisplayName("노드 타입")]
[Description("노드의 타입")]
[ReadOnly(true)]
public NodeType Type
{
get => _node.Type;
}
[Category("라벨")]
[DisplayName("텍스트")]
[Description("표시할 텍스트")]
public string LabelText
{
get => _node.LabelText;
set
{
_node.LabelText = value ?? "";
_node.ModifiedDate = DateTime.Now;
}
}
[Category("라벨")]
[DisplayName("폰트 패밀리")]
[Description("폰트 패밀리")]
public string FontFamily
{
get => _node.FontFamily;
set
{
_node.FontFamily = value ?? "Arial";
_node.ModifiedDate = DateTime.Now;
}
}
[Category("라벨")]
[DisplayName("폰트 크기")]
[Description("폰트 크기")]
public float FontSize
{
get => _node.FontSize;
set
{
_node.FontSize = Math.Max(6, Math.Min(72, value));
_node.ModifiedDate = DateTime.Now;
}
}
[Category("라벨")]
[DisplayName("폰트 스타일")]
[Description("폰트 스타일")]
public FontStyle FontStyle
{
get => _node.FontStyle;
set
{
_node.FontStyle = value;
_node.ModifiedDate = DateTime.Now;
}
}
[Category("라벨")]
[DisplayName("전경색")]
[Description("텍스트 색상")]
public Color ForeColor
{
get => _node.ForeColor;
set
{
_node.ForeColor = value;
_node.ModifiedDate = DateTime.Now;
}
}
[Category("라벨")]
[DisplayName("배경색")]
[Description("배경 색상")]
public Color BackColor
{
get => _node.BackColor;
set
{
_node.BackColor = value;
_node.ModifiedDate = DateTime.Now;
}
}
[Category("라벨")]
[DisplayName("배경 표시")]
[Description("배경을 표시할지 여부")]
public bool ShowBackground
{
get => _node.ShowBackground;
set
{
_node.ShowBackground = value;
_node.ModifiedDate = DateTime.Now;
}
}
[Category("라벨")]
[DisplayName("패딩")]
[Description("텍스트 주변 여백 (픽셀 단위)")]
public int Padding
{
get => _node.Padding;
set
{
_node.Padding = Math.Max(0, Math.Min(50, value));
_node.ModifiedDate = DateTime.Now;
}
}
[Category("위치")]
[DisplayName("X 좌표")]
[Description("맵에서의 X 좌표")]
public int PositionX
{
get => _node.Position.X;
set
{
_node.Position = new Point(value, _node.Position.Y);
_node.ModifiedDate = DateTime.Now;
}
}
[Category("위치")]
[DisplayName("Y 좌표")]
[Description("맵에서의 Y 좌표")]
public int PositionY
{
get => _node.Position.Y;
set
{
_node.Position = new Point(_node.Position.X, value);
_node.ModifiedDate = DateTime.Now;
}
}
[Category("정보")]
[DisplayName("생성 일시")]
[Description("노드가 생성된 일시")]
[ReadOnly(true)]
public DateTime CreatedDate
{
get => _node.CreatedDate;
}
[Category("정보")]
[DisplayName("수정 일시")]
[Description("노드가 마지막으로 수정된 일시")]
[ReadOnly(true)]
public DateTime ModifiedDate
{
get => _node.ModifiedDate;
}
}
///
/// 이미지 노드 전용 PropertyWrapper
///
public class ImageNodePropertyWrapper
{
private MapNode _node;
private List _mapNodes;
public ImageNodePropertyWrapper(MapNode node, List mapNodes)
{
_node = node;
_mapNodes = mapNodes;
}
///
/// 래핑된 MapNode 인스턴스 접근
///
public MapNode WrappedNode => _node;
[Category("기본 정보")]
[DisplayName("노드 ID")]
[Description("노드의 고유 식별자")]
[ReadOnly(true)]
public string NodeId
{
get => _node.NodeId;
}
[Category("기본 정보")]
[DisplayName("노드 타입")]
[Description("노드의 타입")]
[ReadOnly(true)]
public NodeType Type
{
get => _node.Type;
}
[Category("이미지")]
[DisplayName("이미지 경로")]
[Description("이미지 파일 경로 (... 버튼으로 파일 선택)")]
[Editor(typeof(ImagePathEditor), typeof(UITypeEditor))]
public string ImagePath
{
get => _node.ImagePath;
set
{
if (string.IsNullOrEmpty(value))
{
_node.ImagePath = "";
return;
}
// 파일이 존재하면 Base64로 변환하여 저장
if (System.IO.File.Exists(value))
{
_node.ConvertImageToBase64(value);
_node.LoadImage(); // 이미지 다시 로드
}
else
{
_node.ImagePath = value;
}
_node.ModifiedDate = DateTime.Now;
}
}
[Category("이미지")]
[DisplayName("가로 배율")]
[Description("가로 배율 (1.0 = 원본 크기)")]
public float ScaleWidth
{
get => _node.Scale.Width;
set
{
_node.Scale = new SizeF(Math.Max(0.1f, Math.Min(5.0f, value)), _node.Scale.Height);
_node.ModifiedDate = DateTime.Now;
}
}
[Category("이미지")]
[DisplayName("세로 배율")]
[Description("세로 배율 (1.0 = 원본 크기)")]
public float ScaleHeight
{
get => _node.Scale.Height;
set
{
_node.Scale = new SizeF(_node.Scale.Width, Math.Max(0.1f, Math.Min(5.0f, value)));
_node.ModifiedDate = DateTime.Now;
}
}
[Category("이미지")]
[DisplayName("투명도")]
[Description("투명도 (0.0 = 투명, 1.0 = 불투명)")]
public float Opacity
{
get => _node.Opacity;
set
{
_node.Opacity = Math.Max(0.0f, Math.Min(1.0f, value));
_node.ModifiedDate = DateTime.Now;
}
}
[Category("이미지")]
[DisplayName("회전각도")]
[Description("회전 각도 (도 단위)")]
public float Rotation
{
get => _node.Rotation;
set
{
_node.Rotation = value % 360;
_node.ModifiedDate = DateTime.Now;
}
}
[Category("위치")]
[DisplayName("X 좌표")]
[Description("맵에서의 X 좌표")]
public int PositionX
{
get => _node.Position.X;
set
{
_node.Position = new Point(value, _node.Position.Y);
_node.ModifiedDate = DateTime.Now;
}
}
[Category("위치")]
[DisplayName("Y 좌표")]
[Description("맵에서의 Y 좌표")]
public int PositionY
{
get => _node.Position.Y;
set
{
_node.Position = new Point(_node.Position.X, value);
_node.ModifiedDate = DateTime.Now;
}
}
[Category("정보")]
[DisplayName("생성 일시")]
[Description("노드가 생성된 일시")]
[ReadOnly(true)]
public DateTime CreatedDate
{
get => _node.CreatedDate;
}
[Category("정보")]
[DisplayName("수정 일시")]
[Description("노드가 마지막으로 수정된 일시")]
[ReadOnly(true)]
public DateTime ModifiedDate
{
get => _node.ModifiedDate;
}
}
///
/// PropertyGrid에서 사용할 노드 속성 래퍼 클래스
///
public class NodePropertyWrapper
{
private MapNode _node;
private List _mapNodes;
public NodePropertyWrapper(MapNode node, List mapNodes)
{
_node = node;
_mapNodes = mapNodes;
}
///
/// 래핑된 MapNode 인스턴스 접근
///
public MapNode WrappedNode => _node;
[Category("기본 정보")]
[DisplayName("노드 ID")]
[Description("노드의 고유 식별자")]
[ReadOnly(true)]
public string NodeId
{
get => _node.NodeId;
set => _node.NodeId = value;
}
[Category("기본 정보")]
[DisplayName("노드 이름")]
[Description("노드의 표시 이름")]
public string Name
{
get => _node.Name;
set
{
_node.Name = value;
_node.ModifiedDate = DateTime.Now;
}
}
[Category("기본 정보")]
[DisplayName("노드 타입")]
[Description("노드의 타입 (Normal, Rotation, Docking, Charging)")]
public NodeType Type
{
get => _node.Type;
set
{
_node.Type = value;
_node.CanRotate = value == NodeType.Rotation;
_node.SetDefaultColorByType(value);
_node.ModifiedDate = DateTime.Now;
}
}
[Category("기본 정보")]
[DisplayName("도킹 방향")]
[Description("도킹이 필요한 노드의 경우 AGV 진입 방향 (DontCare: 방향 무관, Forward: 전진 도킹, Backward: 후진 도킹)")]
public DockingDirection DockDirection
{
get => _node.DockDirection;
set
{
_node.DockDirection = value;
_node.ModifiedDate = DateTime.Now;
}
}
[Category("위치")]
[DisplayName("X 좌표")]
[Description("맵에서의 X 좌표")]
public int PositionX
{
get => _node.Position.X;
set
{
_node.Position = new Point(value, _node.Position.Y);
_node.ModifiedDate = DateTime.Now;
}
}
[Category("위치")]
[DisplayName("Y 좌표")]
[Description("맵에서의 Y 좌표")]
public int PositionY
{
get => _node.Position.Y;
set
{
_node.Position = new Point(_node.Position.X, value);
_node.ModifiedDate = DateTime.Now;
}
}
[Category("고급")]
[DisplayName("회전 가능")]
[Description("이 노드에서 AGV가 회전할 수 있는지 여부")]
public bool CanRotate
{
get => _node.CanRotate;
set
{
_node.CanRotate = value;
_node.ModifiedDate = DateTime.Now;
}
}
[Category("고급")]
[DisplayName("RFID")]
[Description("RFID ID")]
public string RFID
{
get => _node.RfidId;
set
{
_node.RfidId = value;
_node.ModifiedDate = DateTime.Now;
}
}
[Category("고급")]
[DisplayName("활성화")]
[Description("노드 활성화 여부")]
public bool IsActive
{
get => _node.IsActive;
set
{
_node.IsActive = value;
_node.ModifiedDate = DateTime.Now;
}
}
[Category("표시")]
[DisplayName("노드 배경색")]
[Description("노드 배경 색상")]
public Color DisplayColor
{
get => _node.DisplayColor;
set
{
_node.DisplayColor = value;
_node.ModifiedDate = DateTime.Now;
}
}
[Category("표시")]
[DisplayName("글자 색상")]
[Description("노드 텍스트 색상 (NodeId, Name 등)")]
public Color ForeColor
{
get => _node.ForeColor;
set
{
_node.ForeColor = value;
_node.ModifiedDate = DateTime.Now;
}
}
[Category("표시")]
[DisplayName("글자 크기")]
[Description("노드 텍스트 크기 (픽셀)")]
public float TextFontSize
{
get => _node.TextFontSize;
set
{
_node.TextFontSize = Math.Max(5.0f, Math.Min(20.0f, value));
_node.ModifiedDate = DateTime.Now;
}
}
[Category("표시")]
[DisplayName("글자 굵게")]
[Description("노드 텍스트 볼드 표시")]
public bool TextFontBold
{
get => _node.TextFontBold;
set
{
_node.TextFontBold = value;
_node.ModifiedDate = DateTime.Now;
}
}
[Category("표시")]
[DisplayName("이름 말풍선 배경색")]
[Description("노드 이름 말풍선(하단 표시) 배경색")]
public Color NameBubbleBackColor
{
get => _node.NameBubbleBackColor;
set
{
_node.NameBubbleBackColor = value;
_node.ModifiedDate = DateTime.Now;
}
}
[Category("표시")]
[DisplayName("이름 말풍선 글자색")]
[Description("노드 이름 말풍선(하단 표시) 글자색")]
public Color NameBubbleForeColor
{
get => _node.NameBubbleForeColor;
set
{
_node.NameBubbleForeColor = value;
_node.ModifiedDate = DateTime.Now;
}
}
[Category("정보")]
[DisplayName("생성 일시")]
[Description("노드가 생성된 일시")]
[ReadOnly(true)]
public DateTime CreatedDate
{
get => _node.CreatedDate;
}
[Category("정보")]
[DisplayName("수정 일시")]
[Description("노드가 마지막으로 수정된 일시")]
[ReadOnly(true)]
public DateTime ModifiedDate
{
get => _node.ModifiedDate;
}
}
///
/// 다중 노드 선택 시 공통 속성 편집용 래퍼
///
public class MultiNodePropertyWrapper
{
private List _nodes;
public MultiNodePropertyWrapper(List nodes)
{
_nodes = nodes ?? new List();
}
[Category("다중 선택")]
[DisplayName("선택된 노드 수")]
[Description("현재 선택된 노드의 개수")]
[ReadOnly(true)]
public int SelectedCount => _nodes.Count;
[Category("표시")]
[DisplayName("노드 배경색")]
[Description("선택된 모든 노드의 배경색을 일괄 변경")]
public Color DisplayColor
{
get => _nodes.Count > 0 ? _nodes[0].DisplayColor : Color.Blue;
set
{
foreach (var node in _nodes)
{
node.DisplayColor = value;
node.ModifiedDate = DateTime.Now;
}
}
}
[Category("표시")]
[DisplayName("글자 색상")]
[Description("선택된 모든 노드의 글자 색상을 일괄 변경")]
public Color ForeColor
{
get => _nodes.Count > 0 ? _nodes[0].ForeColor : Color.Black;
set
{
foreach (var node in _nodes)
{
node.ForeColor = value;
node.ModifiedDate = DateTime.Now;
}
}
}
[Category("표시")]
[DisplayName("글자 크기")]
[Description("선택된 모든 노드의 글자 크기를 일괄 변경 (5~20 픽셀)")]
public float TextFontSize
{
get => _nodes.Count > 0 ? _nodes[0].TextFontSize : 7.0f;
set
{
var validValue = Math.Max(5.0f, Math.Min(20.0f, value));
System.Diagnostics.Debug.WriteLine($"[MultiNode] TextFontSize 변경 시작: {validValue}, 노드 수: {_nodes.Count}");
foreach (var node in _nodes)
{
System.Diagnostics.Debug.WriteLine($" - 노드 {node.NodeId}: {node.TextFontSize} → {validValue}");
node.TextFontSize = validValue;
node.ModifiedDate = DateTime.Now;
System.Diagnostics.Debug.WriteLine($" - 변경 후: {node.TextFontSize}");
}
System.Diagnostics.Debug.WriteLine($"[MultiNode] TextFontSize 변경 완료");
}
}
[Category("표시")]
[DisplayName("글자 굵게")]
[Description("선택된 모든 노드의 글자 굵기를 일괄 변경")]
public bool TextFontBold
{
get
{
var result = _nodes.Count > 0 ? _nodes[0].TextFontBold : true;
System.Diagnostics.Debug.WriteLine($"[MultiNode] TextFontBold GET: {result}");
return result;
}
set
{
System.Diagnostics.Debug.WriteLine($"[MultiNode] TextFontBold 변경 시작: {value}, 노드 수: {_nodes.Count}");
foreach (var node in _nodes)
{
System.Diagnostics.Debug.WriteLine($" - 노드 {node.NodeId}: {node.TextFontBold} → {value}");
node.TextFontBold = value;
node.ModifiedDate = DateTime.Now;
System.Diagnostics.Debug.WriteLine($" - 변경 후: {node.TextFontBold}");
}
System.Diagnostics.Debug.WriteLine($"[MultiNode] TextFontBold 변경 완료");
}
}
[Category("표시")]
[DisplayName("이름 말풍선 배경색")]
[Description("선택된 모든 노드의 이름 말풍선(하단 표시) 배경색을 일괄 변경")]
public Color NameBubbleBackColor
{
get => _nodes.Count > 0 ? _nodes[0].NameBubbleBackColor : Color.Gold;
set
{
foreach (var node in _nodes)
{
node.NameBubbleBackColor = value;
node.ModifiedDate = DateTime.Now;
}
}
}
[Category("표시")]
[DisplayName("이름 말풍선 글자색")]
[Description("선택된 모든 노드의 이름 말풍선(하단 표시) 글자색을 일괄 변경")]
public Color NameBubbleForeColor
{
get => _nodes.Count > 0 ? _nodes[0].NameBubbleForeColor : Color.Black;
set
{
foreach (var node in _nodes)
{
node.NameBubbleForeColor = value;
node.ModifiedDate = DateTime.Now;
}
}
}
[Category("고급")]
[DisplayName("활성화")]
[Description("선택된 모든 노드의 활성화 상태를 일괄 변경")]
public bool IsActive
{
get => _nodes.Count > 0 ? _nodes[0].IsActive : true;
set
{
foreach (var node in _nodes)
{
node.IsActive = value;
node.ModifiedDate = DateTime.Now;
}
}
}
[Category("정보")]
[DisplayName("안내")]
[Description("다중 선택 시 공통 속성만 변경할 수 있습니다")]
[ReadOnly(true)]
public string HelpText => "위 속성을 변경하면 선택된 모든 노드에 일괄 적용됩니다.";
}
///
/// 캔버스 속성 래퍼 (배경색 등 캔버스 전체 속성 편집)
///
public class CanvasPropertyWrapper
{
private UnifiedAGVCanvas _canvas;
public CanvasPropertyWrapper(UnifiedAGVCanvas canvas)
{
_canvas = canvas;
}
[Category("배경")]
[DisplayName("배경색")]
[Description("맵 캔버스 배경색")]
public Color BackgroundColor
{
get => _canvas.BackColor;
set
{
_canvas.BackColor = value;
_canvas.Invalidate();
}
}
[Category("그리드")]
[DisplayName("그리드 표시")]
[Description("그리드 표시 여부")]
public bool ShowGrid
{
get => _canvas.ShowGrid;
set
{
_canvas.ShowGrid = value;
_canvas.Invalidate();
}
}
[Category("정보")]
[DisplayName("설명")]
[Description("맵 캔버스 전체 속성")]
[ReadOnly(true)]
public string Description
{
get => "빈 공간을 클릭하면 캔버스 전체 속성을 편집할 수 있습니다.";
}
}
}