Skip to content

Commit c9ef8f0

Browse files
committed
Add custom navigation arrows to About page in Configure window
Replaced the default Frame navigation UI with custom mui:ModernButton back/forward arrows in the About page of the Configure window. The navigation buttons are always visible at the top of the About page and match the styling used in main branch. Key changes: - Added custom navigation panel with mui:ModernButton arrows to About tab - Navigation arrows use Icons.Back and Icons.Forward with proper sizing - Buttons automatically enable/disable based on Frame navigation state - Modified AboutPage.xaml.cs to navigate within AboutFrame instead of parent Frame - Completely suppressed default Frame navigation UI using multiple techniques - Navigation now works correctly when viewing Licenses and Crash Logs pages Also includes merge of classic-ui-modern-fixes branch which adds: - WebCam placement preview page to configuration window - WebCam tab in settings with camera preview and placement controls The custom navigation provides a cleaner, more consistent user experience that matches the application's design aesthetic.
1 parent 15808d2 commit c9ef8f0

10 files changed

Lines changed: 470 additions & 52 deletions

src/Captura/Models/MainModule.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System;
1+
using System;
22
using Captura.Audio;
33
using Captura.FFmpeg;
44
using Captura.Hotkeys;
@@ -29,6 +29,7 @@ public void OnLoad(IBinder Binder)
2929
Binder.BindSingleton<RegionSelectorViewModel>();
3030

3131
Binder.BindSingleton<WebcamPage>();
32+
Binder.BindSingleton<WebcamPlacementPreviewPage>();
3233

3334
// Bind as a Function to ensure the UI objects are referenced only after they have been created.
3435
Binder.Bind<Func<TaskbarIcon>>(() => () => MainWindow.Instance.SystemTray);

src/Captura/Models/ServiceLocator.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ static ServiceLocator()
1818
}
1919

2020
public WebcamPage WebcamPage => ServiceProvider.Get<WebcamPage>();
21+
22+
public WebcamPlacementPreviewPage WebcamPlacementPreviewPage => ServiceProvider.Get<WebcamPlacementPreviewPage>();
2123

2224
public MainViewModel MainViewModel => ServiceProvider.Get<MainViewModel>();
2325

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Windows;
2+
using System.Windows.Controls;
23
using Captura.Views;
34

45
namespace Captura
@@ -7,12 +8,30 @@ public partial class AboutPage
78
{
89
void ViewLicenses(object Sender, RoutedEventArgs E)
910
{
10-
NavigationService?.Navigate(new LicensesPage());
11+
// Navigate using the immediate parent Frame (AboutFrame), not the grandparent
12+
var parentFrame = Parent as Frame;
13+
if (parentFrame != null)
14+
{
15+
parentFrame.Navigate(new LicensesPage());
16+
}
17+
else
18+
{
19+
NavigationService?.Navigate(new LicensesPage());
20+
}
1121
}
1222

1323
void ViewCrashLogs(object Sender, RoutedEventArgs E)
1424
{
15-
NavigationService?.Navigate(new CrashLogsPage());
25+
// Navigate using the immediate parent Frame (AboutFrame), not the grandparent
26+
var parentFrame = Parent as Frame;
27+
if (parentFrame != null)
28+
{
29+
parentFrame.Navigate(new CrashLogsPage());
30+
}
31+
else
32+
{
33+
NavigationService?.Navigate(new CrashLogsPage());
34+
}
1635
}
1736
}
1837
}

