Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions CompactGUI/MainWindow.xaml.vb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
Imports System.ComponentModel
Imports System.Windows.Threading

Imports CompactGUI.Core.Settings

Expand All @@ -20,6 +21,8 @@ Class MainWindow : Implements INavigationWindow, INotifyPropertyChanged

Public Sub New(settingsService As ISettingsService, navigationService As INavigationService, serviceProvider As IServiceProvider, snackbarService As CustomSnackBarService, viewmodel As MainWindowViewModel)

CharcoalTheme.ApplyApplicationResources()

' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
Expand All @@ -34,9 +37,11 @@ Class MainWindow : Implements INavigationWindow, INotifyPropertyChanged
DataContext = viewmodel

ConfigureCompressNavigationItem()
CharcoalTheme.ApplyRootBackground(RootContentDialog)

NotifyIconTrayMenu.DataContext = viewmodel

AddHandler Loaded, AddressOf MainWindow_Loaded
AddHandler Application.GetService(Of HomeViewModel)().PropertyChanged, AddressOf HVPropertyChanged
AddHandler navigationService.GetNavigationControl.Navigated, AddressOf OnNavigated

Expand All @@ -56,6 +61,17 @@ Class MainWindow : Implements INavigationWindow, INotifyPropertyChanged
End Sub


Private Sub MainWindow_Loaded(sender As Object, e As RoutedEventArgs)
ApplyCharcoalPaletteAfterLayout()
End Sub

Private Sub ApplyCharcoalPaletteAfterLayout()
Dispatcher.BeginInvoke(
DispatcherPriority.Loaded,
New Action(Sub() CharcoalTheme.ApplyToVisualTree(Me)))
End Sub


Private Sub ConfigureCompressNavigationItem()
If NavigationView.MenuItems.Count = 0 Then Return

Expand All @@ -82,6 +98,8 @@ Class MainWindow : Implements INavigationWindow, INotifyPropertyChanged
_MainWindowViewModel.IsActive = False
ProgTitle.Visibility = Visibility.Visible
End If

ApplyCharcoalPaletteAfterLayout()
End Sub

Private Sub HVPropertyChanged(sender As Object, e As PropertyChangedEventArgs)
Expand Down
135 changes: 135 additions & 0 deletions CompactGUI/Services/CharcoalTheme.vb
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
Imports System.Windows.Controls
Imports System.Windows.Media
Imports System.Windows.Media.Imaging
Imports System.Windows.Shapes

Public Module CharcoalTheme

Private ReadOnly MutedColorMap As New Dictionary(Of Color, Color) From {
{Color.FromRgb(&H98, &HA9, &HB9), Color.FromRgb(&HB8, &HB8, &HB8)},
{Color.FromRgb(&H4E, &H63, &H79), Color.FromRgb(&H50, &H50, &H50)},
{Color.FromRgb(&H59, &H71, &H86), Color.FromRgb(&H68, &H68, &H68)},
{Color.FromRgb(&H4B, &H61, &H75), Color.FromRgb(&H5A, &H5A, &H5A)},
{Color.FromRgb(&H1F, &H34, &H48), Color.FromRgb(&H20, &H20, &H20)},
{Color.FromRgb(&HD, &H2A, &H41), Color.FromRgb(&H18, &H18, &H18)}
}

Public Sub ApplyApplicationResources()
If Application.Current Is Nothing Then Return

'Secondary/status text stays neutral gray, while interactive selection accents use
'the same crisp blue already present elsewhere in the CompactGUI navigation.
Application.Current.Resources("AccentFillColorDisabledBrush") =
New SolidColorBrush(Color.FromRgb(&HAA, &HAA, &HAA))

Dim selectionBlue As New SolidColorBrush(Color.FromRgb(&H4C, &HA5, &HFF))
Application.Current.Resources("CheckBoxCheckGlyphForeground") = selectionBlue
Application.Current.Resources("CheckBoxCheckBorderBrush") = selectionBlue
End Sub

Public Sub ApplyRootBackground(root As Grid)
If root Is Nothing Then Return

Dim backgroundLayers = root.Children.OfType(Of Border)().Take(3).ToArray()
If backgroundLayers.Length < 3 Then Return

backgroundLayers(0).Background = New SolidColorBrush(Color.FromRgb(&H1A, &H1A, &H1A))

