Files
mmd-pdf/Controls/ThumbViewportFloorConverter.cs
kua-agent 6610acfa44 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.
2026-08-27 07:37:09 +02:00

68 lines
3.1 KiB
C#

using System;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
namespace MmdPdf
{
// Keeps the document scrollbar reactive (thumb sized to the visible proportion) while
// guaranteeing it never shrinks below a grabbable floor.
//
// WPF's Track sizes the thumb AND the repeat buttons from the raw proportional value
// (trackLen * viewport / (range + viewport)). Thumb.MinHeight does NOT feed that math - it
// only stretches the thumb's render, so on a long document the thumb overflows its tiny
// proportional slot and the increase RepeatButton paints over the overflow (the "8px"
// scrollbar). Enforcing the minimum here, by raising the ViewportSize the Track sees, makes
// the Track size the thumb and the buttons from the same floored value - no overflow, no
// overlap, still proportional whenever there is room.
//
// Bindings (in order): ViewportSize, Maximum, Minimum, ActualWidth, ActualHeight, Orientation.
// ConverterParameter: the floor in pixels (default 64).
public sealed class ThumbViewportFloorConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
double vp = AsDouble(values, 0);
// Anything unexpected -> hand back the real ViewportSize so behavior is unchanged.
if (double.IsNaN(vp) || vp <= 0) return vp;
double max = AsDouble(values, 1);
double min = AsDouble(values, 2);
double width = AsDouble(values, 3);
double height = AsDouble(values, 4);
bool vertical = values.Length <= 5 || values[5] is not Orientation o
|| o == Orientation.Vertical;
double trackLen = vertical ? height : width;
double range = max - min;
if (double.IsNaN(trackLen) || trackLen <= 0 || range <= 0) return vp;
double floor = 64;
if (parameter != null &&
double.TryParse(parameter.ToString(), NumberStyles.Any, CultureInfo.InvariantCulture, out var p) && p > 0)
floor = p;
// Never let the floor eat the whole track; leave room for the thumb to travel.
floor = Math.Min(floor, trackLen * 0.5);
if (trackLen <= floor) return vp;
// ViewportSize that yields a thumb exactly = floor; take the larger of it and the real VP.
double vpForFloor = floor * range / (trackLen - floor);
return Math.Max(vp, vpForFloor);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
=> throw new NotSupportedException();
private static double AsDouble(object[] values, int i)
{
if (values == null || i >= values.Length) return double.NaN;
object v = values[i];
if (v == null || v == DependencyProperty.UnsetValue) return double.NaN;
try { return System.Convert.ToDouble(v, CultureInfo.InvariantCulture); }
catch { return double.NaN; }
}
}
}