Initial commit to new repository
This commit is contained in:
483
src/AxCopilot/Views/CustomPresetDialog.cs
Normal file
483
src/AxCopilot/Views/CustomPresetDialog.cs
Normal file
@@ -0,0 +1,483 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Shapes;
|
||||
using AxCopilot.Models;
|
||||
|
||||
namespace AxCopilot.Views;
|
||||
|
||||
/// <summary>커스텀 프리셋 추가/편집 다이얼로그.</summary>
|
||||
internal sealed class CustomPresetDialog : Window
|
||||
{
|
||||
private readonly TextBox _nameBox;
|
||||
private readonly TextBox _descBox;
|
||||
private readonly TextBox _promptBox;
|
||||
private readonly ComboBox _tabCombo;
|
||||
private string _selectedColor;
|
||||
private string _selectedSymbol;
|
||||
private Border? _iconPreview;
|
||||
private TextBlock? _iconPreviewText;
|
||||
|
||||
public string PresetName => _nameBox.Text.Trim();
|
||||
public string PresetDescription => _descBox.Text.Trim();
|
||||
public string PresetSystemPrompt => _promptBox.Text.Trim();
|
||||
public string PresetTab => (_tabCombo.SelectedItem as ComboBoxItem)?.Tag?.ToString() ?? "Chat";
|
||||
public string PresetColor => _selectedColor;
|
||||
public string PresetSymbol => _selectedSymbol;
|
||||
|
||||
// 사전 정의 색상 팔레트
|
||||
private static readonly (string Label, string Hex)[] Colors =
|
||||
{
|
||||
("인디고", "#6366F1"),
|
||||
("블루", "#3B82F6"),
|
||||
("티일", "#14B8A6"),
|
||||
("그린", "#22C55E"),
|
||||
("옐로우", "#EAB308"),
|
||||
("오렌지", "#F97316"),
|
||||
("레드", "#EF4444"),
|
||||
("핑크", "#EC4899"),
|
||||
("퍼플", "#A855F7"),
|
||||
("슬레이트", "#64748B"),
|
||||
};
|
||||
|
||||
// 아이콘 셋트 — (카테고리, 아이콘 목록)
|
||||
private static readonly (string Category, (string Label, string Symbol)[] Icons)[] IconSets =
|
||||
{
|
||||
("업무", new[]
|
||||
{
|
||||
("일반", "\uE771"), ("문서", "\uE8A5"), ("메일", "\uE715"), ("캘린더", "\uE787"),
|
||||
("차트", "\uE9D9"), ("발표", "\uE7F4"), ("계산기", "\uE8EF"), ("메모", "\uE70B"),
|
||||
}),
|
||||
("기술", new[]
|
||||
{
|
||||
("코드", "\uE943"), ("설정", "\uE713"), ("데이터", "\uEA86"), ("검색", "\uE721"),
|
||||
("보안", "\uE72E"), ("서버", "\uE839"), ("버그", "\uEBE8"), ("배포", "\uE7F8"),
|
||||
}),
|
||||
("커뮤니케이션", new[]
|
||||
{
|
||||
("대화", "\uE8BD"), ("사람", "\uE77B"), ("팀", "\uE716"), ("전화", "\uE717"),
|
||||
("알림", "\uEA8F"), ("공유", "\uE72D"), ("피드백", "\uE939"), ("질문", "\uE897"),
|
||||
}),
|
||||
("콘텐츠", new[]
|
||||
{
|
||||
("사진", "\uE722"), ("동영상", "\uE714"), ("음악", "\uE8D6"), ("글쓰기", "\uE70F"),
|
||||
("책", "\uE82D"), ("웹", "\uE774"), ("디자인", "\uE790"), ("다운로드", "\uE896"),
|
||||
}),
|
||||
("분석", new[]
|
||||
{
|
||||
("인사이트", "\uE9D9"), ("대시보드", "\uE809"), ("리포트", "\uE9F9"),("트렌드", "\uE8A1"),
|
||||
("필터", "\uE71C"), ("목표", "\uE7C1"), ("비교", "\uE8FD"), ("측정", "\uE7C8"),
|
||||
}),
|
||||
};
|
||||
|
||||
public CustomPresetDialog(
|
||||
string existingName = "",
|
||||
string existingDesc = "",
|
||||
string existingPrompt = "",
|
||||
string existingColor = "#6366F1",
|
||||
string existingSymbol = "\uE713",
|
||||
string existingTab = "Chat")
|
||||
{
|
||||
bool isEdit = !string.IsNullOrEmpty(existingName);
|
||||
Title = isEdit ? "프리셋 편집" : "프리셋 추가";
|
||||
Width = 520;
|
||||
SizeToContent = SizeToContent.Height;
|
||||
WindowStartupLocation = WindowStartupLocation.CenterOwner;
|
||||
ResizeMode = ResizeMode.NoResize;
|
||||
WindowStyle = WindowStyle.None;
|
||||
AllowsTransparency = true;
|
||||
Background = Brushes.Transparent;
|
||||
|
||||
_selectedColor = existingColor;
|
||||
_selectedSymbol = existingSymbol;
|
||||
|
||||
var bgBrush = Application.Current.TryFindResource("LauncherBackground") as Brush
|
||||
?? new SolidColorBrush(Color.FromRgb(0x1A, 0x1B, 0x2E));
|
||||
var primaryText = Application.Current.TryFindResource("PrimaryText") as Brush ?? Brushes.White;
|
||||
var secondaryText = Application.Current.TryFindResource("SecondaryText") as Brush ?? Brushes.Gray;
|
||||
var accentBrush = Application.Current.TryFindResource("AccentColor") as Brush ?? Brushes.Blue;
|
||||
var itemBg = Application.Current.TryFindResource("ItemBackground") as Brush
|
||||
?? new SolidColorBrush(Color.FromRgb(0x2A, 0x2B, 0x40));
|
||||
var borderBrush = Application.Current.TryFindResource("BorderColor") as Brush ?? Brushes.Gray;
|
||||
|
||||
var root = new Border
|
||||
{
|
||||
Background = bgBrush,
|
||||
CornerRadius = new CornerRadius(16),
|
||||
BorderBrush = borderBrush,
|
||||
BorderThickness = new Thickness(1),
|
||||
Padding = new Thickness(28, 24, 28, 24),
|
||||
Effect = new System.Windows.Media.Effects.DropShadowEffect
|
||||
{
|
||||
BlurRadius = 24, ShadowDepth = 4, Opacity = 0.3, Color = System.Windows.Media.Colors.Black,
|
||||
},
|
||||
};
|
||||
|
||||
var stack = new StackPanel();
|
||||
|
||||
// 헤더
|
||||
var header = new StackPanel { Orientation = Orientation.Horizontal, Margin = new Thickness(0, 0, 0, 20) };
|
||||
header.Children.Add(new TextBlock
|
||||
{
|
||||
Text = "\uE710",
|
||||
FontFamily = new FontFamily("Segoe MDL2 Assets"),
|
||||
FontSize = 18, Foreground = accentBrush,
|
||||
VerticalAlignment = VerticalAlignment.Center,
|
||||
Margin = new Thickness(0, 0, 10, 0),
|
||||
});
|
||||
header.Children.Add(new TextBlock
|
||||
{
|
||||
Text = isEdit ? "프리셋 편집" : "새 커스텀 프리셋",
|
||||
FontSize = 17, FontWeight = FontWeights.Bold,
|
||||
Foreground = primaryText, VerticalAlignment = VerticalAlignment.Center,
|
||||
});
|
||||
stack.Children.Add(header);
|
||||
|
||||
// ── 프리셋 이름 ──
|
||||
AddLabel(stack, "프리셋 이름", primaryText);
|
||||
AddHint(stack, "대화 주제 버튼에 표시될 이름입니다", secondaryText);
|
||||
_nameBox = CreateTextBox(existingName, primaryText, itemBg, accentBrush, borderBrush);
|
||||
stack.Children.Add(new Border { CornerRadius = new CornerRadius(8), ClipToBounds = true, Child = _nameBox });
|
||||
|
||||
// ── 설명 ──
|
||||
AddSeparator(stack, borderBrush);
|
||||
AddLabel(stack, "설명", primaryText);
|
||||
AddHint(stack, "프리셋 카드 하단에 표시될 짧은 설명입니다", secondaryText);
|
||||
_descBox = CreateTextBox(existingDesc, primaryText, itemBg, accentBrush, borderBrush);
|
||||
stack.Children.Add(new Border { CornerRadius = new CornerRadius(8), ClipToBounds = true, Child = _descBox });
|
||||
|
||||
// ── 아이콘 + 색상 ──
|
||||
AddSeparator(stack, borderBrush);
|
||||
AddLabel(stack, "아이콘 & 배경색", primaryText);
|
||||
|
||||
var iconColorRow = new StackPanel { Orientation = Orientation.Horizontal, Margin = new Thickness(0, 0, 0, 8) };
|
||||
|
||||
// 아이콘 미리보기 (클릭하면 아이콘 선택 팝업)
|
||||
_iconPreview = new Border
|
||||
{
|
||||
Width = 48, Height = 48,
|
||||
CornerRadius = new CornerRadius(24),
|
||||
Background = new SolidColorBrush(ParseColor(_selectedColor)) { Opacity = 0.2 },
|
||||
Cursor = Cursors.Hand,
|
||||
Margin = new Thickness(0, 0, 16, 0),
|
||||
ToolTip = "아이콘 선택",
|
||||
};
|
||||
_iconPreviewText = new TextBlock
|
||||
{
|
||||
Text = _selectedSymbol,
|
||||
FontFamily = new FontFamily("Segoe MDL2 Assets"),
|
||||
FontSize = 20,
|
||||
Foreground = BrushFromHex(_selectedColor),
|
||||
HorizontalAlignment = HorizontalAlignment.Center,
|
||||
VerticalAlignment = VerticalAlignment.Center,
|
||||
};
|
||||
_iconPreview.Child = _iconPreviewText;
|
||||
_iconPreview.MouseLeftButtonDown += (_, _) => ShowIconPickerPopup();
|
||||
iconColorRow.Children.Add(_iconPreview);
|
||||
|
||||
// 탭 선택
|
||||
var tabStack = new StackPanel { Margin = new Thickness(0, 0, 16, 0) };
|
||||
tabStack.Children.Add(new TextBlock { Text = "탭", FontSize = 11, Foreground = secondaryText, Margin = new Thickness(0, 0, 0, 4) });
|
||||
_tabCombo = new ComboBox
|
||||
{
|
||||
Width = 100, FontSize = 12,
|
||||
Foreground = primaryText, Background = itemBg,
|
||||
BorderBrush = borderBrush, BorderThickness = new Thickness(1),
|
||||
Padding = new Thickness(6, 4, 6, 4),
|
||||
};
|
||||
_tabCombo.Items.Add(new ComboBoxItem { Content = "Chat", Tag = "Chat", IsSelected = existingTab == "Chat" });
|
||||
_tabCombo.Items.Add(new ComboBoxItem { Content = "Cowork", Tag = "Cowork", IsSelected = existingTab == "Cowork" });
|
||||
tabStack.Children.Add(_tabCombo);
|
||||
iconColorRow.Children.Add(tabStack);
|
||||
|
||||
// 색상 팔레트
|
||||
var colorStack = new StackPanel();
|
||||
colorStack.Children.Add(new TextBlock { Text = "배경색", FontSize = 11, Foreground = secondaryText, Margin = new Thickness(0, 0, 0, 4) });
|
||||
var colorPanel = new WrapPanel();
|
||||
foreach (var (label, hex) in Colors)
|
||||
{
|
||||
var colorHex = hex;
|
||||
var swatch = new Border
|
||||
{
|
||||
Width = 22, Height = 22,
|
||||
CornerRadius = new CornerRadius(11),
|
||||
Background = BrushFromHex(hex),
|
||||
Margin = new Thickness(0, 0, 5, 4),
|
||||
Cursor = Cursors.Hand,
|
||||
BorderThickness = new Thickness(2),
|
||||
BorderBrush = hex == _selectedColor ? primaryText : Brushes.Transparent,
|
||||
ToolTip = label,
|
||||
};
|
||||
swatch.MouseLeftButtonDown += (s, _) =>
|
||||
{
|
||||
_selectedColor = colorHex;
|
||||
foreach (var child in colorPanel.Children)
|
||||
if (child is Border b) b.BorderBrush = Brushes.Transparent;
|
||||
if (s is Border clicked) clicked.BorderBrush = primaryText;
|
||||
UpdateIconPreview();
|
||||
};
|
||||
colorPanel.Children.Add(swatch);
|
||||
}
|
||||
colorStack.Children.Add(colorPanel);
|
||||
iconColorRow.Children.Add(colorStack);
|
||||
stack.Children.Add(iconColorRow);
|
||||
|
||||
// ── 시스템 프롬프트 ──
|
||||
AddSeparator(stack, borderBrush);
|
||||
AddLabel(stack, "시스템 프롬프트", primaryText);
|
||||
AddHint(stack, "AI가 이 프리셋에서 따를 지침입니다. 비워두면 기본 프롬프트가 사용됩니다.", secondaryText);
|
||||
_promptBox = CreateTextBox(existingPrompt, primaryText, itemBg, accentBrush, borderBrush, multiline: true);
|
||||
stack.Children.Add(new Border { CornerRadius = new CornerRadius(8), ClipToBounds = true, Child = _promptBox });
|
||||
|
||||
// 글자 수
|
||||
var charCount = new TextBlock
|
||||
{
|
||||
FontSize = 10.5, Foreground = secondaryText,
|
||||
Margin = new Thickness(0, 6, 0, 0),
|
||||
HorizontalAlignment = HorizontalAlignment.Right,
|
||||
};
|
||||
UpdateCharCount(charCount);
|
||||
_promptBox.TextChanged += (_, _) => UpdateCharCount(charCount);
|
||||
stack.Children.Add(charCount);
|
||||
|
||||
// ── 버튼 바 ──
|
||||
var btnBar = new StackPanel
|
||||
{
|
||||
Orientation = Orientation.Horizontal,
|
||||
HorizontalAlignment = HorizontalAlignment.Right,
|
||||
Margin = new Thickness(0, 20, 0, 0),
|
||||
};
|
||||
|
||||
var cancelBtn = new Button
|
||||
{
|
||||
Content = "취소", Width = 80,
|
||||
Padding = new Thickness(0, 8, 0, 8),
|
||||
Margin = new Thickness(0, 0, 10, 0),
|
||||
Background = Brushes.Transparent, Foreground = secondaryText,
|
||||
BorderBrush = borderBrush, BorderThickness = new Thickness(1),
|
||||
Cursor = Cursors.Hand, FontSize = 13,
|
||||
};
|
||||
cancelBtn.Click += (_, _) => { DialogResult = false; Close(); };
|
||||
btnBar.Children.Add(cancelBtn);
|
||||
|
||||
var okBtn = new Button
|
||||
{
|
||||
Content = isEdit ? "저장" : "추가", Width = 80,
|
||||
Padding = new Thickness(0, 8, 0, 8),
|
||||
Background = accentBrush, Foreground = Brushes.White,
|
||||
BorderThickness = new Thickness(0),
|
||||
Cursor = Cursors.Hand, FontSize = 13, FontWeight = FontWeights.SemiBold,
|
||||
};
|
||||
okBtn.Click += (_, _) =>
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(_nameBox.Text))
|
||||
{
|
||||
CustomMessageBox.Show("프리셋 이름을 입력하세요.", "입력 오류", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
_nameBox.Focus();
|
||||
return;
|
||||
}
|
||||
DialogResult = true;
|
||||
Close();
|
||||
};
|
||||
btnBar.Children.Add(okBtn);
|
||||
stack.Children.Add(btnBar);
|
||||
|
||||
root.Child = stack;
|
||||
Content = root;
|
||||
|
||||
KeyDown += (_, ke) => { if (ke.Key == Key.Escape) { DialogResult = false; Close(); } };
|
||||
Loaded += (_, _) => { _nameBox.Focus(); _nameBox.SelectAll(); };
|
||||
root.MouseLeftButtonDown += (_, me) =>
|
||||
{
|
||||
if (me.LeftButton == MouseButtonState.Pressed)
|
||||
try { DragMove(); } catch { }
|
||||
};
|
||||
}
|
||||
|
||||
private void UpdateIconPreview()
|
||||
{
|
||||
if (_iconPreview == null || _iconPreviewText == null) return;
|
||||
_iconPreview.Background = new SolidColorBrush(ParseColor(_selectedColor)) { Opacity = 0.2 };
|
||||
_iconPreviewText.Text = _selectedSymbol;
|
||||
_iconPreviewText.Foreground = BrushFromHex(_selectedColor);
|
||||
}
|
||||
|
||||
// ── 아이콘 피커 팝업 ────────────────────────────────────────────
|
||||
private void ShowIconPickerPopup()
|
||||
{
|
||||
var bgBrush = Application.Current.TryFindResource("LauncherBackground") as Brush
|
||||
?? new SolidColorBrush(Color.FromRgb(0x1A, 0x1B, 0x2E));
|
||||
var primaryText = Application.Current.TryFindResource("PrimaryText") as Brush ?? Brushes.White;
|
||||
var secondaryText = Application.Current.TryFindResource("SecondaryText") as Brush ?? Brushes.Gray;
|
||||
var borderBrush = Application.Current.TryFindResource("BorderColor") as Brush ?? Brushes.Gray;
|
||||
var hoverBg = Application.Current.TryFindResource("ItemHoverBackground") as Brush ?? Brushes.Transparent;
|
||||
var accentBrush = Application.Current.TryFindResource("AccentColor") as Brush ?? Brushes.Blue;
|
||||
|
||||
// 별도 Window로 표시 (모달 다이얼로그 위에서 Popup 충돌 방지)
|
||||
var pickerWin = new Window
|
||||
{
|
||||
Title = "아이콘 선택",
|
||||
Width = 340,
|
||||
SizeToContent = SizeToContent.Height,
|
||||
WindowStartupLocation = WindowStartupLocation.CenterOwner,
|
||||
Owner = this,
|
||||
ResizeMode = ResizeMode.NoResize,
|
||||
WindowStyle = WindowStyle.None,
|
||||
AllowsTransparency = true,
|
||||
Background = Brushes.Transparent,
|
||||
};
|
||||
|
||||
var popupBorder = new Border
|
||||
{
|
||||
Background = bgBrush,
|
||||
CornerRadius = new CornerRadius(12),
|
||||
BorderBrush = borderBrush,
|
||||
BorderThickness = new Thickness(1),
|
||||
Padding = new Thickness(12),
|
||||
Effect = new System.Windows.Media.Effects.DropShadowEffect
|
||||
{
|
||||
BlurRadius = 16, ShadowDepth = 3, Opacity = 0.3, Color = System.Windows.Media.Colors.Black,
|
||||
},
|
||||
};
|
||||
|
||||
var mainStack = new StackPanel();
|
||||
|
||||
// 타이틀 + 닫기
|
||||
var titleRow = new Grid();
|
||||
titleRow.Children.Add(new TextBlock
|
||||
{
|
||||
Text = "아이콘 선택",
|
||||
FontSize = 14, FontWeight = FontWeights.SemiBold,
|
||||
Foreground = primaryText,
|
||||
Margin = new Thickness(0, 0, 0, 10),
|
||||
HorizontalAlignment = HorizontalAlignment.Left,
|
||||
});
|
||||
var closeBtn = new TextBlock
|
||||
{
|
||||
Text = "\uE711", FontFamily = new FontFamily("Segoe MDL2 Assets"),
|
||||
FontSize = 12, Foreground = secondaryText,
|
||||
Cursor = Cursors.Hand,
|
||||
HorizontalAlignment = HorizontalAlignment.Right, VerticalAlignment = VerticalAlignment.Top,
|
||||
};
|
||||
closeBtn.MouseLeftButtonDown += (_, _) => pickerWin.Close();
|
||||
titleRow.Children.Add(closeBtn);
|
||||
mainStack.Children.Add(titleRow);
|
||||
|
||||
// 드래그로 창 이동
|
||||
popupBorder.MouseLeftButtonDown += (_, e) => { try { pickerWin.DragMove(); } catch { } };
|
||||
|
||||
// 카테고리별 아이콘 그리드
|
||||
foreach (var (category, icons) in IconSets)
|
||||
{
|
||||
mainStack.Children.Add(new TextBlock
|
||||
{
|
||||
Text = category,
|
||||
FontSize = 11, FontWeight = FontWeights.SemiBold,
|
||||
Foreground = secondaryText,
|
||||
Margin = new Thickness(0, 6, 0, 4),
|
||||
});
|
||||
|
||||
var wrapPanel = new WrapPanel();
|
||||
foreach (var (label, symbol) in icons)
|
||||
{
|
||||
var capturedSymbol = symbol;
|
||||
var isSelected = _selectedSymbol == symbol;
|
||||
var iconBtn = new Border
|
||||
{
|
||||
Width = 36, Height = 36,
|
||||
CornerRadius = new CornerRadius(8),
|
||||
Background = isSelected ? new SolidColorBrush(ParseColor(_selectedColor)) { Opacity = 0.2 } : Brushes.Transparent,
|
||||
BorderBrush = isSelected ? accentBrush : Brushes.Transparent,
|
||||
BorderThickness = new Thickness(isSelected ? 1.5 : 0),
|
||||
Cursor = Cursors.Hand,
|
||||
Margin = new Thickness(0, 0, 4, 4),
|
||||
ToolTip = label,
|
||||
};
|
||||
iconBtn.Child = new TextBlock
|
||||
{
|
||||
Text = symbol,
|
||||
FontFamily = new FontFamily("Segoe MDL2 Assets"),
|
||||
FontSize = 16,
|
||||
Foreground = isSelected ? BrushFromHex(_selectedColor) : primaryText,
|
||||
HorizontalAlignment = HorizontalAlignment.Center,
|
||||
VerticalAlignment = VerticalAlignment.Center,
|
||||
};
|
||||
|
||||
iconBtn.MouseEnter += (s, _) => { if (s is Border b && !(_selectedSymbol == capturedSymbol)) b.Background = hoverBg; };
|
||||
iconBtn.MouseLeave += (s, _) => { if (s is Border b && !(_selectedSymbol == capturedSymbol)) b.Background = Brushes.Transparent; };
|
||||
iconBtn.MouseLeftButtonDown += (_, e) =>
|
||||
{
|
||||
e.Handled = true;
|
||||
_selectedSymbol = capturedSymbol;
|
||||
UpdateIconPreview();
|
||||
pickerWin.Close();
|
||||
};
|
||||
|
||||
wrapPanel.Children.Add(iconBtn);
|
||||
}
|
||||
mainStack.Children.Add(wrapPanel);
|
||||
}
|
||||
|
||||
popupBorder.Child = mainStack;
|
||||
pickerWin.Content = popupBorder;
|
||||
pickerWin.ShowDialog();
|
||||
}
|
||||
|
||||
private static void AddLabel(StackPanel parent, string text, Brush fg) =>
|
||||
parent.Children.Add(new TextBlock
|
||||
{
|
||||
Text = text, FontSize = 12, FontWeight = FontWeights.SemiBold,
|
||||
Foreground = fg, Margin = new Thickness(0, 0, 0, 6),
|
||||
});
|
||||
|
||||
private static void AddHint(StackPanel parent, string text, Brush fg) =>
|
||||
parent.Children.Add(new TextBlock
|
||||
{
|
||||
Text = text, FontSize = 11, Foreground = fg,
|
||||
Margin = new Thickness(0, 0, 0, 8),
|
||||
});
|
||||
|
||||
private static void AddSeparator(StackPanel parent, Brush color) =>
|
||||
parent.Children.Add(new Rectangle
|
||||
{
|
||||
Height = 1, Fill = color,
|
||||
Margin = new Thickness(0, 12, 0, 12), Opacity = 0.5,
|
||||
});
|
||||
|
||||
private static TextBox CreateTextBox(string text, Brush fg, Brush bg, Brush caret, Brush border, bool multiline = false)
|
||||
{
|
||||
var tb = new TextBox
|
||||
{
|
||||
Text = text, FontSize = 13,
|
||||
Padding = new Thickness(12, 8, 12, 8),
|
||||
Foreground = fg, Background = bg,
|
||||
CaretBrush = caret, BorderBrush = border,
|
||||
BorderThickness = new Thickness(1),
|
||||
};
|
||||
if (multiline)
|
||||
{
|
||||
tb.AcceptsReturn = true;
|
||||
tb.TextWrapping = TextWrapping.Wrap;
|
||||
tb.MinHeight = 100;
|
||||
tb.MaxHeight = 200;
|
||||
tb.VerticalScrollBarVisibility = ScrollBarVisibility.Auto;
|
||||
}
|
||||
return tb;
|
||||
}
|
||||
|
||||
private void UpdateCharCount(TextBlock tb) =>
|
||||
tb.Text = $"{_promptBox.Text.Length}자";
|
||||
|
||||
private static Brush BrushFromHex(string hex)
|
||||
{
|
||||
try { return new SolidColorBrush((Color)ColorConverter.ConvertFromString(hex)); }
|
||||
catch { return Brushes.Gray; }
|
||||
}
|
||||
|
||||
private static Color ParseColor(string hex)
|
||||
{
|
||||
try { return (Color)ColorConverter.ConvertFromString(hex); }
|
||||
catch { return System.Windows.Media.Colors.Gray; }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user