2using System.Windows.Forms;
15internal sealed class DreamineMessageBoxForm : Form
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;
98 public DialogResult Result {
get;
private set; } = DialogResult.None;
164 public DreamineMessageBoxForm(
168 MessageBoxButtons buttons,
169 DialogResult autoClick,
170 int autoClickDelaySeconds,
171 int enableDelaySeconds)
173 _autoClick = autoClick;
175 FormBorderStyle = FormBorderStyle.None;
176 StartPosition = FormStartPosition.CenterScreen;
177 BackColor = DreamineTheme.CardBackground;
178 Size =
new Size(420, 220);
179 ShowInTaskbar =
false;
183 Padding =
new Padding(2);
185 var header =
new Panel
187 Dock = DockStyle.Top,
189 BackColor = DreamineTheme.NavBackground
191 header.MouseDown += Header_MouseDown;
193 var titleLabel =
new Label
196 ForeColor = DreamineTheme.TextPrimary,
197 Font =
new Font(
"Segoe UI", 10f, FontStyle.Bold),
199 Dock = DockStyle.Fill,
200 TextAlign = ContentAlignment.MiddleLeft,
201 Padding =
new Padding(12, 0, 0, 0)
203 titleLabel.MouseDown += Header_MouseDown;
204 header.Controls.Add(titleLabel);
206 var closeButton =
new Label
209 ForeColor = DreamineTheme.TextSecondary,
210 Font =
new Font(
"Segoe UI", 10f),
211 Dock = DockStyle.Right,
213 TextAlign = ContentAlignment.MiddleCenter,
214 Cursor = Cursors.Hand
216 closeButton.Click += (_, _) => { Result = DialogResult.Cancel; Close(); };
217 header.Controls.Add(closeButton);
219 var iconBox =
new PictureBox
221 Dock = DockStyle.Left,
223 SizeMode = PictureBoxSizeMode.CenterImage,
224 Image = GetIconBitmap(icon)
227 _messageLabel =
new Label
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)
237 var messageRow =
new Panel { Dock = DockStyle.Fill };
238 messageRow.Controls.Add(_messageLabel);
239 messageRow.Controls.Add(iconBox);
241 _buttonPanel =
new FlowLayoutPanel
243 Dock = DockStyle.Bottom,
245 FlowDirection = FlowDirection.RightToLeft,
246 Padding =
new Padding(0, 0, 12, 12)
249 BuildButtons(buttons);
251 Controls.Add(_buttonPanel);
252 Controls.Add(messageRow);
253 Controls.Add(header);
255 if (autoClickDelaySeconds > 0 && autoClick != DialogResult.None)
257 _autoClickRemainingSeconds = autoClickDelaySeconds;
258 _countdownLabel =
new Label
260 Text = $
"({_autoClickRemainingSeconds}s)",
261 ForeColor = DreamineTheme.TextSecondary,
262 Font =
new Font(
"Segoe UI", 8f),
264 Dock = DockStyle.Left,
265 Padding =
new Padding(12, 0, 0, 0)
267 _buttonPanel.Controls.Add(_countdownLabel);
269 _autoClickTimer =
new System.Windows.Forms.Timer { Interval = 1000 };
270 _autoClickTimer.Tick += AutoClickTimer_Tick;
271 _autoClickTimer.Start();
274 if (enableDelaySeconds > 0)
276 SetButtonsEnabled(
false);
277 _enableDelayRemainingSeconds = enableDelaySeconds;
278 _enableDelayTimer =
new System.Windows.Forms.Timer { Interval = 1000 };
279 _enableDelayTimer.Tick += EnableDelayTimer_Tick;
280 _enableDelayTimer.Start();
300 private void BuildButtons(MessageBoxButtons buttons)
302 var specs = buttons
switch
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,
"확인") }
312 foreach (var (result, text) in specs)
314 var button =
new DreamineButton
320 Margin =
new Padding(6, 12, 0, 0)
322 var captured = result;
323 button.MouseUp += (_, e) =>
325 if (e.Button == MouseButtons.Left && button.ClientRectangle.Contains(e.Location))
331 _buttonPanel.Controls.Add(button);
351 private void SetButtonsEnabled(
bool enabled)
353 foreach (Control c
in _buttonPanel.Controls)
354 if (c is DreamineButton btn) btn.Enabled = enabled;
381 private void AutoClickTimer_Tick(
object? sender, EventArgs e)
383 _autoClickRemainingSeconds--;
384 if (_countdownLabel !=
null)
385 _countdownLabel.Text = $
"({_autoClickRemainingSeconds}s)";
387 if (_autoClickRemainingSeconds <= 0)
389 _autoClickTimer?.Stop();
419 private void EnableDelayTimer_Tick(
object? sender, EventArgs e)
421 _enableDelayRemainingSeconds--;
422 if (_enableDelayRemainingSeconds <= 0)
424 _enableDelayTimer?.Stop();
425 SetButtonsEnabled(
true);
453 private static Bitmap? GetIconBitmap(MessageBoxIcon icon)
455 Icon? sysIcon = icon
switch
457 MessageBoxIcon.Information => SystemIcons.Information,
458 MessageBoxIcon.Warning => SystemIcons.Warning,
459 MessageBoxIcon.Error => SystemIcons.Error,
460 MessageBoxIcon.Question => SystemIcons.Question,
463 return sysIcon?.ToBitmap();
475 private const int WM_NCLBUTTONDOWN = 0xA1;
484 private const int HT_CAPTION = 0x2;
502 [System.Runtime.InteropServices.DllImport(
"user32.dll")]
503 private static extern bool ReleaseCapture();
553 [System.Runtime.InteropServices.DllImport(
"user32.dll")]
554 private static extern int SendMessage(IntPtr hWnd,
int Msg,
int wParam,
int lParam);
580 private void Header_MouseDown(
object? sender, MouseEventArgs e)
582 if (e.Button != MouseButtons.Left)
return;
584 SendMessage(Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
603 protected override void OnPaint(PaintEventArgs e)
608 using var pen =
new Pen(DreamineTheme.BorderNormal, 1.5f);
609 e.Graphics.DrawRectangle(pen, 0, 0, Width - 1, Height - 1);
628 protected override void Dispose(
bool disposing)
632 _autoClickTimer?.Dispose();
633 _enableDelayTimer?.Dispose();
635 base.Dispose(disposing);