Private/srgTheme.ps1
|
<#
Visual-Studio-Dark-Farbschema, wie in DbSchemaCompare/SqlRefactorAnalyzer (UI\Theme.cs) und den GUIs von sqmSQLTool / sqmPartitionTool / sqmOlaBackupBuilder - damit alle Werkzeuge gleich aussehen. Set-srgTheme faerbt ein Formular rekursiv ein; Controls, die nachtraeglich entstehen (Dialoge, Kontextmenues), rufen es selbst auf. #> $script:srgColors = @{ Editor = [System.Drawing.Color]::FromArgb(30, 30, 30) # #1E1E1E Editor / Listen Bg = [System.Drawing.Color]::FromArgb(37, 37, 38) # #252526 Fenster Surface = [System.Drawing.Color]::FromArgb(45, 45, 48) # #2D2D30 Eingabefelder, Kopfzeilen Button = [System.Drawing.Color]::FromArgb(62, 62, 66) # #3E3E42 Border = [System.Drawing.Color]::FromArgb(63, 63, 70) # #3F3F46 Text = [System.Drawing.Color]::FromArgb(220, 220, 220) # #DCDCDC Subtle = [System.Drawing.Color]::FromArgb(153, 153, 153) Accent = [System.Drawing.Color]::FromArgb(0, 122, 204) # #007ACC Selection = [System.Drawing.Color]::FromArgb(9, 71, 113) # #094771 Critical = [System.Drawing.Color]::FromArgb(255, 100, 100) Warning = [System.Drawing.Color]::FromArgb(220, 180, 60) Info = [System.Drawing.Color]::FromArgb(108, 180, 220) Ok = [System.Drawing.Color]::FromArgb(78, 201, 176) # Syntaxfarben wie im VS-/SSMS-Dark-Theme SynKeyword = [System.Drawing.Color]::FromArgb(86, 156, 214) SynString = [System.Drawing.Color]::FromArgb(214, 157, 133) SynComment = [System.Drawing.Color]::FromArgb(87, 166, 74) SynVariable = [System.Drawing.Color]::FromArgb(156, 220, 254) SynNumber = [System.Drawing.Color]::FromArgb(181, 206, 168) } function Initialize-srgNative { if ('Srg.Native' -as [type]) { return } Add-Type -Namespace Srg -Name Native -MemberDefinition @' [System.Runtime.InteropServices.DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Unicode)] public static extern System.IntPtr SendMessage(System.IntPtr hWnd, int msg, System.IntPtr wParam, string lParam); [System.Runtime.InteropServices.DllImport("dwmapi.dll")] public static extern int DwmSetWindowAttribute(System.IntPtr hwnd, int attr, ref int attrValue, int attrSize); [System.Runtime.InteropServices.DllImport("uxtheme.dll", CharSet = System.Runtime.InteropServices.CharSet.Unicode)] public static extern int SetWindowTheme(System.IntPtr hWnd, string pszSubAppName, string pszSubIdList); '@ } function Set-srgDarkTitleBar($Form) { try { Initialize-srgNative $on = 1 # 20 = DWMWA_USE_IMMERSIVE_DARK_MODE (Win10 2004+), 19 auf aelteren Builds if ([Srg.Native]::DwmSetWindowAttribute($Form.Handle, 20, [ref]$on, 4) -ne 0) { [void][Srg.Native]::DwmSetWindowAttribute($Form.Handle, 19, [ref]$on, 4) } } catch { } } function Set-srgDarkScrollBars($Control) { # dunkle Scrollbalken (Explorer-Dark-Theme), wirkungslos aber harmlos auf alten Windows-Versionen try { Initialize-srgNative if ($Control.IsHandleCreated) { [void][Srg.Native]::SetWindowTheme($Control.Handle, 'DarkMode_Explorer', $null) } else { $Control.Add_HandleCreated({ [void][Srg.Native]::SetWindowTheme($this.Handle, 'DarkMode_Explorer', $null) }) } } catch { } } function Set-srgTheme($Control) { $c = $script:srgColors switch ($Control) { { $_ -is [System.Windows.Forms.Form] } { $_.BackColor = $c.Bg; $_.ForeColor = $c.Text if ($_.IsHandleCreated) { Set-srgDarkTitleBar $_ } else { $_.Add_HandleCreated({ Set-srgDarkTitleBar $this }) } break } { $_ -is [System.Windows.Forms.RichTextBox] } { $_.BackColor = $c.Editor; $_.ForeColor = $c.Text; $_.BorderStyle = 'None'; Set-srgDarkScrollBars $_; break } { $_ -is [System.Windows.Forms.TextBox] } { $_.BackColor = $c.Surface; $_.ForeColor = $c.Text; $_.BorderStyle = 'FixedSingle'; break } { $_ -is [System.Windows.Forms.ComboBox] } { $_.BackColor = $c.Surface; $_.ForeColor = $c.Text; $_.FlatStyle = 'Flat'; break } { $_ -is [System.Windows.Forms.ListBox] } { $_.BackColor = $c.Editor; $_.ForeColor = $c.Text; $_.BorderStyle = 'None'; Set-srgDarkScrollBars $_; break } { $_ -is [System.Windows.Forms.NumericUpDown] } { $_.BackColor = $c.Surface; $_.ForeColor = $c.Text; $_.BorderStyle = 'FixedSingle'; break } { $_ -is [System.Windows.Forms.Button] } { $_.FlatStyle = 'Flat'; $_.BackColor = $c.Button; $_.ForeColor = $c.Text $_.FlatAppearance.BorderColor = $c.Border $_.FlatAppearance.MouseOverBackColor = $c.Accent $_.Cursor = [System.Windows.Forms.Cursors]::Hand break } { $_ -is [System.Windows.Forms.CheckBox] -or $_ -is [System.Windows.Forms.RadioButton] } { $_.ForeColor = $c.Text; $_.BackColor = [System.Drawing.Color]::Transparent; $_.FlatStyle = 'Flat' $_.FlatAppearance.BorderColor = $c.Subtle $_.FlatAppearance.CheckedBackColor = $c.Surface break } { $_ -is [System.Windows.Forms.Label] } { $_.ForeColor = if ($_.ForeColor -eq [System.Drawing.Color]::DimGray) { $c.Subtle } else { $c.Text } $_.BackColor = [System.Drawing.Color]::Transparent break } { $_ -is [System.Windows.Forms.DataGridView] } { $_.BackgroundColor = $c.Editor; $_.ForeColor = $c.Text; $_.GridColor = $c.Border; $_.BorderStyle = 'None' $_.DefaultCellStyle.BackColor = $c.Editor; $_.DefaultCellStyle.ForeColor = $c.Text $_.DefaultCellStyle.SelectionBackColor = $c.Selection; $_.DefaultCellStyle.SelectionForeColor = $c.Text $_.ColumnHeadersDefaultCellStyle.BackColor = $c.Surface; $_.ColumnHeadersDefaultCellStyle.ForeColor = $c.Text $_.ColumnHeadersDefaultCellStyle.SelectionBackColor = $c.Surface $_.EnableHeadersVisualStyles = $false $_.ColumnHeadersBorderStyle = 'Single' $_.CellBorderStyle = 'SingleHorizontal' break } { $_ -is [System.Windows.Forms.TabControl] } { # Kopfzeilen selbst zeichnen und auf volle Breite ziehen - sonst bleibt der Reiterstreifen hell $_.DrawMode = 'OwnerDrawFixed' $_.SizeMode = 'Fixed' $_.Add_DrawItem({ param($s, $e) Invoke-srgDrawTab $s $e }) $_.Add_Resize({ Update-srgTabWidth $this }) Update-srgTabWidth $_ break } { $_ -is [System.Windows.Forms.TabPage] } { $_.BackColor = $c.Bg; $_.ForeColor = $c.Text; break } { $_ -is [System.Windows.Forms.SplitContainer] } { $_.BackColor = $c.Border; $_.Panel1.BackColor = $c.Bg; $_.Panel2.BackColor = $c.Bg; break } { $_ -is [System.Windows.Forms.GroupBox] } { $_.BackColor = $c.Bg; $_.ForeColor = $c.Subtle; break } { $_ -is [System.Windows.Forms.ScrollableControl] } { $_.BackColor = $c.Bg; $_.ForeColor = $c.Text if ($_.AutoScroll) { Set-srgDarkScrollBars $_ } break } } # zusammengesetzte Controls nicht zerlegen (innere Edit-Felder, Scrollbalken) if ($Control -is [System.Windows.Forms.NumericUpDown] -or $Control -is [System.Windows.Forms.ComboBox] -or $Control -is [System.Windows.Forms.DataGridView]) { return } foreach ($child in @($Control.Controls)) { Set-srgTheme $child } } function Update-srgTabWidth($Tabs) { if ($Tabs.TabCount -eq 0) { return } # .NET 8 (PowerShell 7) loest beim Setzen von ItemSize selbst wieder Resize aus -> Sperre if ($script:srgTabResizing) { return } $w = [math]::Max(60, [int](($Tabs.ClientSize.Width - 6) / $Tabs.TabCount)) if ($Tabs.ItemSize.Width -eq $w) { return } $script:srgTabResizing = $true try { $Tabs.ItemSize = New-Object System.Drawing.Size($w, 26) } finally { $script:srgTabResizing = $false } } function Invoke-srgDrawTab($Tabs, $e) { if ($e.Index -lt 0) { return } $c = $script:srgColors $sel = $e.Index -eq $Tabs.SelectedIndex $g = $e.Graphics # Flaeche hinter den Reitern einmalig dunkel fuellen if ($e.Index -eq 0) { $strip = New-Object System.Drawing.SolidBrush($c.Bg) $g.FillRectangle($strip, 0, 0, $Tabs.Width, $e.Bounds.Bottom + 3) $strip.Dispose() } $back = New-Object System.Drawing.SolidBrush($(if ($sel) { $c.Surface } else { $c.Bg })) $g.FillRectangle($back, $e.Bounds) $back.Dispose() if ($sel) { $bar = New-Object System.Drawing.SolidBrush($c.Accent) $g.FillRectangle($bar, $e.Bounds.X, $e.Bounds.Top, $e.Bounds.Width, 2) $bar.Dispose() } [System.Windows.Forms.TextRenderer]::DrawText($g, $Tabs.TabPages[$e.Index].Text, $Tabs.Font, $e.Bounds, $(if ($sel) { $c.Text } else { $c.Subtle }), [System.Windows.Forms.TextFormatFlags]::HorizontalCenter -bor [System.Windows.Forms.TextFormatFlags]::VerticalCenter) } function Set-srgDarkToolTip($Tip) { $Tip.OwnerDraw = $true $Tip.Add_Draw({ param($s, $e) $c = $script:srgColors $b = New-Object System.Drawing.SolidBrush($c.Surface) $e.Graphics.FillRectangle($b, $e.Bounds); $b.Dispose() $p = New-Object System.Drawing.Pen($c.Border) $e.Graphics.DrawRectangle($p, 0, 0, $e.Bounds.Width - 1, $e.Bounds.Height - 1); $p.Dispose() [System.Windows.Forms.TextRenderer]::DrawText($e.Graphics, $e.ToolTipText, $e.Font, $e.Bounds, $c.Text, [System.Windows.Forms.TextFormatFlags]::VerticalCenter -bor [System.Windows.Forms.TextFormatFlags]::Left -bor [System.Windows.Forms.TextFormatFlags]::WordBreak) }) } function Set-srgDarkMenu($Menu) { $c = $script:srgColors $Menu.BackColor = $c.Surface $Menu.ForeColor = $c.Text $Menu.ShowImageMargin = $false foreach ($it in $Menu.Items) { $it.BackColor = $c.Surface; $it.ForeColor = $c.Text } } function Set-srgSyntaxColor { <# Einfache Syntaxfaerbung (VS-Dark-Farben) fuer Kommandozeile, Batch und PowerShell. #> param($Box, [ValidateSet('Cmd', 'PowerShell')][string]$Language = 'Cmd') $c = $script:srgColors $text = $Box.Text if (-not $text) { return } $rules = New-Object System.Collections.Generic.List[object] if ($Language -eq 'Cmd') { $rules.Add(@('(?im)^\s*(robocopy|@echo|echo|set|if|exit|chcp)\b|\b(GEQ|off)\b', $c.SynKeyword)) $rules.Add(@('(?i)(?<=\s)/[A-Z0-9+]+(?=[:\s]|$)', $c.SynVariable)) $rules.Add(@('%%?\w+%?', $c.SynNumber)) $rules.Add(@('"[^"\r\n]*"', $c.SynString)) $rules.Add(@('(?m)^::[^\n]*', $c.SynComment)) } else { $rules.Add(@('(?i)\b(if|throw|else|foreach)\b|(?i)\b(New-ScheduledTask\w*|Register-ScheduledTask|Get-ScheduledTask|New-TimeSpan|Write-Host|Out-Null)\b', $c.SynKeyword)) $rules.Add(@('(?<![\w''])-[A-Za-z]+\b', $c.Subtle)) $rules.Add(@('\$\w+', $c.SynVariable)) $rules.Add(@("'(?:[^']|'')*'", $c.SynString)) $rules.Add(@('"[^"\r\n]*"', $c.SynString)) $rules.Add(@("(?<=')/[A-Za-z0-9+]+", $c.SynVariable)) $rules.Add(@('(?m)^#[^\n]*', $c.SynComment)) } $selStart = $Box.SelectionStart $Box.SuspendLayout() $Box.SelectAll(); $Box.SelectionColor = $Box.ForeColor foreach ($r in $rules) { foreach ($m in [regex]::Matches($text, $r[0])) { $Box.Select($m.Index, $m.Length) $Box.SelectionColor = $r[1] } } $Box.Select([math]::Min($selStart, $text.Length), 0) $Box.ResumeLayout() } |