feat: rebrand to MMD PDF, single corporate theme, and remove original text under an edit

- 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.
This commit is contained in:
2026-08-27 07:37:09 +02:00
parent 532485a830
commit 6610acfa44
230 changed files with 9362 additions and 11508 deletions
+108 -108
View File
@@ -4,7 +4,7 @@ using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Media;
namespace KillerPDF
namespace MmdPdf
{
// Configurable sidebar placement (left or right). The layout uses three columns in
// MainContentGrid: one sized sidebar column, a 6px splitter, and a star document column.
@@ -12,113 +12,6 @@ namespace KillerPDF
// existing collapse / resize logic keeps working unchanged.
public partial class MainWindow
{
private void ApplySidebarSide()
{
// SplitHost, NOT Viewer. Since the split landed, the element that sits in
// MainContentGrid is the SPLIT HOST - Viewer is one of its children. Setting
// Grid.Column on Viewer therefore moved pane A into SplitHost's column 2, which is
// PaneBCol and is ZERO WIDTH while unsplit, so the document rendered into a pane with
// no width and the whole content area went blank. Same for the margin below: the 8px
// gutter to the window edge belongs to the host, not to one pane.
//
// Do NOT look up TabStripBorder / TabScroll here: those elements live inside PdfViewer,
// so FindName cannot see them (a UserControl is its own namescope and FindName returns
// null SILENTLY). They would only re-span the band across the splitter column, which is
// meaningless when each strip lives inside its own pane and spans it exactly.
if (FindName("SidebarCol") is not ColumnDefinition sidebarColDef ||
FindName("DocCol") is not ColumnDefinition docColDef ||
FindName("SidebarOuterGrid") is not Grid sbOuter ||
FindName("SidebarBorder") is not Border sbContent ||
FindName("SidebarToggleStrip") is not Border sbToggle ||
SplitHost is not FrameworkElement docPane ||
FindName("SbContentCol") is not ColumnDefinition sbContentCol ||
FindName("SbToggleCol") is not ColumnDefinition sbToggleCol)
return;
// Carry the sized column's current width across a flip (24px when collapsed, else the
// user's width). A star length means it isn't the sized column yet, so fall back.
GridLength sized = _sidebarCollapsed
? new GridLength(SbPx(24))
: (_sidebarCol != null && _sidebarCol.Width.GridUnitType == GridUnitType.Pixel)
? _sidebarCol.Width
: new GridLength(SbPx(180));
double maxW = SbPx(_sidebarShowingOutlines ? SidebarMaxOutlines : SidebarMaxPages);
if (!_sidebarRight)
{
// Sidebar on the LEFT (column 0); document fills column 2.
sidebarColDef.MinWidth = SbPx(_sidebarCollapsed ? 24 : SidebarMinOpen); sidebarColDef.MaxWidth = maxW; sidebarColDef.Width = sized;
docColDef.MinWidth = 0; docColDef.MaxWidth = double.PositiveInfinity;
docColDef.Width = new GridLength(1, GridUnitType.Star);
Grid.SetColumn(sbOuter, 0);
Grid.SetColumn(docPane, 2);
_sidebarCol = sidebarColDef;
// Toggle strip faces the document: right edge of the sidebar.
sbContentCol.Width = new GridLength(1, GridUnitType.Star);
sbToggleCol.Width = new GridLength(24, GridUnitType.Pixel);
Grid.SetColumn(sbContent, 0);
Grid.SetColumn(sbToggle, 1);
}
else
{
// Sidebar on the RIGHT (column 2); document fills column 0.
docColDef.MinWidth = SbPx(_sidebarCollapsed ? 24 : SidebarMinOpen); docColDef.MaxWidth = maxW; docColDef.Width = sized;
sidebarColDef.MinWidth = 0; sidebarColDef.MaxWidth = double.PositiveInfinity;
sidebarColDef.Width = new GridLength(1, GridUnitType.Star);
Grid.SetColumn(sbOuter, 2);
Grid.SetColumn(docPane, 0);
_sidebarCol = docColDef;
// Toggle strip faces the document: left edge of the sidebar (inner column 0). The
// inner column defs are fixed in position, so size them by position, not by name.
sbContentCol.Width = new GridLength(24, GridUnitType.Pixel); // inner col 0 -> toggle
sbToggleCol.Width = new GridLength(1, GridUnitType.Star); // inner col 1 -> content
Grid.SetColumn(sbToggle, 0);
Grid.SetColumn(sbContent, 1);
}
// The splitter's edge-line and the SidebarShadow gradient were both handled here. The
// splitter draws a single centered line now, which is symmetric and so needs no side
// handling, and the fake elevation gradient is gone - DocPaneBorder casts a real
// PaneShadow on all four sides. (2026-07-31.)
// The DocTopAccent / DocBottomAccent repositioning was here. Those two 1px rules are
// gone with the squared layout - the card carries its own border on all four sides now,
// so there is nothing left to bridge to the toolbar and footer. (2026-07-31.)
// The document card's 8px inset always sits on its OUTER edge - the window side, away
// from the splitter - so the gap reads as a margin off the window rather than a gutter
// between the pane and the sidebar. Full screen clears the margin, so leave it alone
// there; ApplyFullScreen restores it from this same helper on exit.
// The grip rides the CONTENT column and faces the rail, so it always sits on the list's
// inner lip: right edge with the sidebar on the left, left edge with it on the right.
if (FindName("SidebarSplitter") is Thumb grip)
{
Grid.SetColumn(grip, _sidebarRight ? 1 : 0);
grip.HorizontalAlignment = _sidebarRight ? HorizontalAlignment.Left
: HorizontalAlignment.Right;
}
// The shadow caster is inside the PdfViewer control, so moving the control moves both -
// one less thing that can drift out of alignment than a separate grid child that has to
// be moved in step with the pane.
if (!_fullScreen)
{
// docPane is SplitHost, so this one margin now insets BOTH panes from the window
// edge together, which is what the 8px gutter always meant.
docPane.Margin = DocPaneInsetMargin();
// No tab-band or TabBarRing margins here. Those exist only to stop a window-level
// band overhanging the card's rounded outer corner, where the band runs the full
// width while the card is inset 8px. Each strip is inside its own pane and spans
// exactly that pane, so the band and the card share an edge by construction.
}
UpdateSidebarToggleGlyph();
SyncThemeFlyoutSide();
UpdateTabStripFade();
// The column swap repositions the document pane; re-anchor the footer shadow once layout
// settles (TransformToVisual needs the final positions).
Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Loaded, (Action)UpdateFooterFade);
}
// Document on the right (sidebar left) -> 8px inset on the right; mirrored when the sidebar
// moves. Top and bottom stay 0: PaneShadow is Direction 270 and draws outside the element's
@@ -339,5 +232,112 @@ namespace KillerPDF
}
return null;
}
private void ApplySidebarSide()
{
// SplitHost, NOT Viewer. Since the split landed, the element that sits in
// MainContentGrid is the SPLIT HOST - Viewer is one of its children. Setting
// Grid.Column on Viewer therefore moved pane A into SplitHost's column 2, which is
// PaneBCol and is ZERO WIDTH while unsplit, so the document rendered into a pane with
// no width and the whole content area went blank. Same for the margin below: the 8px
// gutter to the window edge belongs to the host, not to one pane.
//
// Do NOT look up TabStripBorder / TabScroll here: those elements live inside PdfViewer,
// so FindName cannot see them (a UserControl is its own namescope and FindName returns
// null SILENTLY). They would only re-span the band across the splitter column, which is
// meaningless when each strip lives inside its own pane and spans it exactly.
if (FindName("SidebarCol") is not ColumnDefinition sidebarColDef ||
FindName("DocCol") is not ColumnDefinition docColDef ||
FindName("SidebarOuterGrid") is not Grid sbOuter ||
FindName("SidebarBorder") is not Border sbContent ||
FindName("SidebarToggleStrip") is not Border sbToggle ||
SplitHost is not FrameworkElement docPane ||
FindName("SbContentCol") is not ColumnDefinition sbContentCol ||
FindName("SbToggleCol") is not ColumnDefinition sbToggleCol)
return;
// Carry the sized column's current width across a flip (24px when collapsed, else the
// user's width). A star length means it isn't the sized column yet, so fall back.
GridLength sized = _sidebarCollapsed
? new GridLength(SbPx(24))
: (_sidebarCol != null && _sidebarCol.Width.GridUnitType == GridUnitType.Pixel)
? _sidebarCol.Width
: new GridLength(SbPx(180));
double maxW = SbPx(_sidebarShowingOutlines ? SidebarMaxOutlines : SidebarMaxPages);
if (!_sidebarRight)
{
// Sidebar on the LEFT (column 0); document fills column 2.
sidebarColDef.MinWidth = SbPx(_sidebarCollapsed ? 24 : SidebarMinOpen); sidebarColDef.MaxWidth = maxW; sidebarColDef.Width = sized;
docColDef.MinWidth = 0; docColDef.MaxWidth = double.PositiveInfinity;
docColDef.Width = new GridLength(1, GridUnitType.Star);
Grid.SetColumn(sbOuter, 0);
Grid.SetColumn(docPane, 2);
_sidebarCol = sidebarColDef;
// Toggle strip faces the document: right edge of the sidebar.
sbContentCol.Width = new GridLength(1, GridUnitType.Star);
sbToggleCol.Width = new GridLength(24, GridUnitType.Pixel);
Grid.SetColumn(sbContent, 0);
Grid.SetColumn(sbToggle, 1);
}
else
{
// Sidebar on the RIGHT (column 2); document fills column 0.
docColDef.MinWidth = SbPx(_sidebarCollapsed ? 24 : SidebarMinOpen); docColDef.MaxWidth = maxW; docColDef.Width = sized;
sidebarColDef.MinWidth = 0; sidebarColDef.MaxWidth = double.PositiveInfinity;
sidebarColDef.Width = new GridLength(1, GridUnitType.Star);
Grid.SetColumn(sbOuter, 2);
Grid.SetColumn(docPane, 0);
_sidebarCol = docColDef;
// Toggle strip faces the document: left edge of the sidebar (inner column 0). The
// inner column defs are fixed in position, so size them by position, not by name.
sbContentCol.Width = new GridLength(24, GridUnitType.Pixel); // inner col 0 -> toggle
sbToggleCol.Width = new GridLength(1, GridUnitType.Star); // inner col 1 -> content
Grid.SetColumn(sbToggle, 0);
Grid.SetColumn(sbContent, 1);
}
// The splitter's edge-line and the SidebarShadow gradient were both handled here. The
// splitter draws a single centered line now, which is symmetric and so needs no side
// handling, and the fake elevation gradient is gone - DocPaneBorder casts a real
// PaneShadow on all four sides. (2026-07-31.)
// The DocTopAccent / DocBottomAccent repositioning was here. Those two 1px rules are
// gone with the squared layout - the card carries its own border on all four sides now,
// so there is nothing left to bridge to the toolbar and footer. (2026-07-31.)
// The document card's 8px inset always sits on its OUTER edge - the window side, away
// from the splitter - so the gap reads as a margin off the window rather than a gutter
// between the pane and the sidebar. Full screen clears the margin, so leave it alone
// there; ApplyFullScreen restores it from this same helper on exit.
// The grip rides the CONTENT column and faces the rail, so it always sits on the list's
// inner lip: right edge with the sidebar on the left, left edge with it on the right.
if (FindName("SidebarSplitter") is Thumb grip)
{
Grid.SetColumn(grip, _sidebarRight ? 1 : 0);
grip.HorizontalAlignment = _sidebarRight ? HorizontalAlignment.Left
: HorizontalAlignment.Right;
}
// The shadow caster is inside the PdfViewer control, so moving the control moves both -
// one less thing that can drift out of alignment than a separate grid child that has to
// be moved in step with the pane.
if (!_fullScreen)
{
// docPane is SplitHost, so this one margin now insets BOTH panes from the window
// edge together, which is what the 8px gutter always meant.
docPane.Margin = DocPaneInsetMargin();
// No tab-band or TabBarRing margins here. Those exist only to stop a window-level
// band overhanging the card's rounded outer corner, where the band runs the full
// width while the card is inset 8px. Each strip is inside its own pane and spans
// exactly that pane, so the band and the card share an edge by construction.
}
UpdateSidebarToggleGlyph();
UpdateTabStripFade();
// The column swap repositions the document pane; re-anchor the footer shadow once layout
// settles (TransformToVisual needs the final positions).
Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Loaded, (Action)UpdateFooterFade);
}
}
}