src/Captura/Pages/SettingsPage.xaml

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,34 @@
5353
<TabItem Header="FFmpeg">
5454
<Frame Source="FFmpegPage.xaml"/>
5555
</TabItem>
56+
<TabItem Header="{Binding WebCam, Source={StaticResource Loc}, Mode=OneWay}">
57+
<Frame Name="WebcamTabFrame"/>
58+
</TabItem>
5659
<TabItem Header="{Binding Trim, Source={StaticResource Loc}, Mode=OneWay}">
5760
<Frame Source="TrimmerPage.xaml"/>
5861
</TabItem>
5962
<TabItem Header="{Binding About, Source={StaticResource Loc}, Mode=OneWay}">
60-
<Frame Source="AboutPage.xaml"/>
63+
<DockPanel>
64+
<DockPanel DockPanel.Dock="Top"
65+
Margin="5,5,5,10">
66+
<mui:ModernButton IconData="{Binding Icons.Back, Source={StaticResource ServiceLocator}}"
67+
IsEnabled="{Binding CanGoBack, ElementName=AboutFrame}"
68+
EllipseDiameter="40"
69+
IconWidth="35"
70+
IconHeight="25"
71+
Margin="5,0,2,0"
72+
Click="AboutBackButton_Click"/>
73+
74+
<mui:ModernButton IconData="{Binding Icons.Forward, Source={StaticResource ServiceLocator}}"
75+
IsEnabled="{Binding CanGoForward, ElementName=AboutFrame}"
76+
Click="AboutForwardButton_Click"/>
77+
</DockPanel>
78+
<Frame x:Name="AboutFrame"
79+
Source="AboutPage.xaml"
80+
NavigationUIVisibility="Hidden"
81+
JournalOwnership="OwnsJournal"
82+
Navigated="AboutFrame_Navigated"/>
83+
</DockPanel>
6184
</TabItem>
6285
</TabControl>
6386
</Grid>
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,61 @@
1+
using System;
2+
using System.Windows;
3+
using System.Windows.Navigation;
4+
15
namespace Captura
26
{
37
public partial class SettingsPage
48
{
9+
bool _webcamPageNavigated;
10+
511
public SettingsPage()
612
{
713
InitializeComponent();
14+
15+
Loaded += (s, e) =>
16+
{
17+
// Navigate to WebcamPlacementPreviewPage singleton instance for the WebCam tab (only once)
18+
if (WebcamTabFrame != null && !_webcamPageNavigated)
19+
{
20+
_webcamPageNavigated = true;
21+
var webcamPage = ServiceProvider.Get<WebcamPlacementPreviewPage>();
22+
WebcamTabFrame.Navigate(webcamPage);
23+
24+
// Setup preview event handlers only once
25+
webcamPage.SetupPreview();
26+
}
27+
};
28+
}
29+
30+
void AboutBackButton_Click(object sender, RoutedEventArgs e)
31+
{
32+
if (AboutFrame.CanGoBack)
33+
{
34+
AboutFrame.GoBack();
35+
}
36+
}
37+
38+
void AboutForwardButton_Click(object sender, RoutedEventArgs e)
39+
{
40+
if (AboutFrame.CanGoForward)
41+
{
42+
AboutFrame.GoForward();
43+
}
44+
}
45+
46+
void AboutFrame_Navigated(object sender, NavigationEventArgs e)
47+
{
48+
// Forcefully hide NavigationUI after navigation
49+
if (sender is System.Windows.Controls.Frame frame)
50+
{
51+
frame.NavigationUIVisibility = NavigationUIVisibility.Hidden;
52+
53+
// Also ensure the page itself doesn't have NavigationService chrome
54+
if (e.Content is System.Windows.Controls.Page page)
55+
{
56+
page.ShowsNavigationUI = false;
57+
}
58+
}
859
}
960
}
1061
}

src/Captura/Pages/WebcamPage.xaml

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,6 @@
1818
VerticalAlignment="Center"
1919
ToolTip="{Binding WebCam, Source={StaticResource Loc}, Mode=OneWay}"/>
2020

21-
<Button Content="Properties"
22-
DockPanel.Dock="Right"
23-
Click="ShowCameraProperties_Click"
24-
Padding="10,0"
25-
Margin="3,0"
26-
ToolTip="Show Camera Properties"/>
27-
28-
<Button Content="{Binding Preview, Source={StaticResource Loc}, Mode=OneWay}"
29-
DockPanel.Dock="Right"
30-
Click="Preview_Click"
31-
Padding="10,0"
32-
Margin="3,0"/>
33-
3421
<ComboBox ItemsSource="{Binding WebcamModel.AvailableCams, Source={StaticResource ServiceLocator}}"
3522
SelectedItem="{Binding WebcamModel.SelectedCam, Mode=TwoWay, Source={StaticResource ServiceLocator}}"
3623
IsEnabled="{Binding RecordingViewModel.CanChangeWebcam, Source={StaticResource ServiceLocator}}"
Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
using System.Windows;
21
using Captura.ViewModels;
3-
using Captura.Webcam;
42

