Dreamine.UI.WinForms 1.0.1
Dreamine.UI.WinForms 사용자 인터페이스 기능과 구성 요소를 제공합니다.
로딩중...
검색중...
일치하는것 없음
DreamineMessageBoxForm.cs
이 파일의 문서화 페이지로 가기
1using System.Drawing;
2using System.Windows.Forms;
4
6
15internal sealed class DreamineMessageBoxForm : Form
16{
25 private readonly Label _messageLabel;
34 private readonly FlowLayoutPanel _buttonPanel;
43 private readonly System.Windows.Forms.Timer? _autoClickTimer;
52 private readonly System.Windows.Forms.Timer? _enableDelayTimer;
61 private readonly DialogResult _autoClick;
70 private int _autoClickRemainingSeconds;
79 private int _enableDelayRemainingSeconds;
88 private Label? _countdownLabel;
89
98 public DialogResult Result { get; private set; } = DialogResult.None;
99
164 public DreamineMessageBoxForm(
165 string title,
166 string message,
167 MessageBoxIcon icon,
168 MessageBoxButtons buttons,
169 DialogResult autoClick,
170 int autoClickDelaySeconds,
171 int enableDelaySeconds)
172 {
173 _autoClick = autoClick;
174
175 FormBorderStyle = FormBorderStyle.None;
176 StartPosition = FormStartPosition.CenterScreen;
177 BackColor = DreamineTheme.CardBackground;
178 Size = new Size(420, 220);
179 ShowInTaskbar = false;
180 TopMost = true;
181 // 자식 컨트롤이 Form 가장자리까지 꽉 채우면 WS_CLIPCHILDREN 때문에 그 부분의
182 // 테두리가 안 그려진다. Padding으로 여백을 둬서 테두리가 끊김 없이 그려지게 한다.
183 Padding = new Padding(2);
184
185 var header = new Panel
186 {
187 Dock = DockStyle.Top,
188 Height = 36,
189 BackColor = DreamineTheme.NavBackground
190 };
191 header.MouseDown += Header_MouseDown;
192
193 var titleLabel = new Label
194 {
195 Text = title,
196 ForeColor = DreamineTheme.TextPrimary,
197 Font = new Font("Segoe UI", 10f, FontStyle.Bold),
198 AutoSize = false,
199 Dock = DockStyle.Fill,
200 TextAlign = ContentAlignment.MiddleLeft,
201 Padding = new Padding(12, 0, 0, 0)
202 };
203 titleLabel.MouseDown += Header_MouseDown;
204 header.Controls.Add(titleLabel);
205
206 var closeButton = new Label
207 {
208 Text = "✕",
209 ForeColor = DreamineTheme.TextSecondary,
210 Font = new Font("Segoe UI", 10f),
211 Dock = DockStyle.Right,
212 Width = 36,
213 TextAlign = ContentAlignment.MiddleCenter,
214 Cursor = Cursors.Hand
215 };
216 closeButton.Click += (_, _) => { Result = DialogResult.Cancel; Close(); };
217 header.Controls.Add(closeButton);
218
219 var iconBox = new PictureBox
220 {
221 Dock = DockStyle.Left,
222 Width = 56,
223 SizeMode = PictureBoxSizeMode.CenterImage,
224 Image = GetIconBitmap(icon)
225 };
226
227 _messageLabel = new Label
228 {
229 Text = message,
230 ForeColor = DreamineTheme.TextPrimary,
231 Font = new Font("Segoe UI", 10f),
232 Dock = DockStyle.Fill,
233 TextAlign = ContentAlignment.MiddleLeft,
234 Padding = new Padding(8, 16, 16, 16)
235 };
236
237 var messageRow = new Panel { Dock = DockStyle.Fill };
238 messageRow.Controls.Add(_messageLabel);
239 messageRow.Controls.Add(iconBox);
240
241 _buttonPanel = new FlowLayoutPanel
242 {
243 Dock = DockStyle.Bottom,
244 Height = 56,
245 FlowDirection = FlowDirection.RightToLeft,
246 Padding = new Padding(0, 0, 12, 12)
247 };
248
249 BuildButtons(buttons);
250
251 Controls.Add(_buttonPanel);
252 Controls.Add(messageRow);
253 Controls.Add(header);
254
255 if (autoClickDelaySeconds > 0 && autoClick != DialogResult.None)
256 {
257 _autoClickRemainingSeconds = autoClickDelaySeconds;
258 _countdownLabel = new Label
259 {
260 Text = $"({_autoClickRemainingSeconds}s)",
261 ForeColor = DreamineTheme.TextSecondary,
262 Font = new Font("Segoe UI", 8f),
263 AutoSize = true,
264 Dock = DockStyle.Left,
265 Padding = new Padding(12, 0, 0, 0)
266 };
267 _buttonPanel.Controls.Add(_countdownLabel);
268
269 _autoClickTimer = new System.Windows.Forms.Timer { Interval = 1000 };
270 _autoClickTimer.Tick += AutoClickTimer_Tick;
271 _autoClickTimer.Start();
272 }
273
274 if (enableDelaySeconds > 0)
275 {
276 SetButtonsEnabled(false);
277 _enableDelayRemainingSeconds = enableDelaySeconds;
278 _enableDelayTimer = new System.Windows.Forms.Timer { Interval = 1000 };
279 _enableDelayTimer.Tick += EnableDelayTimer_Tick;
280 _enableDelayTimer.Start();
281 }
282 }
283
300 private void BuildButtons(MessageBoxButtons buttons)
301 {
302 var specs = buttons switch
303 {
304 MessageBoxButtons.OKCancel => new[] { (DialogResult.Cancel, "취소"), (DialogResult.OK, "확인") },
305 MessageBoxButtons.YesNo => new[] { (DialogResult.No, "아니오"), (DialogResult.Yes, "예") },
306 MessageBoxButtons.YesNoCancel => new[] { (DialogResult.Cancel, "취소"), (DialogResult.No, "아니오"), (DialogResult.Yes, "예") },
307 MessageBoxButtons.RetryCancel => new[] { (DialogResult.Cancel, "취소"), (DialogResult.Retry, "재시도") },
308 MessageBoxButtons.AbortRetryIgnore => new[] { (DialogResult.Ignore, "무시"), (DialogResult.Retry, "재시도"), (DialogResult.Abort, "중단") },
309 _ => new[] { (DialogResult.OK, "확인") }
310 };
311
312 foreach (var (result, text) in specs)
313 {
314 var button = new DreamineButton
315 {
316 Content = text,
317 Width = 96,
318 Height = 32,
319 CornerRadius = 6,
320 Margin = new Padding(6, 12, 0, 0)
321 };
322 var captured = result;
323 button.MouseUp += (_, e) =>
324 {
325 if (e.Button == MouseButtons.Left && button.ClientRectangle.Contains(e.Location))
326 {
327 Result = captured;
328 Close();
329 }
330 };
331 _buttonPanel.Controls.Add(button);
332 }
333 }
334
351 private void SetButtonsEnabled(bool enabled)
352 {
353 foreach (Control c in _buttonPanel.Controls)
354 if (c is DreamineButton btn) btn.Enabled = enabled;
355 }
356
381 private void AutoClickTimer_Tick(object? sender, EventArgs e)
382 {
383 _autoClickRemainingSeconds--;
384 if (_countdownLabel != null)
385 _countdownLabel.Text = $"({_autoClickRemainingSeconds}s)";
386
387 if (_autoClickRemainingSeconds <= 0)
388 {
389 _autoClickTimer?.Stop();
390 Result = _autoClick;
391 Close();
392 }
393 }
394
419 private void EnableDelayTimer_Tick(object? sender, EventArgs e)
420 {
421 _enableDelayRemainingSeconds--;
422 if (_enableDelayRemainingSeconds <= 0)
423 {
424 _enableDelayTimer?.Stop();
425 SetButtonsEnabled(true);
426 }
427 }
428
453 private static Bitmap? GetIconBitmap(MessageBoxIcon icon)
454 {
455 Icon? sysIcon = icon switch
456 {
457 MessageBoxIcon.Information => SystemIcons.Information,
458 MessageBoxIcon.Warning => SystemIcons.Warning,
459 MessageBoxIcon.Error => SystemIcons.Error,
460 MessageBoxIcon.Question => SystemIcons.Question,
461 _ => null
462 };
463 return sysIcon?.ToBitmap();
464 }
465
466 // ── Draggable header (Win32 캡션 드래그 트릭) ───────────
475 private const int WM_NCLBUTTONDOWN = 0xA1;
484 private const int HT_CAPTION = 0x2;
485
502 [System.Runtime.InteropServices.DllImport("user32.dll")]
503 private static extern bool ReleaseCapture();
504
553 [System.Runtime.InteropServices.DllImport("user32.dll")]
554 private static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
555
580 private void Header_MouseDown(object? sender, MouseEventArgs e)
581 {
582 if (e.Button != MouseButtons.Left) return;
583 ReleaseCapture();
584 SendMessage(Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
585 }
586
603 protected override void OnPaint(PaintEventArgs e)
604 {
605 base.OnPaint(e);
606 // BlinkPopupForm과 동일한 이유로 Form 자체는 사각형 모서리를 유지한다
607 // (Region 클리핑은 안티앨리어싱이 없어 더 거칠게 보임).
608 using var pen = new Pen(DreamineTheme.BorderNormal, 1.5f);
609 e.Graphics.DrawRectangle(pen, 0, 0, Width - 1, Height - 1);
610 }
611
628 protected override void Dispose(bool disposing)
629 {
630 if (disposing)
631 {
632 _autoClickTimer?.Dispose();
633 _enableDelayTimer?.Dispose();
634 }
635 base.Dispose(disposing);
636 }
637}