using System.Diagnostics; using System.Drawing.Drawing2D; using System.Runtime.Versioning; namespace DevDrive; /// /// Retro-styled dialog that prompts the user to select which startup apps to launch. /// [SupportedOSPlatform("windows")] public class StartupDialog : Form { private static readonly Color BackgroundDark = Color.FromArgb(24, 24, 32); private static readonly Color BackgroundMid = Color.FromArgb(32, 32, 44); private static readonly Color AccentCyan = Color.FromArgb(0, 255, 255); private static readonly Color AccentMagenta = Color.FromArgb(255, 0, 128); private static readonly Color TextLight = Color.FromArgb(240, 240, 255); private static readonly Color TextDim = Color.FromArgb(140, 140, 160); private static readonly Color BorderColor = Color.FromArgb(60, 60, 80); private readonly List _apps; private readonly List _checkboxes = []; private readonly string _driveName; private readonly System.Windows.Forms.Timer _animTimer; private float _scanlineOffset; private float _glowPulse; private float _flickerTarget; private float _flickerCurrent; private float _brightLineY; private int _flickerCounter; /// /// Creates a new startup dialog for the given apps. /// public StartupDialog(List apps, string driveName) { _apps = apps; _driveName = driveName; SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.DoubleBuffer, true); Text = "STARTUP"; FormBorderStyle = FormBorderStyle.None; StartPosition = FormStartPosition.CenterScreen; BackColor = BackgroundDark; Opacity = 0.86; var itemHeight = 44; var headerHeight = 60; var footerHeight = 70; var padding = 20; var contentWidth = 380; var contentHeight = headerHeight + (_apps.Count * itemHeight) + footerHeight; ClientSize = new Size(contentWidth, contentHeight); // Set the window region to rounded rectangle for transparent corners UpdateWindowRegion(); var yPos = headerHeight; foreach (var app in _apps) { var checkbox = new RetroCheckBox { Text = app.Name, Tag = app, Checked = app.CheckedByDefault, Location = new Point(padding, yPos), Size = new Size(contentWidth - (padding * 2), itemHeight - 4) }; _checkboxes.Add(checkbox); Controls.Add(checkbox); yPos += itemHeight; } var buttonWidth = 110; var buttonHeight = 36; var buttonY = contentHeight - footerHeight + 17; var launchButton = new RetroButton { Text = "► LAUNCH", Location = new Point(contentWidth - padding - buttonWidth - 12 - buttonWidth, buttonY), Size = new Size(buttonWidth, buttonHeight), IsPrimary = true }; launchButton.Click += (s, e) => { LaunchSelectedApps(); Close(); }; Controls.Add(launchButton); var skipButton = new RetroButton { Text = "SKIP", Location = new Point(contentWidth - padding - buttonWidth, buttonY), Size = new Size(buttonWidth, buttonHeight), IsPrimary = false }; skipButton.Click += (s, e) => Close(); Controls.Add(skipButton); _animTimer = new System.Windows.Forms.Timer { Interval = 50 }; _animTimer.Tick += OnAnimTick; _animTimer.Start(); } private void OnAnimTick(object? sender, EventArgs e) { _scanlineOffset = (_scanlineOffset + 0.3f) % 6f; _glowPulse = (float)(Math.Sin(Environment.TickCount / 800.0) * 20 + 20); _brightLineY = (_brightLineY + 1.5f) % (Height + 40); _flickerCounter++; if (_flickerCounter >= 8) { _flickerCounter = 0; _flickerTarget = Random.Shared.Next(0, 5); } _flickerCurrent += (_flickerTarget - _flickerCurrent) * 0.3f; Invalidate(); } protected override void OnFormClosed(FormClosedEventArgs e) { _animTimer.Stop(); _animTimer.Dispose(); base.OnFormClosed(e); } protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); var g = e.Graphics; g.SmoothingMode = SmoothingMode.AntiAlias; // Apply subtle bulge transformation var centerX = Width / 2f; var centerY = Height / 2f; var bulgeStrength = 0.08f; // Create a slight perspective transform for CRT bulge var scaleX = 1.0f - bulgeStrength; var scaleY = 1.0f - bulgeStrength; g.TranslateTransform(centerX, centerY); g.ScaleTransform(scaleX + bulgeStrength, scaleY + bulgeStrength); g.TranslateTransform(-centerX, -centerY); using var backgroundBrush = new SolidBrush(Color.FromArgb(240, BackgroundDark)); g.FillRectangle(backgroundBrush, 0, 0, Width, Height); var glowAlpha = (int)(180 + _glowPulse); var pulsingCyan = Color.FromArgb(Math.Min(255, glowAlpha), 0, 255, 255); // Inner content DrawContent(g, pulsingCyan); // Reset transform for effects g.ResetTransform(); // CRT bezel effect - subtle outer shadow using var bezelBrush = new LinearGradientBrush( new Rectangle(0, 0, Width, Height), Color.FromArgb(60, 0, 0, 0), Color.Transparent, LinearGradientMode.Vertical); var screenRect = new Rectangle(3, 3, Width - 6, Height - 6); using var screenPath = CreateRoundedRectangle(screenRect, 12); var bezelRect = new Rectangle(0, 0, Width, Height); using var outerPath = CreateRoundedRectangle(bezelRect, 16); using var innerPath = CreateRoundedRectangle(new Rectangle(4, 4, Width - 8, Height - 8), 10); var bezelRegion = new Region(outerPath); bezelRegion.Exclude(innerPath); g.FillRegion(bezelBrush, bezelRegion); // Outer glow using var outerGlow = new Pen(Color.FromArgb((int)(20 + _glowPulse / 2), AccentCyan), 3); g.DrawPath(outerGlow, CreateRoundedRectangle(new Rectangle(1, 1, Width - 2, Height - 2), 14)); // Main border using var borderPen = new Pen(pulsingCyan, 2); g.DrawPath(borderPen, screenPath); // Corner reflections for glass effect DrawCRTReflections(g); } private void UpdateWindowRegion() { using var path = CreateRoundedRectangle(new Rectangle(0, 0, Width, Height), 16); Region = new Region(path); } protected override void OnResize(EventArgs e) { base.OnResize(e); UpdateWindowRegion(); } private void DrawContent(Graphics g, Color pulsingCyan) { using var headerBrush = new LinearGradientBrush( new Rectangle(0, 0, Width, 60), Color.FromArgb((int)(40 + _glowPulse / 2), AccentCyan), Color.FromArgb(5, AccentCyan), LinearGradientMode.Vertical); g.FillRectangle(headerBrush, 5, 5, Width - 10, 55); using var titleFont = new Font("Consolas", 14, FontStyle.Bold); using var titleBrush = new SolidBrush(pulsingCyan); var title = $"▸ {_driveName.ToUpper()}"; g.DrawString(title, titleFont, titleBrush, 20, 15); using var subtitleFont = new Font("Consolas", 9); using var subtitleBrush = new SolidBrush(TextDim); g.DrawString("Select applications to launch", subtitleFont, subtitleBrush, 20, 38); using var linePen = new Pen(BorderColor, 1); g.DrawLine(linePen, 10, 58, Width - 10, 58); var footerY = Height - 70; g.DrawLine(linePen, 10, footerY, Width - 10, footerY); var scanOffset = (int)_scanlineOffset; for (var y = scanOffset; y < Height; y += 3) { var scanAlpha = 10 + (y % 6 == scanOffset ? 5 : 0); using var scanlinePen = new Pen(Color.FromArgb(scanAlpha, 0, 0, 0), 1); g.DrawLine(scanlinePen, 0, y, Width, y); } var brightY = (int)_brightLineY - 20; if (brightY >= 0 && brightY < Height) { using var brightScanline = new Pen(Color.FromArgb(12, 255, 255, 255), 3); g.DrawLine(brightScanline, 0, brightY, Width, brightY); } var flickerAlpha = (int)_flickerCurrent; if (flickerAlpha > 0) { using var flickerBrush = new SolidBrush(Color.FromArgb(flickerAlpha, 255, 255, 255)); g.FillRectangle(flickerBrush, 0, 0, Width, Height); } } private GraphicsPath CreateRoundedRectangle(Rectangle rect, int radius) { var path = new GraphicsPath(); var diameter = radius * 2; path.AddArc(rect.X, rect.Y, diameter, diameter, 180, 90); path.AddArc(rect.Right - diameter, rect.Y, diameter, diameter, 270, 90); path.AddArc(rect.Right - diameter, rect.Bottom - diameter, diameter, diameter, 0, 90); path.AddArc(rect.X, rect.Bottom - diameter, diameter, diameter, 90, 90); path.CloseFigure(); return path; } private void DrawCRTReflections(Graphics g) { // Top-left corner reflection using var reflection1 = new LinearGradientBrush( new Rectangle(8, 8, 60, 40), Color.FromArgb(25, 255, 255, 255), Color.Transparent, 45f); using var reflectPath1 = CreateRoundedRectangle(new Rectangle(8, 8, 60, 40), 8); g.FillPath(reflection1, reflectPath1); // Subtle center highlight using var reflection2 = new LinearGradientBrush( new Rectangle(Width / 4, 15, Width / 2, 25), Color.FromArgb(8, 255, 255, 255), Color.Transparent, LinearGradientMode.Vertical); using var reflectPath2 = CreateRoundedRectangle(new Rectangle(Width / 4, 15, Width / 2, 25), 4); g.FillPath(reflection2, reflectPath2); } private void LaunchSelectedApps() { foreach (var checkbox in _checkboxes) { if (!checkbox.Checked || checkbox.Tag is not StartupApp app) { continue; } try { var startInfo = new ProcessStartInfo { FileName = Environment.ExpandEnvironmentVariables(app.Path), UseShellExecute = true }; if (!string.IsNullOrWhiteSpace(app.Arguments)) { startInfo.Arguments = Environment.ExpandEnvironmentVariables(app.Arguments); } if (!string.IsNullOrWhiteSpace(app.WorkingDirectory)) { startInfo.WorkingDirectory = Environment.ExpandEnvironmentVariables(app.WorkingDirectory); } Process.Start(startInfo); Console.WriteLine($"[DevDrive] Launched: {app.Name}"); } catch (Exception ex) { Console.WriteLine($"[DevDrive] Failed to launch {app.Name}: {ex.Message}"); } } } /// /// Shows the startup dialog if there are apps to display. /// public static void ShowIfNeeded(List apps, string driveName) { if (apps.Count == 0) { return; } Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); using var dialog = new StartupDialog(apps, driveName); dialog.ShowDialog(); } protected override void OnMouseDown(MouseEventArgs e) { base.OnMouseDown(e); if (e.Button == MouseButtons.Left && e.Y < 60) { NativeMethods.ReleaseCapture(); NativeMethods.SendMessage(Handle, 0xA1, 0x2, 0); } } private static class NativeMethods { [System.Runtime.InteropServices.DllImport("user32.dll")] public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam); [System.Runtime.InteropServices.DllImport("user32.dll")] public static extern bool ReleaseCapture(); } } /// /// Custom retro-styled checkbox control. /// [SupportedOSPlatform("windows")] public class RetroCheckBox : Control { private static readonly Color BackgroundDark = Color.FromArgb(24, 24, 32); private static readonly Color AccentCyan = Color.FromArgb(0, 255, 255); private static readonly Color AccentMagenta = Color.FromArgb(255, 0, 128); private static readonly Color TextLight = Color.FromArgb(240, 240, 255); private static readonly Color BorderColor = Color.FromArgb(60, 60, 80); private bool _checked; private bool _hovering; public bool Checked { get => _checked; set { _checked = value; Invalidate(); } } public RetroCheckBox() { SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.DoubleBuffer, true); Size = new Size(200, 40); Cursor = Cursors.Hand; } protected override void OnPaint(PaintEventArgs e) { var g = e.Graphics; g.SmoothingMode = SmoothingMode.AntiAlias; var bgColor = _hovering ? Color.FromArgb(200, 40, 40, 56) : Color.FromArgb(180, 28, 28, 40); using var bgBrush = new SolidBrush(bgColor); g.FillRectangle(bgBrush, 0, 0, Width, Height); var boxSize = 20; var boxX = 8; var boxY = (Height - boxSize) / 2; var boxBorderColor = _checked ? AccentCyan : BorderColor; using var boxPen = new Pen(boxBorderColor, _checked ? 2 : 1); g.DrawRectangle(boxPen, boxX, boxY, boxSize, boxSize); if (_checked) { using var checkBrush = new SolidBrush(AccentCyan); var innerPadding = 5; g.FillRectangle(checkBrush, boxX + innerPadding, boxY + innerPadding, boxSize - (innerPadding * 2) + 1, boxSize - (innerPadding * 2) + 1); using var glowPen = new Pen(Color.FromArgb(60, AccentCyan), 4); g.DrawRectangle(glowPen, boxX - 1, boxY - 1, boxSize + 2, boxSize + 2); } using var textFont = new Font("Consolas", 11, FontStyle.Bold); var textColor = _checked ? TextLight : Color.FromArgb(160, 160, 180); using var textBrush = new SolidBrush(textColor); var textX = boxX + boxSize + 14; var textY = (Height - textFont.Height) / 2; g.DrawString(Text, textFont, textBrush, textX, textY); if (_checked) { using var accentPen = new Pen(AccentCyan, 2); g.DrawLine(accentPen, 0, Height - 1, Width, Height - 1); } } protected override void OnMouseEnter(EventArgs e) { _hovering = true; Invalidate(); base.OnMouseEnter(e); } protected override void OnMouseLeave(EventArgs e) { _hovering = false; Invalidate(); base.OnMouseLeave(e); } protected override void OnClick(EventArgs e) { Checked = !Checked; base.OnClick(e); } } /// /// Custom retro-styled button control. /// [SupportedOSPlatform("windows")] public class RetroButton : Control { private static readonly Color AccentCyan = Color.FromArgb(0, 255, 255); private static readonly Color AccentMagenta = Color.FromArgb(255, 0, 128); private static readonly Color TextLight = Color.FromArgb(240, 240, 255); private static readonly Color BorderColor = Color.FromArgb(60, 60, 80); private bool _hovering; private bool _pressing; public bool IsPrimary { get; set; } public RetroButton() { SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.DoubleBuffer, true); Size = new Size(100, 36); Cursor = Cursors.Hand; } protected override void OnPaint(PaintEventArgs e) { var g = e.Graphics; g.SmoothingMode = SmoothingMode.AntiAlias; var accentColor = IsPrimary ? AccentCyan : AccentMagenta; Color bgColor; if (_pressing) { bgColor = Color.FromArgb(200, Color.FromArgb(60, accentColor)); } else if (_hovering) { bgColor = Color.FromArgb(180, Color.FromArgb(30, accentColor)); } else { bgColor = Color.FromArgb(140, Color.FromArgb(10, accentColor)); } using var bgBrush = new SolidBrush(bgColor); g.FillRectangle(bgBrush, 0, 0, Width, Height); var borderWidth = _hovering ? 2 : 1; using var borderPen = new Pen(accentColor, borderWidth); g.DrawRectangle(borderPen, borderWidth / 2, borderWidth / 2, Width - borderWidth, Height - borderWidth); if (_hovering && IsPrimary) { using var glowPen = new Pen(Color.FromArgb(40, accentColor), 4); g.DrawRectangle(glowPen, -1, -1, Width + 1, Height + 1); } using var textFont = new Font("Consolas", 10, FontStyle.Bold); using var textBrush = new SolidBrush(accentColor); var textSize = g.MeasureString(Text, textFont); var textX = (Width - textSize.Width) / 2; var textY = (Height - textSize.Height) / 2; g.DrawString(Text, textFont, textBrush, textX, textY); } protected override void OnMouseEnter(EventArgs e) { _hovering = true; Invalidate(); base.OnMouseEnter(e); } protected override void OnMouseLeave(EventArgs e) { _hovering = false; _pressing = false; Invalidate(); base.OnMouseLeave(e); } protected override void OnMouseDown(MouseEventArgs e) { _pressing = true; Invalidate(); base.OnMouseDown(e); } protected override void OnMouseUp(MouseEventArgs e) { _pressing = false; Invalidate(); base.OnMouseUp(e); } }