8 Commits

Author SHA1 Message Date
e14598b92e Merge pull request 'hotkey-config' (#1) from hotkey-config into master
Reviewed-on: #1
2026-02-22 12:45:38 -05:00
86b4e10a83 Refactor MainWindow.xaml.cs to improve the visual feedback for active selections in navigation buttons, enhancing user experience. This update includes style adjustments to better indicate the currently selected page. 2026-02-22 12:42:09 -05:00
fa5bc81bd6 Implement visual style updates for navigation buttons in MainWindow.xaml.cs to indicate active selections. This change enhances user experience by providing clear feedback on the currently selected page. 2026-02-22 12:41:51 -05:00
fcd70b699d Refactor hotkey handling in MainWindow.xaml.cs to improve user experience by implementing a visual indicator for active hotkeys and enhancing the feedback mechanism during recording. Adjustments made to ensure better responsiveness and clarity in user interactions. 2026-02-22 12:36:49 -05:00
7f5d80ff68 Enhance hotkey recording functionality in MainWindow.xaml.cs by adding escape key support to cancel recording and improving error handling. Introduce a delayed registration mechanism to prevent immediate re-entry of hotkeys, ensuring stability during hotkey updates. 2026-02-22 12:33:55 -05:00
ae744f1077 Update MainWindow.xaml.cs to replace HotkeyRecorderText with HotkeyRecorderButton for displaying hotkey information, enhancing user interaction during hotkey recording. Adjustments made to ensure proper focus and event handling for the button. 2026-02-22 12:21:38 -05:00
9b73bdbb24 Refactor MainWindow.xaml to streamline the hotkey button definition by consolidating properties and removing unnecessary elements, improving code clarity. 2026-02-22 12:21:27 -05:00
4902802615 Update MainWindow.xaml to include a name and focus properties for the root grid, enhancing accessibility and usability. 2026-02-22 12:17:03 -05:00
4 changed files with 372 additions and 230 deletions

View File

@@ -8,9 +8,44 @@
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
<!-- Other merged dictionaries here -->
</ResourceDictionary.MergedDictionaries>
<!-- Other app resources here -->
<!-- ClipForge custom palette (less Windows, more app identity) -->
<SolidColorBrush x:Key="ClipForgeSidebarBrush" Color="#0A0A0E"/>
<SolidColorBrush x:Key="ClipForgeMainBrush" Color="#0F0F14"/>
<SolidColorBrush x:Key="ClipForgeCardBrush" Color="#16161D"/>
<SolidColorBrush x:Key="ClipForgeCardBorderBrush" Color="#252532"/>
<SolidColorBrush x:Key="ClipForgeAccentBrush" Color="#E8FF47"/>
<SolidColorBrush x:Key="ClipForgeTextPrimaryBrush" Color="#F0F0F5"/>
<SolidColorBrush x:Key="ClipForgeTextSecondaryBrush" Color="#8E8E9A"/>
<SolidColorBrush x:Key="ClipForgeNavHoverBrush" Color="#1E1E26"/>
<!-- Sidebar nav: default (unselected) -->
<Style x:Key="ClipForgeNavButtonStyle" TargetType="Button">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Foreground" Value="{StaticResource ClipForgeTextPrimaryBrush}"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="CornerRadius" Value="8"/>
<Setter Property="Padding" Value="12,10"/>
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="HorizontalContentAlignment" Value="Left"/>
</Style>
<!-- Sidebar nav: selected / accent -->
<Style x:Key="ClipForgeNavButtonSelectedStyle" TargetType="Button" BasedOn="{StaticResource ClipForgeNavButtonStyle}">
<Setter Property="Background" Value="{StaticResource ClipForgeAccentBrush}"/>
<Setter Property="Foreground" Value="#0A0A0E"/>
</Style>
<!-- Accent button (Save Settings, etc.) -->
<Style x:Key="ClipForgeAccentButtonStyle" TargetType="Button">
<Setter Property="Background" Value="{StaticResource ClipForgeAccentBrush}"/>
<Setter Property="Foreground" Value="#0A0A0E"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="CornerRadius" Value="8"/>
<Setter Property="Padding" Value="20,10"/>
<Setter Property="FontWeight" Value="SemiBold"/>
</Style>
</ResourceDictionary>
</Application.Resources>
</Application>

View File

@@ -13,136 +13,144 @@ namespace ClipForge
public const uint MOD_WIN = 0x0008;
public const uint MOD_NOREPEAT = 0x4000;
private static readonly Dictionary<VirtualKey, string> KeyNames = new()
// Built in static ctor with TryAdd so duplicate VirtualKey enum values (e.g. Kana/Hangul = 0x15) don't throw.
private static readonly Dictionary<VirtualKey, string> KeyNames = new();
static HotkeyHelper()
{
{ VirtualKey.LeftButton, "LMB" },
{ VirtualKey.RightButton, "RMB" },
{ VirtualKey.Cancel, "Cancel" },
{ VirtualKey.Back, "Backspace" },
{ VirtualKey.Tab, "Tab" },
{ VirtualKey.Clear, "Clear" },
{ VirtualKey.Enter, "Enter" },
{ VirtualKey.Shift, "Shift" },
{ VirtualKey.Control, "Ctrl" },
{ VirtualKey.Menu, "Alt" },
{ VirtualKey.Pause, "Pause" },
{ VirtualKey.CapitalLock, "Caps Lock" },
{ VirtualKey.Kana, "Kana" },
{ VirtualKey.Hangul, "Hangul" },
{ VirtualKey.Junja, "Junja" },
{ VirtualKey.Final, "Final" },
{ VirtualKey.Hanja, "Hanja" },
{ VirtualKey.Kanji, "Kanji" },
{ VirtualKey.Escape, "Escape" },
{ VirtualKey.Convert, "Convert" },
{ VirtualKey.NonConvert, "NonConvert" },
{ VirtualKey.Accept, "Accept" },
{ VirtualKey.ModeChange, "ModeChange" },
{ VirtualKey.Space, "Space" },
{ VirtualKey.PageUp, "PgUp" },
{ VirtualKey.PageDown, "PgDn" },
{ VirtualKey.End, "End" },
{ VirtualKey.Home, "Home" },
{ VirtualKey.Left, "Left" },
{ VirtualKey.Up, "Up" },
{ VirtualKey.Right, "Right" },
{ VirtualKey.Down, "Down" },
{ VirtualKey.Select, "Select" },
{ VirtualKey.Print, "Print" },
{ VirtualKey.Execute, "Execute" },
{ VirtualKey.Snapshot, "Print Screen" },
{ VirtualKey.Insert, "Insert" },
{ VirtualKey.Delete, "Delete" },
{ VirtualKey.Help, "Help" },
{ VirtualKey.Number0, "0" },
{ VirtualKey.Number1, "1" },
{ VirtualKey.Number2, "2" },
{ VirtualKey.Number3, "3" },
{ VirtualKey.Number4, "4" },
{ VirtualKey.Number5, "5" },
{ VirtualKey.Number6, "6" },
{ VirtualKey.Number7, "7" },
{ VirtualKey.Number8, "8" },
{ VirtualKey.Number9, "9" },
{ VirtualKey.A, "A" },
{ VirtualKey.B, "B" },
{ VirtualKey.C, "C" },
{ VirtualKey.D, "D" },
{ VirtualKey.E, "E" },
{ VirtualKey.F, "F" },
{ VirtualKey.G, "G" },
{ VirtualKey.H, "H" },
{ VirtualKey.I, "I" },
{ VirtualKey.J, "J" },
{ VirtualKey.K, "K" },
{ VirtualKey.L, "L" },
{ VirtualKey.M, "M" },
{ VirtualKey.N, "N" },
{ VirtualKey.O, "O" },
{ VirtualKey.P, "P" },
{ VirtualKey.Q, "Q" },
{ VirtualKey.R, "R" },
{ VirtualKey.S, "S" },
{ VirtualKey.T, "T" },
{ VirtualKey.U, "U" },
{ VirtualKey.V, "V" },
{ VirtualKey.W, "W" },
{ VirtualKey.X, "X" },
{ VirtualKey.Y, "Y" },
{ VirtualKey.Z, "Z" },
{ VirtualKey.LeftWindows, "Win" },
{ VirtualKey.RightWindows, "Win" },
{ VirtualKey.Application, "App" },
{ VirtualKey.Sleep, "Sleep" },
{ VirtualKey.NumberPad0, "Num 0" },
{ VirtualKey.NumberPad1, "Num 1" },
{ VirtualKey.NumberPad2, "Num 2" },
{ VirtualKey.NumberPad3, "Num 3" },
{ VirtualKey.NumberPad4, "Num 4" },
{ VirtualKey.NumberPad5, "Num 5" },
{ VirtualKey.NumberPad6, "Num 6" },
{ VirtualKey.NumberPad7, "Num 7" },
{ VirtualKey.NumberPad8, "Num 8" },
{ VirtualKey.NumberPad9, "Num 9" },
{ VirtualKey.Multiply, "Num *" },
{ VirtualKey.Add, "Num +" },
{ VirtualKey.Separator, "Num ," },
{ VirtualKey.Subtract, "Num -" },
{ VirtualKey.Decimal, "Num ." },
{ VirtualKey.Divide, "Num /" },
{ VirtualKey.F1, "F1" },
{ VirtualKey.F2, "F2" },
{ VirtualKey.F3, "F3" },
{ VirtualKey.F4, "F4" },
{ VirtualKey.F5, "F5" },
{ VirtualKey.F6, "F6" },
{ VirtualKey.F7, "F7" },
{ VirtualKey.F8, "F8" },
{ VirtualKey.F9, "F9" },
{ VirtualKey.F10, "F10" },
{ VirtualKey.F11, "F11" },
{ VirtualKey.F12, "F12" },
{ VirtualKey.F13, "F13" },
{ VirtualKey.F14, "F14" },
{ VirtualKey.F15, "F15" },
{ VirtualKey.F16, "F16" },
{ VirtualKey.F17, "F17" },
{ VirtualKey.F18, "F18" },
{ VirtualKey.F19, "F19" },
{ VirtualKey.F20, "F20" },
{ VirtualKey.F21, "F21" },
{ VirtualKey.F22, "F22" },
{ VirtualKey.F23, "F23" },
{ VirtualKey.F24, "F24" },
{ VirtualKey.NumberKeyLock, "NumLock" },
{ VirtualKey.Scroll, "Scroll Lock" },
{ VirtualKey.LeftShift, "Shift" },
{ VirtualKey.RightShift, "Shift" },
{ VirtualKey.LeftControl, "Ctrl" },
{ VirtualKey.RightControl, "Ctrl" },
{ VirtualKey.LeftMenu, "Alt" },
{ VirtualKey.RightMenu, "Alt" },
};
TryAdd(VirtualKey.LeftButton, "LMB");
TryAdd(VirtualKey.RightButton, "RMB");
TryAdd(VirtualKey.Cancel, "Cancel");
TryAdd(VirtualKey.Back, "Backspace");
TryAdd(VirtualKey.Tab, "Tab");
TryAdd(VirtualKey.Clear, "Clear");
TryAdd(VirtualKey.Enter, "Enter");
TryAdd(VirtualKey.Shift, "Shift");
TryAdd(VirtualKey.Control, "Ctrl");
TryAdd(VirtualKey.Menu, "Alt");
TryAdd(VirtualKey.Pause, "Pause");
TryAdd(VirtualKey.CapitalLock, "Caps Lock");
TryAdd(VirtualKey.Kana, "Kana");
TryAdd(VirtualKey.Hangul, "Hangul"); // same value as Kana on some SDKs; TryAdd skips duplicate
TryAdd(VirtualKey.Junja, "Junja");
TryAdd(VirtualKey.Final, "Final");
TryAdd(VirtualKey.Hanja, "Hanja");
TryAdd(VirtualKey.Kanji, "Kanji");
TryAdd(VirtualKey.Escape, "Escape");
TryAdd(VirtualKey.Convert, "Convert");
TryAdd(VirtualKey.NonConvert, "NonConvert");
TryAdd(VirtualKey.Accept, "Accept");
TryAdd(VirtualKey.ModeChange, "ModeChange");
TryAdd(VirtualKey.Space, "Space");
TryAdd(VirtualKey.PageUp, "PgUp");
TryAdd(VirtualKey.PageDown, "PgDn");
TryAdd(VirtualKey.End, "End");
TryAdd(VirtualKey.Home, "Home");
TryAdd(VirtualKey.Left, "Left");
TryAdd(VirtualKey.Up, "Up");
TryAdd(VirtualKey.Right, "Right");
TryAdd(VirtualKey.Down, "Down");
TryAdd(VirtualKey.Select, "Select");
TryAdd(VirtualKey.Print, "Print");
TryAdd(VirtualKey.Execute, "Execute");
TryAdd(VirtualKey.Snapshot, "Print Screen");
TryAdd(VirtualKey.Insert, "Insert");
TryAdd(VirtualKey.Delete, "Delete");
TryAdd(VirtualKey.Help, "Help");
TryAdd(VirtualKey.Number0, "0");
TryAdd(VirtualKey.Number1, "1");
TryAdd(VirtualKey.Number2, "2");
TryAdd(VirtualKey.Number3, "3");
TryAdd(VirtualKey.Number4, "4");
TryAdd(VirtualKey.Number5, "5");
TryAdd(VirtualKey.Number6, "6");
TryAdd(VirtualKey.Number7, "7");
TryAdd(VirtualKey.Number8, "8");
TryAdd(VirtualKey.Number9, "9");
TryAdd(VirtualKey.A, "A");
TryAdd(VirtualKey.B, "B");
TryAdd(VirtualKey.C, "C");
TryAdd(VirtualKey.D, "D");
TryAdd(VirtualKey.E, "E");
TryAdd(VirtualKey.F, "F");
TryAdd(VirtualKey.G, "G");
TryAdd(VirtualKey.H, "H");
TryAdd(VirtualKey.I, "I");
TryAdd(VirtualKey.J, "J");
TryAdd(VirtualKey.K, "K");
TryAdd(VirtualKey.L, "L");
TryAdd(VirtualKey.M, "M");
TryAdd(VirtualKey.N, "N");
TryAdd(VirtualKey.O, "O");
TryAdd(VirtualKey.P, "P");
TryAdd(VirtualKey.Q, "Q");
TryAdd(VirtualKey.R, "R");
TryAdd(VirtualKey.S, "S");
TryAdd(VirtualKey.T, "T");
TryAdd(VirtualKey.U, "U");
TryAdd(VirtualKey.V, "V");
TryAdd(VirtualKey.W, "W");
TryAdd(VirtualKey.X, "X");
TryAdd(VirtualKey.Y, "Y");
TryAdd(VirtualKey.Z, "Z");
TryAdd(VirtualKey.LeftWindows, "Win");
TryAdd(VirtualKey.RightWindows, "Win");
TryAdd(VirtualKey.Application, "App");
TryAdd(VirtualKey.Sleep, "Sleep");
TryAdd(VirtualKey.NumberPad0, "Num 0");
TryAdd(VirtualKey.NumberPad1, "Num 1");
TryAdd(VirtualKey.NumberPad2, "Num 2");
TryAdd(VirtualKey.NumberPad3, "Num 3");
TryAdd(VirtualKey.NumberPad4, "Num 4");
TryAdd(VirtualKey.NumberPad5, "Num 5");
TryAdd(VirtualKey.NumberPad6, "Num 6");
TryAdd(VirtualKey.NumberPad7, "Num 7");
TryAdd(VirtualKey.NumberPad8, "Num 8");
TryAdd(VirtualKey.NumberPad9, "Num 9");
TryAdd(VirtualKey.Multiply, "Num *");
TryAdd(VirtualKey.Add, "Num +");
TryAdd(VirtualKey.Separator, "Num ,");
TryAdd(VirtualKey.Subtract, "Num -");
TryAdd(VirtualKey.Decimal, "Num .");
TryAdd(VirtualKey.Divide, "Num /");
TryAdd(VirtualKey.F1, "F1");
TryAdd(VirtualKey.F2, "F2");
TryAdd(VirtualKey.F3, "F3");
TryAdd(VirtualKey.F4, "F4");
TryAdd(VirtualKey.F5, "F5");
TryAdd(VirtualKey.F6, "F6");
TryAdd(VirtualKey.F7, "F7");
TryAdd(VirtualKey.F8, "F8");
TryAdd(VirtualKey.F9, "F9");
TryAdd(VirtualKey.F10, "F10");
TryAdd(VirtualKey.F11, "F11");
TryAdd(VirtualKey.F12, "F12");
TryAdd(VirtualKey.F13, "F13");
TryAdd(VirtualKey.F14, "F14");
TryAdd(VirtualKey.F15, "F15");
TryAdd(VirtualKey.F16, "F16");
TryAdd(VirtualKey.F17, "F17");
TryAdd(VirtualKey.F18, "F18");
TryAdd(VirtualKey.F19, "F19");
TryAdd(VirtualKey.F20, "F20");
TryAdd(VirtualKey.F21, "F21");
TryAdd(VirtualKey.F22, "F22");
TryAdd(VirtualKey.F23, "F23");
TryAdd(VirtualKey.F24, "F24");
TryAdd(VirtualKey.NumberKeyLock, "NumLock");
TryAdd(VirtualKey.Scroll, "Scroll Lock");
TryAdd(VirtualKey.LeftShift, "Shift");
TryAdd(VirtualKey.RightShift, "Shift");
TryAdd(VirtualKey.LeftControl, "Ctrl");
TryAdd(VirtualKey.RightControl, "Ctrl");
TryAdd(VirtualKey.LeftMenu, "Alt");
TryAdd(VirtualKey.RightMenu, "Alt");
}
private static void TryAdd(VirtualKey key, string name)
{
KeyNames.TryAdd(key, name);
}
/// <summary>Format modifier flags + virtual key as display string (e.g. "Alt + PgUp").</summary>
public static string ToDisplayString(uint modifiers, uint vk)

