Revert "delete:视频展台"

This reverts commit 0683779e09.
This commit is contained in:
PrefacedCorg
2026-04-23 22:17:55 +08:00
parent b891cb6fe3
commit 532aa03c56
8 changed files with 1342 additions and 5 deletions
+191
View File
@@ -6766,7 +6766,198 @@
</Border>
</Viewbox>
<!-- 视频展台侧栏 -->
<Border
x:Name="VideoPresenterSidebar"
Width="350"
HorizontalAlignment="Left"
VerticalAlignment="Stretch"
Background="{DynamicResource FloatBarBackground}"
BorderBrush="{DynamicResource FloatBarBorderBrush}"
BorderThickness="0,0,1,0"
Visibility="Collapsed"
Panel.ZIndex="996">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="50" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="110" />
</Grid.RowDefinitions>
<!-- 顶部标题栏 -->
<Grid Grid.Row="0" Height="50">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="50" />
</Grid.ColumnDefinitions>
<TextBlock
Grid.Column="0"
Margin="15,0,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Center"
FontSize="16"
FontWeight="Bold"
Foreground="{DynamicResource FloatBarForeground}"
Text="{i18n:I18n Key=Booth_Title}" />
<Button
Grid.Column="1"
Width="50"
Height="50"
Padding="0"
BorderThickness="0"
Background="Transparent"
Click="BtnCloseVideoPresenter_Click">
<Path
Stroke="{DynamicResource IconForeground}"
StrokeThickness="2"
StrokeStartLineCap="Round"
StrokeEndLineCap="Round"
Width="16"
Height="16"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Stretch="Uniform"
Data="M4.5 4.5L11.5 11.5M11.5 4.5L4.5 11.5" />
</Button>
</Grid>
<!-- 预览区域 -->
<Border Grid.Row="1" Margin="10,10,10,2" Padding="10" CornerRadius="6" Background="#1f2328">
<Image x:Name="VideoPresenterPreviewImage" Stretch="Uniform" Height="180" />
</Border>
<!-- 照片显示区域 -->
<Border Grid.Row="2" Margin="10,2,10,2" Padding="10" CornerRadius="6" Background="{DynamicResource FloatBarBackground}">
<StackPanel>
<TextBlock
Margin="0,0,0,8"
HorizontalAlignment="Left"
FontSize="12"
FontWeight="SemiBold"
Foreground="{DynamicResource FloatBarForeground}"
Text="{i18n:I18n Key=Booth_CapturedPhotos}" />
<ScrollViewer
x:Name="CapturedPhotosScrollViewer"
MaxHeight="280"
VerticalScrollBarVisibility="Auto"
PanningMode="VerticalFirst">
<StackPanel x:Name="CapturedPhotosStackPanel" Margin="0,0,0,5" />
</ScrollViewer>
</StackPanel>
</Border>
<!-- 设备选择区域 -->
<Border Grid.Row="3" Margin="10,2,10,5" Padding="10" CornerRadius="6" Background="{DynamicResource FloatBarBackground}">
<StackPanel>
<TextBlock
Margin="0,0,0,8"
HorizontalAlignment="Left"
FontSize="12"
FontWeight="SemiBold"
Foreground="{DynamicResource FloatBarForeground}"
Text="{i18n:I18n Key=Booth_CameraDevices}" />
<ScrollViewer
x:Name="CameraDevicesScrollViewer"
MaxHeight="120"
VerticalScrollBarVisibility="Auto"
PanningMode="VerticalFirst">
<StackPanel x:Name="CameraDevicesStackPanel" />
</ScrollViewer>
</StackPanel>
</Border>
<!-- 底部按钮区域 -->
<Grid Grid.Row="4" Margin="0,0,0,6">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Orientation="Horizontal" HorizontalAlignment="Center" Margin="10,4,10,2">
<ToggleButton
x:Name="BtnToggleVideoPresenterLiveOnCanvas"
Width="70"
Height="40"
Margin="2,0"
Background="{DynamicResource FloatBarBackground}"
BorderBrush="{DynamicResource FloatBarBorderBrush}"
BorderThickness="1"
Checked="BtnToggleVideoPresenterLiveOnCanvas_Checked"
Unchecked="BtnToggleVideoPresenterLiveOnCanvas_Unchecked">
<TextBlock FontSize="12" FontWeight="SemiBold" Foreground="{DynamicResource FloatBarForeground}" Text="{i18n:I18n Key=Booth_Present}" />
</ToggleButton>
<ToggleButton
x:Name="ToggleBtnPhotoCorrection"
Width="70"
Height="40"
Margin="2,0"
Background="{DynamicResource FloatBarBackground}"
BorderBrush="{DynamicResource FloatBarBorderBrush}"
BorderThickness="1"
Checked="ToggleBtnPhotoCorrection_Checked"
Unchecked="ToggleBtnPhotoCorrection_Unchecked">
<TextBlock FontSize="12" FontWeight="SemiBold" Foreground="{DynamicResource FloatBarForeground}" Text="{i18n:I18n Key=Booth_Correction}" />
</ToggleButton>
<Button
x:Name="BtnCapturePhoto"
Width="70"
Height="40"
Margin="2,0"
Background="{DynamicResource FloatBarBackground}"
BorderBrush="{DynamicResource FloatBarBorderBrush}"
BorderThickness="1"
Click="BtnCapturePhoto_Click">
<TextBlock FontSize="12" FontWeight="SemiBold" Foreground="{DynamicResource FloatBarForeground}" Text="{i18n:I18n Key=Booth_Capture}" />
</Button>
<Button
x:Name="BtnRotateImage"
Width="70"
Height="40"
Margin="2,0"
Background="{DynamicResource FloatBarBackground}"
BorderBrush="{DynamicResource FloatBarBorderBrush}"
BorderThickness="1"
Click="BtnRotateImage_Click">
<TextBlock FontSize="12" FontWeight="SemiBold" Foreground="{DynamicResource FloatBarForeground}" Text="{i18n:I18n Key=Booth_Rotate}" />
</Button>
</StackPanel>
<!-- 分辨率 Tab -->
<Grid Grid.Row="1" HorizontalAlignment="Center" Margin="10,6,10,4">
<Border Background="{DynamicResource FloatBarBackground}"
CornerRadius="8" BorderThickness="1" BorderBrush="#616161"
Width="282" Height="40" ToolTip="{x:Static props:Strings.Booth_Resolution_Tooltip}">
<Grid>
<Border x:Name="BoothResolutionTabIndicator"
Background="#66CCFF"
CornerRadius="6"
Width="70" Height="38"
HorizontalAlignment="Left" VerticalAlignment="Center"
Margin="0,0,0,0"/>
<Grid>
<Button x:Name="BtnBoothResolution720" Width="70" Height="40" Background="Transparent" BorderThickness="0"
Click="BoothResolutionTab_Click" Tag="1280,720" Cursor="Hand" HorizontalAlignment="Left">
<TextBlock Text="720p" FontSize="12" FontWeight="SemiBold" Foreground="{DynamicResource FloatBarForeground}" Opacity="0.7"/>
</Button>
<Button x:Name="BtnBoothResolution1080" Width="70" Height="40" Background="Transparent" BorderThickness="0"
Click="BoothResolutionTab_Click" Tag="1920,1080" Cursor="Hand" HorizontalAlignment="Left" Margin="70,0,0,0">
<TextBlock x:Name="TbBoothResolution1080" Text="1080p" FontSize="12" FontWeight="Bold" Foreground="White"/>
</Button>
<Button x:Name="BtnBoothResolution2K" Width="70" Height="40" Background="Transparent" BorderThickness="0"
Click="BoothResolutionTab_Click" Tag="2560,1440" Cursor="Hand" HorizontalAlignment="Left" Margin="140,0,0,0">
<TextBlock Text="2K" FontSize="12" FontWeight="SemiBold" Foreground="{DynamicResource FloatBarForeground}" Opacity="0.7"/>
</Button>
<Button x:Name="BtnBoothResolution4K" Width="70" Height="40" Background="Transparent" BorderThickness="0"
Click="BoothResolutionTab_Click" Tag="3840,2160" Cursor="Hand" HorizontalAlignment="Left" Margin="210,0,0,0">
<TextBlock Text="4K" FontSize="12" FontWeight="SemiBold" Foreground="{DynamicResource FloatBarForeground}" Opacity="0.7"/>
</Button>
</Grid>
</Grid>
</Border>
</Grid>
</Grid>
</Grid>
</Border>
<Border x:Name="TimerContainer"
Visibility="Collapsed"
+78 -1
View File
@@ -73,7 +73,10 @@ namespace Ink_Canvas
// 全屏处理状态标志
public bool isFullScreenApplied = false;
private int _boothResolutionWidth = 1920;
private int _boothResolutionHeight = 1080;
public int BoothResolutionWidth => _boothResolutionWidth;
public int BoothResolutionHeight => _boothResolutionHeight;
private static Cursor _cachedPenCursor = null;
private static readonly object _cursorLock = new object();
@@ -1763,6 +1766,24 @@ namespace Ink_Canvas
{
SystemEvents.DisplaySettingsChanged -= SystemEventsOnDisplaySettingsChanged;
try
{
// 清理视频展台资源
if (_cameraService != null)
{
_cameraService.FrameReceived -= CameraService_FrameReceived;
_cameraService.ErrorOccurred -= CameraService_ErrorOccurred;
_cameraService.Dispose();
_cameraService = null;
}
lock (_videoPresenterFrameLock)
{
_lastFrame?.Dispose();
_lastFrame = null;
}
}
catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex); }
// 释放PPT管理器资源
DisposePPTManagers();
@@ -2997,6 +3018,62 @@ namespace Ink_Canvas
}
#endregion
#region /
private const int BoothResolutionTabCount = 4;
private static readonly (int w, int h)[] BoothResolutionValues = { (1280, 720), (1920, 1080), (2560, 1440), (3840, 2160) };
private void BoothResolutionTab_Click(object sender, RoutedEventArgs e)
{
if (sender is Button btn && btn.Tag is string tag)
{
var parts = tag.Split(',');
if (parts.Length == 2 && int.TryParse(parts[0].Trim(), out int w) && int.TryParse(parts[1].Trim(), out int h) && w > 0 && h > 0)
{
_boothResolutionWidth = w;
_boothResolutionHeight = h;
UpdateBoothResolutionTabState();
SyncBoothResolutionToCameraService();
}
}
}
private void UpdateBoothResolutionTabState()
{
int index = 0;
for (int i = 0; i < BoothResolutionValues.Length; i++)
{
if (BoothResolutionValues[i].w == _boothResolutionWidth && BoothResolutionValues[i].h == _boothResolutionHeight)
{
index = i;
break;
}
}
if (BoothResolutionTabIndicator != null)
{
BoothResolutionTabIndicator.Margin = new Thickness(index * 70, 0, 0, 0);
}
var texts = new[] { BtnBoothResolution720?.Content as TextBlock, BtnBoothResolution1080?.Content as TextBlock, BtnBoothResolution2K?.Content as TextBlock, BtnBoothResolution4K?.Content as TextBlock };
for (int i = 0; i < texts.Length && i < 4; i++)
{
if (texts[i] == null) continue;
if (i == index)
{
texts[i].FontWeight = FontWeights.Bold;
texts[i].Foreground = new SolidColorBrush(Colors.White);
texts[i].Opacity = 1.0;
}
else
{
texts[i].FontWeight = FontWeights.SemiBold;
texts[i].SetResourceReference(TextBlock.ForegroundProperty, "FloatBarForeground");
texts[i].Opacity = 0.7;
}
}
}
#endregion
private void ToggleSwitchEnableInkToShape_Toggled(object sender, RoutedEventArgs e)
{
+13 -1
View File
@@ -54,7 +54,7 @@ namespace Ink_Canvas
/// </summary>
/// <param name="isBackupMain">为 true 时将导出结果保存到主备份槽(索引 0);为 false 时保存到当前白板索引。</param>
/// <remarks>
/// - 会提交画布上缺失于历史记录的 Image/MediaElement 和缺失的墨迹;
/// - 会提交画布上缺失于历史记录的 Image/MediaElement(但跳过 Tag 等于 VideoPresenterLiveFrameTag 的 Image和缺失的墨迹;
/// - 导出后把结果存入 TimeMachineHistories 的相应索引,并保存当前多指书写模式到 savedMultiTouchModeStates
/// - 导出后会清除时间机器的临时墨迹历史以释放内存。
/// - 此方法有副作用:修改 TimeMachineHistories、savedMultiTouchModeStates,并通过 timeMachine 的提交方法改变其内部历史状态。
@@ -85,6 +85,10 @@ namespace Ink_Canvas
{
if (child is Image || child is MediaElement || child is PdfEmbeddedView)
{
if (child is Image img && img.Tag is string tag && tag == VideoPresenterLiveFrameTag)
{
continue;
}
if (!elementsInHistory.Contains(child))
{
timeMachine.CommitElementInsertHistory(child);
@@ -441,12 +445,14 @@ namespace Ink_Canvas
currentSelectedElement = null;
}
VideoPresenter_BeforePageLeave();
SaveStrokes();
ClearStrokes(true);
CurrentWhiteboardIndex--;
RestoreStrokes();
VideoPresenter_OnPageChanged();
UpdateIndexInfoDisplay();
}
@@ -484,12 +490,14 @@ namespace Ink_Canvas
currentSelectedElement = null;
}
VideoPresenter_BeforePageLeave();
SaveStrokes();
ClearStrokes(true);
CurrentWhiteboardIndex++;
RestoreStrokes();
VideoPresenter_OnPageChanged();
UpdateIndexInfoDisplay();
}
@@ -525,6 +533,7 @@ namespace Ink_Canvas
currentSelectedElement = null;
}
VideoPresenter_BeforePageLeave();
SaveStrokes();
ClearStrokes(true);
@@ -540,9 +549,12 @@ namespace Ink_Canvas
}
}
// 确保新页面的历史记录为空
TimeMachineHistories[CurrentWhiteboardIndex] = null;
// 恢复新页面(这会清空画布,因为历史记录为null)
RestoreStrokes();
VideoPresenter_OnPageChanged();
UpdateIndexInfoDisplay();
@@ -3391,6 +3391,7 @@ namespace Ink_Canvas
switch (++currentMode % 2)
{
case 0: //屏幕模式
VideoPresenter_OnExitWhiteboardMode();
currentMode = 0;
GridBackgroundCover.Visibility = Visibility.Collapsed;
AnimationsHelper.HideWithSlideAndFade(BlackboardLeftSide);
File diff suppressed because it is too large Load Diff
+4
View File
@@ -151,6 +151,10 @@ namespace Ink_Canvas
[JsonProperty("enableVelocityBrushTip")]
public bool EnableVelocityBrushTip { get; set; }
/// <summary>为 true 时,白板工具栏「展台」按钮启动希沃视频展台(sweclauncher),否则使用内置展台。</summary>
[JsonProperty("launchSeewoVideoShowcaseForWhiteboardBooth")]
public bool LaunchSeewoVideoShowcaseForWhiteboardBooth { get; set; } = false;
}
public enum OptionalOperation
@@ -96,6 +96,13 @@
SwitchName="ToggleSwitchCompressPicturesUploaded"
Toggled="ToggleSwitchCompressPicturesUploaded_Toggled" />
<controls:LabeledSettingsCard x:Name="CardLaunchSeewoVideoShowcaseForWhiteboardBooth"
Header="{i18n:I18n Key=Canvas_LaunchSeewoVideoShowcaseForWhiteboardBooth}"
Description="{i18n:I18n Key=Canvas_LaunchSeewoVideoShowcaseForWhiteboardBoothHint}"
Icon="{x:Static ui:SegoeFluentIcons.Video}"
SwitchName="ToggleSwitchLaunchSeewoVideoShowcaseForWhiteboardBooth"
Toggled="ToggleSwitchLaunchSeewoVideoShowcaseForWhiteboardBooth_Toggled" />
<ui:SettingsCard Header="{i18n:I18n Key=Canvas_KeepHyperbolaAsymptote}"
Description="{i18n:I18n Key=Canvas_HyperbolaAsymptoteHint}">
<ui:SettingsCard.HeaderIcon>
@@ -40,6 +40,7 @@ namespace Ink_Canvas.Windows.SettingsViews.Pages
CardClearCanvasAndClearTimeMachine.IsOn = settings.Canvas.ClearCanvasAndClearTimeMachine;
CardClearCanvasAlsoClearImages.IsOn = settings.Canvas.ClearCanvasAlsoClearImages;
CardCompressPicturesUploaded.IsOn = settings.Canvas.IsCompressPicturesUploaded;
CardLaunchSeewoVideoShowcaseForWhiteboardBooth.IsOn = settings.Canvas.LaunchSeewoVideoShowcaseForWhiteboardBooth;
ComboBoxHyperbolaAsymptoteOption.SelectedIndex = (int)settings.Canvas.HyperbolaAsymptoteOption;
CardShowCircleCenter.IsOn = settings.Canvas.ShowCircleCenter;
int curveMode = 0;
@@ -175,6 +176,13 @@ namespace Ink_Canvas.Windows.SettingsViews.Pages
SettingsManager.SaveSettingsToFile();
}
private void ToggleSwitchLaunchSeewoVideoShowcaseForWhiteboardBooth_Toggled(object sender, RoutedEventArgs e)
{
if (!_isLoaded) return;
SettingsManager.Settings.Canvas.LaunchSeewoVideoShowcaseForWhiteboardBooth = CardLaunchSeewoVideoShowcaseForWhiteboardBooth.IsOn;
SettingsManager.SaveSettingsToFile();
}
private void ComboBoxHyperbolaAsymptoteOption_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (!_isLoaded) return;