add:PPT增强预览视图
This commit is contained in:
@@ -12,7 +12,10 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Ink;
|
||||
using System.Windows.Markup;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Threading;
|
||||
using Application = System.Windows.Application;
|
||||
@@ -180,6 +183,9 @@ namespace Ink_Canvas
|
||||
/// PowerPoint 全屏放映顶层窗口类名(与编辑态 PPTFrameClass 区分)。
|
||||
/// </summary>
|
||||
private const string PowerPointSlideShowWindowClassName = "screenClass";
|
||||
|
||||
private Popup _pptEnhancedPreviewPopup;
|
||||
private ListBox _pptEnhancedPreviewListBox;
|
||||
#endregion
|
||||
|
||||
#region PPT Managers
|
||||
@@ -1371,6 +1377,8 @@ namespace Ink_Canvas
|
||||
{
|
||||
try
|
||||
{
|
||||
await Application.Current.Dispatcher.InvokeAsync(() => DestroyPptEnhancedPreviewPopup());
|
||||
|
||||
if (Settings.Automation.IsAutoFoldAfterPPTSlideShow && !isFloatingBarFolded)
|
||||
{
|
||||
FoldFloatingBar_MouseUp(new object(), null);
|
||||
@@ -2349,19 +2357,26 @@ namespace Ink_Canvas
|
||||
GridTransparencyFakeBackground.Background = new SolidColorBrush(StringToColor("#01FFFFFF"));
|
||||
CursorIcon_Click(null, null);
|
||||
|
||||
// 使用新的PPT管理器显示导航
|
||||
if (_pptManager.TryShowSlideNavigation())
|
||||
if (Settings.PowerPointSettings.EnablePPTButtonEnhancedPreview)
|
||||
{
|
||||
LogHelper.WriteLogToFile("成功显示PPT幻灯片导航", LogHelper.LogType.Trace);
|
||||
// 若启用了“翻页时跳过PPT动画”,显示导航后把焦点拉回本窗口
|
||||
if (Settings.PowerPointSettings.SkipAnimationsWhenGoNext)
|
||||
{
|
||||
try { this.Activate(); } catch { }
|
||||
}
|
||||
await ShowEnhancedPptPreviewAsync(sender as FrameworkElement);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogHelper.WriteLogToFile("显示PPT幻灯片导航失败", LogHelper.LogType.Warning);
|
||||
// 使用新的PPT管理器显示导航
|
||||
if (_pptManager.TryShowSlideNavigation())
|
||||
{
|
||||
LogHelper.WriteLogToFile("成功显示PPT幻灯片导航", LogHelper.LogType.Trace);
|
||||
// 若启用了“翻页时跳过PPT动画”,显示导航后把焦点拉回本窗口
|
||||
if (Settings.PowerPointSettings.SkipAnimationsWhenGoNext)
|
||||
{
|
||||
try { this.Activate(); } catch { }
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogHelper.WriteLogToFile("显示PPT幻灯片导航失败", LogHelper.LogType.Warning);
|
||||
}
|
||||
}
|
||||
|
||||
// 控制居中
|
||||
@@ -2377,6 +2392,273 @@ namespace Ink_Canvas
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class PptEnhancedPreviewItem
|
||||
{
|
||||
public int SlideNumber { get; set; }
|
||||
public BitmapImage Thumbnail { get; set; }
|
||||
}
|
||||
|
||||
private async Task ShowEnhancedPptPreviewAsync(FrameworkElement placementTarget = null)
|
||||
{
|
||||
if (_pptEnhancedPreviewPopup != null && _pptEnhancedPreviewPopup.IsOpen && placementTarget != null &&
|
||||
ReferenceEquals(_pptEnhancedPreviewPopup.PlacementTarget, placementTarget))
|
||||
{
|
||||
_pptEnhancedPreviewPopup.IsOpen = false;
|
||||
return;
|
||||
}
|
||||
|
||||
var slides = await Task.Run(BuildPptPreviewItems);
|
||||
if (slides == null || slides.Count == 0)
|
||||
{
|
||||
LogHelper.WriteLogToFile("PPT增强预览未生成可用缩略图,改用默认导航", LogHelper.LogType.Warning);
|
||||
_pptManager.TryShowSlideNavigation();
|
||||
return;
|
||||
}
|
||||
|
||||
await Application.Current.Dispatcher.InvokeAsync(() =>
|
||||
{
|
||||
EnsurePptEnhancedPreviewPopupCreated();
|
||||
if (_pptEnhancedPreviewListBox == null || _pptEnhancedPreviewPopup == null) return;
|
||||
|
||||
_pptEnhancedPreviewListBox.ItemsSource = slides;
|
||||
var currentSlide = _pptManager?.GetCurrentSlideNumber() ?? 0;
|
||||
if (currentSlide > 0)
|
||||
{
|
||||
var selected = slides.Find(s => s.SlideNumber == currentSlide);
|
||||
_pptEnhancedPreviewListBox.SelectedItem = selected;
|
||||
if (selected != null)
|
||||
{
|
||||
_pptEnhancedPreviewListBox.ScrollIntoView(selected);
|
||||
}
|
||||
}
|
||||
|
||||
var anchor = placementTarget ?? PPTLSPageButton;
|
||||
if (anchor != null)
|
||||
{
|
||||
_pptEnhancedPreviewPopup.PlacementTarget = anchor;
|
||||
if (anchor == PPTLBPageButton || anchor == PPTRBPageButton)
|
||||
{
|
||||
_pptEnhancedPreviewPopup.Placement = PlacementMode.Top;
|
||||
_pptEnhancedPreviewPopup.HorizontalOffset = 0;
|
||||
_pptEnhancedPreviewPopup.VerticalOffset = -10;
|
||||
}
|
||||
else if (anchor == PPTRSPageButton)
|
||||
{
|
||||
_pptEnhancedPreviewPopup.Placement = PlacementMode.Left;
|
||||
_pptEnhancedPreviewPopup.HorizontalOffset = -12;
|
||||
_pptEnhancedPreviewPopup.VerticalOffset = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
_pptEnhancedPreviewPopup.Placement = PlacementMode.Right;
|
||||
_pptEnhancedPreviewPopup.HorizontalOffset = 12;
|
||||
_pptEnhancedPreviewPopup.VerticalOffset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
_pptEnhancedPreviewPopup.IsOpen = true;
|
||||
});
|
||||
}
|
||||
|
||||
private void DestroyPptEnhancedPreviewPopup()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_pptEnhancedPreviewListBox != null)
|
||||
{
|
||||
_pptEnhancedPreviewListBox.MouseUp -= PPTEnhancedPreviewListBox_OnMouseUp;
|
||||
_pptEnhancedPreviewListBox.ItemsSource = null;
|
||||
}
|
||||
|
||||
if (_pptEnhancedPreviewPopup != null)
|
||||
{
|
||||
_pptEnhancedPreviewPopup.IsOpen = false;
|
||||
_pptEnhancedPreviewPopup.Child = null;
|
||||
_pptEnhancedPreviewPopup.PlacementTarget = null;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignore dispose errors
|
||||
}
|
||||
finally
|
||||
{
|
||||
_pptEnhancedPreviewListBox = null;
|
||||
_pptEnhancedPreviewPopup = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void EnsurePptEnhancedPreviewPopupCreated()
|
||||
{
|
||||
if (_pptEnhancedPreviewPopup != null) return;
|
||||
|
||||
var listBox = new ListBox
|
||||
{
|
||||
Width = 220,
|
||||
Height = 320,
|
||||
Background = Brushes.Transparent,
|
||||
BorderBrush = Brushes.Transparent,
|
||||
BorderThickness = new Thickness(0),
|
||||
SelectionMode = SelectionMode.Single
|
||||
};
|
||||
listBox.SetValue(ScrollViewer.VerticalScrollBarVisibilityProperty, ScrollBarVisibility.Hidden);
|
||||
listBox.SetValue(ScrollViewer.HorizontalScrollBarVisibilityProperty, ScrollBarVisibility.Disabled);
|
||||
listBox.MouseUp += PPTEnhancedPreviewListBox_OnMouseUp;
|
||||
|
||||
var templateXaml = @"
|
||||
<DataTemplate xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'>
|
||||
<Border Margin='6,5' Padding='0' Height='118' CornerRadius='6' BorderThickness='0' Background='Transparent'>
|
||||
<Border BorderBrush='#7a8ea8' BorderThickness='0.6' CornerRadius='6' Background='Transparent' Padding='1'>
|
||||
<Border CornerRadius='5' ClipToBounds='True' Background='Transparent'>
|
||||
<Image Source='{Binding Thumbnail}' Stretch='UniformToFill'/>
|
||||
</Border>
|
||||
</Border>
|
||||
</Border>
|
||||
</DataTemplate>";
|
||||
listBox.ItemTemplate = (DataTemplate)XamlReader.Parse(templateXaml);
|
||||
var itemStyleXaml = @"
|
||||
<Style xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'
|
||||
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
||||
TargetType='ListBoxItem'>
|
||||
<Setter Property='Background' Value='Transparent'/>
|
||||
<Setter Property='BorderThickness' Value='0'/>
|
||||
<Setter Property='FocusVisualStyle' Value='{x:Null}'/>
|
||||
<Setter Property='Template'>
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType='ListBoxItem'>
|
||||
<ContentPresenter/>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>";
|
||||
listBox.ItemContainerStyle = (Style)XamlReader.Parse(itemStyleXaml);
|
||||
|
||||
_pptEnhancedPreviewListBox = listBox;
|
||||
_pptEnhancedPreviewPopup = new Popup
|
||||
{
|
||||
AllowsTransparency = true,
|
||||
StaysOpen = true,
|
||||
Placement = PlacementMode.Right,
|
||||
PopupAnimation = PopupAnimation.Fade,
|
||||
Child = listBox
|
||||
};
|
||||
}
|
||||
|
||||
private void PPTEnhancedPreviewListBox_OnMouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
|
||||
{
|
||||
if (_pptEnhancedPreviewListBox?.SelectedItem is not PptEnhancedPreviewItem item) return;
|
||||
try
|
||||
{
|
||||
if (_pptManager?.TryNavigateToSlide(item.SlideNumber) == true)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"PPT增强预览跳转成功:{item.SlideNumber}", LogHelper.LogType.Trace);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogHelper.WriteLogToFile($"PPT增强预览跳转失败:{item.SlideNumber}", LogHelper.LogType.Warning);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"PPT增强预览跳转异常: {ex}", LogHelper.LogType.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_pptEnhancedPreviewPopup != null)
|
||||
{
|
||||
_pptEnhancedPreviewPopup.IsOpen = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<PptEnhancedPreviewItem> BuildPptPreviewItems()
|
||||
{
|
||||
var result = new List<PptEnhancedPreviewItem>();
|
||||
string tempDir = null;
|
||||
Presentation activePresentation = null;
|
||||
Slides slides = null;
|
||||
|
||||
try
|
||||
{
|
||||
activePresentation = _pptManager?.GetCurrentActivePresentation() as Presentation;
|
||||
if (activePresentation == null)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
slides = activePresentation.Slides;
|
||||
if (slides == null) return result;
|
||||
|
||||
int count = slides.Count;
|
||||
if (count <= 0) return result;
|
||||
|
||||
tempDir = Path.Combine(Path.GetTempPath(), "InkCanvas", "PPTPreviews", Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(tempDir);
|
||||
|
||||
for (int i = 1; i <= count; i++)
|
||||
{
|
||||
Slide slide = null;
|
||||
try
|
||||
{
|
||||
slide = slides[i];
|
||||
var imagePath = Path.Combine(tempDir, $"slide_{i:0000}.png");
|
||||
slide.Export(imagePath, "PNG", 320, 180);
|
||||
var image = LoadBitmapImage(imagePath);
|
||||
if (image == null) continue;
|
||||
|
||||
result.Add(new PptEnhancedPreviewItem
|
||||
{
|
||||
SlideNumber = i,
|
||||
Thumbnail = image
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"生成PPT第{i}页缩略图失败: {ex.Message}", LogHelper.LogType.Warning);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (slide != null)
|
||||
{
|
||||
try { Marshal.ReleaseComObject(slide); } catch { }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"构建PPT增强预览列表失败: {ex}", LogHelper.LogType.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(tempDir) && Directory.Exists(tempDir))
|
||||
{
|
||||
try { Directory.Delete(tempDir, true); } catch { }
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static BitmapImage LoadBitmapImage(string path)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!File.Exists(path)) return null;
|
||||
var bitmap = new BitmapImage();
|
||||
bitmap.BeginInit();
|
||||
bitmap.CacheOption = BitmapCacheOption.OnLoad;
|
||||
bitmap.UriSource = new Uri(path, UriKind.Absolute);
|
||||
bitmap.EndInit();
|
||||
bitmap.Freeze();
|
||||
return bitmap;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理“开始幻灯片放映”按钮的点击事件
|
||||
/// </summary>
|
||||
@@ -2505,6 +2787,8 @@ namespace Ink_Canvas
|
||||
{
|
||||
try
|
||||
{
|
||||
await Application.Current.Dispatcher.InvokeAsync(() => DestroyPptEnhancedPreviewPopup());
|
||||
|
||||
if (Settings.Automation.IsAutoFoldAfterPPTSlideShow && !isFloatingBarFolded)
|
||||
{
|
||||
FoldFloatingBar_MouseUp(new object(), null);
|
||||
|
||||
@@ -905,6 +905,7 @@ namespace Ink_Canvas
|
||||
Settings.PowerPointSettings.IsEnableTwoFingerGestureInPresentationMode = false;
|
||||
Settings.PowerPointSettings.IsEnableFingerGestureSlideShowControl = false;
|
||||
Settings.PowerPointSettings.IsSupportWPS = false;
|
||||
Settings.PowerPointSettings.EnablePPTButtonEnhancedPreview = false;
|
||||
|
||||
Settings.Canvas.InkWidth = 2.5;
|
||||
Settings.Canvas.IsShowCursor = false;
|
||||
|
||||
@@ -925,7 +925,16 @@
|
||||
<value>PPT page button clickable</value>
|
||||
</data>
|
||||
<data name="PPT_PageButtonClickableHint" xml:space="preserve">
|
||||
<value># When enabled, clicking the page button opens PowerPoint grid thumbnails. Not supported in WPS.</value>
|
||||
<value># Enable page-button navigation on click. By default it uses PowerPoint grid thumbnails (not supported in WPS); use the sub-setting below to manually enable enhanced preview for WPS support.</value>
|
||||
</data>
|
||||
<data name="PPT_PageButtonClickable_SubSettings" xml:space="preserve">
|
||||
<value>Page button click sub-settings</value>
|
||||
</data>
|
||||
<data name="PPT_EnhancedPreview" xml:space="preserve">
|
||||
<value>Enhanced preview for page button</value>
|
||||
</data>
|
||||
<data name="PPT_EnhancedPreviewHint" xml:space="preserve">
|
||||
<value># Manually enable this option to show a thumbnail page list when clicking the page button (supports both WPS and PowerPoint), then click a thumbnail to jump.</value>
|
||||
</data>
|
||||
<data name="PPT_LongPressPageTurn" xml:space="preserve">
|
||||
<value>PPT long-press to turn page</value>
|
||||
|
||||
@@ -961,7 +961,16 @@
|
||||
<value>PPT 页码按钮可点击</value>
|
||||
</data>
|
||||
<data name="PPT_PageButtonClickableHint" xml:space="preserve">
|
||||
<value># 开启该选项后,点击页码按钮可以唤起PowerPoint自带的网格缩略图视图。WPS不支持该功能,开启也没用。</value>
|
||||
<value># 开启该选项后,点击页码按钮可唤起页码导航。默认调用 PowerPoint 网格缩略图(WPS 不支持);可在下方子设置手动开启增强型预览以支持 WPS。</value>
|
||||
</data>
|
||||
<data name="PPT_PageButtonClickable_SubSettings" xml:space="preserve">
|
||||
<value>页码按钮点击子设置</value>
|
||||
</data>
|
||||
<data name="PPT_EnhancedPreview" xml:space="preserve">
|
||||
<value>PPT 页码按钮增强型预览</value>
|
||||
</data>
|
||||
<data name="PPT_EnhancedPreviewHint" xml:space="preserve">
|
||||
<value># 手动开启后,点击页码按钮将显示缩略图页列表(支持 WPS 与 PowerPoint),并可点击跳转到目标页。</value>
|
||||
</data>
|
||||
<data name="PPT_LongPressPageTurn" xml:space="preserve">
|
||||
<value>PPT 翻页按钮长按翻页</value>
|
||||
|
||||
@@ -371,6 +371,9 @@ namespace Ink_Canvas
|
||||
[JsonProperty("enablePPTButtonPageClickable")]
|
||||
public bool EnablePPTButtonPageClickable { get; set; } = true;
|
||||
|
||||
[JsonProperty("enablePPTButtonEnhancedPreview")]
|
||||
public bool EnablePPTButtonEnhancedPreview { get; set; } = false;
|
||||
|
||||
[JsonProperty("enablePPTButtonLongPressPageTurn")]
|
||||
public bool EnablePPTButtonLongPressPageTurn { get; set; } = true;
|
||||
|
||||
|
||||
@@ -178,6 +178,13 @@
|
||||
Visibility="{Binding IsOn, ElementName=CardShowPPTButton, Converter={StaticResource BooleanToVisibilityConverter}}"
|
||||
Toggled="ToggleSwitchEnablePPTButtonPageClickable_OnToggled"/>
|
||||
|
||||
<controls:LabeledSettingsCard x:Name="CardEnablePPTButtonEnhancedPreview"
|
||||
Header="{i18n:I18n Key=PPT_EnhancedPreview}"
|
||||
Description="{i18n:I18n Key=PPT_EnhancedPreviewHint}"
|
||||
Icon="{x:Static ui:SegoeFluentIcons.TouchPointer}"
|
||||
Visibility="{Binding IsOn, ElementName=CardEnablePPTButtonPageClickable, Converter={StaticResource BooleanToVisibilityConverter}}"
|
||||
Toggled="ToggleSwitchEnablePPTButtonEnhancedPreview_OnToggled"/>
|
||||
|
||||
<controls:LabeledSettingsCard x:Name="CardEnablePPTButtonLongPressPageTurn"
|
||||
Header="{i18n:I18n Key=PPT_LongPressPageTurn}"
|
||||
Description="{i18n:I18n Key=PPT_LongPressPageTurnHint}"
|
||||
|
||||
@@ -72,6 +72,7 @@ namespace Ink_Canvas.Windows.SettingsViews.Pages
|
||||
CheckboxBPPTBlackBackground.IsChecked = bOpt.Length > 2 && bOpt[2] == '2';
|
||||
|
||||
CardEnablePPTButtonPageClickable.IsOn = ppt.EnablePPTButtonPageClickable;
|
||||
CardEnablePPTButtonEnhancedPreview.IsOn = ppt.EnablePPTButtonEnhancedPreview;
|
||||
CardEnablePPTButtonLongPressPageTurn.IsOn = ppt.EnablePPTButtonLongPressPageTurn;
|
||||
|
||||
CardShowCanvasAtNewSlideShow.IsOn = ppt.IsShowCanvasAtNewSlideShow;
|
||||
@@ -254,6 +255,13 @@ namespace Ink_Canvas.Windows.SettingsViews.Pages
|
||||
SettingsManager.SaveSettingsToFile();
|
||||
}
|
||||
|
||||
private void ToggleSwitchEnablePPTButtonEnhancedPreview_OnToggled(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!_isLoaded) return;
|
||||
SettingsManager.Settings.PowerPointSettings.EnablePPTButtonEnhancedPreview = CardEnablePPTButtonEnhancedPreview.IsOn;
|
||||
SettingsManager.SaveSettingsToFile();
|
||||
}
|
||||
|
||||
private void ToggleSwitchEnablePPTButtonLongPressPageTurn_OnToggled(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!_isLoaded) return;
|
||||
|
||||
Reference in New Issue
Block a user