View File

@@ -13,56 +13,71 @@
<MicaBackdrop />
</Window.SystemBackdrop>
<Grid>
<Grid x:Name="RootGrid" Background="{StaticResource ClipForgeMainBrush}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200"/>
<ColumnDefinition Width="220"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!-- SIDEBAR -->
<Border Grid.Column="0"
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
Background="{StaticResource ClipForgeSidebarBrush}"
BorderBrush="{StaticResource ClipForgeCardBorderBrush}"
BorderThickness="0,0,1,0">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="48"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- App title -->
<Border Grid.Row="0" Padding="16,0">
<TextBlock Text="CLIPFORGE"
FontSize="13"
FontWeight="Bold"
CharacterSpacing="80"
Foreground="#E8FF47"
<!-- Logo + wordmark -->
<Border Grid.Row="0" Padding="20,24,20,20" Margin="0,0,0,8">
<StackPanel Spacing="14" HorizontalAlignment="Left">
<Border Width="44" Height="44"
Background="{StaticResource ClipForgeAccentBrush}"
CornerRadius="10"
HorizontalAlignment="Left">
<TextBlock Text="&#xE8F1;"
FontFamily="Segoe MDL2 Assets"
FontSize="22"
Foreground="#0A0A0E"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Border>
<TextBlock Text="ClipForge"
FontSize="20"
FontWeight="Bold"
Foreground="{StaticResource ClipForgeAccentBrush}"
CharacterSpacing="60"/>
<TextBlock Text="Capture. Trim. Share."
FontSize="11"
Foreground="{StaticResource ClipForgeTextSecondaryBrush}"
Opacity="0.9"/>
</StackPanel>
</Border>
<!-- Nav items -->
<StackPanel Grid.Row="1" Spacing="2" Padding="8,8">
<StackPanel Grid.Row="1" Spacing="4" Padding="12,8" VerticalAlignment="Top">
<Button x:Name="NavClips"
HorizontalAlignment="Stretch"
Click="NavClips_Click"
Style="{StaticResource AccentButtonStyle}">
<StackPanel Orientation="Horizontal" Spacing="10">
Style="{StaticResource ClipForgeNavButtonSelectedStyle}">
<StackPanel Orientation="Horizontal" Spacing="12">
<TextBlock Text="&#xE8F1;"
FontFamily="Segoe MDL2 Assets"
FontSize="14"/>
FontSize="16"/>
<TextBlock Text="Clips"
FontSize="13"
FontWeight="SemiBold"/>
</StackPanel>
</Button>
<Button x:Name="NavSettings"
HorizontalAlignment="Stretch"
Click="NavSettings_Click">
<StackPanel Orientation="Horizontal" Spacing="10">
Click="NavSettings_Click"
Style="{StaticResource ClipForgeNavButtonStyle}">
<StackPanel Orientation="Horizontal" Spacing="12">
<TextBlock Text="&#xE713;"
FontFamily="Segoe MDL2 Assets"
FontSize="14"/>
FontSize="16"/>
<TextBlock Text="Settings"
FontSize="13"
FontWeight="SemiBold"/>
@@ -73,10 +88,15 @@
<!-- Record button -->
<Button x:Name="RecordButton"
Grid.Row="2"
Margin="8"
Margin="12,12,12,20"
HorizontalAlignment="Stretch"
Background="{StaticResource ClipForgeCardBrush}"
BorderBrush="{StaticResource ClipForgeCardBorderBrush}"
BorderThickness="1"
CornerRadius="8"
Padding="12,10"
Click="RecordButton_Click">
<StackPanel Orientation="Horizontal" Spacing="8">
<StackPanel Orientation="Horizontal" Spacing="10">
<Ellipse x:Name="RecordDot"
Width="8" Height="8"
Fill="#FF4757"/>
@@ -84,6 +104,7 @@
Text="CAPTURING"
FontSize="11"
FontWeight="Bold"
Foreground="{StaticResource ClipForgeTextPrimaryBrush}"
CharacterSpacing="40"/>
</StackPanel>
</Button>
@@ -91,7 +112,7 @@
</Border>
<!-- MAIN CONTENT -->
<Grid Grid.Column="1">
<Grid Grid.Column="1" Background="{StaticResource ClipForgeMainBrush}">
<!-- CLIPS PAGE -->
<Grid x:Name="ClipsPage" Visibility="Visible">
@@ -102,37 +123,44 @@
</Grid.RowDefinitions>
<!-- Header -->
<Border Grid.Row="0" Padding="24,20,24,0">
<Border Grid.Row="0" Padding="28,24,28,0">
<Grid>
<StackPanel Orientation="Horizontal" Spacing="12"
VerticalAlignment="Bottom">
<TextBlock Text="My Clips"
FontSize="24"
FontWeight="Bold"/>
FontSize="26"
FontWeight="Bold"
Foreground="{StaticResource ClipForgeTextPrimaryBrush}"/>
<TextBlock x:Name="ClipCountText"
Text="0 clips"
FontSize="12"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
FontSize="13"
Foreground="{StaticResource ClipForgeTextSecondaryBrush}"
VerticalAlignment="Bottom"
Margin="0,0,0,3"/>
Margin="0,0,0,4"/>
</StackPanel>
<Button Content="Open Folder"
HorizontalAlignment="Right"
Background="{StaticResource ClipForgeCardBrush}"
Foreground="{StaticResource ClipForgeTextPrimaryBrush}"
BorderBrush="{StaticResource ClipForgeCardBorderBrush}"
BorderThickness="1"
CornerRadius="8"
Padding="16,8"
Click="OpenFolder_Click"/>
</Grid>
</Border>
<!-- Toolbar -->
<Border Grid.Row="1" Padding="24,12">
<Border Grid.Row="1" Padding="28,16">
<AutoSuggestBox x:Name="SearchBox"
PlaceholderText="Search clips..."
Width="260"
Width="280"
HorizontalAlignment="Left"
TextChanged="SearchBox_TextChanged"/>
</Border>
<!-- Clip Grid -->
<ScrollViewer Grid.Row="2" Padding="24,0,24,24">
<ScrollViewer Grid.Row="2" Padding="28,0,28,28">
<ItemsControl x:Name="ClipGrid">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
@@ -143,11 +171,11 @@
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="local:ClipFile">
<Border Width="220"
Margin="0,0,12,12"
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
Margin="0,0,14,14"
Background="{StaticResource ClipForgeCardBrush}"
BorderBrush="{StaticResource ClipForgeCardBorderBrush}"
BorderThickness="1"
CornerRadius="8">
CornerRadius="10">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="124"/>
@@ -156,8 +184,8 @@
<!-- Thumbnail -->
<Border Grid.Row="0"
Background="#1a1a2e"
CornerRadius="8,8,0,0">
Background="{StaticResource ClipForgeSidebarBrush}"
CornerRadius="10,10,0,0">
<Grid>
<!-- Placeholder icon -->
<TextBlock Text="&#xE786;"
@@ -198,19 +226,23 @@
<TextBlock Text="{x:Bind Title}"
FontSize="12"
FontWeight="SemiBold"
Foreground="{StaticResource ClipForgeTextPrimaryBrush}"
TextTrimming="CharacterEllipsis"/>
<Grid>
<TextBlock Text="{x:Bind CreatedAtDisplay}"
FontSize="10"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"/>
Foreground="{StaticResource ClipForgeTextSecondaryBrush}"/>
<TextBlock Text="{x:Bind FileSize}"
FontSize="10"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Foreground="{StaticResource ClipForgeTextSecondaryBrush}"
HorizontalAlignment="Right"/>
</Grid>
<StackPanel Orientation="Horizontal" Spacing="6">
<Button Tag="{x:Bind Path}"
Click="TrimClip_Click"
Background="Transparent"
BorderThickness="0"
Foreground="{StaticResource ClipForgeTextSecondaryBrush}"
FontSize="11" Padding="8,4">
<TextBlock Text="&#xE8C6;"
FontFamily="Segoe MDL2 Assets"
@@ -218,6 +250,9 @@
</Button>
<Button Tag="{x:Bind Path}"
Click="RenameClip_Click"
Background="Transparent"
BorderThickness="0"
Foreground="{StaticResource ClipForgeTextSecondaryBrush}"
FontSize="11" Padding="8,4">
<TextBlock Text="&#xE8AC;"
FontFamily="Segoe MDL2 Assets"
@@ -225,6 +260,9 @@
</Button>
<Button Tag="{x:Bind Path}"
Click="DeleteClip_Click"
Background="Transparent"
BorderThickness="0"
Foreground="{StaticResource ClipForgeTextSecondaryBrush}"
FontSize="11" Padding="8,4">
<TextBlock Text="&#xE74D;"
FontFamily="Segoe MDL2 Assets"
@@ -243,33 +281,36 @@
<!-- SETTINGS PAGE -->
<Grid x:Name="SettingsPage" Visibility="Collapsed">
<ScrollViewer Padding="24">
<StackPanel Spacing="24" MaxWidth="520" HorizontalAlignment="Left">
<ScrollViewer Padding="28">
<StackPanel Spacing="24" MaxWidth="540" HorizontalAlignment="Left">
<TextBlock Text="Settings"
FontSize="24"
FontWeight="Bold"/>
FontSize="26"
FontWeight="Bold"
Foreground="{StaticResource ClipForgeTextPrimaryBrush}"/>
<!-- Clip Length -->
<Border Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
<Border Background="{StaticResource ClipForgeCardBrush}"
BorderBrush="{StaticResource ClipForgeCardBorderBrush}"
BorderThickness="1"
CornerRadius="8"
CornerRadius="10"
Padding="20">
<StackPanel Spacing="12">
<StackPanel Orientation="Horizontal" Spacing="8">
<TextBlock Text="&#xE714;"
FontFamily="Segoe MDL2 Assets"
FontSize="16"
Foreground="{StaticResource ClipForgeAccentBrush}"
VerticalAlignment="Center"/>
<TextBlock Text="Clip Length"
FontSize="14"
FontWeight="SemiBold"
Foreground="{StaticResource ClipForgeTextPrimaryBrush}"
VerticalAlignment="Center"/>
</StackPanel>
<TextBlock Text="How many seconds to save when you press the hotkey."
FontSize="12"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"/>
Foreground="{StaticResource ClipForgeTextSecondaryBrush}"/>
<Grid>
<Slider x:Name="ClipLengthSlider"
Minimum="10"
@@ -281,7 +322,7 @@
Text="30 seconds"
FontSize="12"
FontWeight="SemiBold"
Foreground="#E8FF47"
Foreground="{StaticResource ClipForgeAccentBrush}"
HorizontalAlignment="Right"
VerticalAlignment="Center"/>
</Grid>
@@ -289,25 +330,27 @@
</Border>
<!-- Video Quality -->
<Border Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
<Border Background="{StaticResource ClipForgeCardBrush}"
BorderBrush="{StaticResource ClipForgeCardBorderBrush}"
BorderThickness="1"
CornerRadius="8"
CornerRadius="10"
Padding="20">
<StackPanel Spacing="12">
<StackPanel Orientation="Horizontal" Spacing="8">
<TextBlock Text="&#xE7F4;"
FontFamily="Segoe MDL2 Assets"
FontSize="16"
Foreground="{StaticResource ClipForgeAccentBrush}"
VerticalAlignment="Center"/>
<TextBlock Text="Video Quality"
FontSize="14"
FontWeight="SemiBold"
Foreground="{StaticResource ClipForgeTextPrimaryBrush}"
VerticalAlignment="Center"/>
</StackPanel>
<TextBlock Text="Higher quality means larger file sizes."
FontSize="12"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"/>
Foreground="{StaticResource ClipForgeTextSecondaryBrush}"/>
<Grid>
<Slider x:Name="QualitySlider"
Minimum="10"
@@ -319,7 +362,7 @@
Text="70%"
FontSize="12"
FontWeight="SemiBold"
Foreground="#E8FF47"
Foreground="{StaticResource ClipForgeAccentBrush}"
HorizontalAlignment="Right"
VerticalAlignment="Center"/>
</Grid>
@@ -327,25 +370,27 @@
</Border>
<!-- Framerate -->
<Border Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
<Border Background="{StaticResource ClipForgeCardBrush}"
BorderBrush="{StaticResource ClipForgeCardBorderBrush}"
BorderThickness="1"
CornerRadius="8"
CornerRadius="10"
Padding="20">
<StackPanel Spacing="12">
<StackPanel Orientation="Horizontal" Spacing="8">
<TextBlock Text="&#xE7F8;"
FontFamily="Segoe MDL2 Assets"
FontSize="16"
Foreground="{StaticResource ClipForgeAccentBrush}"
VerticalAlignment="Center"/>
<TextBlock Text="Framerate"
FontSize="14"
FontWeight="SemiBold"
Foreground="{StaticResource ClipForgeTextPrimaryBrush}"
VerticalAlignment="Center"/>
</StackPanel>
<TextBlock Text="Higher framerates are smoother but use more storage."
FontSize="12"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"/>
Foreground="{StaticResource ClipForgeTextSecondaryBrush}"/>
<ComboBox x:Name="FramerateCombo"
SelectionChanged="FramerateCombo_SelectionChanged">
<ComboBoxItem Content="30 FPS"/>
@@ -355,63 +400,66 @@
</Border>
<!-- Hotkey -->
<Border Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
<Border Background="{StaticResource ClipForgeCardBrush}"
BorderBrush="{StaticResource ClipForgeCardBorderBrush}"
BorderThickness="1"
CornerRadius="8"
CornerRadius="10"
Padding="20">
<StackPanel Spacing="12">
<StackPanel Orientation="Horizontal" Spacing="8">
<TextBlock Text="&#xE92E;"
FontFamily="Segoe MDL2 Assets"
FontSize="16"
Foreground="{StaticResource ClipForgeAccentBrush}"
VerticalAlignment="Center"/>
<TextBlock Text="Clip Hotkey"
FontSize="14"
FontWeight="SemiBold"
Foreground="{StaticResource ClipForgeTextPrimaryBrush}"
VerticalAlignment="Center"/>
</StackPanel>
<TextBlock Text="Click the key below, then press your desired combination."
FontSize="12"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"/>
Foreground="{StaticResource ClipForgeTextSecondaryBrush}"/>
<Button x:Name="HotkeyRecorderButton"
HorizontalAlignment="Left"
Click="HotkeyRecorderButton_Click"
Background="#1a1a2e"
BorderThickness="0"
CornerRadius="6"
Background="{StaticResource ClipForgeSidebarBrush}"
BorderBrush="{StaticResource ClipForgeCardBorderBrush}"
BorderThickness="1"
CornerRadius="8"
Padding="16,10"
MinWidth="140">
<TextBlock x:Name="HotkeyRecorderText"
Text="Alt + F9"
MinWidth="140"
FontFamily="Consolas"
FontSize="14"
FontWeight="Bold"
Foreground="#E8FF47"/>
</Button>
Foreground="{StaticResource ClipForgeAccentBrush}"
Content="Alt + F9"/>
</StackPanel>
</Border>
<!-- Startup with Windows -->
<Border Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
<Border Background="{StaticResource ClipForgeCardBrush}"
BorderBrush="{StaticResource ClipForgeCardBorderBrush}"
BorderThickness="1"
CornerRadius="8"
CornerRadius="10"
Padding="20">
<StackPanel Spacing="12">
<StackPanel Orientation="Horizontal" Spacing="8">
<TextBlock Text="&#xE7E8;"
FontFamily="Segoe MDL2 Assets"
FontSize="16"
Foreground="{StaticResource ClipForgeAccentBrush}"
VerticalAlignment="Center"/>
<TextBlock Text="Startup"
FontSize="14"
FontWeight="SemiBold"
Foreground="{StaticResource ClipForgeTextPrimaryBrush}"
VerticalAlignment="Center"/>
</StackPanel>
<TextBlock Text="Launch ClipForge automatically when Windows starts."
FontSize="12"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"/>
Foreground="{StaticResource ClipForgeTextSecondaryBrush}"/>
<ToggleSwitch x:Name="StartupToggle"
OnContent="Enabled"
OffContent="Disabled"
@@ -422,7 +470,7 @@
<!-- Save button -->
<Button x:Name="SaveSettingsButton"
Content="Save Settings"
Style="{StaticResource AccentButtonStyle}"
Style="{StaticResource ClipForgeAccentButtonStyle}"
Click="SaveSettings_Click"
HorizontalAlignment="Left"/>

