namespace SheetMe.Core.Catalog;
///
/// 팔레트 컨트롤 카탈로그 — 팔레트 목록·기본 크기·필드 생성 규칙의 단일 출처.
/// 속성 편집 스키마(PropertyDef)는 P3(인스펙터)에서 확장한다.
///
public static class ControlRegistry
{
#region Member Fields
private static readonly List all = new()
{
new()
{
Type = "Label", DisplayName = "라벨", DefaultW = 120, DefaultH = 22,
Properties = new PropertyDef[]
{
new() { Key = "Text", Label = "텍스트", Editor = PropEditorKind.MultilineText },
// ContentAlignment 9값 전체 — Bottom* 3값이 빠져 있으면 그 라벨을 선택하는 것만으로 속성이 삭제된다(운영 249건)
new() { Key = "TextAlign", Label = "정렬", Editor = PropEditorKind.Choice, Default = "TopLeft",
Choices = new[] { "TopLeft", "TopCenter", "TopRight", "MiddleLeft", "MiddleCenter", "MiddleRight", "BottomLeft", "BottomCenter", "BottomRight" } },
new() { Key = "ForeColor", Label = "글자색", Editor = PropEditorKind.Color },
new() { Key = "BackColor", Label = "배경색", Editor = PropEditorKind.Color },
},
},
new()
{
Type = "TextBox", DisplayName = "텍스트박스", DefaultW = 160, DefaultH = 22, CreatesField = true,
Properties = new PropertyDef[]
{
new() { Key = "Text", Label = "텍스트", Editor = PropEditorKind.Text },
new() { Key = "Multiline", Label = "여러 줄", Editor = PropEditorKind.Toggle },
new() { Key = "TextAlign", Label = "정렬", Editor = PropEditorKind.Choice, Default = "Left", Choices = new[] { "Left", "Center", "Right" } },
new() { Key = "IsRequiredValue", Label = "필수 입력", Editor = PropEditorKind.Choice, Choices = new[] { "No", "Yes" } },
new() { Key = "InitialValue", Label = "초기값", Editor = PropEditorKind.Text },
new() { Key = "DataInterfaceTag", Label = "데이터 태그", Editor = PropEditorKind.DataInterfaceTag },
new() { Key = "DataActionTag", Label = "액션 태그", Editor = PropEditorKind.DataActionTag },
new() { Key = "DataActionTagControl", Label = "액션 대상 컨트롤", Editor = PropEditorKind.Text },
// 레거시 TextBox.vb:63 mbRwdRsvWrdYon = True — 2022-09-28 추가된 속성이라 그 이전 서식엔 키가 없다.
// 기본값을 알려주지 않으면 항상 '꺼짐'으로 보이고, 사용자가 껐다 켜면 명시 False 가 기록돼 기능이 죽는다.
new() { Key = "RwdRsvWrdYon", Label = "상용구 사용", Editor = PropEditorKind.Toggle, Default = "True" },
new() { Key = "RwdOrderAutYon", Label = "처방연동 상용구", Editor = PropEditorKind.Toggle },
new() { Key = "BackColor", Label = "배경색", Editor = PropEditorKind.Color },
new() { Key = "BorderStyle", Label = "테두리", Editor = PropEditorKind.Choice, Default = "Fixed3D", Choices = new[] { "None", "FixedSingle", "Fixed3D" } },
},
},
new()
{
Type = "MaskedTextBox", DisplayName = "마스크입력", DefaultW = 160, DefaultH = 22, CreatesField = true,
Properties = new PropertyDef[]
{
new() { Key = "Mask", Label = "마스크", Editor = PropEditorKind.Mask },
new() { Key = "IsRequiredValue", Label = "필수 입력", Editor = PropEditorKind.Choice, Choices = new[] { "No", "Yes" } },
new() { Key = "DataInterfaceTag", Label = "데이터 태그", Editor = PropEditorKind.DataInterfaceTag },
},
},
new()
{
Type = "CheckBox", DisplayName = "체크박스", DefaultW = 110, DefaultH = 20, CreatesField = true, DefaultDataType = "bool",
Properties = new PropertyDef[]
{
new() { Key = "Text", Label = "텍스트", Editor = PropEditorKind.Text },
new() { Key = "Checked", Label = "기본 체크", Editor = PropEditorKind.Toggle },
new() { Key = "Score", Label = "점수", Editor = PropEditorKind.Number },
new() { Key = "IsRequiredValue", Label = "필수 입력", Editor = PropEditorKind.Choice, Choices = new[] { "No", "Yes" } },
},
},
new()
{
Type = "RadioButton", DisplayName = "라디오버튼", DefaultW = 110, DefaultH = 20, CreatesField = true,
Properties = new PropertyDef[]
{
new() { Key = "Text", Label = "텍스트", Editor = PropEditorKind.Text },
new() { Key = "Checked", Label = "기본 선택", Editor = PropEditorKind.Toggle },
},
},
new()
{
Type = "ComboBox", DisplayName = "콤보박스", DefaultW = 140, DefaultH = 22, CreatesField = true,
Properties = new PropertyDef[]
{
new() { Key = "Items", Label = "선택지(줄바꿈 구분)", Editor = PropEditorKind.StringList },
new() { Key = "IsRequiredValue", Label = "필수 입력", Editor = PropEditorKind.Choice, Choices = new[] { "No", "Yes" } },
new() { Key = "DataTableField", Label = "데이터 필드", Editor = PropEditorKind.Text },
},
},
new()
{
Type = "ListBox", DisplayName = "리스트박스", DefaultW = 140, DefaultH = 90, CreatesField = true,
Properties = new PropertyDef[]
{
new() { Key = "Items", Label = "항목(줄바꿈 구분)", Editor = PropEditorKind.StringList },
},
},
new()
{
Type = "CheckList", DisplayName = "체크리스트", DefaultW = 160, DefaultH = 90, CreatesField = true,
Properties = new PropertyDef[]
{
new() { Key = "Items", Label = "항목(줄바꿈 구분)", Editor = PropEditorKind.StringList },
},
},
new()
{
Type = "DateTimePicker", DisplayName = "날짜선택", DefaultW = 140, DefaultH = 22, CreatesField = true, DefaultDataType = "datetime",
Properties = new PropertyDef[]
{
new() { Key = "Format", Label = "형식", Editor = PropEditorKind.Choice, Default = "Long", Choices = new[] { "Long", "Short", "Time", "Custom" } },
new() { Key = "CustomFormat", Label = "사용자 형식", Editor = PropEditorKind.Text },
},
},
new()
{
Type = "Panel", DisplayName = "패널", DefaultW = 240, DefaultH = 140, IsContainer = true,
Properties = new PropertyDef[]
{
new() { Key = "BackColor", Label = "배경색", Editor = PropEditorKind.Color },
new() { Key = "BorderStyle", Label = "테두리", Editor = PropEditorKind.Choice, Default = "None", Choices = new[] { "None", "FixedSingle", "Fixed3D" } },
},
},
new()
{
Type = "GroupBox", DisplayName = "그룹박스", DefaultW = 240, DefaultH = 140, IsContainer = true,
Properties = new PropertyDef[]
{
new() { Key = "Text", Label = "제목", Editor = PropEditorKind.Text },
},
},
new()
{
Type = "Line", DisplayName = "선", DefaultW = 200, DefaultH = 1,
Properties = new PropertyDef[]
{
new() { Key = "LineColor", Label = "선 색", Editor = PropEditorKind.Color },
},
},
new()
{
Type = "PictureBox", DisplayName = "이미지", DefaultW = 120, DefaultH = 90,
Properties = new PropertyDef[]
{
new() { Key = "DataInterfaceTag", Label = "데이터 태그", Editor = PropEditorKind.DataInterfaceTag },
new() { Key = "SizeMode", Label = "크기 모드", Editor = PropEditorKind.Choice, Default = "Normal", Choices = new[] { "Normal", "StretchImage", "AutoSize", "CenterImage", "Zoom" } },
},
},
new()
{
Type = "CalcBox", DisplayName = "계산박스", DefaultW = 100, DefaultH = 22, CreatesField = true, DefaultDataType = "decimal",
Properties = new PropertyDef[]
{
new() { Key = "Formula", Label = "수식", Editor = PropEditorKind.MultilineText },
new() { Key = "Text", Label = "텍스트", Editor = PropEditorKind.Text },
},
},
new()
{
Type = "Button", DisplayName = "버튼", DefaultW = 90, DefaultH = 26,
Properties = new PropertyDef[]
{
new() { Key = "Text", Label = "텍스트", Editor = PropEditorKind.Text },
new() { Key = "DataActionTag", Label = "액션 태그", Editor = PropEditorKind.DataActionTag },
new() { Key = "DataActionTagControl", Label = "액션 대상 컨트롤", Editor = PropEditorKind.Text },
new() { Key = "GetDataActionTagControl", Label = "입력 파라미터 컨트롤", Editor = PropEditorKind.Text },
new() { Key = "KeyboardShortcut", Label = "단축키", Editor = PropEditorKind.Text },
new() { Key = "BackColor", Label = "배경색", Editor = PropEditorKind.Color },
},
},
new()
{
Type = "DataTable", DisplayName = "데이터소스", DefaultW = 34, DefaultH = 34,
Properties = new PropertyDef[]
{
new() { Key = "Query", Label = "쿼리(SQL)", Editor = PropEditorKind.SqlQuery },
new() { Key = "DataInterfaceTag", Label = "데이터 태그", Editor = PropEditorKind.DataInterfaceTag },
// 레거시 MDataTable.vb:15 mbExcuteQuery = True — 미기록 서식에서 '꺼짐'으로 보이면 안 된다
new() { Key = "ExcuteQuery", Label = "쿼리 실행", Editor = PropEditorKind.Toggle, Default = "True" },
},
},
};
private static readonly Dictionary byType =
all.ToDictionary(d => d.Type, StringComparer.Ordinal);
#endregion
#region Properties
/// 팔레트에 노출할 전체 컨트롤 목록
public static IReadOnlyList All => all;
#endregion
#region Methods
/// 타입명으로 기술자 조회 — 미지원 타입(Placeholder 포함)은 null
public static ControlDescriptor? Find(string type)
=> byType.TryGetValue(type, out var descriptor) ? descriptor : null;
#endregion
}
/// 팔레트 컨트롤 1종의 기술자
public sealed class ControlDescriptor
{
/// 중립 타입명(LegacyTypeCatalog 와 공유하는 키)
public string Type { get; init; } = string.Empty;
/// 팔레트 표시명(한글)
public string DisplayName { get; init; } = string.Empty;
/// 드롭 시 기본 너비(px)
public double DefaultW { get; init; }
/// 드롭 시 기본 높이(px)
public double DefaultH { get; init; }
/// 컨테이너 여부(Panel/GroupBox — 자식 배치 가능)
public bool IsContainer { get; init; }
/// 배치 시 데이터 필드를 만드는 입력 컨트롤인지
public bool CreatesField { get; init; }
/// 필드 기본 데이터 타입
public string DefaultDataType { get; init; } = "string";
/// 인스펙터 속성 편집 스키마(타입 전용 — 공통 X/Y/W/H/Id/폰트는 인스펙터가 별도 제공)
public IReadOnlyList Properties { get; init; } = Array.Empty();
}
/// 속성 편집기 종류
public enum PropEditorKind
{
/// 문자열
Text,
/// 여러 줄 문자열
MultilineText,
/// 숫자
Number,
/// 참/거짓
Toggle,
/// 선택지
Choice,
/// 색(레거시 invariant 문자열)
Color,
/// 문자열 목록(콤보 items 등 — 줄바꿈 구분 편집)
StringList,
/// 데이터 태그 피커(bzDataInterface 메서드 — 자동 채움 원천)
DataInterfaceTag,
/// 액션 태그 피커(EN_DataActionTyp — 더블클릭/버튼 액션)
DataActionTag,
/// SQL 쿼리 — 전용 편집기 창(치환 변수 삽입 지원)
SqlQuery,
/// 입력 마스크 — 프리셋 목록 + 미리보기 대화상자
Mask,
}
/// 인스펙터 속성 정의 1건 — PropBag 의 레거시 Property 를 편집
public sealed class PropertyDef
{
/// PropBag 키(레거시 Property 이름)
public string Key { get; init; } = string.Empty;
/// 표시 라벨(한글)
public string Label { get; init; } = string.Empty;
/// 편집기 종류
public PropEditorKind Editor { get; init; }
/// Choice 편집기의 선택지
public string[]? Choices { get; init; }
///
/// PropBag 에 키가 없을 때(미설정) 인스펙터에 표시할 값 — 표시 전용이다.
/// 사용자가 건드리지 않으면 XML 에 기록되지 않는다(왕복 무손실 불변식 유지).
/// 레거시 필드 초기값이 True 인 속성이나 WinForms DefaultValueAttribute 로 미기록되는 속성처럼,
/// "키 부재"와 "명시적 False/빈값"이 UI 상 구분되지 않아 오조작을 부르는 경우에만 지정한다.
///
public string? Default { get; init; }
}