'Keep the softly-lit charcoal look from the previous pass, but make the falloff much
'broader and lower-contrast. ScRGB interpolation plus a one-level dither layer below
'breaks up the visible WPF gradient contouring that showed up as large streaks.
Dim topGlow As New RadialGradientBrush With {
.Center = New Point(0.48, 0.02),
.GradientOrigin = New Point(0.48, -0.12),
.RadiusX = 1.35,
.RadiusY = 1.7,
.ColorInterpolationMode = ColorInterpolationMode.ScRgbLinearInterpolation
}
topGlow.GradientStops.Add(New GradientStop(Color.FromRgb(&H20, &H20, &H20), 0))
topGlow.GradientStops.Add(New GradientStop(Color.FromRgb(&H1E, &H1E, &H1E), 0.46))
topGlow.GradientStops.Add(New GradientStop(Color.FromRgb(&H1C, &H1C, &H1C), 0.78))
topGlow.GradientStops.Add(New GradientStop(Color.FromRgb(&H1A, &H1A, &H1A), 1))
backgroundLayers(1).Background = topGlow
backgroundLayers(1).Opacity = 1

backgroundLayers(2).Background = CreateDitherBrush()
backgroundLayers(2).Opacity = 1
End Sub

Private Function CreateDitherBrush() As Brush
Const tileSize As Integer = 64
Const bytesPerPixel As Integer = 4
Dim pixels(tileSize * tileSize * bytesPerPixel - 1) As Byte
Dim random As New Random(&H434755)

For pixelIndex = 0 To tileSize * tileSize - 1
Dim offset = pixelIndex * bytesPerPixel
Dim isLight = random.Next(0, 2) = 0

pixels(offset) = If(isLight, CByte(255), CByte(0))
pixels(offset + 1) = pixels(offset)
pixels(offset + 2) = pixels(offset)
pixels(offset + 3) = 1
Next

Dim bitmap As New WriteableBitmap(tileSize, tileSize, 96, 96, PixelFormats.Bgra32, Nothing)
bitmap.WritePixels(New Int32Rect(0, 0, tileSize, tileSize), pixels, tileSize * bytesPerPixel, 0)
bitmap.Freeze()

Dim brush As New ImageBrush(bitmap) With {
.TileMode = TileMode.Tile,
.ViewportUnits = BrushMappingMode.Absolute,
.ViewboxUnits = BrushMappingMode.Absolute,
.Viewport = New Rect(0, 0, tileSize, tileSize),
.Viewbox = New Rect(0, 0, tileSize, tileSize),
.Stretch = Stretch.None
}
brush.Freeze()
Return brush
End Function

Public Sub ApplyToVisualTree(root As DependencyObject)
If root Is Nothing Then Return

ApplyMutedPalette(root)

For index = 0 To VisualTreeHelper.GetChildrenCount(root) - 1
ApplyToVisualTree(VisualTreeHelper.GetChild(root, index))
Next
End Sub

Private Sub ApplyMutedPalette(element As DependencyObject)
Dim textBlock = TryCast(element, TextBlock)
If textBlock IsNot Nothing Then textBlock.Foreground = MapBrush(textBlock.Foreground)

Dim control = TryCast(element, Control)
If control IsNot Nothing Then
control.Foreground = MapBrush(control.Foreground)
control.Background = MapBrush(control.Background)
control.BorderBrush = MapBrush(control.BorderBrush)
End If

Dim border = TryCast(element, Border)
If border IsNot Nothing Then
border.Background = MapBrush(border.Background)
border.BorderBrush = MapBrush(border.BorderBrush)
End If

Dim shape = TryCast(element, Shape)
If shape IsNot Nothing Then
shape.Fill = MapBrush(shape.Fill)
shape.Stroke = MapBrush(shape.Stroke)
End If
End Sub

Private Function MapBrush(brush As Brush) As Brush
Dim solid = TryCast(brush, SolidColorBrush)
If solid Is Nothing Then Return brush

Dim replacement As Color
If Not MutedColorMap.TryGetValue(solid.Color, replacement) Then Return brush

Return New SolidColorBrush(Color.FromArgb(solid.Color.A, replacement.R, replacement.G, replacement.B))
End Function

End Module
24 changes: 10 additions & 14 deletions CompactGUI/Views/Components/CompressionMode_Radio.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -156,17 +156,6 @@

</Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CheckStates">
<VisualState x:Name="Checked">
<Storyboard>
<ColorAnimation Storyboard.TargetName="CheckMark"
Storyboard.TargetProperty="(BorderBrush).(SolidColorBrush.Color)" To="#92F1AB"
Duration="0:0:0.4" />
</Storyboard>
</VisualState>
<VisualState x:Name="Unchecked" />
<VisualState x:Name="Indeterminate" />
</VisualStateGroup>
<VisualStateGroup x:Name="HoverStates">
<VisualState x:Name="MouseOver">
<Storyboard>
Expand All @@ -189,8 +178,6 @@
Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleY)" To="0.3"
Duration="0:0:0.2" />



