123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400 |
- using System.Runtime.InteropServices;
- namespace PicView.Core.Sizing;
- public static class ImageSizeCalculationHelper
- {
- private const int MinTitleWidth = 250;
- private const int Padding = 45;
-
- /// <summary>
- /// Returns the interface size of the titlebar based on OS
- /// </summary>
- public static double GetInterfaceSize()
- {
- // TODO: find a more elegant solution
- return RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 165 : 215;
- }
-
- public static double GetWindowMargin()
- {
- // TODO: find a more elegant solution
- return RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? 7 : 0;
- }
- public static ImageSize GetImageSize(double width,
- double height,
- ScreenSize screenSize,
- double minWidth,
- double minHeight,
- double interfaceSize,
- double rotationAngle,
- double dpiScaling,
- double uiTopSize,
- double uiBottomSize,
- double galleryHeight,
- double containerWidth,
- double containerHeight)
- {
- if (width <= 0 || height <= 0 || rotationAngle > 360 || rotationAngle < 0)
- {
- return ErrorImageSize(minWidth, minHeight, interfaceSize, containerWidth);
- }
- double aspectRatio;
- double maxWidth, maxHeight;
- var margin = 0d;
- var fullscreen = Settings.WindowProperties.Fullscreen ||
- Settings.WindowProperties.Maximized;
-
- var borderSpaceHeight = fullscreen ? 0 : uiTopSize + uiBottomSize + galleryHeight;
- var borderSpaceWidth = fullscreen ? 0 : Padding;
- var workAreaWidth = screenSize.WorkingAreaWidth - borderSpaceWidth;
- var workAreaHeight = screenSize.WorkingAreaHeight - borderSpaceHeight;
- if (Settings.Zoom.ScrollEnabled)
- {
- workAreaWidth -= SizeDefaults.ScrollbarSize * dpiScaling;
- containerWidth -= SizeDefaults.ScrollbarSize * dpiScaling;
- maxWidth = Settings.ImageScaling.StretchImage
- ? workAreaWidth
- : Math.Min(workAreaWidth - Padding, width);
-
- maxHeight = workAreaHeight;
- }
- else if (Settings.WindowProperties.AutoFit)
- {
- maxWidth = Settings.ImageScaling.StretchImage
- ? workAreaWidth - Padding
- : Math.Min(workAreaWidth - Padding, width);
-
- maxHeight = Settings.ImageScaling.StretchImage
- ? workAreaHeight - Padding
- : Math.Min(workAreaHeight - Padding, height);
- }
- else
- {
- maxWidth = Settings.ImageScaling.StretchImage
- ? containerWidth
- : Math.Min(containerWidth, width);
- maxHeight = Settings.ImageScaling.StretchImage
- ? containerHeight - galleryHeight
- : Math.Min(containerHeight - galleryHeight, height);
- }
- if (Settings.Gallery.IsBottomGalleryShown)
- {
- if (!Settings.UIProperties.ShowInterface)
- {
- if (Settings.Gallery.ShowBottomGalleryInHiddenUI)
- {
- margin = galleryHeight > 0 ? galleryHeight : 0;
- }
- else
- {
- margin = 0;
- }
- }
- else
- {
- margin = galleryHeight > 0 ? galleryHeight : 0;
- }
- }
- // aspect ratio calculation
- switch (rotationAngle)
- {
- case 0:
- case 180:
- aspectRatio = Math.Min(maxWidth / width, maxHeight / height);
- break;
- case 90:
- case 270:
- aspectRatio = Math.Min(maxWidth / height, maxHeight / width);
- break;
- default:
- var rotationRadians = rotationAngle * Math.PI / 180;
- var newWidth = Math.Abs(width * Math.Cos(rotationRadians)) +
- Math.Abs(height * Math.Sin(rotationRadians));
- var newHeight = Math.Abs(width * Math.Sin(rotationRadians)) +
- Math.Abs(height * Math.Cos(rotationRadians));
- aspectRatio = Math.Min(maxWidth / newWidth, maxHeight / newHeight);
- break;
- }
- // Fit image by aspect ratio calculation
- // and update values
- double scrollWidth, scrollHeight, xWidth, xHeight;
- if (Settings.Zoom.ScrollEnabled)
- {
- if (fullscreen)
- {
- xWidth = width * aspectRatio;
- xHeight = height * aspectRatio;
- scrollWidth = screenSize.Width;
- scrollHeight = screenSize.Height;
- }
- else if (Settings.WindowProperties.AutoFit)
- {
- xWidth = width * aspectRatio;
- xHeight = height * aspectRatio;
- scrollWidth = Math.Max(xWidth + SizeDefaults.ScrollbarSize, SizeDefaults.WindowMinSize + SizeDefaults.ScrollbarSize + Padding + 16);
- scrollHeight = containerHeight - margin;
- }
- else
- {
- xWidth = containerWidth - SizeDefaults.ScrollbarSize + 10;
- xHeight = height / width * xWidth;
-
- scrollWidth = containerWidth + SizeDefaults.ScrollbarSize;
- scrollHeight = containerHeight - margin;
- }
- }
- else
- {
- scrollWidth = double.NaN;
- scrollHeight = double.NaN;
- xWidth = width * aspectRatio;
- xHeight = height * aspectRatio;
- }
- var titleMaxWidth = GetTitleMaxWidth(rotationAngle, xWidth, xHeight, minWidth, minHeight,
- interfaceSize, containerWidth);
- return new ImageSize(xWidth, xHeight, 0, scrollWidth, scrollHeight, titleMaxWidth, margin, aspectRatio);
- }
- public static ImageSize GetSideBySideImageSize(double width,
- double height,
- double secondaryWidth,
- double secondaryHeight,
- ScreenSize screenSize,
- double minWidth,
- double minHeight,
- double interfaceSize,
- double rotationAngle,
- double dpiScaling,
- double uiTopSize,
- double uiBottomSize,
- double galleryHeight,
- double containerWidth,
- double containerHeight)
- {
- if (width <= 0 || height <= 0 || secondaryWidth <= 0 || secondaryHeight <= 0 || rotationAngle > 360 ||
- rotationAngle < 0)
- {
- return ErrorImageSize(minWidth, minHeight, interfaceSize, containerWidth);
- }
- // Get sizes for both images
- var firstSize = GetImageSize(width, height, screenSize, minWidth, minHeight,
- interfaceSize, rotationAngle, dpiScaling, uiTopSize, uiBottomSize, galleryHeight,
- containerWidth,
- containerHeight);
- var secondSize = GetImageSize(secondaryWidth, secondaryHeight, screenSize, minWidth,
- minHeight, interfaceSize, rotationAngle, dpiScaling, uiTopSize, uiBottomSize,
- galleryHeight,
- containerWidth, containerHeight);
- // Determine maximum height for both images
- var xHeight = Math.Max(firstSize.Height, secondSize.Height);
- // Recalculate the widths to maintain the aspect ratio with the new maximum height
- var xWidth1 = firstSize.Width / firstSize.Height * xHeight;
- var xWidth2 = secondSize.Width / secondSize.Height * xHeight;
- // Combined width of both images
- var combinedWidth = xWidth1 + xWidth2;
- if (Settings.WindowProperties.AutoFit)
- {
- var widthPadding = Settings.ImageScaling.StretchImage ? 4 : Padding;
- var availableWidth = screenSize.WorkingAreaWidth - widthPadding;
- var availableHeight = screenSize.WorkingAreaHeight - (widthPadding + uiBottomSize + uiTopSize);
- if (rotationAngle is 0 or 180)
- {
- // If combined width exceeds available width, scale both images down proportionally
- if (combinedWidth > availableWidth)
- {
- var scaleFactor = availableWidth / combinedWidth;
- xWidth1 *= scaleFactor;
- xWidth2 *= scaleFactor;
- xHeight *= scaleFactor;
- combinedWidth = xWidth1 + xWidth2;
- }
- }
- else
- {
- if (combinedWidth > availableHeight)
- {
- var scaleFactor = availableHeight / combinedWidth;
- xWidth1 *= scaleFactor;
- xWidth2 *= scaleFactor;
- xHeight *= scaleFactor;
-
- combinedWidth = xWidth1 + xWidth2;
- }
- }
- }
- else
- {
- if (rotationAngle is 0 or 180)
- {
- if (combinedWidth > containerWidth)
- {
- var scaleFactor = containerWidth / combinedWidth;
- xWidth1 *= scaleFactor;
- xWidth2 *= scaleFactor;
- xHeight *= scaleFactor;
- combinedWidth = xWidth1 + xWidth2;
- }
- }
- else
- {
- if (combinedWidth > containerHeight)
- {
- var scaleFactor = containerHeight / combinedWidth;
- xWidth1 *= scaleFactor;
- xWidth2 *= scaleFactor;
- xHeight *= scaleFactor;
-
- combinedWidth = xWidth1 + xWidth2;
- }
- }
- }
- double scrollWidth, scrollHeight;
- if (Settings.Zoom.ScrollEnabled)
- {
- if (Settings.WindowProperties.AutoFit)
- {
- combinedWidth -= SizeDefaults.ScrollbarSize;
- scrollWidth = combinedWidth + SizeDefaults.ScrollbarSize + 8;
- var fullscreen = Settings.WindowProperties.Fullscreen ||
- Settings.WindowProperties.Maximized;
- var borderSpaceHeight = fullscreen ? 0 : uiTopSize + uiBottomSize + galleryHeight;
- var workAreaHeight = screenSize.WorkingAreaHeight * dpiScaling - borderSpaceHeight;
- scrollHeight = Math.Min(xHeight,
- Settings.ImageScaling.StretchImage ? workAreaHeight : workAreaHeight - Padding);
- }
- else
- {
- combinedWidth -= SizeDefaults.ScrollbarSize + 8;
- scrollWidth = double.NaN;
- scrollHeight = double.NaN;
- }
- }
- else
- {
- scrollWidth = double.NaN;
- scrollHeight = double.NaN;
- }
- var titleMaxWidth = GetTitleMaxWidth(rotationAngle, combinedWidth, xHeight, minWidth,
- minHeight, interfaceSize, containerWidth);
- var margin = firstSize.Height > secondSize.Height ? firstSize.Margin : secondSize.Margin;
- return new ImageSize(combinedWidth, xHeight, xWidth2, scrollWidth, scrollHeight, titleMaxWidth, margin,
- firstSize.AspectRatio);
- }
- public static double GetTitleMaxWidth(double rotationAngle, double width, double height, double monitorMinWidth,
- double monitorMinHeight, double interfaceSize, double containerWidth)
- {
- if (Settings.WindowProperties.Fullscreen)
- {
- // Title bar is not shown in fullscreen
- return 0;
- }
-
- double titleMaxWidth;
-
- if (Settings.WindowProperties.AutoFit && !Settings.WindowProperties.Maximized)
- {
- switch (rotationAngle)
- {
- case 0 or 180:
- titleMaxWidth = Math.Max(width, monitorMinWidth);
- break;
- case 90 or 270:
- titleMaxWidth = Math.Max(height, monitorMinHeight);
- break;
- default:
- {
- var rotationRadians = rotationAngle * Math.PI / 180;
- var newWidth = Math.Abs(width * Math.Cos(rotationRadians)) +
- Math.Abs(height * Math.Sin(rotationRadians));
- titleMaxWidth = Math.Max(newWidth, monitorMinWidth);
- break;
- }
- }
- titleMaxWidth = titleMaxWidth - interfaceSize < MinTitleWidth
- ? MinTitleWidth
- : titleMaxWidth - interfaceSize;
- }
- else
- {
- if (Settings.WindowProperties.Maximized)
- {
- interfaceSize += GetWindowMargin() * 2;
- }
- // Fix title width to window size
- titleMaxWidth = containerWidth - interfaceSize;
- }
- if (!Settings.Zoom.ScrollEnabled)
- {
- return titleMaxWidth;
- }
- if (Settings.ImageScaling.ShowImageSideBySide)
- {
- return titleMaxWidth + (SizeDefaults.ScrollbarSize + 10);
- }
- return titleMaxWidth + SizeDefaults.ScrollbarSize;
- }
-
- private static ImageSize ErrorImageSize(double monitorMinWidth, double monitorMinHeight, double interfaceSize, double containerWidth)
- => new(0, 0, 0, 0, 0, GetTitleMaxWidth(0, 0, 0, monitorMinWidth,
- monitorMinHeight, interfaceSize, containerWidth), 0, 0);
-
- public readonly struct ImageSize(
- double width,
- double height,
- double secondaryWidth,
- double scrollViewerWidth,
- double scrollViewerHeight,
- double titleMaxWidth,
- double margin,
- double aspectRatio)
- {
- public double TitleMaxWidth { get; } = titleMaxWidth;
- public double Width { get; } = width;
- public double Height { get; } = height;
- public double ScrollViewerWidth { get; } = scrollViewerWidth;
- public double ScrollViewerHeight { get; } = scrollViewerHeight;
- public double SecondaryWidth { get; } = secondaryWidth;
- public double Margin { get; } = margin;
- public double AspectRatio { get; } = aspectRatio;
- }
- }
|