2 Commits
Author SHA1 Message Date
alex 4602fbc22b reflow to vertical 2026-08-14 02:11:58 +05:00
alex 5dea510bbc fixed msi pipeline
Release / release (push) Successful in 5m10s
2026-08-13 17:13:51 +05:00
4 changed files with 379 additions and 366 deletions
+324 -346
View File
@@ -8,7 +8,7 @@
mc:Ignorable="d" mc:Ignorable="d"
d:DataContext="{d:DesignInstance Type=vm:SettingsViewModel}" d:DataContext="{d:DesignInstance Type=vm:SettingsViewModel}"
Title="{Binding Title}" Title="{Binding Title}"
Width="1000" SizeToContent="Height" MaxHeight="900" Width="560" SizeToContent="Height" MaxHeight="940"
ResizeMode="CanMinimize" ResizeMode="CanMinimize"
Background="{DynamicResource Theme.WindowBackground}" Background="{DynamicResource Theme.WindowBackground}"
Foreground="{DynamicResource Theme.Foreground}"> Foreground="{DynamicResource Theme.Foreground}">
@@ -59,370 +59,348 @@
</Style> </Style>
</Window.Resources> </Window.Resources>
<!-- The settings are laid out in two columns: this way the window fits on the
screen entirely and does without scrolling. Scrolling is kept for the case of
a large system font, with which the content is taller than the monitor after all.
The left column holds what the popup does; the right one holds the single
section describing how and where the popup looks -->
<ScrollViewer VerticalScrollBarVisibility="Auto" Padding="16"> <ScrollViewer VerticalScrollBarVisibility="Auto" Padding="16">
<Grid> <StackPanel>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<StackPanel> <GroupBox Header="{Binding Localization[SectionInterface]}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="164" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<GroupBox Header="{Binding Localization[SectionInterface]}"> <TextBlock Style="{StaticResource FieldLabel}"
<Grid> Text="{Binding Localization[LanguageLabel]}" />
<Grid.ColumnDefinitions> <ComboBox Grid.Column="1"
<ColumnDefinition Width="164" /> ItemsSource="{Binding Localization.AvailableLanguages}"
<ColumnDefinition Width="*" /> DisplayMemberPath="DisplayName"
</Grid.ColumnDefinitions> SelectedValuePath="Code"
<Grid.RowDefinitions> SelectedValue="{Binding Settings.Language}" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Style="{StaticResource FieldLabel}" <TextBlock Grid.Row="1" Margin="0,12,12,0"
Text="{Binding Localization[LanguageLabel]}" /> Style="{StaticResource FieldLabel}"
<ComboBox Grid.Column="1" Text="{Binding Localization[ThemeLabel]}" />
ItemsSource="{Binding Localization.AvailableLanguages}" <ComboBox Grid.Row="1" Grid.Column="1" Margin="0,12,0,0"
DisplayMemberPath="DisplayName" ItemsSource="{Binding Themes}"
SelectedValuePath="Code" ItemTemplate="{StaticResource EnumOptionTemplate}"
SelectedValue="{Binding Settings.Language}" /> SelectedValuePath="Value"
SelectedValue="{Binding Settings.Theme}" />
</Grid>
</GroupBox>
<TextBlock Grid.Row="1" Margin="0,12,12,0" <GroupBox Header="{Binding Localization[SectionPopup]}">
Style="{StaticResource FieldLabel}" <Grid>
Text="{Binding Localization[ThemeLabel]}" /> <Grid.ColumnDefinitions>
<ComboBox Grid.Row="1" Grid.Column="1" Margin="0,12,0,0" <ColumnDefinition Width="164" />
ItemsSource="{Binding Themes}" <ColumnDefinition Width="*" />
ItemTemplate="{StaticResource EnumOptionTemplate}" <ColumnDefinition Width="Auto" />
SelectedValuePath="Value" </Grid.ColumnDefinitions>
SelectedValue="{Binding Settings.Theme}" /> <Grid.RowDefinitions>
</Grid> <RowDefinition Height="Auto" />
</GroupBox> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<GroupBox Header="{Binding Localization[SectionBehavior]}"> <TextBlock Style="{StaticResource FieldLabel}">
<Grid> <Run Text="{Binding Localization[PlacementModeLabel], Mode=OneWay}" />
<Grid.ColumnDefinitions> <InlineUIContainer BaselineAlignment="Baseline">
<ColumnDefinition Width="164" /> <TextBlock Text="{Binding Localization[MoreInfoLink]}"
<ColumnDefinition Width="*" /> Foreground="{DynamicResource Theme.Accent}"
<ColumnDefinition Width="Auto" /> TextDecorations="Underline"
</Grid.ColumnDefinitions> Cursor="Help"
<Grid.RowDefinitions> ToolTipService.InitialShowDelay="200"
<RowDefinition Height="Auto" /> ToolTipService.ShowDuration="60000">
<RowDefinition Height="Auto" /> <TextBlock.ToolTip>
<RowDefinition Height="Auto" /> <ToolTip>
<RowDefinition Height="Auto" /> <TextBlock TextWrapping="Wrap" MaxWidth="320"
<RowDefinition Height="Auto" /> Text="{Binding Localization[PopupLookPerModeHint]}" />
<RowDefinition Height="Auto" /> </ToolTip>
</Grid.RowDefinitions> </TextBlock.ToolTip>
</TextBlock>
</InlineUIContainer>
</TextBlock>
<ComboBox Grid.Column="1" Grid.ColumnSpan="2"
ItemsSource="{Binding PlacementModes}"
ItemTemplate="{StaticResource EnumOptionTemplate}"
SelectedValuePath="Value"
SelectedValue="{Binding Settings.PlacementMode}" />
<TextBlock Style="{StaticResource FieldLabel}" <!-- The "at cursor" mode: a side and an offset of its own -->
Text="{Binding Localization[DurationLabel]}" /> <TextBlock Grid.Row="1" Margin="0,12,12,0"
<Slider Grid.Column="1" Minimum="200" Maximum="5000" TickFrequency="100" Style="{StaticResource FieldLabel}"
Value="{Binding Settings.DurationMilliseconds}" /> Text="{Binding Localization[CursorCornerLabel]}"
<StackPanel Grid.Column="2" Orientation="Horizontal" VerticalAlignment="Center"> Visibility="{Binding Settings.PlacementMode,
<TextBlock Style="{StaticResource FieldValue}" Converter={StaticResource EnumToVisibility},
Text="{Binding Settings.DurationMilliseconds, StringFormat={}{0:F0}}" /> ConverterParameter=AtCursor}" />
<TextBlock Margin="4,0,0,0" <ComboBox Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="2" Margin="0,12,0,0"
Foreground="{DynamicResource Theme.SecondaryForeground}" ItemsSource="{Binding AnchorSides}"
Text="{Binding Localization[MillisecondsSuffix]}" /> ItemTemplate="{StaticResource EnumOptionTemplate}"
</StackPanel> SelectedValuePath="Value"
SelectedValue="{Binding Settings.AtCursor.Side}"
Visibility="{Binding Settings.PlacementMode,
Converter={StaticResource EnumToVisibility},
ConverterParameter=AtCursor}" />
<TextBlock Grid.Row="1" Margin="0,12,12,0" <TextBlock Grid.Row="2" Margin="0,12,12,0"
Style="{StaticResource FieldLabel}" Style="{StaticResource FieldLabel}"
Text="{Binding Localization[CapsLockLabel]}" /> Text="{Binding Localization[CursorOffsetLabel]}"
<CheckBox Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="2" Margin="0,12,0,0" Visibility="{Binding Settings.PlacementMode,
IsChecked="{Binding Settings.UseCapsLockHotkey}" Converter={StaticResource EnumToVisibility},
Content="{Binding Localization[CapsLockHotkeyCheck]}" /> ConverterParameter=AtCursor}" />
<Slider Grid.Row="2" Grid.Column="1" Margin="0,12,0,0"
Minimum="0" Maximum="80" TickFrequency="1"
Value="{Binding Settings.AtCursor.Offset}"
Visibility="{Binding Settings.PlacementMode,
Converter={StaticResource EnumToVisibility},
ConverterParameter=AtCursor}" />
<TextBlock Grid.Row="2" Grid.Column="2" Margin="12,12,0,0"
Style="{StaticResource FieldValue}"
Text="{Binding Settings.AtCursor.Offset, StringFormat={}{0:F0}}"
Visibility="{Binding Settings.PlacementMode,
Converter={StaticResource EnumToVisibility},
ConverterParameter=AtCursor}" />
<TextBlock Grid.Row="2" Margin="0,12,12,0" <!-- The "at caret" mode: a side and an offset of its own -->
Style="{StaticResource FieldLabel}" <TextBlock Grid.Row="3" Margin="0,12,12,0"
Text="{Binding Localization[CapsLockHoldLabel]}" /> Style="{StaticResource FieldLabel}"
<Slider Grid.Row="2" Grid.Column="1" Margin="0,12,0,0" Text="{Binding Localization[CursorCornerLabel]}"
Minimum="150" Maximum="1500" TickFrequency="50" Visibility="{Binding Settings.PlacementMode,
Value="{Binding Settings.CapsLockHoldMilliseconds}" Converter={StaticResource EnumToVisibility},
IsEnabled="{Binding Settings.UseCapsLockHotkey}" /> ConverterParameter=AtCaret}" />
<StackPanel Grid.Row="2" Grid.Column="2" Margin="0,12,0,0" <ComboBox Grid.Row="3" Grid.Column="1" Grid.ColumnSpan="2" Margin="0,12,0,0"
Orientation="Horizontal" VerticalAlignment="Center"> ItemsSource="{Binding CaretSides}"
<TextBlock Style="{StaticResource FieldValue}" ItemTemplate="{StaticResource EnumOptionTemplate}"
Text="{Binding Settings.CapsLockHoldMilliseconds, StringFormat={}{0:F0}}" /> SelectedValuePath="Value"
<TextBlock Margin="4,0,0,0" SelectedValue="{Binding Settings.AtCaret.Side}"
Foreground="{DynamicResource Theme.SecondaryForeground}" Visibility="{Binding Settings.PlacementMode,
Text="{Binding Localization[MillisecondsSuffix]}" /> Converter={StaticResource EnumToVisibility},
</StackPanel> ConverterParameter=AtCaret}" />
<TextBlock Grid.Row="3" Grid.Column="1" Grid.ColumnSpan="2" <TextBlock Grid.Row="4" Margin="0,12,12,0"
Margin="0,6,0,0" TextWrapping="Wrap" Style="{StaticResource FieldLabel}"
Foreground="{DynamicResource Theme.SecondaryForeground}"> Text="{Binding Localization[CursorOffsetLabel]}"
<Run Text="{Binding Localization[CapsLockHoldHint], Mode=OneWay}" /> Visibility="{Binding Settings.PlacementMode,
<InlineUIContainer BaselineAlignment="Baseline"> Converter={StaticResource EnumToVisibility},
<!-- The elevation caveat lives in the tooltip to keep the section compact --> ConverterParameter=AtCaret}" />
<TextBlock Text="{Binding Localization[MoreInfoLink]}" <Slider Grid.Row="4" Grid.Column="1" Margin="0,12,0,0"
Foreground="{DynamicResource Theme.Accent}" Minimum="0" Maximum="80" TickFrequency="1"
TextDecorations="Underline" Value="{Binding Settings.AtCaret.Offset}"
Cursor="Help" Visibility="{Binding Settings.PlacementMode,
ToolTipService.InitialShowDelay="200" Converter={StaticResource EnumToVisibility},
ToolTipService.ShowDuration="60000" ConverterParameter=AtCaret}" />
Visibility="{Binding Settings.UseCapsLockHotkey, Converter={StaticResource BooleanToVisibility}}"> <TextBlock Grid.Row="4" Grid.Column="2" Margin="12,12,0,0"
<TextBlock.ToolTip> Style="{StaticResource FieldValue}"
<ToolTip> Text="{Binding Settings.AtCaret.Offset, StringFormat={}{0:F0}}"
<TextBlock TextWrapping="Wrap" Visibility="{Binding Settings.PlacementMode,
Text="{Binding Localization[CapsLockElevationHint]}" /> Converter={StaticResource EnumToVisibility},
</ToolTip> ConverterParameter=AtCaret}" />
</TextBlock.ToolTip>
</TextBlock>
</InlineUIContainer>
</TextBlock>
<TextBlock Grid.Row="4" Margin="0,12,12,0" <!-- The "fixed point" mode -->
Style="{StaticResource FieldLabel}" <TextBlock Grid.Row="5" Margin="0,12,12,0"
Visibility="{Binding IsStartupAvailable, Converter={StaticResource BooleanToVisibility}}" Style="{StaticResource FieldLabel}"
Text="{Binding Localization[StartupLabel]}" /> Text="{Binding Localization[ScreenPositionLabel]}"
<CheckBox Grid.Row="4" Grid.Column="1" Grid.ColumnSpan="2" Margin="0,12,0,0" Visibility="{Binding Settings.PlacementMode,
Visibility="{Binding IsStartupAvailable, Converter={StaticResource BooleanToVisibility}}" Converter={StaticResource EnumToVisibility},
IsEnabled="{Binding CanChangeStartup}" ConverterParameter=FixedPoint}" />
IsChecked="{Binding RunAtStartup}" <ComboBox Grid.Row="5" Grid.Column="1" Grid.ColumnSpan="2" Margin="0,12,0,0"
Content="{Binding Localization[StartupCheck]}" /> ItemsSource="{Binding ScreenPositions}"
ItemTemplate="{StaticResource EnumOptionTemplate}"
SelectedValuePath="Value"
SelectedValue="{Binding Settings.FixedPoint.Position}"
Visibility="{Binding Settings.PlacementMode,
Converter={StaticResource EnumToVisibility},
ConverterParameter=FixedPoint}" />
<TextBlock Grid.Row="5" Grid.Column="1" Grid.ColumnSpan="2" <TextBlock Grid.Row="6" Margin="0,12,12,0"
Margin="0,6,0,0" TextWrapping="Wrap" Style="{StaticResource FieldLabel}"
Foreground="{DynamicResource Theme.SecondaryForeground}" Text="{Binding Localization[ScreenMarginLabel]}"
Visibility="{Binding IsStartupLocked, Converter={StaticResource BooleanToVisibility}}" IsEnabled="{Binding Settings.FixedPoint.IsAtAnEdge}"
Text="{Binding Localization[StartupLockedHint]}" /> Visibility="{Binding Settings.PlacementMode,
</Grid> Converter={StaticResource EnumToVisibility},
</GroupBox> ConverterParameter=FixedPoint}" />
<Slider Grid.Row="6" Grid.Column="1" Margin="0,12,0,0"
Minimum="0" Maximum="200" TickFrequency="1"
Value="{Binding Settings.FixedPoint.Offset}"
IsEnabled="{Binding Settings.FixedPoint.IsAtAnEdge}"
Visibility="{Binding Settings.PlacementMode,
Converter={StaticResource EnumToVisibility},
ConverterParameter=FixedPoint}" />
<TextBlock Grid.Row="6" Grid.Column="2" Margin="12,12,0,0"
Style="{StaticResource FieldValue}"
Text="{Binding Settings.FixedPoint.Offset, StringFormat={}{0:F0}}"
IsEnabled="{Binding Settings.FixedPoint.IsAtAnEdge}"
Visibility="{Binding Settings.PlacementMode,
Converter={StaticResource EnumToVisibility},
ConverterParameter=FixedPoint}" />
</StackPanel> <Border Grid.Row="7" Grid.ColumnSpan="3"
Margin="0,16,0,0" Height="1"
Background="{DynamicResource Theme.ControlBorder}" />
<StackPanel Grid.Column="1" Margin="16,0,0,0"> <TextBlock Grid.Row="8" Margin="0,12,12,0"
Style="{StaticResource FieldLabel}"
Text="{Binding Localization[FontSizeLabel]}" />
<Slider Grid.Row="8" Grid.Column="1" Margin="0,12,0,0"
Minimum="10" Maximum="72" TickFrequency="1"
Value="{Binding Settings.Current.FontSize}" />
<TextBlock Grid.Row="8" Grid.Column="2" Margin="12,12,0,0"
Style="{StaticResource FieldValue}"
Text="{Binding Settings.Current.FontSize, StringFormat={}{0:F0}}" />
<!-- Where the popup appears and how it looks are one question for the <TextBlock Grid.Row="9" Margin="0,12,12,0"
user, so both live in a single section: the rule is picked at the Style="{StaticResource FieldLabel}"
top and its result is seen in the preview at the bottom --> Text="{Binding Localization[OpacityLabel]}" />
<GroupBox Header="{Binding Localization[SectionPopup]}"> <Slider Grid.Row="9" Grid.Column="1" Margin="0,12,0,0"
<Grid> Minimum="0.1" Maximum="1" TickFrequency="0.05"
<Grid.ColumnDefinitions> Value="{Binding Settings.Current.Opacity}" />
<ColumnDefinition Width="164" /> <TextBlock Grid.Row="9" Grid.Column="2" Margin="12,12,0,0"
<ColumnDefinition Width="*" /> Style="{StaticResource FieldValue}"
<ColumnDefinition Width="Auto" /> Text="{Binding Settings.Current.Opacity, StringFormat={}{0:P0}}" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Style="{StaticResource FieldLabel}"> <TextBlock Grid.Row="10" Margin="0,12,12,0"
<Run Text="{Binding Localization[PlacementModeLabel], Mode=OneWay}" /> Style="{StaticResource FieldLabel}"
<InlineUIContainer BaselineAlignment="Baseline"> Text="{Binding Localization[BackgroundColorLabel]}" />
<TextBlock Text="{Binding Localization[MoreInfoLink]}" <ComboBox Grid.Row="10" Grid.Column="1" Grid.ColumnSpan="2" Margin="0,12,0,0"
Foreground="{DynamicResource Theme.Accent}" ItemsSource="{Binding BackgroundPalette}"
TextDecorations="Underline" ItemTemplate="{StaticResource ColorSwatchTemplate}"
Cursor="Help" SelectedItem="{Binding Settings.Current.BackgroundColor}" />
ToolTipService.InitialShowDelay="200"
ToolTipService.ShowDuration="60000">
<TextBlock.ToolTip>
<ToolTip>
<TextBlock TextWrapping="Wrap" MaxWidth="320"
Text="{Binding Localization[PopupLookPerModeHint]}" />
</ToolTip>
</TextBlock.ToolTip>
</TextBlock>
</InlineUIContainer>
</TextBlock>
<ComboBox Grid.Column="1" Grid.ColumnSpan="2"
ItemsSource="{Binding PlacementModes}"
ItemTemplate="{StaticResource EnumOptionTemplate}"
SelectedValuePath="Value"
SelectedValue="{Binding Settings.PlacementMode}" />
<!-- The "at cursor" mode: a side and an offset of its own --> <TextBlock Grid.Row="11" Margin="0,12,12,0"
<TextBlock Grid.Row="1" Margin="0,12,12,0" Style="{StaticResource FieldLabel}"
Style="{StaticResource FieldLabel}" Text="{Binding Localization[TextColorLabel]}" />
Text="{Binding Localization[CursorCornerLabel]}" <ComboBox Grid.Row="11" Grid.Column="1" Grid.ColumnSpan="2" Margin="0,12,0,0"
Visibility="{Binding Settings.PlacementMode, ItemsSource="{Binding TextPalette}"
Converter={StaticResource EnumToVisibility}, ItemTemplate="{StaticResource ColorSwatchTemplate}"
ConverterParameter=AtCursor}" /> SelectedItem="{Binding Settings.Current.ForegroundColor}" />
<ComboBox Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="2" Margin="0,12,0,0"
ItemsSource="{Binding AnchorSides}"
ItemTemplate="{StaticResource EnumOptionTemplate}"
SelectedValuePath="Value"
SelectedValue="{Binding Settings.AtCursor.Side}"
Visibility="{Binding Settings.PlacementMode,
Converter={StaticResource EnumToVisibility},
ConverterParameter=AtCursor}" />
<TextBlock Grid.Row="2" Margin="0,12,12,0" <TextBlock Grid.Row="12" Margin="0,12,12,0"
Style="{StaticResource FieldLabel}" Style="{StaticResource FieldLabel}"
Text="{Binding Localization[CursorOffsetLabel]}" Text="{Binding Localization[PreviewLabel]}" />
Visibility="{Binding Settings.PlacementMode, <Border Grid.Row="12" Grid.Column="1" Grid.ColumnSpan="2"
Converter={StaticResource EnumToVisibility}, Margin="0,12,0,0" Padding="16"
ConverterParameter=AtCursor}" /> Height="152" ClipToBounds="True"
<Slider Grid.Row="2" Grid.Column="1" Margin="0,12,0,0" Background="{DynamicResource Theme.SurfaceStrong}" CornerRadius="4"
Minimum="0" Maximum="80" TickFrequency="1" HorizontalAlignment="Stretch">
Value="{Binding Settings.AtCursor.Offset}" <Border CornerRadius="4" Padding="10,4"
Visibility="{Binding Settings.PlacementMode, HorizontalAlignment="Center" VerticalAlignment="Center"
Converter={StaticResource EnumToVisibility}, Opacity="{Binding Settings.Current.Opacity}"
ConverterParameter=AtCursor}" /> Background="{Binding Settings.Current.BackgroundColor,
<TextBlock Grid.Row="2" Grid.Column="2" Margin="12,12,0,0" Converter={StaticResource ColorToBrush}}">
Style="{StaticResource FieldValue}" <TextBlock Text="RU" FontWeight="SemiBold"
Text="{Binding Settings.AtCursor.Offset, StringFormat={}{0:F0}}" FontSize="{Binding Settings.Current.FontSize}"
Visibility="{Binding Settings.PlacementMode, Foreground="{Binding Settings.Current.ForegroundColor,
Converter={StaticResource EnumToVisibility}, Converter={StaticResource ColorToBrush}}" />
ConverterParameter=AtCursor}" />
<!-- The "at caret" mode: a side and an offset of its own -->
<TextBlock Grid.Row="3" Margin="0,12,12,0"
Style="{StaticResource FieldLabel}"
Text="{Binding Localization[CursorCornerLabel]}"
Visibility="{Binding Settings.PlacementMode,
Converter={StaticResource EnumToVisibility},
ConverterParameter=AtCaret}" />
<ComboBox Grid.Row="3" Grid.Column="1" Grid.ColumnSpan="2" Margin="0,12,0,0"
ItemsSource="{Binding CaretSides}"
ItemTemplate="{StaticResource EnumOptionTemplate}"
SelectedValuePath="Value"
SelectedValue="{Binding Settings.AtCaret.Side}"
Visibility="{Binding Settings.PlacementMode,
Converter={StaticResource EnumToVisibility},
ConverterParameter=AtCaret}" />
<TextBlock Grid.Row="4" Margin="0,12,12,0"
Style="{StaticResource FieldLabel}"
Text="{Binding Localization[CursorOffsetLabel]}"
Visibility="{Binding Settings.PlacementMode,
Converter={StaticResource EnumToVisibility},
ConverterParameter=AtCaret}" />
<Slider Grid.Row="4" Grid.Column="1" Margin="0,12,0,0"
Minimum="0" Maximum="80" TickFrequency="1"
Value="{Binding Settings.AtCaret.Offset}"
Visibility="{Binding Settings.PlacementMode,
Converter={StaticResource EnumToVisibility},
ConverterParameter=AtCaret}" />
<TextBlock Grid.Row="4" Grid.Column="2" Margin="12,12,0,0"
Style="{StaticResource FieldValue}"
Text="{Binding Settings.AtCaret.Offset, StringFormat={}{0:F0}}"
Visibility="{Binding Settings.PlacementMode,
Converter={StaticResource EnumToVisibility},
ConverterParameter=AtCaret}" />
<!-- The "fixed point" mode -->
<TextBlock Grid.Row="5" Margin="0,12,12,0"
Style="{StaticResource FieldLabel}"
Text="{Binding Localization[ScreenPositionLabel]}"
Visibility="{Binding Settings.PlacementMode,
Converter={StaticResource EnumToVisibility},
ConverterParameter=FixedPoint}" />
<ComboBox Grid.Row="5" Grid.Column="1" Grid.ColumnSpan="2" Margin="0,12,0,0"
ItemsSource="{Binding ScreenPositions}"
ItemTemplate="{StaticResource EnumOptionTemplate}"
SelectedValuePath="Value"
SelectedValue="{Binding Settings.FixedPoint.Position}"
Visibility="{Binding Settings.PlacementMode,
Converter={StaticResource EnumToVisibility},
ConverterParameter=FixedPoint}" />
<TextBlock Grid.Row="6" Margin="0,12,12,0"
Style="{StaticResource FieldLabel}"
Text="{Binding Localization[ScreenMarginLabel]}"
IsEnabled="{Binding Settings.FixedPoint.IsAtAnEdge}"
Visibility="{Binding Settings.PlacementMode,
Converter={StaticResource EnumToVisibility},
ConverterParameter=FixedPoint}" />
<Slider Grid.Row="6" Grid.Column="1" Margin="0,12,0,0"
Minimum="0" Maximum="200" TickFrequency="1"
Value="{Binding Settings.FixedPoint.Offset}"
IsEnabled="{Binding Settings.FixedPoint.IsAtAnEdge}"
Visibility="{Binding Settings.PlacementMode,
Converter={StaticResource EnumToVisibility},
ConverterParameter=FixedPoint}" />
<TextBlock Grid.Row="6" Grid.Column="2" Margin="12,12,0,0"
Style="{StaticResource FieldValue}"
Text="{Binding Settings.FixedPoint.Offset, StringFormat={}{0:F0}}"
IsEnabled="{Binding Settings.FixedPoint.IsAtAnEdge}"
Visibility="{Binding Settings.PlacementMode,
Converter={StaticResource EnumToVisibility},
ConverterParameter=FixedPoint}" />
<!-- A hairline between the two halves of the section: the
placement above, the look of the popup below -->
<Border Grid.Row="7" Grid.ColumnSpan="3"
Margin="0,16,0,0" Height="1"
Background="{DynamicResource Theme.ControlBorder}" />
<TextBlock Grid.Row="8" Margin="0,12,12,0"
Style="{StaticResource FieldLabel}"
Text="{Binding Localization[FontSizeLabel]}" />
<Slider Grid.Row="8" Grid.Column="1" Margin="0,12,0,0"
Minimum="10" Maximum="72" TickFrequency="1"
Value="{Binding Settings.Current.FontSize}" />
<TextBlock Grid.Row="8" Grid.Column="2" Margin="12,12,0,0"
Style="{StaticResource FieldValue}"
Text="{Binding Settings.Current.FontSize, StringFormat={}{0:F0}}" />
<TextBlock Grid.Row="9" Margin="0,12,12,0"
Style="{StaticResource FieldLabel}"
Text="{Binding Localization[OpacityLabel]}" />
<Slider Grid.Row="9" Grid.Column="1" Margin="0,12,0,0"
Minimum="0.1" Maximum="1" TickFrequency="0.05"
Value="{Binding Settings.Current.Opacity}" />
<TextBlock Grid.Row="9" Grid.Column="2" Margin="12,12,0,0"
Style="{StaticResource FieldValue}"
Text="{Binding Settings.Current.Opacity, StringFormat={}{0:P0}}" />
<TextBlock Grid.Row="10" Margin="0,12,12,0"
Style="{StaticResource FieldLabel}"
Text="{Binding Localization[BackgroundColorLabel]}" />
<ComboBox Grid.Row="10" Grid.Column="1" Grid.ColumnSpan="2" Margin="0,12,0,0"
ItemsSource="{Binding BackgroundPalette}"
ItemTemplate="{StaticResource ColorSwatchTemplate}"
SelectedItem="{Binding Settings.Current.BackgroundColor}" />
<TextBlock Grid.Row="11" Margin="0,12,12,0"
Style="{StaticResource FieldLabel}"
Text="{Binding Localization[TextColorLabel]}" />
<ComboBox Grid.Row="11" Grid.Column="1" Grid.ColumnSpan="2" Margin="0,12,0,0"
ItemsSource="{Binding TextPalette}"
ItemTemplate="{StaticResource ColorSwatchTemplate}"
SelectedItem="{Binding Settings.Current.ForegroundColor}" />
<TextBlock Grid.Row="12" Margin="0,12,12,0"
Style="{StaticResource FieldLabel}"
Text="{Binding Localization[PreviewLabel]}" />
<Border Grid.Row="12" Grid.Column="1" Grid.ColumnSpan="2"
Margin="0,12,0,0" Padding="16"
Height="152" ClipToBounds="True"
Background="{DynamicResource Theme.SurfaceStrong}" CornerRadius="4"
HorizontalAlignment="Stretch">
<Border CornerRadius="4" Padding="10,4"
HorizontalAlignment="Center" VerticalAlignment="Center"
Opacity="{Binding Settings.Current.Opacity}"
Background="{Binding Settings.Current.BackgroundColor,
Converter={StaticResource ColorToBrush}}">
<TextBlock Text="RU" FontWeight="SemiBold"
FontSize="{Binding Settings.Current.FontSize}"
Foreground="{Binding Settings.Current.ForegroundColor,
Converter={StaticResource ColorToBrush}}" />
</Border>
</Border> </Border>
</Grid> </Border>
</GroupBox> </Grid>
</GroupBox>
</StackPanel> <GroupBox Header="{Binding Localization[SectionBehavior]}">
</Grid> <Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="164" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Style="{StaticResource FieldLabel}"
Text="{Binding Localization[DurationLabel]}" />
<Slider Grid.Column="1" Minimum="200" Maximum="5000" TickFrequency="100"
Value="{Binding Settings.DurationMilliseconds}" />
<StackPanel Grid.Column="2" Orientation="Horizontal" VerticalAlignment="Center">
<TextBlock Style="{StaticResource FieldValue}"
Text="{Binding Settings.DurationMilliseconds, StringFormat={}{0:F0}}" />
<TextBlock Margin="4,0,0,0"
Foreground="{DynamicResource Theme.SecondaryForeground}"
Text="{Binding Localization[MillisecondsSuffix]}" />
</StackPanel>
<TextBlock Grid.Row="1" Margin="0,12,12,0"
Style="{StaticResource FieldLabel}"
Text="{Binding Localization[CapsLockLabel]}" />
<CheckBox Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="2" Margin="0,12,0,0"
IsChecked="{Binding Settings.UseCapsLockHotkey}"
Content="{Binding Localization[CapsLockHotkeyCheck]}" />
<TextBlock Grid.Row="2" Margin="0,12,12,0"
Style="{StaticResource FieldLabel}"
Text="{Binding Localization[CapsLockHoldLabel]}" />
<Slider Grid.Row="2" Grid.Column="1" Margin="0,12,0,0"
Minimum="150" Maximum="1500" TickFrequency="50"
Value="{Binding Settings.CapsLockHoldMilliseconds}"
IsEnabled="{Binding Settings.UseCapsLockHotkey}" />
<StackPanel Grid.Row="2" Grid.Column="2" Margin="0,12,0,0"
Orientation="Horizontal" VerticalAlignment="Center">
<TextBlock Style="{StaticResource FieldValue}"
Text="{Binding Settings.CapsLockHoldMilliseconds, StringFormat={}{0:F0}}" />
<TextBlock Margin="4,0,0,0"
Foreground="{DynamicResource Theme.SecondaryForeground}"
Text="{Binding Localization[MillisecondsSuffix]}" />
</StackPanel>
<TextBlock Grid.Row="3" Grid.Column="1" Grid.ColumnSpan="2"
Margin="0,6,0,0" TextWrapping="Wrap"
Foreground="{DynamicResource Theme.SecondaryForeground}">
<Run Text="{Binding Localization[CapsLockHoldHint], Mode=OneWay}" />
<InlineUIContainer BaselineAlignment="Baseline">
<!-- The elevation caveat lives in the tooltip to keep the section compact -->
<TextBlock Text="{Binding Localization[MoreInfoLink]}"
Foreground="{DynamicResource Theme.Accent}"
TextDecorations="Underline"
Cursor="Help"
ToolTipService.InitialShowDelay="200"
ToolTipService.ShowDuration="60000"
Visibility="{Binding Settings.UseCapsLockHotkey, Converter={StaticResource BooleanToVisibility}}">
<TextBlock.ToolTip>
<ToolTip>
<TextBlock TextWrapping="Wrap"
Text="{Binding Localization[CapsLockElevationHint]}" />
</ToolTip>
</TextBlock.ToolTip>
</TextBlock>
</InlineUIContainer>
</TextBlock>
<TextBlock Grid.Row="4" Margin="0,12,12,0"
Style="{StaticResource FieldLabel}"
Visibility="{Binding IsStartupAvailable, Converter={StaticResource BooleanToVisibility}}"
Text="{Binding Localization[StartupLabel]}" />
<CheckBox Grid.Row="4" Grid.Column="1" Grid.ColumnSpan="2" Margin="0,12,0,0"
Visibility="{Binding IsStartupAvailable, Converter={StaticResource BooleanToVisibility}}"
IsEnabled="{Binding CanChangeStartup}"
IsChecked="{Binding RunAtStartup}"
Content="{Binding Localization[StartupCheck]}" />
<TextBlock Grid.Row="5" Grid.Column="1" Grid.ColumnSpan="2"
Margin="0,6,0,0" TextWrapping="Wrap"
Foreground="{DynamicResource Theme.SecondaryForeground}"
Visibility="{Binding IsStartupLocked, Converter={StaticResource BooleanToVisibility}}"
Text="{Binding Localization[StartupLockedHint]}" />
</Grid>
</GroupBox>
</StackPanel>
</ScrollViewer> </ScrollViewer>
</Window> </Window>
+19 -6
View File
@@ -16,12 +16,25 @@
<OutputType>Package</OutputType> <OutputType>Package</OutputType>
<!-- <!--
MSI validation still assumes an installation for the whole machine. The ICE checks run inside the Windows Installer service, and a build
Installing into the user's own profile trips three of its rules: a agent has no access to it: every single check comes back as WIX0217,
component whose key path is a file (ICE38), a folder it wants listed "The Windows Installer Service could not be accessed", and the build
for removal (ICE64), and a warning that the files will not follow other fails on close to a hundred of them. Since the release is built by the
users of the machine (ICE91). All three describe exactly what was agent, validation cannot be part of it.
intended here, so they are turned off rather than worked around.
It stays switchable rather than deleted: -p:SuppressValidation=false
turns it back on where the service does answer, which is any ordinary
desktop machine.
-->
<SuppressValidation Condition="'$(SuppressValidation)' == ''">true</SuppressValidation>
<!--
What validation says when it does run. MSI still assumes an
installation for the whole machine, and installing into the user's own
profile trips three of its rules: a component whose key path is a file
(ICE38), a folder it wants listed for removal (ICE64), and a warning
that the files will not follow other users of the machine (ICE91). All
three describe exactly what was intended here.
--> -->
<SuppressIces>ICE38;ICE64;ICE91</SuppressIces> <SuppressIces>ICE38;ICE64;ICE91</SuppressIces>
+18 -7
View File
@@ -333,10 +333,21 @@ pwsh -File Packaging\build-installer.ps1 -Version 1.0.1
снимет: SmartScreen смотрит на репутацию, а у нового сертификата её нет, пока снимет: SmartScreen смотрит на репутацию, а у нового сертификата её нет, пока
приложение не наберёт установок. приложение не наберёт установок.
Про проект WiX стоит знать две вещи, прежде чем его править. Он закреплён на WiX Про проект WiX стоит знать две вещи, прежде чем его править.
5, а не на нынешней 7: начиная с шестой версии инструмент требует принимать
лицензию Open Source Maintenance Fee — бесплатную при доходе меньше $10 000 в Он закреплён на WiX 5, а не на нынешней 7: начиная с шестой версии инструмент
год, но принимать её должен человек, а не сборочный скрипт. И он отключает три требует принимать лицензию Open Source Maintenance Fee — бесплатную при доходе
проверки ICE: MSI по-прежнему исходит из установки на всю машину, а установка в меньше $10 000 в год, но принимать её должен человек, а не сборочный скрипт.
профиль пользователя нарушает правила, которые описывают ровно то, что здесь и
задумано. И он собирается без проверки MSI. Проверки ICE выполняются службой установщика
Windows, до которой сборочному агенту не дотянуться: каждая возвращается
ошибкой `WIX0217`, и сборка умирает на без малого сотне таких. На обычной
машине служба отвечает, и проверка включается одним ключом:
```powershell
dotnet build Packaging\Installer\CursorLang.wixproj -p:SuppressValidation=false
```
Три правила остаются подавленными и тогда. MSI исходит из установки на всю
машину, а установка в профиль пользователя нарушает правила, которые описывают
ровно то, что здесь и задумано.
+18 -7
View File
@@ -327,10 +327,21 @@ user has to insist. Buying a certificate would not silence it at once either:
SmartScreen goes by reputation, and a fresh certificate has none until enough SmartScreen goes by reputation, and a fresh certificate has none until enough
people have installed the application. people have installed the application.
Two things about the WiX project are worth knowing before touching it. It pins Two things about the WiX project are worth knowing before touching it.
WiX 5 rather than the current 7: from version 6 the toolset asks every build to
accept the Open Source Maintenance Fee licence — free below $10,000 of yearly It pins WiX 5 rather than the current 7: from version 6 the toolset asks every
revenue, but a decision for a person rather than for a build script. And it turns build to accept the Open Source Maintenance Fee licence — free below $10,000 of
off three ICE validation rules: MSI still assumes an installation for the whole yearly revenue, but a decision for a person rather than for a build script.
machine, and installing into the user's own profile trips rules that describe
exactly what was intended here. And it builds without MSI validation. The ICE checks run inside the Windows
Installer service, which a build agent cannot reach: every check comes back as
`WIX0217` and the build dies on close to a hundred of them. On an ordinary
desktop machine the service does answer, and validation is one switch away:
```powershell
dotnet build Packaging\Installer\CursorLang.wixproj -p:SuppressValidation=false
```
Three of its rules stay suppressed even then. MSI assumes an installation for the
whole machine, and installing into the user's own profile trips rules that
describe exactly what was intended here.