View File

@@ -182,8 +182,8 @@ namespace ClipForge
QualityLabel.Text = $"{s.VideoQuality}%";
FramerateCombo.SelectedIndex = s.Framerate == 30 ? 0 : 1;
StartupToggle.IsOn = IsStartupEnabled();
if (HotkeyRecorderText != null)
HotkeyRecorderText.Text = HotkeyHelper.ToDisplayString((uint)s.HotkeyModifiers, (uint)s.HotkeyVirtualKey);
if (HotkeyRecorderButton != null)
HotkeyRecorderButton.Content = HotkeyHelper.ToDisplayString((uint)s.HotkeyModifiers, (uint)s.HotkeyVirtualKey);
}
// --- STARTUP WITH WINDOWS ---
@@ -255,8 +255,9 @@ namespace ClipForge
{
if (_isRecordingHotkey) return;
_isRecordingHotkey = true;
HotkeyRecorderText.Text = "Press any key...";
this.KeyDown += OnHotkeyCaptureKeyDown;
HotkeyRecorderButton.Content = "Press any key... (Esc to cancel)";
HotkeyRecorderButton.Focus(FocusState.Programmatic);
HotkeyRecorderButton.KeyDown += OnHotkeyCaptureKeyDown;
}
private void OnHotkeyCaptureKeyDown(object sender, KeyRoutedEventArgs e)
@@ -264,9 +265,19 @@ namespace ClipForge
if (!_isRecordingHotkey) return;
e.Handled = true;
try
{
var key = e.Key;
// Escape cancels without changing the hotkey
if (key == VirtualKey.Escape)
{
StopRecordingHotkey(restoreDisplay: true);
return;
}
if (HotkeyHelper.IsModifierKey(key))
return; // wait for a non-modifier key
if (key == VirtualKey.None)
return;
uint mod = 0;
if ((GetAsyncKeyState(VK_CONTROL) & 0x8000) != 0) mod |= HotkeyHelper.MOD_CONTROL;
@@ -278,12 +289,48 @@ namespace ClipForge
_settingsService.Settings.HotkeyModifiers = (int)mod;
_settingsService.Settings.HotkeyVirtualKey = (int)vk;
var ok = _hotkeyService.UpdateHotkey(mod, vk);
var display = HotkeyHelper.ToDisplayString(mod, vk);
HotkeyRecorderText.Text = ok ? display : display + " (in use?)";
StopRecordingHotkey(restoreDisplay: false);
HotkeyRecorderButton.Content = display;
this.KeyDown -= OnHotkeyCaptureKeyDown;
// Defer registration so the key is released first; otherwise the new hotkey can fire
// immediately and re-enter (e.g. OnClipRequested) and crash.
_ = DelayedHotkeyRegister(mod, vk, display);
}
catch (Exception ex)
{
StopRecordingHotkey(restoreDisplay: true);
_ = ShowToastAsync("⚠ " + ex.Message);
}
}
private void StopRecordingHotkey(bool restoreDisplay)
{
HotkeyRecorderButton.KeyDown -= OnHotkeyCaptureKeyDown;
_isRecordingHotkey = false;
if (restoreDisplay)
{
var s = _settingsService.Settings;
HotkeyRecorderButton.Content = HotkeyHelper.ToDisplayString((uint)s.HotkeyModifiers, (uint)s.HotkeyVirtualKey);
}
}
private async System.Threading.Tasks.Task DelayedHotkeyRegister(uint mod, uint vk, string display)
{
await System.Threading.Tasks.Task.Delay(300);
App.MainQueue?.TryEnqueue(() =>
{
try
{
var ok = _hotkeyService.UpdateHotkey(mod, vk);
HotkeyRecorderButton.Content = ok ? display : display + " (in use?)";
}
catch (Exception ex)
{
HotkeyRecorderButton.Content = display;
_ = ShowToastAsync("⚠ " + ex.Message);
}
});
}
// --- NAV ---
@@ -291,12 +338,16 @@ namespace ClipForge
{
ClipsPage.Visibility = Visibility.Visible;
SettingsPage.Visibility = Visibility.Collapsed;
NavClips.Style = (Microsoft.UI.Xaml.Style)Application.Current.Resources["ClipForgeNavButtonSelectedStyle"];
NavSettings.Style = (Microsoft.UI.Xaml.Style)Application.Current.Resources["ClipForgeNavButtonStyle"];
}
private void NavSettings_Click(object sender, RoutedEventArgs e)
{
ClipsPage.Visibility = Visibility.Collapsed;
SettingsPage.Visibility = Visibility.Visible;
NavSettings.Style = (Microsoft.UI.Xaml.Style)Application.Current.Resources["ClipForgeNavButtonSelectedStyle"];
NavClips.Style = (Microsoft.UI.Xaml.Style)Application.Current.Resources["ClipForgeNavButtonStyle"];
}
private void RecordButton_Click(object sender, RoutedEventArgs e)