Files
mmd-pdf/Features/Viewer/IViewerHost.cs
T

167 lines
9.0 KiB
C#

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);
}
}