- Services/PdfRedactText.cs: strip text whose origin falls inside a CoverAnnotation from the page content stream at save time, hooked into PdfBurn.DrawAnnotationsIntoDoc. Fixes edited values staying recoverable by text extraction. - Themes/MMD.xaml replaces all thirteen themes; picker and accent strip removed; no dark mode. - Rename KillerPDF -> MMD PDF across code, resources, packaging and locale strings; new icon. - Remove the upstream author credit and the in-app install button.
551 lines
39 KiB
XML
551 lines
39 KiB
XML
<!-- Themed replacement for Microsoft.Win32.OpenFileDialog / SaveFileDialog.
|
|
Same chrome, places rail, view modes and sortable columns as FolderPickerDialog - the row
|
|
styles and templates are shared from Controls.xaml - plus a file name box, a filter combo
|
|
and Open/Save behavior. The property surface deliberately mirrors the Win32 dialogs
|
|
(Title, Filter, FilterIndex, FileName, InitialDirectory, DefaultExt, ...) so a call site
|
|
changes by one word. -->
|
|
<Window x:Class="MmdPdf.Controls.FileDialog"
|
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
xmlns:kui="clr-namespace:MmdPdf.Controls"
|
|
Title="MMD PDF"
|
|
Width="720" Height="520" MinWidth="560" MinHeight="420"
|
|
WindowStyle="None" ResizeMode="CanResize" ShowInTaskbar="False"
|
|
AllowsTransparency="True"
|
|
Background="Transparent"
|
|
TextOptions.TextFormattingMode="Display"
|
|
TextOptions.TextRenderingMode="ClearType"
|
|
UseLayoutRounding="True"
|
|
SnapsToDevicePixels="True"
|
|
WindowStartupLocation="CenterOwner">
|
|
|
|
<!-- The picker's styles are merged HERE, not into App.xaml. LocaleManager owns application
|
|
merged-dictionary slot [2] - it assigns the locale override there and, for English,
|
|
REMOVES it - so anything parked at [2] is deleted at startup. That is what "Cannot find
|
|
resource named 'DarkTextBox'" was. These styles are the picker's own, so scoping them to
|
|
the picker removes the index coupling entirely rather than competing for a slot. -->
|
|
<Window.Resources>
|
|
<ResourceDictionary Source="pack://application:,,,/Controls/PickerStyles.xaml"/>
|
|
</Window.Resources>
|
|
|
|
<!-- NO shell:WindowChrome. On an AllowsTransparency window it fills its own non-client area,
|
|
which paints as a flat band all the way round the card - the "halo". It was NOT the only
|
|
difference from the other four dialogs: the code-behind also called
|
|
DwmChrome.SetRoundedCorners/SetThemeBorder, and on a layered window the DWM corner
|
|
preference composites DWM's own rounded frame around the WINDOW rect (halo included),
|
|
tinted by the border color - the band survived the WindowChrome removal because of it.
|
|
Both are gone now; no WindowChrome, no DWM calls, same as the other four.
|
|
|
|
Resize is done by hand instead, on the halo itself: Resize_MouseDown works out which edge
|
|
or corner the pointer is in and hands the drag to Windows with WM_NCLBUTTONDOWN, the same
|
|
mechanism Shell/Chrome.cs uses for the main window's grip. That needs the halo to receive
|
|
mouse input, which is why this Grid is #01000000 (alpha 1/255) rather than Transparent -
|
|
a fully transparent area gets no mouse events at all.
|
|
|
|
Two earlier attempts blamed the wrong thing. The shadow WAS also wrong - it sat on the
|
|
content Border, and this is the only dialog with a ComboBox, whose dropdown is an
|
|
AllowsTransparency Popup; a WPF Effect over a subtree containing one renders as a filled
|
|
rectangle. That is fixed below and is a real bug, it just was not this one.
|
|
(2026-07-30, four attempts) -->
|
|
<!-- RootFade, not RootBorder, is what the open/close animation drives - and it starts at 0,
|
|
the same way KillerShell's RootGrid does. The fade used to run on RootBorder alone, but
|
|
the shadow layer below is a SIBLING carrying the identical BackgroundBrush and geometry,
|
|
with no starting opacity: it slammed in solid on the first frame and only the card faded
|
|
on top of it, so the dialog read as blinking into existence rather than fading. Fading the
|
|
shared parent takes the shadow with it. (2026-07-31) -->
|
|
<Grid x:Name="RootFade" Opacity="0" Background="#01000000"
|
|
MouseMove="Resize_MouseMove" MouseLeftButtonDown="Resize_MouseDown">
|
|
|
|
<!-- Shadow layer: same geometry, NO content, not hit-testable. -->
|
|
<Border Margin="{DynamicResource DialogHaloMargin}" CornerRadius="{DynamicResource PanelCornerRadius}" Background="{DynamicResource BackgroundBrush}"
|
|
IsHitTestVisible="False">
|
|
<Border.Effect>
|
|
<!-- RenderingBias Quality: at radius 18 the default Performance bias renders the
|
|
blur at reduced resolution and scales it up, which blocks up into stair-steps
|
|
on this card's rounded corners. Same fix as App.xaml's PaneShadow. -->
|
|
<!-- Opacity follows the theme. A flat palette sets FlyoutShadowOpacity to 0, which
|
|
removes the cast entirely rather than leaving a soft halo round a hard-edged
|
|
window. Every other theme keeps the 0.6 it had. -->
|
|
<DropShadowEffect Color="Black" BlurRadius="18" ShadowDepth="3" Direction="270"
|
|
Opacity="{DynamicResource FlyoutShadowOpacity}"
|
|
RenderingBias="Quality"/>
|
|
</Border.Effect>
|
|
</Border>
|
|
|
|
<!-- Corner radius follows the theme, not a hardcoded 6: a square-cornered palette was
|
|
getting a rounded card, and its square bevel then cut across the corners. -->
|
|
<Border x:Name="RootBorder" BorderBrush="{DynamicResource DialogFrameBrush}" BorderThickness="{DynamicResource DialogFrameThickness}"
|
|
Background="{DynamicResource BackgroundBrush}"
|
|
CornerRadius="{DynamicResource PanelCornerRadius}" Margin="{DynamicResource DialogHaloMargin}"
|
|
Padding="{DynamicResource DialogWindowFramePadding}">
|
|
<Grid>
|
|
<Grid.RowDefinitions>
|
|
<!-- Auto, with the height on the band itself: DialogTitleBarHeight is a Double and
|
|
a RowDefinition wants a GridLength, which will not convert. -->
|
|
<RowDefinition Height="Auto"/> <!-- title bar -->
|
|
<RowDefinition Height="Auto"/> <!-- heading -->
|
|
<RowDefinition Height="Auto"/> <!-- path row -->
|
|
<RowDefinition Height="*"/> <!-- places | entries -->
|
|
<RowDefinition Height="Auto"/> <!-- file name + filter -->
|
|
<RowDefinition Height="Auto"/> <!-- footer -->
|
|
</Grid.RowDefinitions>
|
|
|
|
<!-- Shared film grain over the whole dialog surface -->
|
|
<Border Grid.RowSpan="6" IsHitTestVisible="False"
|
|
Background="{DynamicResource GrainTileBrush}" Opacity="{DynamicResource GrainOpacity}"/>
|
|
|
|
<!-- Title bar. TitleBarBrush, not Transparent: the row already spans the card, so this
|
|
gives it a real caption band - a gradient on the themes that define one, and
|
|
identical to BackgroundBrush on the themes that do not, which is why the other
|
|
palettes look unchanged. -->
|
|
<Border Grid.Row="0" Height="{DynamicResource DialogTitleBarHeight}"
|
|
Background="{DynamicResource DialogTitleBarBrush}" MouseLeftButtonDown="TitleBar_MouseLeftButtonDown">
|
|
<Grid>
|
|
<!-- The caption band paints OVER the dialog-wide grain (declared before this row),
|
|
so it carries its own tile - same as the main window's chrome. -->
|
|
<Border IsHitTestVisible="False"
|
|
Background="{DynamicResource GrainTileBrush}" Opacity="{DynamicResource GrainOpacity}"/>
|
|
<Grid Margin="{DynamicResource TitleBarPadding}">
|
|
<!-- A file picker caption names the operation. It is window chrome, not a
|
|
branding surface; the caller's Title belongs here and nowhere else. -->
|
|
<TextBlock Text="{Binding Title, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
|
|
FontFamily="{DynamicResource ChromeFontFamily}"
|
|
FontSize="{DynamicResource MenuFontSize}" FontWeight="Bold"
|
|
Foreground="{DynamicResource ChromeTextBrush}"
|
|
VerticalAlignment="Center" IsHitTestVisible="False"/>
|
|
<Button x:Name="CaptionCloseButton" Content="" Click="Cancel_Click"
|
|
HorizontalAlignment="Right" VerticalAlignment="Top"
|
|
Width="{DynamicResource DialogCloseWidth}" Height="{DynamicResource DialogCloseHeight}"
|
|
Margin="{DynamicResource DialogCaptionButtonsMargin}"
|
|
FontSize="10" FontFamily="Segoe MDL2 Assets"
|
|
Foreground="{DynamicResource CaptionCloseBrush}"
|
|
Background="Transparent" BorderThickness="0" Cursor="Hand"/>
|
|
</Grid>
|
|
</Grid>
|
|
</Border>
|
|
|
|
<!-- Path row: up one level + current path + view modes -->
|
|
<Grid Grid.Row="2" Margin="16,8,16,8">
|
|
<Grid.ColumnDefinitions>
|
|
<ColumnDefinition Width="Auto"/>
|
|
<ColumnDefinition Width="*"/>
|
|
<ColumnDefinition Width="Auto"/>
|
|
</Grid.ColumnDefinitions>
|
|
<Button x:Name="UpButton" Grid.Column="0" Content="" Click="Up_Click"
|
|
ToolTip="{DynamicResource Str_TT_Up}" Style="{StaticResource PickerViewBtn}"
|
|
Margin="0,0,6,0"/>
|
|
<!-- Explicit style: an unstyled TextBox falls back to WPF's white fill and blue
|
|
focus border. The chevron overlays the box's right edge (the box pads 28 to
|
|
clear it) and drops the recent-locations list, like Explorer's address bar. -->
|
|
<Grid Grid.Column="1">
|
|
<TextBox x:Name="PathBox" Height="28" Style="{StaticResource DarkTextBox}"
|
|
FontFamily="Consolas" FontSize="12" Padding="8,0,28,0"
|
|
VerticalContentAlignment="Center" KeyDown="PathBox_KeyDown"/>
|
|
<Button x:Name="RecentsBtn" Content="{DynamicResource ComboChevGlyph}" Click="RecentsBtn_Click"
|
|
ToolTip="{DynamicResource Str_TT_RecentLocations}"
|
|
Style="{StaticResource PickerComboArrowBtn}"
|
|
HorizontalAlignment="Right" Margin="0,0,1,0"/>
|
|
<!-- Recent locations. Same raised-surface pattern as everything else:
|
|
shadow on an item-free sibling, content border on top. -->
|
|
<Popup x:Name="RecentsPopup" PlacementTarget="{Binding ElementName=PathBox}"
|
|
Placement="Bottom" StaysOpen="False" AllowsTransparency="True"
|
|
VerticalOffset="2" HorizontalOffset="-8">
|
|
<Grid Margin="8">
|
|
<Border Background="{DynamicResource FileDialogPaneBrush}" CornerRadius="{DynamicResource ControlCornerRadius}" IsHitTestVisible="False">
|
|
<Border.Effect>
|
|
<DropShadowEffect Color="Black" BlurRadius="14" ShadowDepth="2" Direction="270" Opacity="{DynamicResource FlyoutShadowOpacity}"/>
|
|
</Border.Effect>
|
|
</Border>
|
|
<Border Background="{DynamicResource FileDialogPaneBrush}" BorderBrush="{DynamicResource MenuBorderBrush}"
|
|
BorderThickness="1" CornerRadius="{DynamicResource ControlCornerRadius}">
|
|
<Grid>
|
|
<Border IsHitTestVisible="False" CornerRadius="{DynamicResource ControlCornerRadius}"
|
|
Background="{DynamicResource GrainTileBrush}" Opacity="{DynamicResource GrainOpacity}"/>
|
|
<ListBox x:Name="RecentsList" Background="Transparent" BorderThickness="0" Padding="2,4"
|
|
Width="{Binding ActualWidth, ElementName=PathBox}" MaxHeight="260"
|
|
ItemContainerStyle="{StaticResource PickerRow}"
|
|
SelectionChanged="RecentsList_SelectionChanged"
|
|
ScrollViewer.HorizontalScrollBarVisibility="Disabled">
|
|
<ListBox.ItemTemplate>
|
|
<DataTemplate>
|
|
<TextBlock Text="{Binding}" FontFamily="Consolas" FontSize="12"
|
|
TextTrimming="CharacterEllipsis"/>
|
|
</DataTemplate>
|
|
</ListBox.ItemTemplate>
|
|
</ListBox>
|
|
</Grid>
|
|
</Border>
|
|
<Control Panel.ZIndex="20" Style="{StaticResource PaneBevelOverlay}"/>
|
|
</Grid>
|
|
</Popup>
|
|
</Grid>
|
|
<StackPanel Grid.Column="2" Orientation="Horizontal" Margin="8,0,0,0" VerticalAlignment="Center">
|
|
<!-- E7B3 (off) / E890 (on) - KillerShell's build-proven pair (ViewOptions.cs). -->
|
|
<Button x:Name="ShowHiddenBtn" Style="{StaticResource PickerViewBtn}" Content="" ToolTip="{DynamicResource Str_TT_ShowHidden}" Click="ShowHidden_Click" Margin="0,0,6,0"/>
|
|
<Button x:Name="ViewListBtn" Style="{StaticResource PickerViewBtn}" Content="" ToolTip="{DynamicResource Str_TT_ViewList}" Click="ViewList_Click"/>
|
|
<Button x:Name="ViewIconsBtn" Style="{StaticResource PickerViewBtn}" Content="" ToolTip="{DynamicResource Str_TT_ViewIcons}" Click="ViewIcons_Click" Margin="2,0"/>
|
|
<Button x:Name="ViewDetailsBtn" Style="{StaticResource PickerViewBtn}" Content="" ToolTip="{DynamicResource Str_TT_ViewDetails}" Click="ViewDetails_Click"/>
|
|
</StackPanel>
|
|
</Grid>
|
|
|
|
<!-- Main: quick places on the left, folder contents on the right -->
|
|
<Grid Grid.Row="3" Margin="16,0">
|
|
<Grid.ColumnDefinitions>
|
|
<ColumnDefinition Width="170"/>
|
|
<ColumnDefinition Width="8"/>
|
|
<ColumnDefinition Width="*"/>
|
|
<ColumnDefinition x:Name="ImagePreviewGapColumn" Width="0"/>
|
|
<ColumnDefinition x:Name="ImagePreviewColumn" Width="0"/>
|
|
</Grid.ColumnDefinitions>
|
|
|
|
<!-- A lifted card matching the file list (2026-08-15, revising the 2026-07-30 flat
|
|
call - the pane carried a fill anyway, so square shadowless edges read as a
|
|
bug, not flatness). Shadow on a SEPARATE border so text keeps ClearType.
|
|
|
|
KillerShell's own arrangement, not Explorer's: the tree fills the panel and
|
|
the pinned places sit BELOW it, the same slot its favorites drawer occupies,
|
|
so the two apps read identically. Draggable divider between. -->
|
|
<Border Grid.Column="0" IsHitTestVisible="False"
|
|
Background="{DynamicResource FileDialogPaneBrush}"
|
|
CornerRadius="{DynamicResource ControlCornerRadius}">
|
|
<Border.Effect>
|
|
<DropShadowEffect Color="Black" BlurRadius="14" ShadowDepth="2" Direction="270" Opacity="{DynamicResource FlyoutShadowOpacity}"/>
|
|
</Border.Effect>
|
|
</Border>
|
|
<!-- Film grain on the places card - the card's fill covers the dialog-wide tile. -->
|
|
<Border Grid.Column="0" IsHitTestVisible="False"
|
|
CornerRadius="{DynamicResource ControlCornerRadius}"
|
|
Background="{DynamicResource GrainTileBrush}" Opacity="{DynamicResource GrainOpacity}"/>
|
|
<Grid Grid.Column="0">
|
|
<Grid.RowDefinitions>
|
|
<RowDefinition Height="0"/>
|
|
<RowDefinition Height="0"/>
|
|
<RowDefinition x:Name="PlacesRow" Height="*" MinHeight="56"/>
|
|
</Grid.RowDefinitions>
|
|
<Control Grid.RowSpan="3" Panel.ZIndex="20" Style="{StaticResource PaneBevelOverlay}"/>
|
|
<ListBox x:Name="PlacesList" Grid.Row="2" Background="Transparent" BorderThickness="0" Padding="2,4"
|
|
ItemContainerStyle="{StaticResource PickerPlaceRow}" SelectionChanged="Places_SelectionChanged"
|
|
ContextMenuOpening="Places_ContextMenuOpening"
|
|
ScrollViewer.HorizontalScrollBarVisibility="Disabled">
|
|
<ListBox.ContextMenu>
|
|
<ContextMenu>
|
|
<MenuItem Header="{DynamicResource Str_Menu_UnpinPlace}" Click="UnpinPlace_Click">
|
|
<MenuItem.Icon><TextBlock Text="" FontFamily="Segoe MDL2 Assets" FontSize="12"/></MenuItem.Icon>
|
|
</MenuItem>
|
|
</ContextMenu>
|
|
</ListBox.ContextMenu>
|
|
<ListBox.ItemTemplate>
|
|
<DataTemplate>
|
|
<StackPanel Orientation="Horizontal" Style="{StaticResource PickerRowContent}">
|
|
<Image Source="{Binding Icon}" Width="16" Height="16" VerticalAlignment="Center"
|
|
Margin="0,0,8,0" SnapsToDevicePixels="True"
|
|
RenderOptions.BitmapScalingMode="NearestNeighbor"/>
|
|
<TextBlock Text="{Binding Label}" FontFamily="Consolas" FontSize="12" VerticalAlignment="Center"
|
|
TextTrimming="CharacterEllipsis"/>
|
|
</StackPanel>
|
|
</DataTemplate>
|
|
</ListBox.ItemTemplate>
|
|
</ListBox>
|
|
<!-- KillerShell's divider verbatim (MainWindow.xaml, terms/filters split):
|
|
invisible grab band, 1px CardBorderBrush line, accent on hover and
|
|
while dragging. -->
|
|
<GridSplitter Grid.Row="1" Height="0" Visibility="Collapsed" HorizontalAlignment="Stretch" Background="Transparent"
|
|
ResizeBehavior="PreviousAndNext" ResizeDirection="Rows"
|
|
Cursor="SizeNS" ShowsPreview="False" Focusable="False">
|
|
<GridSplitter.Template>
|
|
<ControlTemplate TargetType="GridSplitter">
|
|
<Border Background="Transparent">
|
|
<Border x:Name="line" Height="1" VerticalAlignment="Center"
|
|
Background="{DynamicResource CardBorderBrush}" Margin="12,0"/>
|
|
</Border>
|
|
<ControlTemplate.Triggers>
|
|
<Trigger Property="IsMouseOver" Value="True"><Setter TargetName="line" Property="Background" Value="{DynamicResource PrimaryBrush}"/></Trigger>
|
|
<Trigger Property="IsDragging" Value="True"><Setter TargetName="line" Property="Background" Value="{DynamicResource PrimaryBrush}"/></Trigger>
|
|
</ControlTemplate.Triggers>
|
|
</ControlTemplate>
|
|
</GridSplitter.Template>
|
|
</GridSplitter>
|
|
<!-- Left margin 0, not 4: the 16px expander gutter already provides the
|
|
inset, and the extra margin pushed the root icons visibly right of the
|
|
places icons below - dead space that cost horizontal room.
|
|
(2026-07-30) -->
|
|
<TreeView x:Name="FolderTreeCtl" Grid.Row="0" Style="{StaticResource FolderTreeView}" Visibility="Collapsed"
|
|
Margin="0,3,2,4"
|
|
PreviewMouseWheel="FolderTree_PreviewMouseWheel"
|
|
TreeViewItem.Expanded="FolderTree_Expanded"
|
|
ContextMenuOpening="FolderTree_ContextMenuOpening"
|
|
SelectedItemChanged="FolderTree_SelectedItemChanged">
|
|
<TreeView.ContextMenu>
|
|
<ContextMenu>
|
|
<MenuItem Header="{DynamicResource Str_Menu_PinPlace}" Click="TreePin_Click">
|
|
<MenuItem.Icon><TextBlock Text="" FontFamily="Segoe MDL2 Assets" FontSize="12"/></MenuItem.Icon>
|
|
</MenuItem>
|
|
</ContextMenu>
|
|
</TreeView.ContextMenu>
|
|
<TreeView.ItemContainerStyle>
|
|
<!-- Inherits the themed template and adds the two-way state bindings,
|
|
so RevealInTree can drive the tree from code. -->
|
|
<Style TargetType="TreeViewItem" BasedOn="{StaticResource FolderTreeItem}">
|
|
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}"/>
|
|
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}"/>
|
|
</Style>
|
|
</TreeView.ItemContainerStyle>
|
|
<TreeView.ItemTemplate>
|
|
<HierarchicalDataTemplate DataType="{x:Type kui:FolderNode}"
|
|
ItemsSource="{Binding Children}">
|
|
<StackPanel Orientation="Horizontal" Margin="0,1">
|
|
<Image Source="{Binding Icon}" Width="16" Height="16"
|
|
VerticalAlignment="Center" Margin="0,0,6,0" SnapsToDevicePixels="True"
|
|
RenderOptions.BitmapScalingMode="NearestNeighbor"/>
|
|
<TextBlock Text="{Binding Name}" Style="{StaticResource TreeName}"
|
|
ToolTip="{Binding Path}"/>
|
|
</StackPanel>
|
|
</HierarchicalDataTemplate>
|
|
</TreeView.ItemTemplate>
|
|
</TreeView>
|
|
<!-- Edge fades, KillerShell's tree pattern verbatim (MainWindow.xaml): the
|
|
overlay IS the surface - BackgroundBrush plus the same grain, exactly as
|
|
KillerShell's, now that the pane is flat on the card - under an opacity
|
|
mask, so rows dissolve into an exact match instead of a flat band.
|
|
Hit-test-transparent; each edge only shows while there is something PAST
|
|
it, ramped in code (SyncTreeEdgeFades). Right inset clears the
|
|
scrollbar; the bottom margin is driven from code when a horizontal bar
|
|
appears (SyncTreeFade). -->
|
|
|
|
<Border x:Name="TreeFadeTop" Grid.Row="0" Height="18" Opacity="0" Visibility="Collapsed"
|
|
VerticalAlignment="Top" Margin="0,3,14,0" IsHitTestVisible="False">
|
|
<Border.OpacityMask>
|
|
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
|
|
<GradientStop Color="#FF000000" Offset="0"/>
|
|
<GradientStop Color="#00000000" Offset="1"/>
|
|
</LinearGradientBrush>
|
|
</Border.OpacityMask>
|
|
<Grid>
|
|
<Border Background="{DynamicResource BackgroundBrush}"/>
|
|
<Border Background="{DynamicResource GrainTileBrush}" Opacity="{DynamicResource GrainOpacity}"/>
|
|
</Grid>
|
|
</Border>
|
|
<Border x:Name="TreeFadeBottom" Grid.Row="0" Height="22" Opacity="0" Visibility="Collapsed"
|
|
VerticalAlignment="Bottom" Margin="0,0,14,4" IsHitTestVisible="False">
|
|
<Border.OpacityMask>
|
|
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
|
|
<GradientStop Color="#00000000" Offset="0"/>
|
|
<GradientStop Color="#FF000000" Offset="1"/>
|
|
</LinearGradientBrush>
|
|
</Border.OpacityMask>
|
|
<Grid>
|
|
<Border Background="{DynamicResource BackgroundBrush}"/>
|
|
<Border Background="{DynamicResource GrainTileBrush}" Opacity="{DynamicResource GrainOpacity}"/>
|
|
</Grid>
|
|
</Border>
|
|
<!-- Same edge fades for the places list (2026-07-30): rows dissolve
|
|
at both ends unless the list is flush there. Same surface, same ramp
|
|
(SyncPlacesEdgeFades); no scrollbar lift needed - horizontal scrolling
|
|
is disabled on this list. -->
|
|
<Border x:Name="PlacesFadeTop" Grid.Row="2" Height="18" Opacity="0"
|
|
VerticalAlignment="Top" Margin="0,0,12,0" IsHitTestVisible="False">
|
|
<Border.OpacityMask>
|
|
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
|
|
<GradientStop Color="#FF000000" Offset="0"/>
|
|
<GradientStop Color="#00000000" Offset="1"/>
|
|
</LinearGradientBrush>
|
|
</Border.OpacityMask>
|
|
<Grid>
|
|
<Border Background="{DynamicResource BackgroundBrush}"/>
|
|
<Border Background="{DynamicResource GrainTileBrush}" Opacity="{DynamicResource GrainOpacity}"/>
|
|
</Grid>
|
|
</Border>
|
|
<Border x:Name="PlacesFadeBottom" Grid.Row="2" Height="22" Opacity="0"
|
|
VerticalAlignment="Bottom" Margin="0,0,12,0" IsHitTestVisible="False">
|
|
<Border.OpacityMask>
|
|
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
|
|
<GradientStop Color="#00000000" Offset="0"/>
|
|
<GradientStop Color="#FF000000" Offset="1"/>
|
|
</LinearGradientBrush>
|
|
</Border.OpacityMask>
|
|
<Grid>
|
|
<Border Background="{DynamicResource BackgroundBrush}"/>
|
|
<Border Background="{DynamicResource GrainTileBrush}" Opacity="{DynamicResource GrainOpacity}"/>
|
|
</Grid>
|
|
</Border>
|
|
</Grid>
|
|
|
|
<Grid Grid.Column="2">
|
|
<Border Background="{DynamicResource FileDialogPaneBrush}" CornerRadius="{DynamicResource ControlCornerRadius}" IsHitTestVisible="False">
|
|
<Border.Effect>
|
|
<DropShadowEffect Color="Black" BlurRadius="14" ShadowDepth="2" Direction="270" Opacity="{DynamicResource FlyoutShadowOpacity}"/>
|
|
</Border.Effect>
|
|
</Border>
|
|
<Border Background="{DynamicResource FileDialogPaneBrush}" CornerRadius="{DynamicResource ControlCornerRadius}">
|
|
<Grid>
|
|
<Border IsHitTestVisible="False" CornerRadius="{DynamicResource ControlCornerRadius}"
|
|
Background="{DynamicResource GrainTileBrush}" Opacity="{DynamicResource GrainOpacity}"/>
|
|
<DockPanel>
|
|
<Grid DockPanel.Dock="Top" x:Name="DetailsHeader" Visibility="Collapsed" Margin="12,4,26,0">
|
|
<Grid.ColumnDefinitions>
|
|
<ColumnDefinition Width="*"/>
|
|
<ColumnDefinition Width="80"/>
|
|
<ColumnDefinition Width="150"/>
|
|
</Grid.ColumnDefinitions>
|
|
<Button Grid.Column="0" Style="{StaticResource PickerColBtn}" Click="SortName_Click">
|
|
<StackPanel Orientation="Horizontal">
|
|
<TextBlock Text="{DynamicResource Str_Col_Name}"/>
|
|
<TextBlock x:Name="NameArrow" FontFamily="Segoe MDL2 Assets" FontSize="8" Margin="4,1,0,0"/>
|
|
</StackPanel>
|
|
</Button>
|
|
<Button Grid.Column="1" Style="{StaticResource PickerColBtn}" HorizontalContentAlignment="Right" Click="SortSize_Click">
|
|
<StackPanel Orientation="Horizontal">
|
|
<TextBlock Text="{DynamicResource Str_Col_Size}"/>
|
|
<TextBlock x:Name="SizeArrow" FontFamily="Segoe MDL2 Assets" FontSize="8" Margin="4,1,0,0"/>
|
|
</StackPanel>
|
|
</Button>
|
|
<Button Grid.Column="2" Style="{StaticResource PickerColBtn}" Margin="10,0,0,0" Click="SortModified_Click">
|
|
<StackPanel Orientation="Horizontal">
|
|
<TextBlock Text="{DynamicResource Str_Col_Modified}"/>
|
|
<TextBlock x:Name="ModArrow" FontFamily="Segoe MDL2 Assets" FontSize="8" Margin="4,1,0,0"/>
|
|
</StackPanel>
|
|
</Button>
|
|
</Grid>
|
|
<Grid>
|
|
<ListBox x:Name="FileList" Background="Transparent" BorderThickness="0" Padding="2,4"
|
|
ItemContainerStyle="{StaticResource PickerRow}"
|
|
ItemTemplate="{StaticResource RowTemplate}"
|
|
ItemsPanel="{StaticResource PanelStack}"
|
|
SelectionChanged="Files_SelectionChanged" MouseDoubleClick="Files_DoubleClick"
|
|
ContextMenuOpening="Files_ContextMenuOpening"
|
|
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
|
|
ScrollViewer.CanContentScroll="False"
|
|
PreviewMouseWheel="FileList_PreviewMouseWheel">
|
|
<ListBox.ContextMenu>
|
|
<ContextMenu>
|
|
<MenuItem Header="{DynamicResource Str_Menu_PinPlace}" Click="FilePin_Click">
|
|
<MenuItem.Icon><TextBlock Text="" FontFamily="Segoe MDL2 Assets" FontSize="12"/></MenuItem.Icon>
|
|
</MenuItem>
|
|
</ContextMenu>
|
|
</ListBox.ContextMenu>
|
|
</ListBox>
|
|
<TextBlock x:Name="EmptyHint" Text="{DynamicResource Str_Dlg_NoMatchingFiles}" Visibility="Collapsed"
|
|
Foreground="{DynamicResource DimTextBrush}" FontFamily="Consolas" FontSize="11"
|
|
HorizontalAlignment="Center" VerticalAlignment="Center" TextWrapping="Wrap"
|
|
TextAlignment="Center" Margin="20"/>
|
|
</Grid>
|
|
</DockPanel>
|
|
</Grid>
|
|
</Border>
|
|
<Control Panel.ZIndex="20" Style="{StaticResource PaneBevelOverlay}"/>
|
|
</Grid>
|
|
|
|
<!-- Image-only pickers opt into this pane. Keeping it in the shared dialog makes
|
|
Insert Image, image signatures, image stamps, and image-to-PDF import behave
|
|
identically without changing ordinary Open/Save dialogs. -->
|
|
<Grid x:Name="ImagePreviewHost" Grid.Column="4" Visibility="Collapsed">
|
|
<Border Background="{DynamicResource FileDialogPaneBrush}"
|
|
CornerRadius="{DynamicResource ControlCornerRadius}"
|
|
IsHitTestVisible="False">
|
|
<Border.Effect>
|
|
<DropShadowEffect Color="Black" BlurRadius="14" ShadowDepth="2" Direction="270"
|
|
Opacity="{DynamicResource FlyoutShadowOpacity}"/>
|
|
</Border.Effect>
|
|
</Border>
|
|
<Border Background="{DynamicResource FileDialogPaneBrush}"
|
|
CornerRadius="{DynamicResource ControlCornerRadius}">
|
|
<Grid>
|
|
<Border IsHitTestVisible="False"
|
|
CornerRadius="{DynamicResource ControlCornerRadius}"
|
|
Background="{DynamicResource GrainTileBrush}"
|
|
Opacity="{DynamicResource GrainOpacity}"/>
|
|
<Grid Margin="12">
|
|
<Grid.RowDefinitions>
|
|
<RowDefinition Height="Auto"/>
|
|
<RowDefinition Height="*"/>
|
|
</Grid.RowDefinitions>
|
|
<TextBlock Text="{DynamicResource Str_Dlg_Preview}"
|
|
FontFamily="Consolas" FontSize="11"
|
|
Foreground="{DynamicResource MutedTextBrush}"/>
|
|
<Grid Grid.Row="1" Margin="0,10,0,0">
|
|
<TextBlock x:Name="ImagePreviewPlaceholder" Text=""
|
|
FontFamily="Segoe MDL2 Assets" FontSize="42"
|
|
Foreground="{DynamicResource DimTextBrush}"
|
|
HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
|
<Image x:Name="ImagePreview" Stretch="Uniform"
|
|
SnapsToDevicePixels="True"
|
|
RenderOptions.BitmapScalingMode="HighQuality"/>
|
|
</Grid>
|
|
</Grid>
|
|
</Grid>
|
|
</Border>
|
|
<Control Panel.ZIndex="20" Style="{StaticResource PaneBevelOverlay}"/>
|
|
</Grid>
|
|
</Grid>
|
|
|
|
<!-- File name + filter. Labels are DimTextBrush on the dark card: 3.15:1, the tier
|
|
these brushes are calibrated for. -->
|
|
<Grid Grid.Row="4" Margin="16,12,16,0">
|
|
<Grid.ColumnDefinitions>
|
|
<ColumnDefinition Width="Auto"/>
|
|
<ColumnDefinition Width="*"/>
|
|
</Grid.ColumnDefinitions>
|
|
<Grid.RowDefinitions>
|
|
<RowDefinition Height="Auto"/>
|
|
<RowDefinition Height="Auto"/>
|
|
</Grid.RowDefinitions>
|
|
|
|
<TextBlock Grid.Row="0" Grid.Column="0" Text="{DynamicResource Str_Dlg_FileName}" VerticalAlignment="Center"
|
|
Margin="0,0,10,0" Foreground="{DynamicResource MutedTextBrush}" FontFamily="Consolas" FontSize="11"/>
|
|
<!-- Left padding 5, not 8: a TextBox's content host carries its own ~2px inset
|
|
(WPF's TextBoxView), so at 8 the name started visibly right of the filter
|
|
combo's text directly below it (combo padding is 7 with no inherent inset).
|
|
5 + 2 lines the two up. (2026-07-31) -->
|
|
<TextBox x:Name="FileNameBox" Grid.Row="0" Grid.Column="1" Height="28"
|
|
Style="{StaticResource DarkTextBox}"
|
|
FontFamily="Consolas" FontSize="12" Padding="5,0,8,0"
|
|
VerticalContentAlignment="Center" KeyDown="FileNameBox_KeyDown"/>
|
|
|
|
<TextBlock x:Name="FilterLabel" Grid.Row="1" Grid.Column="0" Text="{DynamicResource Str_Dlg_FileType}" VerticalAlignment="Center"
|
|
Margin="0,8,10,0" Foreground="{DynamicResource MutedTextBrush}" FontFamily="Consolas" FontSize="11"/>
|
|
<ComboBox x:Name="FilterCombo" Grid.Row="1" Grid.Column="1" Height="28" Margin="0,8,0,0"
|
|
Style="{StaticResource DarkComboBox}"
|
|
SelectionChanged="Filter_SelectionChanged"/>
|
|
</Grid>
|
|
|
|
<!-- Footer: selection details on the left, actions on the right -->
|
|
<Grid Grid.Row="5" Margin="16,12,16,16">
|
|
<Grid.ColumnDefinitions>
|
|
<ColumnDefinition Width="*"/>
|
|
<ColumnDefinition Width="Auto"/>
|
|
</Grid.ColumnDefinitions>
|
|
<StackPanel Grid.Column="0" VerticalAlignment="Center" Margin="0,0,12,0">
|
|
<TextBlock x:Name="SelName" FontFamily="Consolas" FontSize="12" Foreground="{DynamicResource TextBrush}"
|
|
TextTrimming="CharacterEllipsis"/>
|
|
<TextBlock x:Name="SelMeta" FontFamily="Consolas" FontSize="10" Foreground="{DynamicResource MutedTextBrush}"
|
|
TextTrimming="CharacterEllipsis" Margin="0,2,0,0"/>
|
|
</StackPanel>
|
|
<StackPanel Grid.Column="1" Orientation="Horizontal" VerticalAlignment="Center">
|
|
<Button Content="{DynamicResource Str_Btn_Cancel}" Style="{StaticResource SurfaceButton}" MinWidth="90" Margin="0,0,8,0" Click="Cancel_Click"/>
|
|
<Button x:Name="AcceptButton" Style="{StaticResource OutlineButton}" MinWidth="90" Click="OK_Click"/>
|
|
</StackPanel>
|
|
</Grid>
|
|
|
|
</Grid>
|
|
</Border>
|
|
|
|
<!-- The same directional 98SE window frame used by DialogChrome. Modern themes set these
|
|
thicknesses to zero, so their existing card treatment is unchanged. -->
|
|
<Grid Margin="{DynamicResource DialogHaloMargin}" IsHitTestVisible="False">
|
|
<Border Margin="{DynamicResource WindowFrameMargin}"
|
|
BorderBrush="{DynamicResource WindowFrameBrush}"
|
|
BorderThickness="{DynamicResource DialogWindowFrameThickness}"/>
|
|
<Border Margin="{DynamicResource FrameInnerMargin}"
|
|
BorderBrush="{DynamicResource FrameInnerLightBrush}"
|
|
BorderThickness="{DynamicResource FrameInnerLightThickness}"/>
|
|
<Border Margin="{DynamicResource FrameInnerMargin}"
|
|
BorderBrush="{DynamicResource FrameInnerDarkBrush}"
|
|
BorderThickness="{DynamicResource FrameInnerDarkThickness}"/>
|
|
<Border BorderBrush="{DynamicResource FrameOuterLightBrush}"
|
|
BorderThickness="{DynamicResource FrameOuterLightThickness}"/>
|
|
<Border BorderBrush="{DynamicResource FrameOuterDarkBrush}"
|
|
BorderThickness="{DynamicResource FrameOuterDarkThickness}"/>
|
|
</Grid>
|
|
</Grid>
|
|
</Window>
|