53
namespace Captura
64
{
@@ -15,37 +13,5 @@ public WebcamPage()
1513
WebcamComboBox?.Shake();
1614
};
1715
}
18-
19-
void Preview_Click(object Sender, RoutedEventArgs E)
20-
{
21-
WebCamWindow.Instance.ShowAndFocus();
22-
}
23-
24-
void ShowCameraProperties_Click(object sender, RoutedEventArgs e)
25-
{
26-
// Access the webcam through the WebCamWindow in classic UI
27-
var webcamControl = WebCamWindow.Instance.GetWebCamControl();
28-
var capture = webcamControl?.Capture;
29-
30-
if (capture == null)
31-
{
32-
ServiceProvider.MessageProvider?.ShowError("No camera is currently active.\n\nPlease select a camera and start preview first.", "Camera Not Active");
33-
return;
34-
}
35-
36-
try
37-
{
38-
var properties = capture.GetCameraProperties();
39-
var window = new CameraPropertiesWindow(properties)
40-
{
41-
Owner = Window.GetWindow(this)
42-
};
43-
window.ShowDialog();
44-
}
45-
catch (System.Exception ex)
46-
{
47-
ServiceProvider.MessageProvider?.ShowError($"Failed to get camera properties:\n\n{ex.Message}", "Error");
48-
}
49-
}
5016
}
5117
}
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
<Page x:Class="Captura.WebcamPlacementPreviewPage"
2+
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4+
xmlns:captura="clr-namespace:Captura"
5+
Title="{Binding WebCam, Source={StaticResource Loc}, Mode=OneWay}"
6+
DataContext="{Binding MainViewModel, Source={StaticResource ServiceLocator}}">
7+
<Grid Margin="5,0">
8+
<Grid.ColumnDefinitions>
9+
<ColumnDefinition Width="250"/>
10+
<ColumnDefinition Width="Auto"/>
11+
<ColumnDefinition Width="*"/>
12+
</Grid.ColumnDefinitions>
13+
<StackPanel DataContext="{Binding Settings.WebcamOverlay}">
14+
<DockPanel>
15+
<captura:ModernButton ToolTip="{Binding Refresh, Source={StaticResource Loc}, Mode=OneWay}"
16+
Command="{Binding WebcamModel.RefreshCommand, Source={StaticResource ServiceLocator}}"
17+
IconData="{Binding Icons.Refresh, Source={StaticResource ServiceLocator}}"
18+
DockPanel.Dock="Right"/>
19+
20+
<captura:ModernButton ToolTip="Camera Properties"
21+
Click="CameraProperties_OnClick"
22+
IconData="{Binding Icons.Settings, Source={StaticResource ServiceLocator}}"
23+
DockPanel.Dock="Right"/>
24+
25+
<captura:ModernButton ToolTip="Capture Image"
26+
Click="CaptureImage_OnClick"
27+
IconData="{Binding Icons.Camera, Source={StaticResource ServiceLocator}}"
28+
DockPanel.Dock="Right"/>
29+
30+
<Path Data="{Binding Icons.Webcam, Source={StaticResource ServiceLocator}}"
31+
Width="15"
32+
Height="15"
33+
Margin="0,0,7,0"
34+
Stretch="Uniform"
35+
HorizontalAlignment="Center"
36+
VerticalAlignment="Center"
37+
ToolTip="{Binding WebCam, Source={StaticResource Loc}, Mode=OneWay}"/>
38+
39+
<ComboBox ItemsSource="{Binding WebcamModel.AvailableCams, Source={StaticResource ServiceLocator}}"
40+
SelectedItem="{Binding WebcamModel.SelectedCam, Mode=TwoWay, Source={StaticResource ServiceLocator}}"
41+
IsEnabled="{Binding ViewConditions.CanChangeWebcam.Value, Source={StaticResource ServiceLocator}}"
42+
DisplayMemberPath="Name"
43+
VerticalAlignment="Center"
44+
Margin="0,0,7,0"/>
45+
</DockPanel>
46+
47+
<CheckBox IsChecked="{Binding SeparateFile}"
48+
Content="{Binding WebCamSeparateFile, Source={StaticResource Loc}, Mode=OneWay}"
49+
IsEnabled="{Binding ViewConditions.IsEnabled.Value, Source={StaticResource ServiceLocator}}"
50+
Visibility="{Binding ViewConditions.CanWebcamSeparateFile.Value, Source={StaticResource ServiceLocator}, Converter={StaticResource BoolToVisibilityConverter}}"
51+
Margin="0,5"/>
52+
53+
<Grid Margin="0,15,0,5">
54+
<Grid.ColumnDefinitions>
55+
<ColumnDefinition Width="Auto"/>
56+
<ColumnDefinition Width="Auto"/>
57+
<ColumnDefinition Width="*"/>
58+
</Grid.ColumnDefinitions>
59+
60+
<Path Data="{Binding Icons.Opacity, Source={StaticResource ServiceLocator}}"
61+
Width="15"
62+
Height="15"
63+
Margin="0,0,10,0"
64+
Stretch="Uniform"
65+
HorizontalAlignment="Center"
66+
VerticalAlignment="Center"/>
67+
68+
<Label Content="{Binding Opacity, Source={StaticResource Loc}, Mode=OneWay}"
69+
ContentStringFormat="{}{0}: "
70+
Grid.Column="1"
71+
Margin="0,3"/>
72+
73+
<Slider Grid.Column="2"
74+
Minimum="1"
75+
Maximum="100"
76+
Value="{Binding Opacity, Mode=TwoWay}"
77+
SmallChange="1"
78+
LargeChange="10"/>
79+
</Grid>
80+
</StackPanel>
81+
<GridSplitter Grid.Column="1"
82+
Width="1"
83+
Margin="5,0"/>
84+
<DockPanel Grid.Column="2"
85+
DataContext="{Binding Settings.WebcamOverlay}">
86+
<DockPanel Margin="5"
87+
DockPanel.Dock="Top">
88+
<Label Content="Scale: "/>
89+
<Slider Value="{Binding Scale, Mode=TwoWay}"
90+
TickPlacement="BottomRight"
91+
TickFrequency="0.1"
92+
SmallChange="0.01"
93+
LargeChange="0.1"
94+
Minimum="0"
95+
Maximum="1"/>
96+
</DockPanel>
97+
98+
<DockPanel VerticalAlignment="Center"
99+
HorizontalAlignment="Center"
100+
Margin="0,0,0,10">
101+
<DockPanel DockPanel.Dock="Bottom"
102+
Margin="5,5,40,5">
103+
<Label Content="X"
104+
Margin="0,0,5,0"/>
105+
<Slider Value="{Binding XLoc, Mode=TwoWay}"
106+
SmallChange="0.01"
107+
LargeChange="0.1"
108+
Minimum="0"
109+
Maximum="1"/>
110+
</DockPanel>
111+
<DockPanel DockPanel.Dock="Right"
112+
Margin="5">
113+
<Label Content="Y"
114+
HorizontalContentAlignment="Center"
115+
Margin="0,0,0,5"
116+
DockPanel.Dock="Top"/>
117+
<Slider Value="{Binding YLoc, Mode=TwoWay}"
118+
Orientation="Vertical"
119+
IsDirectionReversed="True"
120+
SmallChange="0.01"
121+
LargeChange="0.1"
122+
Minimum="0"
123+
Maximum="1"/>
124+
</DockPanel>
125+
<Grid Name="PreviewGrid"
126+
Background="DimGray">
127+
<Image Name="Img"
128+
Stretch="Uniform"/>
129+
130+
<!-- Invisible but still required to prevent render errors -->
131+
<Label Name="PreviewTarget"
132+
HorizontalAlignment="Left"
133+
VerticalAlignment="Top"
134+
Background="#00FFFFFF"
135+
MaxWidth="{Binding ActualWidth, ElementName=Img}"
136+
MaxHeight="{Binding ActualHeight, ElementName=Img}"/>
137+
</Grid>
138+
</DockPanel>
139+
</DockPanel>
140+
</Grid>
141+
</Page>

0 commit comments

Comments
 (0)