Files
mmd-pdf/Shell/RailFlyouts.cs
T

103 lines
5.1 KiB
C#

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Animation;
namespace KillerPDF
{
/// <summary>
/// The rail's flyout buttons (family order, locked 2026-07-30: app-specific toggles, then
/// ? / language / theme, theme bottom-most) and their flyouts. The theme, language and view
/// pickers all moved here OUT of the retired Settings panel - one implementation each, as
/// family-standard flyouts: ContextMenus with FlyoutCard/FlyoutGrain chrome, opened against
/// the content pane's bottom-left corner via FlyoutPlacement so they never cover the rail,
/// the footer, or the desktop. Their radio/dot sync is SyncPickerState (SettingsPanel.cs).
/// </summary>
public partial class MainWindow
{
// The shortcuts ? is the strip's ORIGINAL button (ShortcutHelp_Click) - it just moved
// into the family slot above language; no second implementation was added.
private void RailLang_Click(object sender, RoutedEventArgs e) => ToggleRailFlyout(LangFlyout);
private void RailTheme_Click(object sender, RoutedEventArgs e) => ToggleRailFlyout(ThemeFlyout);
private void RailView_Click(object sender, RoutedEventArgs e) => ToggleRailFlyout(ViewFlyout);
// Rolling the wheel over the view-mode rail button steps through the modes without
// opening the flyout: up = next, down = previous (2026-07-31 - down-as-next felt
// reversed). F9 jogs forward from the keyboard.
private void RailView_Wheel(object sender, System.Windows.Input.MouseWheelEventArgs e)
{
CycleViewMode(forward: e.Delta > 0);
e.Handled = true;
}
/// <summary>Steps to the neighboring view mode, wrapping at the ends. Cycle order is the
/// enum order: Single -> Continuous -> TwoPage -> Grid. Syncs the flyout radios in case
/// the flyout is open while the wheel or F9 drives the change.</summary>
private void CycleViewMode(bool forward = true)
{
var modes = (ViewMode[])Enum.GetValues(typeof(ViewMode));
// Step from the PENDING mode when a fade-wrapped switch is in flight: _viewMode only
// updates after the ~90ms fade-out, so wheel notches faster than that would otherwise
// recompute from the stale mode and retarget the same switch - several notches
// collapsing into one step (2-4 clicks per mode, as first built).
int idx = Array.IndexOf(modes, _pendingViewMode ?? _viewMode);
int next = (idx + (forward ? 1 : -1) + modes.Length) % modes.Length;
SetViewMode(modes[next]);
SyncPickerState();
}
private void ToggleRailFlyout(ContextMenu menu)
{
if (menu.IsOpen) { menu.IsOpen = false; return; }
// The theme strip always faces the document. Mirroring the two columns also makes its
// width animation grow outward from the rail on either side of the window.
if (menu == ThemeFlyout)
SyncThemeFlyoutSide();
// Radios and accent dots reflect live state before the card shows - the same single
// sync the Settings panel runs on open.
SyncPickerState();
// SplitHost is the full document region between the rail and the window edge. Its
// rail-adjacent bottom corner is left when the sidebar is left and right when the
// sidebar is right. Using one viewer pane here stranded the flyouts on the left after
// the sidebar moved right, and could place them in the middle of a split document.
if (SplitHost is FrameworkElement pane)
FlyoutPlacement.UsePane(pane, _sidebarRight);
FlyoutPlacement.Attach(menu, this);
menu.IsOpen = true;
// 150ms ease-out, the family fade (the flyout template replaces the implicit
// ContextMenu template, whose Loaded trigger normally drives this).
menu.BeginAnimation(UIElement.OpacityProperty,
new DoubleAnimation(0, 1, new Duration(TimeSpan.FromMilliseconds(150)))
{
EasingFunction = new QuadraticEase { EasingMode = EasingMode.EaseOut }
});
}
private void SyncThemeFlyoutSide()
{
if (ThemePickerLayout is null || ThemeSubmenu is null || AccentStripHost is null ||
AccentStripDivider is null || AccentStrip is null)
return;
Grid.SetColumn(ThemeSubmenu, _sidebarRight ? 1 : 0);
Grid.SetColumn(AccentStripHost, _sidebarRight ? 0 : 1);
AccentStripDivider.HorizontalAlignment = _sidebarRight
? HorizontalAlignment.Right
: HorizontalAlignment.Left;
AccentStrip.Margin = _sidebarRight
? new Thickness(2, 6, 7, 6)
: new Thickness(7, 6, 2, 6);
ThemePickerLayout.Margin = _sidebarRight
? new Thickness(3, 10, 12, 10)
: new Thickness(12, 10, 3, 10);
}
}
}