<DoubleAnimation Storyboard.TargetName="BytesAfter_Text"
Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.Y)" To="20"
Duration="0:0:0.2">
Expand Down Expand Up @@ -240,7 +227,6 @@
Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleY)" To="1"
Duration="0:0:0.2" />


<DoubleAnimation Storyboard.TargetName="BytesAfter_Text"
Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.Y)" To="0"
Duration="0:0:0.2">
Expand Down Expand Up @@ -276,6 +262,16 @@
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</ui:Card>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter TargetName="CheckMark" Property="BorderBrush" Value="#4CA5FF" />
<Setter TargetName="CheckMark" Property="BorderThickness" Value="2" />
</Trigger>
<Trigger Property="IsChecked" Value="False">
<Setter TargetName="CheckMark" Property="BorderBrush" Value="#38FFFFFF" />
<Setter TargetName="CheckMark" Property="BorderThickness" Value="1" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</RadioButton.Template>
</RadioButton>
35 changes: 35 additions & 0 deletions CompactGUI/Views/Components/CompressionMode_Radio.xaml.vb
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
Public Class CompressionMode_Radio
Inherits RadioButton

Private Shared ReadOnly SelectionBlueBorder As Brush = New SolidColorBrush(Color.FromRgb(&H4C, &HA5, &HFF))
Private Shared ReadOnly UnselectedModeBorder As Brush = New SolidColorBrush(Color.FromArgb(&H38, &HFF, &HFF, &HFF))

Public Shared ReadOnly CompressionModeProperty As DependencyProperty = DependencyProperty.RegisterAttached(
NameOf(CompressionMode),
Expand Down Expand Up @@ -170,17 +172,49 @@
InitializeComponent()
AddHandler Me.Loaded, AddressOf OnLoaded
AddHandler Me.Unloaded, AddressOf OnUnloaded
AddHandler Me.Checked, AddressOf OnSelectionStateChanged
AddHandler Me.Unchecked, AddressOf OnSelectionStateChanged
End Sub

Private Sub OnLoaded(sender As Object, e As RoutedEventArgs)
RemoveHandler GlobalHoverChanged, AddressOf OnGlobalHoverChanged
AddHandler GlobalHoverChanged, AddressOf OnGlobalHoverChanged
ApplySelectionBorder()
End Sub

Private Sub OnUnloaded(sender As Object, e As RoutedEventArgs)
RemoveHandler GlobalHoverChanged, AddressOf OnGlobalHoverChanged
End Sub

Private Sub OnSelectionStateChanged(sender As Object, e As RoutedEventArgs)
ApplySelectionBorder()
End Sub

Private Sub ApplySelectionBorder()
If Template Is Nothing Then Return

Dim card = TryCast(Template.FindName("CheckMark", Me), Wpf.Ui.Controls.Card)
If card Is Nothing Then Return

Dim selected = IsChecked.GetValueOrDefault(False)
Dim borderBrush = If(selected, SelectionBlueBorder, UnselectedModeBorder)
Dim borderThickness = If(selected, New Thickness(2), New Thickness(1))

'Set the Card itself, then also set its rendered ContentBorder directly. The latter
'avoids WPF-UI template/style precedence swallowing the selected outline on some states.
card.BorderBrush = borderBrush
card.BorderThickness = borderThickness
card.ApplyTemplate()

If card.Template IsNot Nothing Then
Dim renderedBorder = TryCast(card.Template.FindName("ContentBorder", card), Border)
If renderedBorder IsNot Nothing Then
renderedBorder.BorderBrush = borderBrush
renderedBorder.BorderThickness = borderThickness
End If
End If
End Sub

Private Sub OnGlobalHoverChanged(sender As Object, e As EventArgs)
' Update the local dependency property to trigger visual state
SetValue(IsGloballyHoveredProperty, IsAnyHovered)
Expand Down Expand Up @@ -226,6 +260,7 @@

Public Overrides Sub OnApplyTemplate()
MyBase.OnApplyTemplate()
ApplySelectionBorder()
If IsForcedDetailed Then
VisualStateManager.GoToState(Me, "MouseOver", False)
End If
Expand Down
5 changes: 5 additions & 0 deletions CompactGUI/Views/Pages/PendingCompression.xaml.vb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ Public Class PendingCompression
Sub New()
InitializeComponent()
_settingsService = Application.GetService(Of ISettingsService)
AddHandler Loaded, AddressOf PendingCompression_Loaded
End Sub

Private Sub PendingCompression_Loaded(sender As Object, e As RoutedEventArgs)
CharcoalTheme.ApplyToVisualTree(Me)
End Sub

Private Sub CompressionMode_Radio_Checked(sender As Object, e As RoutedEventArgs)
Expand Down
Loading