vendor: import KillerPDF 1.7.5 source (GPL-3.0) as the base for MMD PDF
This commit is contained in:
@@ -0,0 +1,166 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Controls;
|
||||
using KillerPDF.Controls;
|
||||
|
||||
namespace KillerPDF.Features
|
||||
{
|
||||
/// <summary>
|
||||
/// What a document viewer needs from the window around it.
|
||||
///
|
||||
/// EXTENDS IShellServices, per the family rule in that file - the shell implements Window /
|
||||
/// Loc / SetStatus once, not once per feature. Those three cover the viewer's two heaviest
|
||||
/// call groups on their own (Loc 70 uses, SetStatus 68) plus the modal-dialog owner that
|
||||
/// TextEditing and Links need for KillerDialog (3 uses).
|
||||
///
|
||||
/// DERIVED FROM MEASUREMENT, not guessed: every member here came from grepping what the nine
|
||||
/// files bound for the viewer control (Viewport, Zoom, Annotations, Selection, TextEditing,
|
||||
/// Crop, Links, Forms, PageSelection) actually reach for on MainWindow today. Use counts are
|
||||
/// noted per member so the cost of each is visible.
|
||||
///
|
||||
/// That audit split the coupling into three groups, and only the first belongs here:
|
||||
///
|
||||
/// A. HOST SERVICES - chrome and app-level services the viewer asks for. This interface.
|
||||
///
|
||||
/// B. PER-DOCUMENT STATE - _doc (120 uses), _currentFile (33), _annotations (56),
|
||||
/// _renderDims (34), _pageRotations (11), _undoStack (4). These are NOT host services:
|
||||
/// they already ride in DocumentSession, which tab switching swaps by reference. The
|
||||
/// viewer will hold its own active session and read them from it. Routing them through
|
||||
/// the host would be a mistake that undoes the session design.
|
||||
///
|
||||
/// C. PageList - 84 uses, the single biggest coupling, and a DESIGN DECISION rather than a
|
||||
/// mechanical one. The sidebar's page-thumbnail list is window chrome, but the viewer
|
||||
/// drives it constantly (selection sync, scroll-to-page). With two panes there is still
|
||||
/// ONE sidebar, so it has to follow the FOCUSED pane. The viewer therefore must not touch
|
||||
/// PageList directly; it raises the notifications below and the window decides whether
|
||||
/// this viewer is the focused one before acting. Getting this wrong is how the two panes
|
||||
/// would end up fighting over the sidebar.
|
||||
/// </summary>
|
||||
internal interface IViewerHost : IShellServices
|
||||
{
|
||||
// ── Chrome the viewer updates (group A) ─────────────────────────────────────────────
|
||||
/// <summary>Mark the active document dirty (unsaved changes). 32 uses. Stays a host
|
||||
/// service even though dirtiness is per-document, because it also drives window chrome -
|
||||
/// the tab's dirty dot and the title bar.</summary>
|
||||
void MarkDirty(bool dirty = true);
|
||||
|
||||
// PushUndo is deliberately NOT here, despite 9 uses. Undo is per-document state (group B):
|
||||
// _undoStack rides in DocumentSession, so the viewer pushes onto the session it is showing
|
||||
// rather than asking the window. It was in this interface briefly and the compiler caught
|
||||
// it - UndoEntry is a private nested record struct on MainWindow, and widening it plus its
|
||||
// UndoKind enum just to satisfy the signature would have been the wrong fix for a member
|
||||
// that should not have been here. (2026-08-01.)
|
||||
|
||||
/// <summary>Switch tools - Crop uses this to drop back to Select when it finishes. 2 uses.</summary>
|
||||
void SetTool(EditTool tool);
|
||||
bool SidebarShowingOutlines { get; }
|
||||
void PopulateRecentFilesList(PdfViewer viewer);
|
||||
void SwitchSidebarToPagesTab();
|
||||
void SyncSidebarToDocState(bool hasDoc, bool startup);
|
||||
void OpenFile(string path);
|
||||
void UpdateFooterFade();
|
||||
void UpdateTabStripFade();
|
||||
Border? SearchBar { get; }
|
||||
SearchController Search { get; }
|
||||
TextBlock FileNameLabel { get; }
|
||||
TreeView OutlineTree { get; }
|
||||
Button SidebarOutlinesTab { get; }
|
||||
TextBlock StatusText { get; }
|
||||
FrameworkElement ShortcutOverlay { get; }
|
||||
CheckBox LinkConfirmCheck { get; }
|
||||
ContextMenu MakeThemedMenu();
|
||||
void CloseSearchBar();
|
||||
void HideSignaturePopup();
|
||||
void SaveTempAndReload(bool keepAnnotations, bool preserveZoom);
|
||||
void RecordNavJump();
|
||||
PageAnnotation? PairPartner(PageAnnotation annotation);
|
||||
void RenderStamps(int page);
|
||||
void OpenStampTool();
|
||||
bool StampHitTest(int page, Point position);
|
||||
void ApplySearchHighlights(int page, Canvas canvas);
|
||||
void HighlightSearchResultsOnCurrentPage();
|
||||
void ShowTextSettings();
|
||||
void HideTextSettings();
|
||||
void StyleEditBox(TextBox textBox);
|
||||
void ApplyTextStyleToSelection();
|
||||
void ShowDrawSettings(EditTool tool);
|
||||
void HideDrawSettings();
|
||||
Border MakeBarGrip(int dotCount);
|
||||
FrameworkElement BuildBarHost(FrameworkElement content);
|
||||
void PlaceAnnotationBar(Border bar, Border grip, bool fadeIn);
|
||||
void PlaceImageFromDialog(Point position, int pageIndex);
|
||||
void PlaceSignature(Point position, int pageIndex);
|
||||
void ShowSignaturePopup();
|
||||
void FillSignField(bool initials, int objectNumber, int pageIndex,
|
||||
double x, double y, double width, double height);
|
||||
void ShapeToolMouseDown(int pageIndex, Point position, MouseButtonEventArgs e);
|
||||
void CommitShapeDrag(int pageIndex);
|
||||
void UpdateShapePolyRubber(MouseEventArgs e);
|
||||
void OcrRegion(int pageIndex, Rect canvasBounds);
|
||||
void ShowShortcutsOverlayExclusive();
|
||||
System.Windows.Media.SolidColorBrush SwatchDimBorder { get; }
|
||||
PageAnnotation? CloneAnnotation(PageAnnotation annotation);
|
||||
System.Windows.TextDecorationCollection? BuildDecorations(bool underline, bool strike);
|
||||
System.Windows.Media.Effects.DropShadowEffect AnnotBarShadow();
|
||||
void FadeOverlayOut(UIElement element);
|
||||
void FadeOutAndRemoveBar(Border? bar);
|
||||
PdfSharpCore.Pdf.PdfItem DerefItem(PdfSharpCore.Pdf.PdfItem item);
|
||||
string WordsToText(System.Collections.Generic.IEnumerable<UglyToad.PdfPig.Content.Word> words);
|
||||
MenuItem MakeMenuItem(string header, RoutedEventHandler click, string? gesture, string? glyph);
|
||||
bool FullScreen { get; }
|
||||
bool VerticalScrollVisible { get; set; }
|
||||
bool SpaceHeld { get; }
|
||||
void RepositionAnnotationBars();
|
||||
void PopulateContextMenu(PdfViewer viewer, Point point, int pageIndex);
|
||||
void RefreshPageList(PdfViewer viewer);
|
||||
void LoadOutlines(PdfViewer viewer);
|
||||
Cursor CursorForTool(EditTool tool);
|
||||
|
||||
// ── Notifications, so the window can update chrome for the FOCUSED viewer only ───────
|
||||
// These replace the viewer poking at PageList / ZoomBox / PageLabel / StatusText itself.
|
||||
/// <summary>This viewer scrolled or paged to a different page.</summary>
|
||||
void ViewerPageChanged(PdfViewer viewer, int pageIndex);
|
||||
void EnsureSidebarPageVisible(PdfViewer viewer, int pageIndex);
|
||||
void ScrollSidebar(PdfViewer viewer, double delta);
|
||||
void ClearSidebarPages(PdfViewer viewer);
|
||||
string PageJumpText { get; set; }
|
||||
bool PageJumpEnabled { set; }
|
||||
bool CloseFileEnabled { set; }
|
||||
string PageTotalText { set; }
|
||||
void SelectAllPageJumpText();
|
||||
void SyncZoomDisplay(string? fitTag, string displayText);
|
||||
string? SelectedZoomTag { get; }
|
||||
void CollapseZoomTextSelection();
|
||||
|
||||
/// <summary>This viewer's zoom or fit mode changed (updates the zoom box). 16 uses of
|
||||
/// ZoomBox today.</summary>
|
||||
void ViewerZoomChanged(double zoomLevel);
|
||||
|
||||
/// <summary>This viewer took focus - the window repoints the sidebar, page list and
|
||||
/// status line at it, and moves the accent halo.</summary>
|
||||
void ViewerFocused();
|
||||
|
||||
// Window-owned chrome and start-screen actions raised by one viewer instance.
|
||||
void ViewerSizeChanged(PdfViewer viewer, object sender, SizeChangedEventArgs e);
|
||||
void ViewerDrop(PdfViewer viewer, object sender, DragEventArgs e);
|
||||
void ViewerDragOver(object sender, DragEventArgs e);
|
||||
void ViewerDropZoneClick(object sender, MouseButtonEventArgs e);
|
||||
void ClearRecentFiles(object sender, MouseButtonEventArgs e);
|
||||
void ViewerBackgroundRightClick(object sender, MouseButtonEventArgs e);
|
||||
void ViewerTabStripMouseDown(object sender, MouseButtonEventArgs e);
|
||||
|
||||
bool IsViewerFocused(PdfViewer viewer);
|
||||
bool IsSplitView { get; }
|
||||
void FocusViewer(PdfViewer viewer);
|
||||
bool OtherViewerHasFile(PdfViewer viewer, string? originalFile);
|
||||
|
||||
PdfViewer? TabDropTarget(PdfViewer source, MouseEventArgs e);
|
||||
void UpdateTabDragFeedback(PdfViewer source, PdfViewer.DocumentSession session,
|
||||
MouseEventArgs e, PdfViewer? target);
|
||||
void HideTabDragFeedback();
|
||||
void MoveTabToPane(PdfViewer source, PdfViewer target,
|
||||
PdfViewer.DocumentSession session, MouseEventArgs e);
|
||||
|
||||
void RunWithViewerContext(PdfViewer viewer, System.Action work);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace KillerPDF
|
||||
{
|
||||
/// <summary>
|
||||
/// The tab and session members under the names the window already calls them by, routed to the
|
||||
/// focused pane. Keeping the old names resolvable leaves the call sites in FileOperations,
|
||||
/// KeyboardShortcuts, ImportAndZip, TempReload, WindowChrome and SettingsPanel unchanged while
|
||||
/// making them act on whichever pane has focus.
|
||||
///
|
||||
/// Ctrl+W, Ctrl+Tab, Ctrl+Q and CloseFile_Click are keyboard- or XAML-bound, so these
|
||||
/// declarations are load-bearing rather than convenience.
|
||||
/// </summary>
|
||||
public partial class MainWindow
|
||||
{
|
||||
private void OpenInNewTab(string path) => ActiveViewer.OpenInNewTabExt(path);
|
||||
private void CloseTab(Controls.PdfViewer.DocumentSession? s) => ActiveViewer.CloseTabExt(s);
|
||||
private void CloseAllTabs() => ActiveViewer.CloseAllTabsExt();
|
||||
private void CloseOtherTabs(Controls.PdfViewer.DocumentSession? s) => ActiveViewer.CloseOtherTabsExt(s);
|
||||
private void CycleTab(int dir) => ActiveViewer.CycleTabExt(dir);
|
||||
private void EnsureInitialSession() => ActiveViewer.EnsureInitialSessionExt();
|
||||
private void MaterializeDeferred(Controls.PdfViewer.DocumentSession target)
|
||||
=> ActiveViewer.MaterializeDeferredExt(target);
|
||||
|
||||
private Controls.PdfViewer.DocumentSession BeginTabLoad(
|
||||
out Controls.PdfViewer.DocumentSession? prev, out bool createdNew)
|
||||
=> ActiveViewer.BeginTabLoadExt(out prev, out createdNew);
|
||||
private void AbortTabLoad(Controls.PdfViewer.DocumentSession target,
|
||||
Controls.PdfViewer.DocumentSession? prev, bool createdNew)
|
||||
=> ActiveViewer.AbortTabLoadExt(target, prev, createdNew);
|
||||
|
||||
private void CaptureSessionState(Controls.PdfViewer.DocumentSession s)
|
||||
=> ActiveViewer.CaptureSessionStateExt(s);
|
||||
private void ApplySessionState(Controls.PdfViewer.DocumentSession s)
|
||||
=> ActiveViewer.ApplySessionStateExt(s);
|
||||
private void SaveDocState(string? path, FitMode fit, double zoom, ViewMode view, int page)
|
||||
=> ActiveViewer.SaveDocStateExt(path, fit, zoom, view, page);
|
||||
private bool TryGetDocState(string? path, out FitMode fit, out double zoom,
|
||||
out ViewMode view, out int page)
|
||||
=> ActiveViewer.TryGetDocStateExt(path, out fit, out zoom, out view, out page);
|
||||
|
||||
private void RebuildTabStrip() => ActiveViewer.RebuildTabStripExt();
|
||||
private void ScheduleTabReflow() => ActiveViewer.ScheduleTabReflowExt();
|
||||
private void RenderActiveSession() => ActiveViewer.RenderActiveSessionExt();
|
||||
private void ShowEmptyState() => ActiveViewer.ShowEmptyStateExt();
|
||||
/// <summary>Night mode changed: flush both panes. The invert state is baked into cached
|
||||
/// pixels, so pane B's cache is as stale as pane A's.</summary>
|
||||
private void FlushAllRenderCaches()
|
||||
{
|
||||
Viewer.FlushAllRenderCachesExt();
|
||||
ViewerB.FlushAllRenderCachesExt();
|
||||
}
|
||||
|
||||
/// <summary>Every open document across both panes. The quit prompt and the settings writer
|
||||
/// need all of them, or closing the window silently drops pane B's unsaved work.</summary>
|
||||
private IEnumerable<Controls.PdfViewer.DocumentSession> AllSessions()
|
||||
{
|
||||
foreach (var s in Viewer.SessionsRef) yield return s;
|
||||
foreach (var s in ViewerB.SessionsRef) yield return s;
|
||||
}
|
||||
|
||||
/// <summary>The focused pane's open documents. Callers that mean "this pane" - the tab
|
||||
/// context menu's Close Others, the reorder resync - want this rather than AllSessions.</summary>
|
||||
private System.Collections.ObjectModel.ObservableCollection<Controls.PdfViewer.DocumentSession> _sessions
|
||||
=> ActiveViewer.SessionsRef;
|
||||
|
||||
/// <summary>The focused pane's tab strip, for the chrome that positions or hides it.
|
||||
/// AppScale and FullScreen act on both panes at their own call sites; SidebarLayout's fade
|
||||
/// mask only describes the pane it is measuring, so it takes the active one.</summary>
|
||||
private System.Windows.Controls.Border TabStripBorder => ActiveViewer.TabStripBorderCtl;
|
||||
private System.Windows.Controls.Border TabStripFade => ActiveViewer.TabStripFadeCtl;
|
||||
|
||||
/// <summary>True when the other pane holds an unsaved copy of the same file.
|
||||
///
|
||||
/// The split opens a file as two independent copies, not two views of one document: each
|
||||
/// pane has its own annotations, undo stack and dirty flag, so whichever saves last wins.
|
||||
/// This is the guard on that.
|
||||
///
|
||||
/// Compares OriginalFile, not CurrentFile: crop and rotate swap the working file out to a
|
||||
/// temp path, so CurrentFile can differ between two panes showing the same document.</summary>
|
||||
private bool OtherPaneHasDirtyCopyOf(string? originalFile)
|
||||
{
|
||||
if (string.IsNullOrEmpty(originalFile)) return false;
|
||||
var other = ReferenceEquals(ActiveViewer, Viewer) ? ViewerB : Viewer;
|
||||
other.CaptureActiveIfAny(); // its live dirty flag may not be folded into its session yet
|
||||
return other.SessionsRef.Any(s => s.IsDirty
|
||||
&& string.Equals(s.OriginalFile, originalFile, System.StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
/// <summary>Place the restored session list into pane A. The startup restore builds the list
|
||||
/// itself rather than going through EnsureInitialSession, so it hands the result over.
|
||||
/// Per-pane restore is not implemented; everything reopens in pane A.</summary>
|
||||
private void SetRestoredSessions(IEnumerable<Controls.PdfViewer.DocumentSession> sessions,
|
||||
Controls.PdfViewer.DocumentSession? active)
|
||||
=> Viewer.SetSessionsExt(sessions, active);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Shapes;
|
||||
using PdfSharpCore.Pdf;
|
||||
|
||||
namespace KillerPDF
|
||||
{
|
||||
/// <summary>
|
||||
/// The window's half of the viewer bridge. Read this alongside
|
||||
/// Controls/PdfViewer.Bridge.cs, which is the other end of every line here.
|
||||
///
|
||||
/// TWO DIRECTIONS, and they are kept apart on purpose:
|
||||
///
|
||||
/// INWARD - accessors the viewer reads. MainWindow's own members are private and a control
|
||||
/// in another namespace cannot see them. Rather than widen ~40 fields in place and
|
||||
/// scatter `internal` through fifteen files, each is exposed once, here, under a
|
||||
/// name that says it is a bridge rather than an ordinary member. The private
|
||||
/// fields stay private, so nothing else in the app gains reach by accident.
|
||||
///
|
||||
/// OUTWARD - focused-pane routing for shared toolbar and keyboard commands. Per-viewer
|
||||
/// editing and document state stays on PdfViewer; only window-owned commands
|
||||
/// cross this boundary.
|
||||
///
|
||||
/// XAML handlers remain on MainWindow because WPF resolves them against the XAML root.
|
||||
/// </summary>
|
||||
public partial class MainWindow
|
||||
{
|
||||
// ══ INWARD: chrome the viewer reads ═════════════════════════════════════════════════
|
||||
// PageList is not here - x:Name fields are generated internal, so the control already
|
||||
// sees it. These four are hand-declared private fields assigned from FindName, so they
|
||||
// are not.
|
||||
/// <summary>The window's ONE PageList selection delegate. Handed out rather than rebuilt
|
||||
/// because SyncCurrentPageTo detaches and reattaches it - a method group would make a new
|
||||
/// delegate per call and the -= would quietly remove nothing.</summary>
|
||||
internal SelectionChangedEventHandler PageListSelectionHandler
|
||||
=> _pageListSelectionHandler ??= PageList_SelectionChanged;
|
||||
private SelectionChangedEventHandler? _pageListSelectionHandler;
|
||||
|
||||
// ══ INWARD: per-document state (group B - goes when the viewer owns its session) ═════
|
||||
// Settable: the xref-repair path in Annotations.cs, which lives in the viewer, reopens the
|
||||
// document and re-points the temp file.
|
||||
// Reads OUT of the focused pane rather than exposing a window field: the session list
|
||||
// belongs to the viewer. Callers still spell it `_active` - see the alias below.
|
||||
internal Controls.PdfViewer.DocumentSession? ActiveSession => ActiveViewer.ActiveSessionRef;
|
||||
private Controls.PdfViewer.DocumentSession? _active => ActiveViewer.ActiveSessionRef;
|
||||
// Reads OUT of the control rather than exposing a window field: the link-rect map belongs
|
||||
// to the viewer, alongside Links.cs. ContextMenu.cs and FileOperations.cs still call it by
|
||||
// this name.
|
||||
private Dictionary<int, List<LinkInfo>> _continuousLinks => ActiveViewer.ContinuousLinks;
|
||||
|
||||
// Live gesture state, shared with the annotation and crop tools that have not moved yet.
|
||||
|
||||
// ══ OUTWARD: the viewer's members, under the names the window already calls ══════════
|
||||
// Signatures mirror the originals exactly, defaults included, so no call site changed.
|
||||
private System.Threading.Tasks.Task RenderContinuousPages(int centerPage) => ActiveViewer.RenderContinuousPages(centerPage);
|
||||
private void BootstrapDocumentView(int initialPage, bool autoFit, bool restoreFitMode = false)
|
||||
=> ActiveViewer.BootstrapDocumentView(initialPage, autoFit, restoreFitMode);
|
||||
private void RefreshPageView(int pageIndex) => ActiveViewer.RefreshPageView(pageIndex);
|
||||
private void ScrollContinuousToPage(int pageIndex) => ActiveViewer.ScrollContinuousToPage(pageIndex);
|
||||
|
||||
private void StartRerenderTimer() => ActiveViewer.StartRerenderTimer();
|
||||
private void SetZoom(double level) => ActiveViewer.SetZoom(level);
|
||||
private void SetTrueZoom(double trueZoom) => ActiveViewer.SetTrueZoom(trueZoom);
|
||||
private void GridZoomStep(bool zoomOut) => ActiveViewer.GridZoomStep(zoomOut);
|
||||
private double GridZoomForN(int n) => ActiveViewer.GridZoomForN(n);
|
||||
private double DisplayZoomPct() => ActiveViewer.DisplayZoomPct();
|
||||
private void SyncZoomBox() => ActiveViewer.SyncZoomBox();
|
||||
private void FitToWidth(bool lite = false) => ActiveViewer.FitToWidth(lite);
|
||||
private void FitToPage(bool lite = false) => ActiveViewer.FitToPage(lite);
|
||||
|
||||
private void SetViewMode(ViewMode mode) => ActiveViewer.SetViewMode(mode);
|
||||
private void SelectViewMode(ViewMode mode) => ActiveViewer.SelectViewMode(mode);
|
||||
private void ApplyViewMode(ViewMode mode) => ActiveViewer.ApplyViewMode(mode);
|
||||
private ViewMode? _pendingViewMode { get => ActiveViewer.PendingViewMode; set => ActiveViewer.PendingViewMode = value; }
|
||||
|
||||
private bool NavigatePageStep(int direction) => ActiveViewer.NavigatePageStep(direction);
|
||||
private void NavigatePageByWheel(int delta) => ActiveViewer.NavigatePageByWheel(delta);
|
||||
|
||||
private int _gridColumns { get => ActiveViewer.GridColumns; set => ActiveViewer.GridColumns = value; }
|
||||
|
||||
private void BuildPrimaryTile() => ActiveViewer.BuildPrimaryTile();
|
||||
private void PagePreviewPanel_SizeChanged(object sender, SizeChangedEventArgs e)
|
||||
=> ActiveViewer.PagePreviewPanel_SizeChanged(sender, e);
|
||||
|
||||
// Bound from MainWindow.xaml (the zoom toolbar stays on the window) and from
|
||||
// ContextMenu.cs, so these three cannot simply live on the control.
|
||||
private void ZoomIn_Click(object sender, RoutedEventArgs e) => ActiveViewer.ZoomIn_Click(sender, e);
|
||||
private void ZoomOut_Click(object sender, RoutedEventArgs e) => ActiveViewer.ZoomOut_Click(sender, e);
|
||||
|
||||
// ACTIVEVIEWER, like every other stub in this file - this one said `Viewer` (pane A,
|
||||
// hardcoded) and was the split's cross-zoom bug: FocusPane(B) -> SyncZoomBox writes the
|
||||
// shared box -> SelectionChanged -> this stub ran PANE A's handler, which FitToWidth'd
|
||||
// pane A against pane B's document (proven by zoomtrace, 2026-08-01).
|
||||
// NULL-CONDITIONAL, and it must stay that way. ZoomBox declares
|
||||
// <ComboBoxItem Tag="1.0" IsSelected="True"> (MainWindow.xaml), so SelectionChanged fires
|
||||
// while InitializeComponent is still walking the tree - ActiveViewer is not assigned until
|
||||
// InitSplitPanes runs after it, so the `?.` no-ops the mid-parse fire exactly like the old
|
||||
// `_zoomBox?.SelectedItem` guard did. Click handlers do not need this - a click cannot
|
||||
// happen mid-parse.
|
||||
private void ZoomBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
=> ActiveViewer?.ZoomBox_SelectionChanged(sender, e);
|
||||
|
||||
// Wheel over the zoom dropdown nudges the zoom like Ctrl+scroll. Null-conditional for the
|
||||
// same mid-parse reason as SelectionChanged above.
|
||||
private void ZoomBox_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
|
||||
=> ActiveViewer?.ZoomBoxWheel(e);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using System.Windows.Controls;
|
||||
using KillerPDF.Controls;
|
||||
|
||||
namespace KillerPDF
|
||||
{
|
||||
// The element names MainWindow.xaml used to generate, now that the document pane is a control
|
||||
// (Controls/PdfViewer.xaml).
|
||||
//
|
||||
// Same trick as the ViewerState forwarding: the names stay, the storage moves. Every
|
||||
// existing call site - DocPaneBorder.CornerRadius in Tabs.cs, DocPaneShadow.Visibility in
|
||||
// FullScreen.cs, PagePreviewPanel and MarqueeLayer across the render and annotation code -
|
||||
// compiles untouched.
|
||||
//
|
||||
// Get-only is correct here: callers mutate the ELEMENT (its margin, radius, visibility), never
|
||||
// rebind the reference.
|
||||
//
|
||||
// NOTE the one thing that could NOT be forwarded: the card's MARGIN. It lives on the control
|
||||
// now, not on PaneBorder, because the control is what the layout positions. ApplySidebarSide
|
||||
// and ApplyFullScreen set ActiveViewer.Margin directly.
|
||||
public partial class MainWindow
|
||||
{
|
||||
private Border DocPaneShadow => ActiveViewer.PaneShadowBorder;
|
||||
private Border DocPaneBorder => ActiveViewer.PaneCardBorder;
|
||||
private Grid DocPaneContent => ActiveViewer.ContentHost;
|
||||
// 7 bare uses in Tabs.cs and Viewport.cs. Note this is a SEPARATE member from the
|
||||
// underscore-prefixed _pageContentGrid, which forwards to ViewerState - the code uses both
|
||||
// spellings, so both have to resolve.
|
||||
private Grid PageContentGrid => ActiveViewer.PageGrid;
|
||||
private ScrollViewer PagePreviewPanel => ActiveViewer.PreviewScroller;
|
||||
private Border DropZone => ActiveViewer.DropSurface;
|
||||
private Border RecentFilesBox => ActiveViewer.RecentBox;
|
||||
private ItemsControl RecentFilesList => ActiveViewer.RecentList;
|
||||
private Canvas MarqueeLayer => ActiveViewer.Marquee;
|
||||
private Border DocSurfacePad => ActiveViewer.SurfacePad;
|
||||
private System.Windows.Media.ImageBrush GrainBrush => ActiveViewer.Grain;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,241 @@
|
||||
using KillerPDF.Features;
|
||||
using KillerPDF.Controls;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace KillerPDF
|
||||
{
|
||||
// MainWindow's half of IViewerHost.
|
||||
//
|
||||
// Explicit implementation throughout, matching Shell/About.cs: MainWindow's own members are
|
||||
// private, and a private member cannot implement an interface. Forwarding explicitly satisfies
|
||||
// the contract without widening anything to public - a change nobody asked for.
|
||||
//
|
||||
// IShellServices (Window / Loc / SetStatus) is already implemented in Shell/About.cs and is
|
||||
// inherited through IViewerHost, so it is deliberately NOT repeated here.
|
||||
public partial class MainWindow : IViewerHost
|
||||
{
|
||||
void IViewerHost.MarkDirty(bool dirty) => MarkDirty(dirty);
|
||||
|
||||
void IViewerHost.SetTool(EditTool tool) => SetTool(tool);
|
||||
bool IViewerHost.SidebarShowingOutlines => _sidebarShowingOutlines;
|
||||
void IViewerHost.PopulateRecentFilesList(PdfViewer viewer) => PopulateRecentFilesList(viewer);
|
||||
void IViewerHost.SwitchSidebarToPagesTab() => SwitchSidebarToPagesTab();
|
||||
void IViewerHost.SyncSidebarToDocState(bool hasDoc, bool startup)
|
||||
=> SyncSidebarToDocState(hasDoc, startup);
|
||||
void IViewerHost.OpenFile(string path) => OpenFile(path);
|
||||
void IViewerHost.UpdateFooterFade() => UpdateFooterFade();
|
||||
void IViewerHost.UpdateTabStripFade() => UpdateTabStripFade();
|
||||
System.Windows.Controls.Border? IViewerHost.SearchBar => _searchBar;
|
||||
Features.SearchController IViewerHost.Search => Search;
|
||||
System.Windows.Controls.TextBlock IViewerHost.FileNameLabel => FileNameLabel;
|
||||
System.Windows.Controls.TreeView IViewerHost.OutlineTree => OutlineTree;
|
||||
System.Windows.Controls.Button IViewerHost.SidebarOutlinesTab => SidebarOutlinesTab;
|
||||
System.Windows.Controls.TextBlock IViewerHost.StatusText => StatusText;
|
||||
FrameworkElement IViewerHost.ShortcutOverlay => ShortcutOverlay;
|
||||
System.Windows.Controls.CheckBox IViewerHost.LinkConfirmCheck => LinkConfirmCheck;
|
||||
System.Windows.Controls.ContextMenu IViewerHost.MakeThemedMenu() => MakeThemedMenu();
|
||||
void IViewerHost.CloseSearchBar() => CloseSearchBar();
|
||||
void IViewerHost.HideSignaturePopup() => HideSignaturePopup();
|
||||
void IViewerHost.SaveTempAndReload(bool keepAnnotations, bool preserveZoom)
|
||||
=> SaveTempAndReload(keepAnnotations, preserveZoom);
|
||||
void IViewerHost.RecordNavJump() => RecordNavJump();
|
||||
PageAnnotation? IViewerHost.PairPartner(PageAnnotation annotation) => PairPartner(annotation);
|
||||
void IViewerHost.RenderStamps(int page) => RenderStamps(page);
|
||||
void IViewerHost.OpenStampTool() => OpenStampTool();
|
||||
bool IViewerHost.StampHitTest(int page, Point position) => StampHitTest(page, position);
|
||||
void IViewerHost.ApplySearchHighlights(int page, System.Windows.Controls.Canvas canvas)
|
||||
=> ApplySearchHighlights(page, canvas);
|
||||
void IViewerHost.HighlightSearchResultsOnCurrentPage() => HighlightSearchResultsOnCurrentPage();
|
||||
void IViewerHost.ShowTextSettings() => ShowTextSettings();
|
||||
void IViewerHost.HideTextSettings() => HideTextSettings();
|
||||
void IViewerHost.StyleEditBox(System.Windows.Controls.TextBox textBox) => StyleEditBox(textBox);
|
||||
void IViewerHost.ApplyTextStyleToSelection() => ApplyTextStyleToSelection();
|
||||
void IViewerHost.ShowDrawSettings(EditTool tool) => ShowDrawSettings(tool);
|
||||
void IViewerHost.HideDrawSettings() => HideDrawSettings();
|
||||
System.Windows.Controls.Border IViewerHost.MakeBarGrip(int dotCount) => MakeBarGrip(dotCount);
|
||||
FrameworkElement IViewerHost.BuildBarHost(FrameworkElement content) => BuildBarHost(content);
|
||||
void IViewerHost.PlaceAnnotationBar(System.Windows.Controls.Border bar,
|
||||
System.Windows.Controls.Border grip, bool fadeIn) => PlaceAnnotationBar(bar, grip, fadeIn);
|
||||
void IViewerHost.PlaceImageFromDialog(Point position, int pageIndex)
|
||||
=> PlaceImageFromDialog(position, pageIndex);
|
||||
void IViewerHost.PlaceSignature(Point position, int pageIndex) => PlaceSignature(position, pageIndex);
|
||||
void IViewerHost.ShowSignaturePopup() => ShowSignaturePopup();
|
||||
void IViewerHost.FillSignField(bool initials, int objectNumber, int pageIndex,
|
||||
double x, double y, double width, double height)
|
||||
=> FillSignField(initials, objectNumber, pageIndex, x, y, width, height);
|
||||
void IViewerHost.ShapeToolMouseDown(int pageIndex, Point position, MouseButtonEventArgs e)
|
||||
=> ShapeToolMouseDown(pageIndex, position, e);
|
||||
void IViewerHost.CommitShapeDrag(int pageIndex) => CommitShapeDrag(pageIndex);
|
||||
void IViewerHost.UpdateShapePolyRubber(MouseEventArgs e) => UpdateShapePolyRubber(e);
|
||||
void IViewerHost.OcrRegion(int pageIndex, Rect canvasBounds) => OcrRegion(pageIndex, canvasBounds);
|
||||
void IViewerHost.ShowShortcutsOverlayExclusive() => ShowShortcutsOverlayExclusive();
|
||||
System.Windows.Media.SolidColorBrush IViewerHost.SwatchDimBorder => _swatchDimBorder;
|
||||
PageAnnotation? IViewerHost.CloneAnnotation(PageAnnotation annotation) => CloneAnnotation(annotation);
|
||||
System.Windows.TextDecorationCollection? IViewerHost.BuildDecorations(bool underline, bool strike)
|
||||
=> BuildDecorations(underline, strike);
|
||||
System.Windows.Media.Effects.DropShadowEffect IViewerHost.AnnotBarShadow() => AnnotBarShadow();
|
||||
void IViewerHost.FadeOverlayOut(UIElement element) => FadeOverlayOut(element);
|
||||
void IViewerHost.FadeOutAndRemoveBar(System.Windows.Controls.Border? bar) => FadeOutAndRemoveBar(bar);
|
||||
PdfSharpCore.Pdf.PdfItem IViewerHost.DerefItem(PdfSharpCore.Pdf.PdfItem item) => DerefItem(item);
|
||||
string IViewerHost.WordsToText(System.Collections.Generic.IEnumerable<UglyToad.PdfPig.Content.Word> words)
|
||||
=> WordsToText(words);
|
||||
System.Windows.Controls.MenuItem IViewerHost.MakeMenuItem(string header, RoutedEventHandler click,
|
||||
string? gesture, string? glyph) => MakeMenuItem(header, click, gesture, glyph);
|
||||
|
||||
bool IViewerHost.FullScreen => _fullScreen;
|
||||
bool IViewerHost.VerticalScrollVisible
|
||||
{
|
||||
get => _vScrollVisible;
|
||||
set => _vScrollVisible = value;
|
||||
}
|
||||
bool IViewerHost.SpaceHeld => _spaceHeld;
|
||||
void IViewerHost.RepositionAnnotationBars() => RepositionAnnotationBars();
|
||||
void IViewerHost.PopulateContextMenu(PdfViewer viewer, Point point, int pageIndex)
|
||||
=> ((IViewerHost)this).RunWithViewerContext(viewer, () => PopulateContextMenu(point, pageIndex));
|
||||
void IViewerHost.RefreshPageList(PdfViewer viewer)
|
||||
=> ((IViewerHost)this).RunWithViewerContext(viewer, RefreshPageList);
|
||||
void IViewerHost.LoadOutlines(PdfViewer viewer)
|
||||
=> ((IViewerHost)this).RunWithViewerContext(viewer, LoadOutlines);
|
||||
Cursor IViewerHost.CursorForTool(EditTool tool) => CursorForTool(tool);
|
||||
|
||||
// ---- Focused-viewer notifications ----------------------------------------------------
|
||||
// Single pane today, so these just drive the existing chrome directly. When there are two,
|
||||
// each body gains a "is the caller the focused viewer?" guard - the sidebar, page list and
|
||||
// status line follow focus rather than whichever pane happened to update last. Keeping the
|
||||
// calls routed through here means that guard lands in three known places instead of being
|
||||
// hunted through 84 PageList call sites. (BACKLOG.md, group C.)
|
||||
|
||||
void IViewerHost.ViewerPageChanged(PdfViewer viewer, int pageIndex)
|
||||
{
|
||||
if (!ReferenceEquals(ActiveViewer, viewer)) return;
|
||||
// Direct assignment, because that is what the 84 existing call sites do - there is no
|
||||
// SyncPageListSelection helper today. The guard avoids re-entering the selection
|
||||
// handler when the list already agrees.
|
||||
if (pageIndex < 0 || PageList is null) return;
|
||||
if (PageList.SelectedIndex != pageIndex) PageList.SelectedIndex = pageIndex;
|
||||
}
|
||||
|
||||
void IViewerHost.EnsureSidebarPageVisible(PdfViewer viewer, int pageIndex)
|
||||
{
|
||||
if (!ReferenceEquals(ActiveViewer, viewer) || pageIndex < 0 || pageIndex >= PageList.Items.Count) return;
|
||||
PageList.ScrollIntoView(PageList.Items[pageIndex]);
|
||||
}
|
||||
|
||||
void IViewerHost.ScrollSidebar(PdfViewer viewer, double delta)
|
||||
{
|
||||
if (!ReferenceEquals(ActiveViewer, viewer)) return;
|
||||
var scroller = FindSidebarDescendant<System.Windows.Controls.ScrollViewer>(PageList);
|
||||
scroller?.ScrollToVerticalOffset(scroller.VerticalOffset + delta);
|
||||
}
|
||||
|
||||
void IViewerHost.ClearSidebarPages(PdfViewer viewer)
|
||||
{
|
||||
if (ReferenceEquals(ActiveViewer, viewer)) PageList.ItemsSource = null;
|
||||
}
|
||||
|
||||
string IViewerHost.PageJumpText { get => _pageJumpBox.Text; set => _pageJumpBox.Text = value; }
|
||||
bool IViewerHost.PageJumpEnabled { set => _pageJumpBox.IsEnabled = value; }
|
||||
bool IViewerHost.CloseFileEnabled { set => _closeFileBtnRef.IsEnabled = value; }
|
||||
string IViewerHost.PageTotalText { set => _pageTotalLabel.Text = value; }
|
||||
void IViewerHost.SelectAllPageJumpText() => _pageJumpBox.SelectAll();
|
||||
|
||||
void IViewerHost.SyncZoomDisplay(string? fitTag, string displayText)
|
||||
{
|
||||
if (fitTag != null)
|
||||
foreach (System.Windows.Controls.ComboBoxItem item in _zoomBox.Items)
|
||||
if (item.Tag?.ToString() == fitTag) { _zoomBox.SelectedItem = item; return; }
|
||||
foreach (System.Windows.Controls.ComboBoxItem item in _zoomBox.Items)
|
||||
if (item.Content?.ToString() == displayText) { _zoomBox.SelectedItem = item; return; }
|
||||
_zoomBox.SelectedItem = null;
|
||||
_zoomBox.Text = displayText;
|
||||
}
|
||||
|
||||
string? IViewerHost.SelectedZoomTag
|
||||
=> (_zoomBox.SelectedItem as System.Windows.Controls.ComboBoxItem)?.Tag?.ToString();
|
||||
|
||||
void IViewerHost.CollapseZoomTextSelection()
|
||||
{
|
||||
if (_zoomBox.Template?.FindName("PART_EditableTextBox", _zoomBox) is System.Windows.Controls.TextBox box)
|
||||
box.Select(box.Text.Length, 0);
|
||||
}
|
||||
|
||||
// SyncZoomBox reads the current zoom itself rather than taking one, so the parameter is
|
||||
// unused today. It stays in the signature because with two panes the window has to know
|
||||
// WHICH viewer's zoom changed before deciding whether the toolbar box should follow.
|
||||
void IViewerHost.ViewerZoomChanged(double zoomLevel) => SyncZoomBox();
|
||||
|
||||
void IViewerHost.ViewerFocused()
|
||||
{
|
||||
// Nothing to do while there is one viewer. With two panes this moves the accent halo
|
||||
// here and repoints the sidebar at the caller.
|
||||
}
|
||||
|
||||
void IViewerHost.ViewerSizeChanged(PdfViewer viewer, object sender, SizeChangedEventArgs e)
|
||||
=> DocPane_SizeChanged(sender, e);
|
||||
|
||||
void IViewerHost.ViewerDrop(PdfViewer viewer, object sender, DragEventArgs e)
|
||||
{
|
||||
FocusPane(viewer);
|
||||
DropZone_Drop(sender, e);
|
||||
}
|
||||
|
||||
void IViewerHost.ViewerDragOver(object sender, DragEventArgs e)
|
||||
=> DropZone_DragOver(sender, e);
|
||||
|
||||
void IViewerHost.ViewerDropZoneClick(object sender, MouseButtonEventArgs e)
|
||||
=> DropZone_Click(sender, e);
|
||||
|
||||
void IViewerHost.ClearRecentFiles(object sender, MouseButtonEventArgs e)
|
||||
=> RecentClearAll_Click(sender, e);
|
||||
|
||||
void IViewerHost.ViewerBackgroundRightClick(object sender, MouseButtonEventArgs e)
|
||||
=> DocPaneBackground_RightClick(sender, e);
|
||||
|
||||
void IViewerHost.ViewerTabStripMouseDown(object sender, MouseButtonEventArgs e)
|
||||
=> TitleBar_MouseLeftButtonDown(sender, e);
|
||||
|
||||
bool IViewerHost.IsViewerFocused(PdfViewer viewer)
|
||||
=> ReferenceEquals(ActiveViewer, viewer);
|
||||
|
||||
bool IViewerHost.IsSplitView => _isSplit;
|
||||
|
||||
void IViewerHost.FocusViewer(PdfViewer viewer) => FocusPane(viewer);
|
||||
|
||||
bool IViewerHost.OtherViewerHasFile(PdfViewer viewer, string? originalFile)
|
||||
{
|
||||
if (string.IsNullOrEmpty(originalFile)) return false;
|
||||
var other = ReferenceEquals(Viewer, viewer) ? ViewerB : Viewer;
|
||||
return other.SessionsRef.Any(x => (x.Doc != null || x.DeferredPath != null)
|
||||
&& string.Equals(x.OriginalFile, originalFile, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
PdfViewer? IViewerHost.TabDropTarget(PdfViewer source, MouseEventArgs e)
|
||||
=> TabDropTargetPane(source, e);
|
||||
|
||||
void IViewerHost.UpdateTabDragFeedback(PdfViewer source,
|
||||
PdfViewer.DocumentSession session, MouseEventArgs e, PdfViewer? target)
|
||||
=> UpdateTabDragFeedback(source, session, e, target);
|
||||
|
||||
void IViewerHost.HideTabDragFeedback() => HideTabDragFeedback();
|
||||
|
||||
void IViewerHost.MoveTabToPane(PdfViewer source, PdfViewer target,
|
||||
PdfViewer.DocumentSession session, MouseEventArgs e)
|
||||
=> MoveTabToPane(source, target, session, e);
|
||||
|
||||
void IViewerHost.RunWithViewerContext(PdfViewer viewer, Action work)
|
||||
{
|
||||
var focused = ActiveViewer;
|
||||
focused.CaptureActiveIfAny();
|
||||
var previous = SwapActiveViewer(viewer);
|
||||
try { work(); }
|
||||
finally
|
||||
{
|
||||
SwapActiveViewer(previous);
|
||||
focused.RestoreActiveFieldsOnly();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using PdfSharpCore.Pdf;
|
||||
|
||||
namespace KillerPDF
|
||||
{
|
||||
/// <summary>
|
||||
/// Outward stubs: the annotation, text, crop, form and link members under the names the rest of
|
||||
/// the window already calls them by.
|
||||
///
|
||||
/// The point of this file is that ~170 call sites across ContextMenu.cs, TextSettingsBar.cs,
|
||||
/// KeyboardShortcuts.cs, FileOperations.cs, Tabs.cs, Signing.cs, Shapes.cs, Search.cs,
|
||||
/// SidebarOutline.cs, Stamps.cs, ToolSelection.cs, TempReload.cs, Rotate.cs, Ocr.cs and
|
||||
/// DirtyTracking.cs need no changes at all.
|
||||
///
|
||||
/// THE XAML ONES ARE NOT OPTIONAL. WPF resolves Click="Undo_Click" against the code-behind of
|
||||
/// the XAML ROOT - MainWindow - not against whichever class the method ended up in. Eleven
|
||||
/// handlers in MainWindow.xaml point at members that now live in the viewer, and without these
|
||||
/// declarations InitializeComponent throws XamlParseException before the window ever appears.
|
||||
/// Verified against MainWindow.xaml rather than remembered: Undo_Click (2 bindings),
|
||||
/// ClearAllAnnotations_Click (2), PageJumpBox_KeyDown, PageJumpBox_GotFocus,
|
||||
/// PageList_SelectionChanged, ShortcutHelp_Click, ShortcutOverlay_MouseLeftButtonDown (2),
|
||||
/// ShortcutOverlayCard_MouseLeftButtonDown (2), ShortcutOverlayClose_Click,
|
||||
/// Hyperlink_RequestNavigate.
|
||||
/// </summary>
|
||||
public partial class MainWindow
|
||||
{
|
||||
// ── Annotations ──────────────────────────────────────────────────────────────────────
|
||||
private void RenderAllAnnotations(int pageIndex) => ActiveViewer.RenderAllAnnotations(pageIndex);
|
||||
private void ClearSelection() => ActiveViewer.ClearSelection();
|
||||
private void ClearTextSelection() => ActiveViewer.ClearTextSelection();
|
||||
private SolidColorBrush AccentBrush(byte alpha = 255) => ActiveViewer.AccentBrush(alpha);
|
||||
private void AddAnnotation(PageAnnotation a) => ActiveViewer.AddAnnotationExt(a);
|
||||
private Rect AnnotBounds(PageAnnotation a) => ActiveViewer.AnnotBoundsExt(a);
|
||||
private static Point AnnotGetPos(PageAnnotation a) => Controls.PdfViewer.AnnotGetPosExt(a);
|
||||
private static void AnnotSetPos(PageAnnotation a, Point pos) => Controls.PdfViewer.AnnotSetPosExt(a, pos);
|
||||
private Point ClampAnnotPos(PageAnnotation a) => ActiveViewer.ClampAnnotPosExt(a);
|
||||
private bool HitTestAnnotation(PageAnnotation a, Point pos, out Rect bounds)
|
||||
=> ActiveViewer.HitTestAnnotationExt(a, pos, out bounds);
|
||||
private static bool IsDraggable(PageAnnotation a) => Controls.PdfViewer.IsDraggableExt(a);
|
||||
private void SelectAnnotation(PageAnnotation a, Rect bounds) => ActiveViewer.SelectAnnotationExt(a, bounds);
|
||||
private void ToggleMultiSelect(PageAnnotation a, Rect bounds, Canvas canvas)
|
||||
=> ActiveViewer.ToggleMultiSelectExt(a, bounds, canvas);
|
||||
private void SelectGroup(PageAnnotation lead) => ActiveViewer.SelectGroupExt(lead);
|
||||
private PageAnnotation? SelectedPaired() => ActiveViewer.SelectedPairedExt();
|
||||
private int SelectionCount() => ActiveViewer.SelectionCountExt();
|
||||
private void ReattachSelectionVisuals() => ActiveViewer.ReattachSelectionVisualsExt();
|
||||
private void UnpairSelected() => ActiveViewer.UnpairSelectedExt();
|
||||
private void GroupSelected() => ActiveViewer.GroupSelectedExt();
|
||||
private void UngroupAnnotation(PageAnnotation a) => ActiveViewer.UngroupAnnotationExt(a);
|
||||
private void RemoveFromGroup(PageAnnotation a) => ActiveViewer.RemoveFromGroupExt(a);
|
||||
private void DeleteSelected() => ActiveViewer.DeleteSelectedExt();
|
||||
private bool SelectAllAnnotations() => ActiveViewer.SelectAllAnnotationsExt();
|
||||
private void HideBrushPreview() => ActiveViewer.HideBrushPreviewExt();
|
||||
private void FinishStuckGesture() => ActiveViewer.FinishStuckGestureExt();
|
||||
private void RefreshSelectionAccent() => ActiveViewer.RefreshSelectionAccentExt();
|
||||
|
||||
// ── Page canvases ────────────────────────────────────────────────────────────────────
|
||||
private Canvas CanvasForPage(int page) => ActiveViewer.CanvasForPageExt(page);
|
||||
private Canvas? VisibleCanvasForPage(int page) => ActiveViewer.VisibleCanvasForPageExt(page);
|
||||
private IEnumerable<Canvas> AllPageCanvases() => ActiveViewer.AllPageCanvasesExt();
|
||||
|
||||
// ── Undo ─────────────────────────────────────────────────────────────────────────────
|
||||
private void PushDocUndo() => ActiveViewer.PushDocUndoExt();
|
||||
private void PushPageSnapshotUndo(int pageIdx) => ActiveViewer.PushPageSnapshotUndoExt(pageIdx);
|
||||
|
||||
// ── Text editing ─────────────────────────────────────────────────────────────────────
|
||||
private void CommitActiveTextBox() => ActiveViewer.CommitActiveTextBoxExt();
|
||||
private void RemoveTextEditHandles() => ActiveViewer.RemoveTextEditHandlesExt();
|
||||
private void EditTextAtPosition(Point canvasPos, int pageIdx) => ActiveViewer.EditTextAtPositionExt(canvasPos, pageIdx);
|
||||
private void PlaceTextBox(Point pos, int pageIdx) => ActiveViewer.PlaceTextBoxExt(pos, pageIdx);
|
||||
private Brush TextEditBackground() => ActiveViewer.TextEditBackgroundExt();
|
||||
private static ControlTemplate FlatTextBoxTemplate() => Controls.PdfViewer.FlatTextBoxTemplateExt();
|
||||
|
||||
// ── Text selection ───────────────────────────────────────────────────────────────────
|
||||
private void CopySelectedText() => ActiveViewer.CopySelectedTextExt();
|
||||
private void SelectAllText() => ActiveViewer.SelectAllTextExt();
|
||||
|
||||
// ── Crop ─────────────────────────────────────────────────────────────────────────────
|
||||
private void ApplyCrop(int[] pageIndices) => ActiveViewer.ApplyCropExt(pageIndices);
|
||||
private void HideCropConfirmBar() => ActiveViewer.HideCropConfirmBarExt();
|
||||
private void ShowDefaultCropBox() => ActiveViewer.ShowDefaultCropBoxExt();
|
||||
private void RebuildCropBarForLocale() => ActiveViewer.RebuildCropBarForLocaleExt();
|
||||
|
||||
// ── Links ────────────────────────────────────────────────────────────────────────────
|
||||
private void CloseLinkPdfiumDoc() => ActiveViewer.CloseLinkPdfiumDocExt();
|
||||
private void AddLinkMenuItems(ContextMenu menu, object target, int annotIndex, int pageIndex)
|
||||
=> ActiveViewer.AddLinkMenuItemsExt(menu, target, annotIndex, pageIndex);
|
||||
private int? ResolveDest(PdfItem? destItem) => ActiveViewer.ResolveDestExt(destItem);
|
||||
private const double LinkHitPad = Controls.PdfViewer.LinkHitPadShared;
|
||||
internal const string ConfirmLinksSetting = Controls.PdfViewer.ConfirmLinksSetting;
|
||||
|
||||
// ── Save paths ───────────────────────────────────────────────────────────────────────
|
||||
private void DrawAnnotationsOnDocument(int? onlyPage = null) => ActiveViewer.DrawAnnotationsOnDocumentExt(onlyPage);
|
||||
private void WriteFormValuesToDocument() => ActiveViewer.WriteFormValuesToDocumentExt();
|
||||
|
||||
// ── Bound from MainWindow.xaml - see the class comment, these are load-bearing ───────
|
||||
private void Undo_Click(object sender, RoutedEventArgs e) => ActiveViewer.UndoClickExt(sender, e);
|
||||
private void Redo_Click(object sender, RoutedEventArgs e) => ActiveViewer.RedoClickExt(sender, e);
|
||||
private void ClearAnnotations_Click(object sender, RoutedEventArgs e) => ActiveViewer.ClearAnnotationsClickExt(sender, e);
|
||||
private void ClearAllAnnotations_Click(object sender, RoutedEventArgs e) => ActiveViewer.ClearAllAnnotationsClickExt(sender, e);
|
||||
private void PageJumpBox_KeyDown(object sender, KeyEventArgs e) => ActiveViewer.PageJumpBoxKeyDownExt(sender, e);
|
||||
private void PageJumpBox_GotFocus(object sender, RoutedEventArgs e) => ActiveViewer.PageJumpBoxGotFocusExt(sender, e);
|
||||
private void PageList_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
=> ActiveViewer.PageListSelectionChangedExt(sender, e);
|
||||
private void ShortcutHelp_Click(object sender, RoutedEventArgs e) => ActiveViewer.ShortcutHelpClickExt(sender, e);
|
||||
private void ShortcutOverlay_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
=> FadeOverlayOut(ShortcutOverlay);
|
||||
private void ShortcutOverlayCard_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
=> e.Handled = true;
|
||||
private void ShortcutOverlayClose_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
e.Handled = true;
|
||||
FadeOverlayOut(ShortcutOverlay);
|
||||
}
|
||||
private void Hyperlink_RequestNavigate(object sender, System.Windows.Navigation.RequestNavigateEventArgs e)
|
||||
=> ActiveViewer.HyperlinkRequestNavigateExt(sender, e);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user