Restore SEBPatch
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
<UserControl x:Class="SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenter.ApplicationButton" x:ClassModifier="internal"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop.Controls"
|
||||
mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800">
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="../../Templates/Buttons.xaml" />
|
||||
<ResourceDictionary Source="../../Templates/Colors.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
<Grid>
|
||||
<Button x:Name="Button" Background="Transparent" Height="40" Padding="10" Template="{StaticResource ActionCenterButton}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<ContentControl x:Name="Icon" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="0,0,10,0" Width="20" />
|
||||
<TextBlock x:Name="Text" HorizontalAlignment="Left" VerticalAlignment="Center" Padding="5" MaxWidth="350" TextTrimming="CharacterEllipsis" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
</Grid>
|
||||
</UserControl>
|
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Windows.Automation;
|
||||
using System.Windows.Controls;
|
||||
using SafeExamBrowser.Applications.Contracts;
|
||||
using SafeExamBrowser.Core.Contracts.Resources.Icons;
|
||||
using SafeExamBrowser.UserInterface.Shared.Utilities;
|
||||
|
||||
namespace SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenter
|
||||
{
|
||||
internal partial class ApplicationButton : UserControl
|
||||
{
|
||||
private readonly IApplication<IApplicationWindow> application;
|
||||
private readonly IApplicationWindow window;
|
||||
|
||||
internal event EventHandler Clicked;
|
||||
|
||||
internal ApplicationButton(IApplication<IApplicationWindow> application, IApplicationWindow window = null)
|
||||
{
|
||||
this.application = application;
|
||||
this.window = window;
|
||||
|
||||
InitializeComponent();
|
||||
InitializeApplicationInstanceButton();
|
||||
}
|
||||
|
||||
private void InitializeApplicationInstanceButton()
|
||||
{
|
||||
var tooltip = window?.Title ?? application.Tooltip;
|
||||
|
||||
Button.Click += (o, args) => Clicked?.Invoke(this, EventArgs.Empty);
|
||||
Button.ToolTip = tooltip;
|
||||
Icon.Content = IconResourceLoader.Load(window?.Icon ?? application.Icon);
|
||||
Text.Text = window?.Title ?? application.Name;
|
||||
|
||||
if (tooltip != default)
|
||||
{
|
||||
AutomationProperties.SetName(Button, string.Empty);
|
||||
}
|
||||
|
||||
if (window != default)
|
||||
{
|
||||
window.IconChanged += Window_IconChanged;
|
||||
window.TitleChanged += Window_TitleChanged;
|
||||
}
|
||||
}
|
||||
|
||||
private void Window_IconChanged(IconResource icon)
|
||||
{
|
||||
Dispatcher.InvokeAsync(() => Icon.Content = IconResourceLoader.Load(icon));
|
||||
}
|
||||
|
||||
private void Window_TitleChanged(string title)
|
||||
{
|
||||
Dispatcher.InvokeAsync(() =>
|
||||
{
|
||||
Text.Text = title;
|
||||
Button.ToolTip = title;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,27 @@
|
||||
<UserControl x:Class="SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenter.ApplicationControl" x:ClassModifier="internal"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop.Controls"
|
||||
mc:Ignorable="d" d:DesignHeight="250" d:DesignWidth="500">
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="../../Templates/Buttons.xaml" />
|
||||
<ResourceDictionary Source="../../Templates/Colors.xaml" />
|
||||
<ResourceDictionary Source="../../Templates/ScrollViewers.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock Grid.Row="0" x:Name="ApplicationName" Background="{StaticResource BackgroundTransparentEmphasisBrush}" FontWeight="Bold" Padding="5" TextAlignment="Center" />
|
||||
<ContentControl Grid.Row="1" x:Name="ApplicationButton" FontWeight="Bold" />
|
||||
<StackPanel Grid.Row="2" x:Name="WindowPanel" Background="{StaticResource BackgroundTransparentEmphasisBrush}" Orientation="Vertical" />
|
||||
</Grid>
|
||||
</UserControl>
|
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using SafeExamBrowser.Applications.Contracts;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Shell;
|
||||
|
||||
namespace SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenter
|
||||
{
|
||||
internal partial class ApplicationControl : UserControl, IApplicationControl
|
||||
{
|
||||
private readonly IApplication<IApplicationWindow> application;
|
||||
|
||||
internal ApplicationControl(IApplication<IApplicationWindow> application)
|
||||
{
|
||||
this.application = application;
|
||||
|
||||
InitializeComponent();
|
||||
InitializeApplicationControl();
|
||||
}
|
||||
|
||||
private void InitializeApplicationControl()
|
||||
{
|
||||
var button = new ApplicationButton(application);
|
||||
|
||||
application.WindowsChanged += Application_WindowsChanged;
|
||||
button.Clicked += (o, args) => application.Start();
|
||||
ApplicationName.Text = application.Name;
|
||||
ApplicationName.Visibility = Visibility.Collapsed;
|
||||
ApplicationButton.Content = button;
|
||||
}
|
||||
|
||||
private void Application_WindowsChanged()
|
||||
{
|
||||
Dispatcher.InvokeAsync(Update);
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
var windows = application.GetWindows();
|
||||
|
||||
WindowPanel.Children.Clear();
|
||||
|
||||
foreach (var window in windows)
|
||||
{
|
||||
var button = new ApplicationButton(application, window);
|
||||
|
||||
button.Clicked += (o, args) => window.Activate();
|
||||
WindowPanel.Children.Add(button);
|
||||
}
|
||||
|
||||
if (WindowPanel.Children.Count == 0)
|
||||
{
|
||||
ApplicationName.Visibility = Visibility.Collapsed;
|
||||
ApplicationButton.Visibility = Visibility.Visible;
|
||||
}
|
||||
else
|
||||
{
|
||||
ApplicationName.Visibility = Visibility.Visible;
|
||||
ApplicationButton.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,45 @@
|
||||
<UserControl x:Class="SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenter.AudioControl" x:ClassModifier="internal"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop.Controls"
|
||||
mc:Ignorable="d" d:DesignHeight="100" d:DesignWidth="125">
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="../../Templates/Buttons.xaml" />
|
||||
<ResourceDictionary Source="../../Templates/Colors.xaml" />
|
||||
<ResourceDictionary Source="../../Templates/ScrollViewers.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
<Grid x:Name="Grid" Background="{StaticResource ActionCenterDarkBrush}" Height="64" Margin="2">
|
||||
<Popup x:Name="Popup" IsOpen="False" Placement="Top" PlacementTarget="{Binding ElementName=Button}">
|
||||
<Border Background="Gray">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<TextBlock x:Name="AudioDeviceName" Foreground="White" Margin="5" TextAlignment="Center" />
|
||||
<StackPanel Orientation="Horizontal" Height="40">
|
||||
<Button x:Name="MuteButton" Background="Transparent" Foreground="White" Padding="5" Template="{StaticResource ActionCenterButton}" Width="40">
|
||||
<ContentControl x:Name="PopupIcon" Focusable="False" />
|
||||
</Button>
|
||||
<Slider x:Name="Volume" Grid.Column="1" Orientation="Horizontal" TickFrequency="1" Maximum="100" IsSnapToTickEnabled="True"
|
||||
IsMoveToPointEnabled="True" VerticalAlignment="Center" Width="250" Thumb.DragStarted="Volume_DragStarted" Thumb.DragCompleted="Volume_DragCompleted" />
|
||||
<TextBlock Grid.Column="2" FontWeight="DemiBold" FontSize="16" Text="{Binding ElementName=Volume, Path=Value}"
|
||||
TextAlignment="Center" VerticalAlignment="Center" Foreground="White" Width="40" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Popup>
|
||||
<Button x:Name="Button" Padding="2" Template="{StaticResource ActionCenterButton}">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="2*" />
|
||||
<RowDefinition Height="3*" />
|
||||
</Grid.RowDefinitions>
|
||||
<ContentControl x:Name="ButtonIcon" />
|
||||
<TextBlock Grid.Row="1" x:Name="Text" FontSize="11" Foreground="White" TextAlignment="Center" TextTrimming="CharacterEllipsis" TextWrapping="Wrap" VerticalAlignment="Bottom" />
|
||||
</Grid>
|
||||
</Button>
|
||||
</Grid>
|
||||
</UserControl>
|
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Automation;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Threading;
|
||||
using SafeExamBrowser.Core.Contracts.Resources.Icons;
|
||||
using SafeExamBrowser.I18n.Contracts;
|
||||
using SafeExamBrowser.SystemComponents.Contracts.Audio;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Shell;
|
||||
using SafeExamBrowser.UserInterface.Shared.Utilities;
|
||||
|
||||
namespace SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenter
|
||||
{
|
||||
internal partial class AudioControl : UserControl, ISystemControl
|
||||
{
|
||||
private readonly IAudio audio;
|
||||
private readonly IText text;
|
||||
private bool muted;
|
||||
private IconResource MutedIcon;
|
||||
private IconResource NoDeviceIcon;
|
||||
|
||||
internal AudioControl(IAudio audio, IText text)
|
||||
{
|
||||
this.audio = audio;
|
||||
this.text = text;
|
||||
|
||||
InitializeComponent();
|
||||
InitializeAudioControl();
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
Popup.IsOpen = false;
|
||||
}
|
||||
|
||||
private void InitializeAudioControl()
|
||||
{
|
||||
var originalBrush = Grid.Background;
|
||||
|
||||
audio.VolumeChanged += Audio_VolumeChanged;
|
||||
Button.Click += (o, args) => Popup.IsOpen = !Popup.IsOpen;
|
||||
var lastOpenedBySpacePress = false;
|
||||
Button.PreviewKeyDown += (o, args) =>
|
||||
{
|
||||
// For some reason, the popup immediately closes again if opened by a Space Bar key event - as a mitigation,
|
||||
// we record the space bar event and leave the popup open for at least 3 seconds.
|
||||
if (args.Key == System.Windows.Input.Key.Space)
|
||||
{
|
||||
lastOpenedBySpacePress = true;
|
||||
}
|
||||
};
|
||||
Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() =>
|
||||
{
|
||||
if (Popup.IsOpen && lastOpenedBySpacePress)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Popup.IsOpen = Popup.IsMouseOver;
|
||||
}));
|
||||
MuteButton.Click += MuteButton_Click;
|
||||
MutedIcon = new XamlIconResource { Uri = new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/Audio_Muted.xaml") };
|
||||
NoDeviceIcon = new XamlIconResource { Uri = new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/Audio_Light_NoDevice.xaml") };
|
||||
Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() =>
|
||||
{
|
||||
if (Popup.IsOpen && lastOpenedBySpacePress)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Popup.IsOpen = IsMouseOver;
|
||||
}));
|
||||
Popup.Opened += (o, args) => Grid.Background = Brushes.Gray;
|
||||
Popup.Closed += (o, args) =>
|
||||
{
|
||||
Grid.Background = originalBrush;
|
||||
lastOpenedBySpacePress = false;
|
||||
};
|
||||
Volume.ValueChanged += Volume_ValueChanged;
|
||||
|
||||
if (audio.HasOutputDevice)
|
||||
{
|
||||
AudioDeviceName.Text = audio.DeviceFullName;
|
||||
Button.IsEnabled = true;
|
||||
UpdateVolume(audio.OutputVolume, audio.OutputMuted);
|
||||
}
|
||||
else
|
||||
{
|
||||
AudioDeviceName.Text = text.Get(TextKey.SystemControl_AudioDeviceNotFound);
|
||||
Button.IsEnabled = false;
|
||||
Button.ToolTip = text.Get(TextKey.SystemControl_AudioDeviceNotFound);
|
||||
ButtonIcon.Content = IconResourceLoader.Load(NoDeviceIcon);
|
||||
Text.Text = text.Get(TextKey.SystemControl_AudioDeviceNotFound);
|
||||
}
|
||||
}
|
||||
|
||||
private void Audio_VolumeChanged(double volume, bool muted)
|
||||
{
|
||||
Dispatcher.InvokeAsync(() => UpdateVolume(volume, muted));
|
||||
}
|
||||
|
||||
private void MuteButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (muted)
|
||||
{
|
||||
audio.Unmute();
|
||||
}
|
||||
else
|
||||
{
|
||||
audio.Mute();
|
||||
}
|
||||
}
|
||||
|
||||
private void Volume_DragStarted(object sender, DragStartedEventArgs e)
|
||||
{
|
||||
Volume.ValueChanged -= Volume_ValueChanged;
|
||||
}
|
||||
|
||||
private void Volume_DragCompleted(object sender, DragCompletedEventArgs e)
|
||||
{
|
||||
audio.SetVolume(Volume.Value / 100);
|
||||
Volume.ValueChanged += Volume_ValueChanged;
|
||||
}
|
||||
|
||||
private void Volume_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
|
||||
{
|
||||
audio.SetVolume(Volume.Value / 100);
|
||||
}
|
||||
|
||||
private void UpdateVolume(double volume, bool muted)
|
||||
{
|
||||
var info = BuildInfoText(volume, muted);
|
||||
|
||||
this.muted = muted;
|
||||
|
||||
Button.ToolTip = info;
|
||||
Text.Text = info;
|
||||
Volume.ValueChanged -= Volume_ValueChanged;
|
||||
Volume.Value = Math.Round(volume * 100);
|
||||
Volume.ValueChanged += Volume_ValueChanged;
|
||||
|
||||
AutomationProperties.SetName(Button, info);
|
||||
|
||||
if (muted)
|
||||
{
|
||||
var tooltip = text.Get(TextKey.SystemControl_AudioDeviceUnmuteTooltip);
|
||||
|
||||
MuteButton.ToolTip = tooltip;
|
||||
ButtonIcon.Content = IconResourceLoader.Load(MutedIcon);
|
||||
PopupIcon.Content = IconResourceLoader.Load(MutedIcon);
|
||||
|
||||
AutomationProperties.SetName(MuteButton, tooltip);
|
||||
}
|
||||
else
|
||||
{
|
||||
var tooltip = text.Get(TextKey.SystemControl_AudioDeviceMuteTooltip);
|
||||
|
||||
MuteButton.ToolTip = tooltip;
|
||||
ButtonIcon.Content = LoadIcon(volume);
|
||||
PopupIcon.Content = LoadIcon(volume);
|
||||
|
||||
AutomationProperties.SetName(MuteButton, tooltip);
|
||||
}
|
||||
}
|
||||
|
||||
private string BuildInfoText(double volume, bool muted)
|
||||
{
|
||||
var info = text.Get(muted ? TextKey.SystemControl_AudioDeviceInfoMuted : TextKey.SystemControl_AudioDeviceInfo);
|
||||
|
||||
info = info.Replace("%%NAME%%", audio.DeviceShortName);
|
||||
info = info.Replace("%%VOLUME%%", Convert.ToString(Math.Round(volume * 100)));
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
private UIElement LoadIcon(double volume)
|
||||
{
|
||||
var icon = volume > 0.66 ? "100" : (volume > 0.33 ? "66" : "33");
|
||||
var uri = new Uri($"pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/Audio_Light_{icon}.xaml");
|
||||
var resource = new XamlIconResource { Uri = uri };
|
||||
|
||||
return IconResourceLoader.Load(resource);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,36 @@
|
||||
<UserControl x:Class="SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenter.Clock" x:ClassModifier="internal"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:fa="http://schemas.fontawesome.io/icons/"
|
||||
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop.Controls"
|
||||
mc:Ignorable="d" d:DesignHeight="100" d:DesignWidth="125">
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="../../Templates/Buttons.xaml" />
|
||||
<ResourceDictionary Source="../../Templates/Colors.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
<Grid Background="{StaticResource ActionCenterDarkBrush}" Height="64" Margin="2" ToolTip="{Binding Path=ToolTip}">
|
||||
<Button x:Name="Button" IsEnabled="False" Padding="2" Template="{StaticResource ActionCenterButton}">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="2*" />
|
||||
<RowDefinition Height="3*" />
|
||||
</Grid.RowDefinitions>
|
||||
<fa:ImageAwesome Grid.Row="0" Foreground="Black" Icon="ClockOutline" Margin="2" VerticalAlignment="Center" />
|
||||
<Grid Grid.Row="1" Background="Transparent" Margin="5,0" VerticalAlignment="Bottom">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="1*" />
|
||||
<RowDefinition Height="1*" />
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock x:Name="TimeTextBlock" Grid.Row="0" Text="{Binding Path=Time}" FontSize="11" Foreground="White" HorizontalAlignment="Center" />
|
||||
<TextBlock x:Name="DateTextBlock" Grid.Row="1" Text="{Binding Path=Date}" FontSize="11" Foreground="White" HorizontalAlignment="Center" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Button>
|
||||
</Grid>
|
||||
</UserControl>
|
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System.Windows.Controls;
|
||||
using SafeExamBrowser.UserInterface.Desktop.ViewModels;
|
||||
|
||||
namespace SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenter
|
||||
{
|
||||
internal partial class Clock : UserControl
|
||||
{
|
||||
private DateTimeViewModel model;
|
||||
|
||||
public Clock()
|
||||
{
|
||||
InitializeComponent();
|
||||
InitializeControl();
|
||||
}
|
||||
|
||||
private void InitializeControl()
|
||||
{
|
||||
model = new DateTimeViewModel(true);
|
||||
DataContext = model;
|
||||
TimeTextBlock.DataContext = model;
|
||||
DateTextBlock.DataContext = model;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,37 @@
|
||||
<UserControl x:Class="SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenter.KeyboardLayoutButton" x:ClassModifier="internal"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:fa="http://schemas.fontawesome.io/icons/"
|
||||
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop.Controls"
|
||||
mc:Ignorable="d" d:DesignHeight="40" d:DesignWidth="250" IsTabStop="True">
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="../../Templates/Buttons.xaml" />
|
||||
<ResourceDictionary Source="../../Templates/Colors.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
<Grid>
|
||||
<Button x:Name="Button" Background="Transparent" Height="40" Padding="10,0" Template="{StaticResource ActionCenterButton}">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock x:Name="IsCurrentTextBlock" Grid.Column="0" FontSize="20" HorizontalAlignment="Center" VerticalAlignment="Center" Visibility="Hidden">•</TextBlock>
|
||||
<TextBlock x:Name="CultureCodeTextBlock" Grid.Column="1" FontWeight="Bold" HorizontalAlignment="Left" Margin="10,0,5,0" VerticalAlignment="Center" />
|
||||
<StackPanel Grid.Column="2" VerticalAlignment="Center">
|
||||
<TextBlock x:Name="CultureNameTextBlock" Foreground="White" HorizontalAlignment="Left" Margin="5,0,10,0" TextDecorations="Underline" VerticalAlignment="Center" />
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<fa:ImageAwesome Foreground="LightGray" Height="10" Icon="KeyboardOutline" Margin="5,0" />
|
||||
<TextBlock x:Name="LayoutNameTextBlock" Foreground="LightGray" HorizontalAlignment="Left" Margin="0,0,10,0" VerticalAlignment="Center" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Button>
|
||||
</Grid>
|
||||
</UserControl>
|
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Automation;
|
||||
using System.Windows.Controls;
|
||||
using SafeExamBrowser.SystemComponents.Contracts.Keyboard;
|
||||
|
||||
namespace SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenter
|
||||
{
|
||||
internal partial class KeyboardLayoutButton : UserControl
|
||||
{
|
||||
private readonly IKeyboardLayout layout;
|
||||
|
||||
internal bool IsCurrent
|
||||
{
|
||||
set { IsCurrentTextBlock.Visibility = value ? Visibility.Visible : Visibility.Hidden; }
|
||||
}
|
||||
|
||||
internal Guid LayoutId
|
||||
{
|
||||
get { return layout.Id; }
|
||||
}
|
||||
|
||||
internal event EventHandler LayoutSelected;
|
||||
|
||||
internal KeyboardLayoutButton(IKeyboardLayout layout)
|
||||
{
|
||||
this.layout = layout;
|
||||
|
||||
InitializeComponent();
|
||||
InitializeLayoutButton();
|
||||
}
|
||||
|
||||
private void InitializeLayoutButton()
|
||||
{
|
||||
Button.Click += (o, args) => LayoutSelected?.Invoke(this, EventArgs.Empty);
|
||||
CultureCodeTextBlock.Text = layout.CultureCode;
|
||||
CultureNameTextBlock.Text = layout.CultureName;
|
||||
LayoutNameTextBlock.Text = layout.LayoutName;
|
||||
|
||||
AutomationProperties.SetName(Button, layout.CultureName);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,37 @@
|
||||
<UserControl x:Class="SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenter.KeyboardLayoutControl" x:ClassModifier="internal"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:fa="http://schemas.fontawesome.io/icons/"
|
||||
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop.Controls"
|
||||
mc:Ignorable="d" d:DesignHeight="100" d:DesignWidth="125">
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="../../Templates/Buttons.xaml" />
|
||||
<ResourceDictionary Source="../../Templates/Colors.xaml" />
|
||||
<ResourceDictionary Source="../../Templates/ScrollViewers.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
<Grid x:Name="Grid" Background="{StaticResource ActionCenterDarkBrush}" Height="64" Margin="2">
|
||||
<Popup x:Name="Popup" IsOpen="False" Placement="Top" PlacementTarget="{Binding ElementName=Button}" KeyUp="Popup_KeyUp">
|
||||
<Border Background="Gray">
|
||||
<ScrollViewer MaxHeight="250" VerticalScrollBarVisibility="Auto" Template="{StaticResource SmallBarScrollViewer}">
|
||||
<StackPanel x:Name="LayoutsStackPanel" />
|
||||
</ScrollViewer>
|
||||
</Border>
|
||||
</Popup>
|
||||
<Button x:Name="Button" Padding="2" Template="{StaticResource ActionCenterButton}">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="2*" />
|
||||
<RowDefinition Height="3*" />
|
||||
</Grid.RowDefinitions>
|
||||
<fa:ImageAwesome Grid.Row="0" Foreground="Black" Icon="KeyboardOutline" Margin="2" VerticalAlignment="Center" />
|
||||
<TextBlock Grid.Row="1" x:Name="Text" FontSize="11" Foreground="White" TextAlignment="Center" TextTrimming="CharacterEllipsis" TextWrapping="Wrap" VerticalAlignment="Bottom" />
|
||||
</Grid>
|
||||
</Button>
|
||||
</Grid>
|
||||
</UserControl>
|
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Automation;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using SafeExamBrowser.I18n.Contracts;
|
||||
using SafeExamBrowser.SystemComponents.Contracts.Keyboard;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Shell;
|
||||
|
||||
namespace SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenter
|
||||
{
|
||||
internal partial class KeyboardLayoutControl : UserControl, ISystemControl
|
||||
{
|
||||
private readonly IKeyboard keyboard;
|
||||
private readonly IText text;
|
||||
|
||||
internal KeyboardLayoutControl(IKeyboard keyboard, IText text)
|
||||
{
|
||||
this.keyboard = keyboard;
|
||||
this.text = text;
|
||||
|
||||
InitializeComponent();
|
||||
InitializeKeyboardLayoutControl();
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
Dispatcher.Invoke(() => Popup.IsOpen = false);
|
||||
}
|
||||
|
||||
private void InitializeKeyboardLayoutControl()
|
||||
{
|
||||
var originalBrush = Grid.Background;
|
||||
|
||||
InitializeLayouts();
|
||||
|
||||
keyboard.LayoutChanged += Keyboard_LayoutChanged;
|
||||
Button.Click += (o, args) =>
|
||||
{
|
||||
Popup.IsOpen = !Popup.IsOpen;
|
||||
this.Dispatcher.BeginInvoke((System.Action) (() =>
|
||||
{
|
||||
LayoutsStackPanel.Children[0].Focus();
|
||||
}));
|
||||
};
|
||||
var lastOpenedBySpacePress = false;
|
||||
Button.PreviewKeyDown += (o, args) =>
|
||||
{
|
||||
// For some reason, the popup immediately closes again if opened by a Space Bar key event - as a mitigation,
|
||||
// we record the space bar event and leave the popup open for at least 3 seconds.
|
||||
if (args.Key == System.Windows.Input.Key.Space)
|
||||
{
|
||||
lastOpenedBySpacePress = true;
|
||||
}
|
||||
};
|
||||
Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() =>
|
||||
{
|
||||
if (Popup.IsOpen && lastOpenedBySpacePress)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Popup.IsOpen = Popup.IsMouseOver;
|
||||
}));
|
||||
Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() =>
|
||||
{
|
||||
if (Popup.IsOpen && lastOpenedBySpacePress)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Popup.IsOpen = IsMouseOver;
|
||||
}));
|
||||
Popup.Opened += (o, args) => Grid.Background = Brushes.Gray;
|
||||
Popup.Closed += (o, args) =>
|
||||
{
|
||||
Grid.Background = originalBrush;
|
||||
lastOpenedBySpacePress = false;
|
||||
};
|
||||
}
|
||||
|
||||
private void Keyboard_LayoutChanged(IKeyboardLayout layout)
|
||||
{
|
||||
Dispatcher.InvokeAsync(() => SetCurrent(layout));
|
||||
}
|
||||
|
||||
private void InitializeLayouts()
|
||||
{
|
||||
foreach (var layout in keyboard.GetLayouts())
|
||||
{
|
||||
var button = new KeyboardLayoutButton(layout);
|
||||
|
||||
button.LayoutSelected += (o, args) => ActivateLayout(layout);
|
||||
LayoutsStackPanel.Children.Add(button);
|
||||
|
||||
if (layout.IsCurrent)
|
||||
{
|
||||
SetCurrent(layout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ActivateLayout(IKeyboardLayout layout)
|
||||
{
|
||||
Popup.IsOpen = false;
|
||||
keyboard.ActivateLayout(layout.Id);
|
||||
}
|
||||
|
||||
private void SetCurrent(IKeyboardLayout layout)
|
||||
{
|
||||
var tooltip = text.Get(TextKey.SystemControl_KeyboardLayoutTooltip).Replace("%%LAYOUT%%", layout.CultureName);
|
||||
|
||||
foreach (var child in LayoutsStackPanel.Children)
|
||||
{
|
||||
if (child is KeyboardLayoutButton layoutButton)
|
||||
{
|
||||
layoutButton.IsCurrent = layout.Id == layoutButton.LayoutId;
|
||||
}
|
||||
}
|
||||
|
||||
Text.Text = layout.CultureName;
|
||||
Button.ToolTip = tooltip;
|
||||
|
||||
AutomationProperties.SetName(Button, tooltip);
|
||||
}
|
||||
|
||||
private void Popup_KeyUp(object sender, System.Windows.Input.KeyEventArgs e)
|
||||
{
|
||||
if (e.Key == System.Windows.Input.Key.Enter || e.Key == System.Windows.Input.Key.Escape)
|
||||
{
|
||||
Popup.IsOpen = false;
|
||||
Button.Focus();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,30 @@
|
||||
<UserControl x:Class="SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenter.NetworkButton" x:ClassModifier="internal"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop.Controls"
|
||||
mc:Ignorable="d" d:DesignHeight="40" d:DesignWidth="250">
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="../../Templates/Buttons.xaml" />
|
||||
<ResourceDictionary Source="../../Templates/Colors.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
<Grid>
|
||||
<Button x:Name="Button" Background="Transparent" Height="40" Padding="10,0" Template="{StaticResource ActionCenterButton}">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock x:Name="IsCurrentTextBlock" Grid.Column="0" FontSize="20" HorizontalAlignment="Center" VerticalAlignment="Center" Visibility="Hidden">•</TextBlock>
|
||||
<TextBlock x:Name="SignalStrengthTextBlock" Grid.Column="1" Foreground="White" HorizontalAlignment="Left" Margin="10,0,5,0" VerticalAlignment="Center" />
|
||||
<TextBlock x:Name="NetworkNameTextBlock" Grid.Column="2" FontWeight="Bold" HorizontalAlignment="Left" Margin="5,0,10,0" VerticalAlignment="Center" />
|
||||
</Grid>
|
||||
</Button>
|
||||
</Grid>
|
||||
</UserControl>
|
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using SafeExamBrowser.SystemComponents.Contracts.Network;
|
||||
|
||||
namespace SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenter
|
||||
{
|
||||
internal partial class NetworkButton : UserControl
|
||||
{
|
||||
private readonly IWirelessNetwork network;
|
||||
|
||||
internal event EventHandler NetworkSelected;
|
||||
|
||||
internal NetworkButton(IWirelessNetwork network)
|
||||
{
|
||||
this.network = network;
|
||||
|
||||
InitializeComponent();
|
||||
InitializeNetworkButton();
|
||||
}
|
||||
|
||||
private void InitializeNetworkButton()
|
||||
{
|
||||
Button.Click += (o, args) => NetworkSelected?.Invoke(this, EventArgs.Empty);
|
||||
IsCurrentTextBlock.Visibility = network.Status == ConnectionStatus.Connected ? Visibility.Visible : Visibility.Hidden;
|
||||
NetworkNameTextBlock.Text = network.Name;
|
||||
SignalStrengthTextBlock.Text = $"{network.SignalStrength}%";
|
||||
}
|
||||
|
||||
public void SetFocus()
|
||||
{
|
||||
Button.Focus();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,43 @@
|
||||
<UserControl x:Class="SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenter.NetworkControl" x:ClassModifier="internal"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:fa="http://schemas.fontawesome.io/icons/"
|
||||
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop.Controls"
|
||||
mc:Ignorable="d" d:DesignHeight="100" d:DesignWidth="125">
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="../../Templates/Buttons.xaml" />
|
||||
<ResourceDictionary Source="../../Templates/Colors.xaml" />
|
||||
<ResourceDictionary Source="../../Templates/ScrollViewers.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
<Grid x:Name="Grid" Background="{StaticResource ActionCenterDarkBrush}" Height="64" Margin="2">
|
||||
<Popup x:Name="Popup" IsOpen="False" Placement="Top" PlacementTarget="{Binding ElementName=Button}">
|
||||
<Border Background="Gray">
|
||||
<ScrollViewer MaxHeight="250" VerticalScrollBarVisibility="Auto" Template="{StaticResource SmallBarScrollViewer}">
|
||||
<StackPanel x:Name="WirelessNetworksStackPanel" />
|
||||
</ScrollViewer>
|
||||
</Border>
|
||||
</Popup>
|
||||
<Button x:Name="Button" Padding="2" Template="{StaticResource ActionCenterButton}" ToolTipService.ShowOnDisabled="True">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="2*" />
|
||||
<RowDefinition Height="3*" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid Grid.Row="0" HorizontalAlignment="Center" VerticalAlignment="Center">
|
||||
<Viewbox x:Name="WirelessIcon" Stretch="Uniform" Width="Auto" Visibility="Collapsed" />
|
||||
<fa:ImageAwesome x:Name="WiredIcon" Icon="Tv" Margin="0,2,4,4" Visibility="Collapsed" />
|
||||
<Border Background="White" CornerRadius="6" Height="12" HorizontalAlignment="Right" Margin="-3,0" Panel.ZIndex="10" VerticalAlignment="Bottom">
|
||||
<fa:ImageAwesome x:Name="NetworkStatusIcon" />
|
||||
</Border>
|
||||
</Grid>
|
||||
<TextBlock Grid.Row="1" x:Name="Text" FontSize="11" Foreground="White" TextAlignment="Center" TextTrimming="CharacterEllipsis" TextWrapping="Wrap" VerticalAlignment="Bottom" />
|
||||
</Grid>
|
||||
</Button>
|
||||
</Grid>
|
||||
</UserControl>
|
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using FontAwesome.WPF;
|
||||
using SafeExamBrowser.Core.Contracts.Resources.Icons;
|
||||
using SafeExamBrowser.I18n.Contracts;
|
||||
using SafeExamBrowser.SystemComponents.Contracts.Network;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Shell;
|
||||
using SafeExamBrowser.UserInterface.Shared.Utilities;
|
||||
|
||||
namespace SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenter
|
||||
{
|
||||
internal partial class NetworkControl : UserControl, ISystemControl
|
||||
{
|
||||
private readonly INetworkAdapter adapter;
|
||||
private readonly IText text;
|
||||
|
||||
internal NetworkControl(INetworkAdapter adapter, IText text)
|
||||
{
|
||||
this.adapter = adapter;
|
||||
this.text = text;
|
||||
|
||||
InitializeComponent();
|
||||
InitializeWirelessNetworkControl();
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
Dispatcher.InvokeAsync(() => Popup.IsOpen = false);
|
||||
}
|
||||
|
||||
private void InitializeWirelessNetworkControl()
|
||||
{
|
||||
var lastOpenedBySpacePress = false;
|
||||
var originalBrush = Grid.Background;
|
||||
|
||||
adapter.Changed += () => Dispatcher.InvokeAsync(Update);
|
||||
Button.Click += (o, args) => Popup.IsOpen = !Popup.IsOpen;
|
||||
Button.PreviewKeyDown += (o, args) =>
|
||||
{
|
||||
// For some reason, the popup immediately closes again if opened by a Space Bar key event - as a mitigation,
|
||||
// we record the space bar event and leave the popup open for at least 3 seconds.
|
||||
if (args.Key == System.Windows.Input.Key.Space)
|
||||
{
|
||||
lastOpenedBySpacePress = true;
|
||||
}
|
||||
};
|
||||
Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() =>
|
||||
{
|
||||
if (Popup.IsOpen && lastOpenedBySpacePress)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Popup.IsOpen = Popup.IsMouseOver;
|
||||
}));
|
||||
Popup.Closed += (o, args) =>
|
||||
{
|
||||
adapter.StopWirelessNetworkScanning();
|
||||
Grid.Background = originalBrush;
|
||||
lastOpenedBySpacePress = false;
|
||||
};
|
||||
Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() =>
|
||||
{
|
||||
if (Popup.IsOpen && lastOpenedBySpacePress)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Popup.IsOpen = IsMouseOver;
|
||||
}));
|
||||
Popup.Opened += (o, args) =>
|
||||
{
|
||||
adapter.StartWirelessNetworkScanning();
|
||||
Grid.Background = Brushes.Gray;
|
||||
Task.Delay(100).ContinueWith((task) => Dispatcher.Invoke(() =>
|
||||
{
|
||||
if (WirelessNetworksStackPanel.Children.Count > 0)
|
||||
{
|
||||
(WirelessNetworksStackPanel.Children[0] as NetworkButton)?.SetFocus();
|
||||
}
|
||||
}));
|
||||
};
|
||||
WirelessIcon.Child = GetWirelessIcon(0);
|
||||
|
||||
Update();
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
switch (adapter.Type)
|
||||
{
|
||||
case ConnectionType.Wired:
|
||||
Button.IsEnabled = false;
|
||||
UpdateText(text.Get(TextKey.SystemControl_NetworkWiredConnected));
|
||||
WiredIcon.Visibility = Visibility.Visible;
|
||||
WirelessIcon.Visibility = Visibility.Collapsed;
|
||||
break;
|
||||
case ConnectionType.Wireless:
|
||||
Button.IsEnabled = true;
|
||||
WiredIcon.Visibility = Visibility.Collapsed;
|
||||
WirelessIcon.Visibility = Visibility.Visible;
|
||||
break;
|
||||
default:
|
||||
Button.IsEnabled = false;
|
||||
UpdateText(text.Get(TextKey.SystemControl_NetworkNotAvailable));
|
||||
WiredIcon.Visibility = Visibility.Visible;
|
||||
WirelessIcon.Visibility = Visibility.Collapsed;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (adapter.Status)
|
||||
{
|
||||
case ConnectionStatus.Connected:
|
||||
UpdateText(text.Get(TextKey.SystemControl_NetworkWiredConnected));
|
||||
NetworkStatusIcon.Rotation = 0;
|
||||
NetworkStatusIcon.Source = ImageAwesome.CreateImageSource(FontAwesomeIcon.Globe, Brushes.Green);
|
||||
NetworkStatusIcon.Spin = false;
|
||||
break;
|
||||
case ConnectionStatus.Connecting:
|
||||
UpdateText(text.Get(TextKey.SystemControl_NetworkWirelessConnecting));
|
||||
NetworkStatusIcon.Rotation = 0;
|
||||
NetworkStatusIcon.Source = ImageAwesome.CreateImageSource(FontAwesomeIcon.Cog, Brushes.DimGray);
|
||||
NetworkStatusIcon.Spin = true;
|
||||
NetworkStatusIcon.SpinDuration = 2;
|
||||
break;
|
||||
default:
|
||||
UpdateText(text.Get(TextKey.SystemControl_NetworkDisconnected));
|
||||
NetworkStatusIcon.Source = ImageAwesome.CreateImageSource(FontAwesomeIcon.Ban, Brushes.DarkOrange);
|
||||
NetworkStatusIcon.Spin = false;
|
||||
WirelessIcon.Child = GetWirelessIcon(0);
|
||||
break;
|
||||
}
|
||||
|
||||
WirelessNetworksStackPanel.Children.Clear();
|
||||
|
||||
foreach (var network in adapter.GetWirelessNetworks())
|
||||
{
|
||||
var button = new NetworkButton(network);
|
||||
|
||||
button.NetworkSelected += (o, args) => adapter.ConnectToWirelessNetwork(network.Name);
|
||||
|
||||
if (network.Status == ConnectionStatus.Connected)
|
||||
{
|
||||
WirelessIcon.Child = GetWirelessIcon(network.SignalStrength);
|
||||
UpdateText(text.Get(TextKey.SystemControl_NetworkWirelessConnected).Replace("%%NAME%%", network.Name));
|
||||
}
|
||||
|
||||
WirelessNetworksStackPanel.Children.Add(button);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateText(string text)
|
||||
{
|
||||
Button.ToolTip = text;
|
||||
Text.Text = text;
|
||||
Button.SetValue(System.Windows.Automation.AutomationProperties.NameProperty, text);
|
||||
}
|
||||
|
||||
private UIElement GetWirelessIcon(int signalStrength)
|
||||
{
|
||||
var icon = signalStrength > 66 ? "100" : (signalStrength > 33 ? "66" : (signalStrength > 0 ? "33" : "0"));
|
||||
var uri = new Uri($"pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/WiFi_Light_{icon}.xaml");
|
||||
var resource = new XamlIconResource { Uri = uri };
|
||||
|
||||
return IconResourceLoader.Load(resource);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,28 @@
|
||||
<UserControl x:Class="SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenter.NotificationButton" x:ClassModifier="internal"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop.Controls"
|
||||
mc:Ignorable="d" d:DesignHeight="100" d:DesignWidth="125">
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="../../Templates/Buttons.xaml" />
|
||||
<ResourceDictionary Source="../../Templates/Colors.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
<Grid Background="{StaticResource ActionCenterDarkBrush}" Height="64" Margin="2">
|
||||
<Button x:Name="IconButton" Click="IconButton_Click" Padding="2" Template="{StaticResource ActionCenterButton}" ToolTipService.ShowOnDisabled="True">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="2*" />
|
||||
<RowDefinition Height="3*" />
|
||||
</Grid.RowDefinitions>
|
||||
<ContentControl Grid.Row="0" x:Name="Icon" VerticalAlignment="Center" />
|
||||
<TextBlock Grid.Row="1" x:Name="Text" FontSize="11" Foreground="White" TextAlignment="Center" TextTrimming="CharacterEllipsis" TextWrapping="Wrap" VerticalAlignment="Bottom" />
|
||||
</Grid>
|
||||
</Button>
|
||||
</Grid>
|
||||
</UserControl>
|
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using SafeExamBrowser.Core.Contracts.Notifications;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Shell;
|
||||
using SafeExamBrowser.UserInterface.Shared.Utilities;
|
||||
|
||||
namespace SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenter
|
||||
{
|
||||
internal partial class NotificationButton : UserControl, INotificationControl
|
||||
{
|
||||
private readonly INotification notification;
|
||||
|
||||
internal NotificationButton(INotification notification)
|
||||
{
|
||||
this.notification = notification;
|
||||
|
||||
InitializeComponent();
|
||||
InitializeNotification();
|
||||
UpdateNotification();
|
||||
}
|
||||
|
||||
private void IconButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (notification.CanActivate)
|
||||
{
|
||||
notification.Activate();
|
||||
}
|
||||
}
|
||||
|
||||
private void InitializeNotification()
|
||||
{
|
||||
notification.NotificationChanged += () => Dispatcher.Invoke(UpdateNotification);
|
||||
}
|
||||
|
||||
private void UpdateNotification()
|
||||
{
|
||||
Icon.Content = IconResourceLoader.Load(notification.IconResource);
|
||||
IconButton.IsEnabled = notification.CanActivate;
|
||||
IconButton.ToolTip = notification.Tooltip;
|
||||
Text.Text = notification.Tooltip;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,51 @@
|
||||
<UserControl x:Class="SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenter.PowerSupplyControl" x:ClassModifier="internal"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop.Controls"
|
||||
mc:Ignorable="d" d:DesignHeight="100" d:DesignWidth="125">
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="../../Templates/Buttons.xaml" />
|
||||
<ResourceDictionary Source="../../Templates/Colors.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
<Grid Background="{StaticResource ActionCenterDarkBrush}" Height="64" Margin="2">
|
||||
<Button x:Name="Button" IsEnabled="False" Padding="2" ToolTipService.ShowOnDisabled="True" Template="{StaticResource ActionCenterButton}">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="2*" />
|
||||
<RowDefinition Height="3*" />
|
||||
</Grid.RowDefinitions>
|
||||
<Viewbox Grid.Row="0" Stretch="Uniform" Width="Auto">
|
||||
<Canvas Height="40" Width="40">
|
||||
<Viewbox Stretch="Uniform" Width="40" Panel.ZIndex="2">
|
||||
<Canvas Width="1024.000" Height="1024.000">
|
||||
<Canvas.LayoutTransform>
|
||||
<RotateTransform Angle="180" />
|
||||
</Canvas.LayoutTransform>
|
||||
<Canvas>
|
||||
<Path Data=" M 0.000,0.000 L 1024.000,0.000 L 1024.000,1024.000 L 0.000,1024.000 L 0.000,0.000 Z"/>
|
||||
<Path StrokeThickness="35.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 112.000,300.000 L 951.000,300.000 C 970.330,300.000 986.000,315.670 986.000,335.000 L 986.000,689.000 C 986.000,708.330 970.330,724.000 951.000,724.000 L 112.000,724.000 C 92.670,724.000 77.000,708.330 77.000,689.000 L 77.000,335.000 C 77.000,315.670 92.670,300.000 112.000,300.000 Z"/>
|
||||
<Path StrokeThickness="1.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Fill="#ff000000" Data=" M 25.000,462.500 L 50.000,462.500 C 52.760,462.500 55.000,464.740 55.000,467.500 L 55.000,557.500 C 55.000,560.260 52.760,562.500 50.000,562.500 L 25.000,562.500 C 22.240,562.500 20.000,560.260 20.000,557.500 L 20.000,467.500 C 20.000,464.740 22.240,462.500 25.000,462.500 Z"/>
|
||||
</Canvas>
|
||||
</Canvas>
|
||||
</Viewbox>
|
||||
<Rectangle x:Name="BatteryCharge" Canvas.Left="2" Canvas.Top="12" Fill="Green" Height="16" Width="35" Panel.ZIndex="1" />
|
||||
<Canvas x:Name="PowerPlug" Panel.ZIndex="3" Canvas.Left="4" Canvas.Top="-3">
|
||||
<Canvas.LayoutTransform>
|
||||
<ScaleTransform ScaleX="2" ScaleY="2" />
|
||||
</Canvas.LayoutTransform>
|
||||
<Path Stroke="Black" StrokeStartLineCap="Round" Fill="Black" Data="M2.5,17.5 V10 Q5,10 5,6 H4 V4 H4 V6 H1 V4 H1 V6 H0 Q0,10 2.5,10" />
|
||||
</Canvas>
|
||||
<TextBlock x:Name="Warning" FontSize="36" FontWeight="ExtraBold" Foreground="Red" Canvas.Left="13" Canvas.Top="-7" Panel.ZIndex="3">!</TextBlock>
|
||||
</Canvas>
|
||||
</Viewbox>
|
||||
<TextBlock Grid.Row="1" x:Name="Text" FontSize="11" Foreground="White" TextAlignment="Center" TextTrimming="CharacterEllipsis" TextWrapping="Wrap" VerticalAlignment="Bottom" />
|
||||
</Grid>
|
||||
</Button>
|
||||
</Grid>
|
||||
</UserControl>
|
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using SafeExamBrowser.I18n.Contracts;
|
||||
using SafeExamBrowser.SystemComponents.Contracts.PowerSupply;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Shell;
|
||||
|
||||
namespace SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenter
|
||||
{
|
||||
internal partial class PowerSupplyControl : UserControl, ISystemControl
|
||||
{
|
||||
private Brush initialBrush;
|
||||
private bool infoShown, warningShown;
|
||||
private double maxWidth;
|
||||
private IPowerSupply powerSupply;
|
||||
private IText text;
|
||||
|
||||
internal PowerSupplyControl(IPowerSupply powerSupply, IText text)
|
||||
{
|
||||
this.powerSupply = powerSupply;
|
||||
this.text = text;
|
||||
|
||||
InitializeComponent();
|
||||
InitializePowerSupplyControl();
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
}
|
||||
|
||||
public void SetInformation(string text)
|
||||
{
|
||||
Dispatcher.InvokeAsync(() => Text.Text = text);
|
||||
}
|
||||
|
||||
private void InitializePowerSupplyControl()
|
||||
{
|
||||
initialBrush = BatteryCharge.Fill;
|
||||
maxWidth = BatteryCharge.Width;
|
||||
powerSupply.StatusChanged += PowerSupply_StatusChanged;
|
||||
UpdateStatus(powerSupply.GetStatus());
|
||||
}
|
||||
|
||||
private void PowerSupply_StatusChanged(IPowerSupplyStatus status)
|
||||
{
|
||||
Dispatcher.InvokeAsync(() => UpdateStatus(status));
|
||||
}
|
||||
|
||||
private void UpdateStatus(IPowerSupplyStatus status)
|
||||
{
|
||||
var percentage = Math.Round(status.BatteryCharge * 100);
|
||||
var tooltip = string.Empty;
|
||||
|
||||
RenderCharge(status.BatteryCharge, status.BatteryChargeStatus);
|
||||
|
||||
if (status.IsOnline)
|
||||
{
|
||||
infoShown = false;
|
||||
warningShown = false;
|
||||
tooltip = text.Get(percentage == 100 ? TextKey.SystemControl_BatteryCharged : TextKey.SystemControl_BatteryCharging);
|
||||
tooltip = tooltip.Replace("%%CHARGE%%", percentage.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
tooltip = text.Get(TextKey.SystemControl_BatteryRemainingCharge);
|
||||
tooltip = tooltip.Replace("%%CHARGE%%", percentage.ToString());
|
||||
tooltip = tooltip.Replace("%%HOURS%%", status.BatteryTimeRemaining.Hours.ToString());
|
||||
tooltip = tooltip.Replace("%%MINUTES%%", status.BatteryTimeRemaining.Minutes.ToString());
|
||||
|
||||
HandleBatteryStatus(status.BatteryChargeStatus);
|
||||
}
|
||||
|
||||
if (!infoShown && !warningShown)
|
||||
{
|
||||
Button.ToolTip = tooltip;
|
||||
}
|
||||
|
||||
PowerPlug.Visibility = status.IsOnline ? Visibility.Visible : Visibility.Collapsed;
|
||||
Text.Text = tooltip;
|
||||
Warning.Visibility = status.BatteryChargeStatus == BatteryChargeStatus.Critical ? Visibility.Visible : Visibility.Collapsed;
|
||||
this.SetValue(System.Windows.Automation.AutomationProperties.NameProperty, tooltip);
|
||||
}
|
||||
|
||||
private void RenderCharge(double charge, BatteryChargeStatus status)
|
||||
{
|
||||
var width = maxWidth * charge;
|
||||
|
||||
BatteryCharge.Width = width > maxWidth ? maxWidth : (width < 0 ? 0 : width);
|
||||
|
||||
switch (status)
|
||||
{
|
||||
case BatteryChargeStatus.Critical:
|
||||
BatteryCharge.Fill = Brushes.Red;
|
||||
break;
|
||||
case BatteryChargeStatus.Low:
|
||||
BatteryCharge.Fill = Brushes.Orange;
|
||||
break;
|
||||
default:
|
||||
BatteryCharge.Fill = initialBrush;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleBatteryStatus(BatteryChargeStatus chargeStatus)
|
||||
{
|
||||
if (chargeStatus == BatteryChargeStatus.Low && !infoShown)
|
||||
{
|
||||
Button.ToolTip = text.Get(TextKey.SystemControl_BatteryChargeLowInfo);
|
||||
infoShown = true;
|
||||
}
|
||||
|
||||
if (chargeStatus == BatteryChargeStatus.Critical && !warningShown)
|
||||
{
|
||||
Button.ToolTip = text.Get(TextKey.SystemControl_BatteryChargeCriticalWarning);
|
||||
warningShown = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,28 @@
|
||||
<UserControl x:Class="SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenter.QuitButton" x:ClassModifier="internal"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop.Controls"
|
||||
mc:Ignorable="d" d:DesignHeight="100" d:DesignWidth="125">
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="../../Templates/Buttons.xaml" />
|
||||
<ResourceDictionary Source="../../Templates/Colors.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
<Grid Background="{StaticResource ActionCenterDarkBrush}" Height="64" Margin="2">
|
||||
<Button x:Name="Button" Padding="2" Template="{StaticResource ActionCenterButton}">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="2*" />
|
||||
<RowDefinition Height="3*" />
|
||||
</Grid.RowDefinitions>
|
||||
<ContentControl Grid.Row="0" x:Name="Icon" Foreground="Black" VerticalAlignment="Center" />
|
||||
<TextBlock Grid.Row="1" x:Name="Text" FontSize="11" Foreground="White" TextAlignment="Center" TextTrimming="CharacterEllipsis" TextWrapping="Wrap" VerticalAlignment="Bottom" />
|
||||
</Grid>
|
||||
</Button>
|
||||
</Grid>
|
||||
</UserControl>
|
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Windows.Controls;
|
||||
using SafeExamBrowser.Core.Contracts.Resources.Icons;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Shell.Events;
|
||||
using SafeExamBrowser.UserInterface.Shared.Utilities;
|
||||
|
||||
namespace SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenter
|
||||
{
|
||||
internal partial class QuitButton : UserControl
|
||||
{
|
||||
internal event QuitButtonClickedEventHandler Clicked;
|
||||
|
||||
public QuitButton()
|
||||
{
|
||||
InitializeComponent();
|
||||
InitializeControl();
|
||||
}
|
||||
|
||||
private void InitializeControl()
|
||||
{
|
||||
var uri = new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/ShutDown.xaml");
|
||||
var resource = new XamlIconResource { Uri = uri };
|
||||
|
||||
Icon.Content = IconResourceLoader.Load(resource);
|
||||
Button.Click += (o, args) => Clicked?.Invoke(new CancelEventArgs());
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,42 @@
|
||||
<UserControl x:Class="SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenter.RaiseHandControl"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
mc:Ignorable="d" d:DesignHeight="100" d:DesignWidth="125">
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="../../Templates/Buttons.xaml" />
|
||||
<ResourceDictionary Source="../../Templates/Colors.xaml" />
|
||||
<ResourceDictionary Source="../../Templates/ScrollViewers.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
<Grid Name="Grid" Background="{StaticResource ActionCenterDarkBrush}" Height="64" Margin="2">
|
||||
<Popup x:Name="Popup" IsOpen="False" Placement="Custom" PlacementTarget="{Binding ElementName=Button}">
|
||||
<Border Background="Gray" BorderThickness="0" >
|
||||
<StackPanel>
|
||||
<TextBox Name="Message" AcceptsReturn="True" Height="150" IsReadOnly="False" Margin="5,5,5,0" Width="350" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" />
|
||||
<Grid>
|
||||
<Button Name="HandButton" Background="Transparent" Height="30" Margin="5" Padding="5" Template="{StaticResource TaskbarButton}" Width="150">
|
||||
<Viewbox Stretch="Uniform">
|
||||
<TextBlock x:Name="HandButtonText" FontWeight="Bold" TextAlignment="Center" />
|
||||
</Viewbox>
|
||||
</Button>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Popup>
|
||||
<Button x:Name="NotificationButton" Padding="2" Template="{StaticResource ActionCenterButton}">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="2*" />
|
||||
<RowDefinition Height="3*" />
|
||||
</Grid.RowDefinitions>
|
||||
<ContentControl x:Name="Icon" />
|
||||
<TextBlock Grid.Row="1" x:Name="Text" FontSize="11" Foreground="White" TextAlignment="Center" TextTrimming="CharacterEllipsis" TextWrapping="Wrap" VerticalAlignment="Bottom" />
|
||||
</Grid>
|
||||
</Button>
|
||||
</Grid>
|
||||
</UserControl>
|
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using SafeExamBrowser.Core.Contracts.Resources.Icons;
|
||||
using SafeExamBrowser.I18n.Contracts;
|
||||
using SafeExamBrowser.Proctoring.Contracts;
|
||||
using SafeExamBrowser.Settings.Proctoring;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Shell;
|
||||
using SafeExamBrowser.UserInterface.Shared.Utilities;
|
||||
|
||||
namespace SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenter
|
||||
{
|
||||
public partial class RaiseHandControl : UserControl, INotificationControl
|
||||
{
|
||||
private readonly IProctoringController controller;
|
||||
private readonly ProctoringSettings settings;
|
||||
private readonly IText text;
|
||||
|
||||
private IconResource LoweredIcon;
|
||||
private IconResource RaisedIcon;
|
||||
|
||||
public RaiseHandControl(IProctoringController controller, ProctoringSettings settings, IText text)
|
||||
{
|
||||
this.controller = controller;
|
||||
this.settings = settings;
|
||||
this.text = text;
|
||||
|
||||
InitializeComponent();
|
||||
InitializeRaiseHandControl();
|
||||
}
|
||||
|
||||
private void InitializeRaiseHandControl()
|
||||
{
|
||||
var originalBrush = Grid.Background;
|
||||
|
||||
controller.HandLowered += () => Dispatcher.Invoke(ShowLowered);
|
||||
controller.HandRaised += () => Dispatcher.Invoke(ShowRaised);
|
||||
|
||||
HandButton.Click += RaiseHandButton_Click;
|
||||
HandButtonText.Text = text.Get(TextKey.Notification_ProctoringRaiseHand);
|
||||
|
||||
LoweredIcon = new XamlIconResource { Uri = new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/Hand_Lowered.xaml") };
|
||||
RaisedIcon = new XamlIconResource { Uri = new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/Hand_Raised.xaml") };
|
||||
Icon.Content = IconResourceLoader.Load(LoweredIcon);
|
||||
|
||||
var lastOpenedBySpacePress = false;
|
||||
NotificationButton.PreviewKeyDown += (o, args) =>
|
||||
{
|
||||
if (args.Key == System.Windows.Input.Key.Space) // for some reason, the popup immediately closes again if opened by a Space Bar key event - as a mitigation, we record the space bar event and leave the popup open for at least 3 seconds
|
||||
{
|
||||
lastOpenedBySpacePress = true;
|
||||
}
|
||||
};
|
||||
NotificationButton.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() =>
|
||||
{
|
||||
if (Popup.IsOpen && lastOpenedBySpacePress)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Popup.IsOpen = Popup.IsMouseOver;
|
||||
}));
|
||||
NotificationButton.PreviewMouseLeftButtonUp += NotificationButton_PreviewMouseLeftButtonUp;
|
||||
NotificationButton.PreviewMouseRightButtonUp += NotificationButton_PreviewMouseRightButtonUp;
|
||||
NotificationButton.ToolTip = text.Get(TextKey.Notification_ProctoringHandLowered);
|
||||
|
||||
Popup.CustomPopupPlacementCallback = new CustomPopupPlacementCallback(Popup_PlacementCallback);
|
||||
Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() =>
|
||||
{
|
||||
if (Popup.IsOpen && lastOpenedBySpacePress)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Popup.IsOpen = IsMouseOver;
|
||||
}));
|
||||
Popup.Opened += (o, args) => Grid.Background = Brushes.Gray;
|
||||
Popup.Closed += (o, args) =>
|
||||
{
|
||||
Grid.Background = originalBrush;
|
||||
lastOpenedBySpacePress = false;
|
||||
};
|
||||
|
||||
Text.Text = text.Get(TextKey.Notification_ProctoringHandLowered);
|
||||
}
|
||||
|
||||
private void NotificationButton_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (settings.ForceRaiseHandMessage || Popup.IsOpen)
|
||||
{
|
||||
Popup.IsOpen = !Popup.IsOpen;
|
||||
}
|
||||
else
|
||||
{
|
||||
ToggleHand();
|
||||
}
|
||||
}
|
||||
|
||||
private void NotificationButton_PreviewMouseRightButtonUp(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
Popup.IsOpen = !Popup.IsOpen;
|
||||
}
|
||||
|
||||
private CustomPopupPlacement[] Popup_PlacementCallback(Size popupSize, Size targetSize, Point offset)
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
new CustomPopupPlacement(new Point(targetSize.Width / 2 - popupSize.Width / 2, -popupSize.Height), PopupPrimaryAxis.None)
|
||||
};
|
||||
}
|
||||
|
||||
private void RaiseHandButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
ToggleHand();
|
||||
}
|
||||
|
||||
private void ToggleHand()
|
||||
{
|
||||
if (controller.IsHandRaised)
|
||||
{
|
||||
controller.LowerHand();
|
||||
}
|
||||
else
|
||||
{
|
||||
controller.RaiseHand(Message.Text);
|
||||
Message.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
private void ShowLowered()
|
||||
{
|
||||
HandButtonText.Text = text.Get(TextKey.Notification_ProctoringRaiseHand);
|
||||
Icon.Content = IconResourceLoader.Load(LoweredIcon);
|
||||
Message.IsEnabled = true;
|
||||
NotificationButton.ToolTip = text.Get(TextKey.Notification_ProctoringHandLowered);
|
||||
Popup.IsOpen = false;
|
||||
Text.Text = text.Get(TextKey.Notification_ProctoringHandLowered);
|
||||
}
|
||||
|
||||
private void ShowRaised()
|
||||
{
|
||||
HandButtonText.Text = text.Get(TextKey.Notification_ProctoringLowerHand);
|
||||
Icon.Content = IconResourceLoader.Load(RaisedIcon);
|
||||
Message.IsEnabled = false;
|
||||
NotificationButton.ToolTip = text.Get(TextKey.Notification_ProctoringHandRaised);
|
||||
Text.Text = text.Get(TextKey.Notification_ProctoringHandRaised);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,22 @@
|
||||
<UserControl x:Class="SafeExamBrowser.UserInterface.Desktop.Controls.Browser.DownloadItemControl" x:ClassModifier="internal"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop.Controls.Browser"
|
||||
mc:Ignorable="d" d:DesignHeight="50" d:DesignWidth="200">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<ContentControl Grid.Row="0" Grid.RowSpan="2" Grid.Column="0" Panel.ZIndex="2" Name="Icon" Margin="10" Width="25" />
|
||||
<ProgressBar Grid.Row="0" Grid.RowSpan="2" Grid.Column="0" Grid.ColumnSpan="2" Panel.ZIndex="1" Name="Progress" BorderThickness="0" />
|
||||
<TextBlock Grid.Row="0" Grid.Column="1" Panel.ZIndex="2" Name="ItemName" FontWeight="Bold" Margin="0,10,10,0" />
|
||||
<TextBlock Grid.Row="1" Grid.Column="1" Panel.ZIndex="2" Name="Status" FontStyle="Italic" Margin="0,0,10,10" />
|
||||
</Grid>
|
||||
</UserControl>
|
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Windows.Controls;
|
||||
using SafeExamBrowser.I18n.Contracts;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Browser.Data;
|
||||
using SafeExamBrowser.UserInterface.Shared.Utilities;
|
||||
|
||||
namespace SafeExamBrowser.UserInterface.Desktop.Controls.Browser
|
||||
{
|
||||
internal partial class DownloadItemControl : UserControl
|
||||
{
|
||||
private IText text;
|
||||
|
||||
internal Guid Id { get; }
|
||||
|
||||
internal DownloadItemControl(Guid id, IText text)
|
||||
{
|
||||
this.Id = id;
|
||||
this.text = text;
|
||||
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
internal void Update(DownloadItemState state)
|
||||
{
|
||||
ItemName.Text = Uri.TryCreate(state.Url, UriKind.Absolute, out var uri) ? Path.GetFileName(uri.AbsolutePath) : state.Url;
|
||||
Progress.Value = state.Completion * 100;
|
||||
Status.Text = $"{text.Get(TextKey.BrowserWindow_Downloading)} ({state.Completion * 100}%)";
|
||||
|
||||
if (File.Exists(state.FullPath))
|
||||
{
|
||||
ItemName.Text = Path.GetFileName(state.FullPath);
|
||||
Icon.Content = new Image { Source = IconLoader.LoadIconFor(new FileInfo(state.FullPath)) };
|
||||
}
|
||||
|
||||
if (state.IsCancelled)
|
||||
{
|
||||
Progress.Visibility = System.Windows.Visibility.Collapsed;
|
||||
Status.Text = text.Get(TextKey.BrowserWindow_DownloadCancelled);
|
||||
}
|
||||
else if (state.IsComplete)
|
||||
{
|
||||
Progress.Visibility = System.Windows.Visibility.Collapsed;
|
||||
Status.Text = text.Get(TextKey.BrowserWindow_DownloadComplete);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,31 @@
|
||||
<UserControl x:Class="SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar.ApplicationControl" x:ClassModifier="internal"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop.Controls"
|
||||
xmlns:s="clr-namespace:System;assembly=mscorlib"
|
||||
mc:Ignorable="d" d:DesignHeight="40" d:DesignWidth="50">
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="../../Templates/Buttons.xaml" />
|
||||
<ResourceDictionary Source="../../Templates/Colors.xaml" />
|
||||
<ResourceDictionary Source="../../Templates/ScrollViewers.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
<Grid>
|
||||
<Popup x:Name="WindowPopup" IsOpen="False" Placement="Custom" PlacementTarget="{Binding ElementName=Button}">
|
||||
<Border Background="LightGray" BorderBrush="Gray" BorderThickness="1,1,1,0">
|
||||
<ScrollViewer MaxHeight="400" VerticalScrollBarVisibility="Auto" Template="{StaticResource SmallBarScrollViewer}">
|
||||
<StackPanel x:Name="WindowStackPanel" />
|
||||
</ScrollViewer>
|
||||
</Border>
|
||||
</Popup>
|
||||
<Button x:Name="Button" Background="{StaticResource BackgroundBrush}" Padding="4" Template="{StaticResource TaskbarButton}" Width="50" />
|
||||
<Grid>
|
||||
<Rectangle x:Name="ActiveBar" Cursor="Hand" Height="2.5" Width="40" VerticalAlignment="Bottom" Fill="DodgerBlue" Visibility="Collapsed" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</UserControl>
|
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Automation;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Threading;
|
||||
using SafeExamBrowser.Applications.Contracts;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Shell;
|
||||
using SafeExamBrowser.UserInterface.Shared.Utilities;
|
||||
|
||||
namespace SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar
|
||||
{
|
||||
internal partial class ApplicationControl : UserControl, IApplicationControl
|
||||
{
|
||||
private readonly IApplication<IApplicationWindow> application;
|
||||
private IApplicationWindow single;
|
||||
|
||||
internal ApplicationControl(IApplication<IApplicationWindow> application)
|
||||
{
|
||||
this.application = application;
|
||||
|
||||
InitializeComponent();
|
||||
InitializeApplicationControl();
|
||||
}
|
||||
|
||||
private void InitializeApplicationControl()
|
||||
{
|
||||
var originalBrush = Button.Background;
|
||||
|
||||
application.WindowsChanged += Application_WindowsChanged;
|
||||
|
||||
ActiveBar.MouseLeave += (o, args) => WindowPopup.IsOpen &= WindowPopup.IsMouseOver || Button.IsMouseOver;
|
||||
Button.Click += Button_Click;
|
||||
Button.Content = IconResourceLoader.Load(application.Icon);
|
||||
Button.MouseEnter += (o, args) => WindowPopup.IsOpen = WindowStackPanel.Children.Count > 0;
|
||||
Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => WindowPopup.IsOpen = WindowPopup.IsMouseOver || ActiveBar.IsMouseOver));
|
||||
Button.ToolTip = application.Tooltip;
|
||||
WindowPopup.CustomPopupPlacementCallback = new CustomPopupPlacementCallback(WindowPopup_PlacementCallback);
|
||||
WindowPopup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => WindowPopup.IsOpen = IsMouseOver));
|
||||
|
||||
if (application.Tooltip != default)
|
||||
{
|
||||
AutomationProperties.SetName(Button, application.Tooltip);
|
||||
}
|
||||
|
||||
WindowPopup.Opened += (o, args) =>
|
||||
{
|
||||
ActiveBar.Width = double.NaN;
|
||||
Background = Brushes.LightGray;
|
||||
Button.Background = Brushes.LightGray;
|
||||
};
|
||||
|
||||
WindowPopup.Closed += (o, args) =>
|
||||
{
|
||||
ActiveBar.Width = 40;
|
||||
Background = originalBrush;
|
||||
Button.Background = originalBrush;
|
||||
};
|
||||
}
|
||||
|
||||
private void Application_WindowsChanged()
|
||||
{
|
||||
Dispatcher.InvokeAsync(Update);
|
||||
}
|
||||
|
||||
private void Button_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (WindowStackPanel.Children.Count == 0)
|
||||
{
|
||||
application.Start();
|
||||
}
|
||||
else if (WindowStackPanel.Children.Count == 1)
|
||||
{
|
||||
single?.Activate();
|
||||
}
|
||||
}
|
||||
|
||||
private CustomPopupPlacement[] WindowPopup_PlacementCallback(Size popupSize, Size targetSize, Point offset)
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
new CustomPopupPlacement(new Point(targetSize.Width / 2 - popupSize.Width / 2, -popupSize.Height), PopupPrimaryAxis.None)
|
||||
};
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
var windows = application.GetWindows();
|
||||
|
||||
ActiveBar.Visibility = windows.Any() ? Visibility.Visible : Visibility.Collapsed;
|
||||
WindowStackPanel.Children.Clear();
|
||||
|
||||
foreach (var window in windows)
|
||||
{
|
||||
WindowStackPanel.Children.Add(new ApplicationWindowButton(window));
|
||||
}
|
||||
|
||||
if (WindowStackPanel.Children.Count == 1)
|
||||
{
|
||||
single = windows.First();
|
||||
}
|
||||
else
|
||||
{
|
||||
single = default;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,24 @@
|
||||
<UserControl x:Class="SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar.ApplicationWindowButton" x:ClassModifier="internal"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop.Controls"
|
||||
mc:Ignorable="d" d:DesignWidth="250">
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="../../Templates/Buttons.xaml" />
|
||||
<ResourceDictionary Source="../../Templates/Colors.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
<Grid>
|
||||
<Button x:Name="Button" Background="Transparent" Height="40" Padding="10" Template="{StaticResource TaskbarButton}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<ContentControl x:Name="Icon" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="0,0,10,0" Width="20" />
|
||||
<TextBlock x:Name="Text" HorizontalAlignment="Left" VerticalAlignment="Center" Padding="5" MaxWidth="350" TextTrimming="CharacterEllipsis" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
</Grid>
|
||||
</UserControl>
|
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using SafeExamBrowser.Applications.Contracts;
|
||||
using SafeExamBrowser.Core.Contracts.Resources.Icons;
|
||||
using SafeExamBrowser.UserInterface.Shared.Utilities;
|
||||
|
||||
namespace SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar
|
||||
{
|
||||
internal partial class ApplicationWindowButton : UserControl
|
||||
{
|
||||
private IApplicationWindow window;
|
||||
|
||||
internal ApplicationWindowButton(IApplicationWindow window)
|
||||
{
|
||||
this.window = window;
|
||||
|
||||
InitializeComponent();
|
||||
InitializeApplicationInstanceButton();
|
||||
}
|
||||
|
||||
private void InitializeApplicationInstanceButton()
|
||||
{
|
||||
Button.Click += Button_Click;
|
||||
Button.ToolTip = window.Title;
|
||||
Icon.Content = IconResourceLoader.Load(window.Icon);
|
||||
window.IconChanged += Instance_IconChanged;
|
||||
window.TitleChanged += Window_TitleChanged;
|
||||
Text.Text = window.Title;
|
||||
}
|
||||
|
||||
private void Button_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
window.Activate();
|
||||
}
|
||||
|
||||
private void Instance_IconChanged(IconResource icon)
|
||||
{
|
||||
Dispatcher.InvokeAsync(() => Icon.Content = IconResourceLoader.Load(icon));
|
||||
}
|
||||
|
||||
private void Window_TitleChanged(string title)
|
||||
{
|
||||
Dispatcher.InvokeAsync(() =>
|
||||
{
|
||||
Text.Text = title;
|
||||
Button.ToolTip = title;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,39 @@
|
||||
<UserControl x:Class="SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar.AudioControl" x:ClassModifier="internal"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:fa="http://schemas.fontawesome.io/icons/"
|
||||
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop.Controls"
|
||||
mc:Ignorable="d" d:DesignHeight="40" d:DesignWidth="40">
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="../../Templates/Buttons.xaml" />
|
||||
<ResourceDictionary Source="../../Templates/Colors.xaml" />
|
||||
<ResourceDictionary Source="../../Templates/ScrollViewers.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
<Grid>
|
||||
<Popup x:Name="Popup" IsOpen="False" Placement="Custom" PlacementTarget="{Binding ElementName=Button}" KeyDown="Popup_KeyDown">
|
||||
<Border Background="LightGray" BorderBrush="Gray" BorderThickness="1,1,1,0">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<TextBlock x:Name="AudioDeviceName" Margin="5" TextAlignment="Center" />
|
||||
<StackPanel Orientation="Horizontal" Height="40">
|
||||
<Button x:Name="MuteButton" Background="Transparent" Padding="5" Template="{StaticResource TaskbarButton}" Width="40">
|
||||
<ContentControl x:Name="PopupIcon" Focusable="False" />
|
||||
</Button>
|
||||
<Slider x:Name="Volume" Grid.Column="1" Orientation="Horizontal" TickFrequency="1" Maximum="100" IsSnapToTickEnabled="True" KeyDown="Volume_KeyDown"
|
||||
IsMoveToPointEnabled="True" VerticalAlignment="Center" Width="250" Thumb.DragStarted="Volume_DragStarted" Thumb.DragCompleted="Volume_DragCompleted" />
|
||||
<TextBlock Grid.Column="2" FontWeight="DemiBold" FontSize="16" Text="{Binding ElementName=Volume, Path=Value}"
|
||||
TextAlignment="Center" VerticalAlignment="Center" Width="40" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Popup>
|
||||
<Button x:Name="Button" Background="Transparent" Padding="5" Template="{StaticResource TaskbarButton}" ToolTipService.ShowOnDisabled="True" Width="40">
|
||||
<ContentControl x:Name="ButtonIcon" Focusable="False" />
|
||||
</Button>
|
||||
</Grid>
|
||||
</UserControl>
|
@@ -0,0 +1,226 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Automation;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Media;
|
||||
using SafeExamBrowser.Core.Contracts.Resources.Icons;
|
||||
using SafeExamBrowser.I18n.Contracts;
|
||||
using SafeExamBrowser.SystemComponents.Contracts.Audio;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Shell;
|
||||
using SafeExamBrowser.UserInterface.Shared.Utilities;
|
||||
|
||||
namespace SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar
|
||||
{
|
||||
internal partial class AudioControl : UserControl, ISystemControl
|
||||
{
|
||||
private readonly IAudio audio;
|
||||
private readonly IText text;
|
||||
private bool muted;
|
||||
private IconResource MutedIcon;
|
||||
private IconResource NoDeviceIcon;
|
||||
|
||||
internal AudioControl(IAudio audio, IText text)
|
||||
{
|
||||
this.audio = audio;
|
||||
this.text = text;
|
||||
|
||||
InitializeComponent();
|
||||
InitializeAudioControl();
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
Popup.IsOpen = false;
|
||||
}
|
||||
|
||||
private void InitializeAudioControl()
|
||||
{
|
||||
var originalBrush = Button.Background;
|
||||
|
||||
audio.VolumeChanged += Audio_VolumeChanged;
|
||||
Button.Click += (o, args) => Popup.IsOpen = !Popup.IsOpen;
|
||||
var lastOpenedBySpacePress = false;
|
||||
Button.PreviewKeyDown += (o, args) =>
|
||||
{
|
||||
// For some reason, the popup immediately closes again if opened by a Space Bar key event - as a mitigation,
|
||||
// we record the space bar event and leave the popup open for at least 3 seconds.
|
||||
if (args.Key == System.Windows.Input.Key.Space)
|
||||
{
|
||||
lastOpenedBySpacePress = true;
|
||||
}
|
||||
};
|
||||
Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() =>
|
||||
{
|
||||
if (Popup.IsOpen && lastOpenedBySpacePress)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Popup.IsOpen = Popup.IsMouseOver;
|
||||
}));
|
||||
MuteButton.Click += MuteButton_Click;
|
||||
MutedIcon = new XamlIconResource { Uri = new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/Audio_Muted.xaml") };
|
||||
NoDeviceIcon = new XamlIconResource { Uri = new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/Audio_NoDevice.xaml") };
|
||||
Popup.CustomPopupPlacementCallback = new CustomPopupPlacementCallback(Popup_PlacementCallback);
|
||||
Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() =>
|
||||
{
|
||||
if (Popup.IsOpen && lastOpenedBySpacePress)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Popup.IsOpen = IsMouseOver;
|
||||
}));
|
||||
Volume.ValueChanged += Volume_ValueChanged;
|
||||
|
||||
Popup.Opened += (o, args) =>
|
||||
{
|
||||
Background = Brushes.LightGray;
|
||||
Button.Background = Brushes.LightGray;
|
||||
Volume.Focus();
|
||||
};
|
||||
|
||||
Popup.Closed += (o, args) =>
|
||||
{
|
||||
Background = originalBrush;
|
||||
Button.Background = originalBrush;
|
||||
lastOpenedBySpacePress = false;
|
||||
};
|
||||
|
||||
if (audio.HasOutputDevice)
|
||||
{
|
||||
AudioDeviceName.Text = audio.DeviceFullName;
|
||||
Button.IsEnabled = true;
|
||||
UpdateVolume(audio.OutputVolume, audio.OutputMuted);
|
||||
}
|
||||
else
|
||||
{
|
||||
AudioDeviceName.Text = text.Get(TextKey.SystemControl_AudioDeviceNotFound);
|
||||
Button.IsEnabled = false;
|
||||
Button.ToolTip = text.Get(TextKey.SystemControl_AudioDeviceNotFound);
|
||||
ButtonIcon.Content = IconResourceLoader.Load(NoDeviceIcon);
|
||||
}
|
||||
}
|
||||
|
||||
private void Audio_VolumeChanged(double volume, bool muted)
|
||||
{
|
||||
Dispatcher.InvokeAsync(() => UpdateVolume(volume, muted));
|
||||
}
|
||||
|
||||
private void MuteButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (muted)
|
||||
{
|
||||
audio.Unmute();
|
||||
}
|
||||
else
|
||||
{
|
||||
audio.Mute();
|
||||
}
|
||||
}
|
||||
|
||||
private CustomPopupPlacement[] Popup_PlacementCallback(Size popupSize, Size targetSize, Point offset)
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
new CustomPopupPlacement(new Point(targetSize.Width / 2 - popupSize.Width / 2, -popupSize.Height), PopupPrimaryAxis.None)
|
||||
};
|
||||
}
|
||||
|
||||
private void Volume_DragStarted(object sender, DragStartedEventArgs e)
|
||||
{
|
||||
Volume.ValueChanged -= Volume_ValueChanged;
|
||||
}
|
||||
|
||||
private void Volume_DragCompleted(object sender, DragCompletedEventArgs e)
|
||||
{
|
||||
audio.SetVolume(Volume.Value / 100);
|
||||
Volume.ValueChanged += Volume_ValueChanged;
|
||||
}
|
||||
|
||||
private void Volume_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
|
||||
{
|
||||
audio.SetVolume(Volume.Value / 100);
|
||||
}
|
||||
|
||||
private void UpdateVolume(double volume, bool muted)
|
||||
{
|
||||
var info = BuildInfoText(volume, muted);
|
||||
|
||||
this.muted = muted;
|
||||
|
||||
Button.ToolTip = info;
|
||||
Volume.ValueChanged -= Volume_ValueChanged;
|
||||
Volume.Value = Math.Round(volume * 100);
|
||||
Volume.ValueChanged += Volume_ValueChanged;
|
||||
|
||||
AutomationProperties.SetName(Button, info);
|
||||
|
||||
if (muted)
|
||||
{
|
||||
var tooltip = text.Get(TextKey.SystemControl_AudioDeviceUnmuteTooltip);
|
||||
|
||||
MuteButton.ToolTip = tooltip;
|
||||
PopupIcon.Content = IconResourceLoader.Load(MutedIcon);
|
||||
ButtonIcon.Content = IconResourceLoader.Load(MutedIcon);
|
||||
|
||||
AutomationProperties.SetName(MuteButton, tooltip);
|
||||
}
|
||||
else
|
||||
{
|
||||
var tooltip = text.Get(TextKey.SystemControl_AudioDeviceMuteTooltip);
|
||||
|
||||
MuteButton.ToolTip = tooltip;
|
||||
PopupIcon.Content = LoadIcon(volume);
|
||||
ButtonIcon.Content = LoadIcon(volume);
|
||||
|
||||
AutomationProperties.SetName(MuteButton, tooltip);
|
||||
}
|
||||
}
|
||||
|
||||
private string BuildInfoText(double volume, bool muted)
|
||||
{
|
||||
var info = text.Get(muted ? TextKey.SystemControl_AudioDeviceInfoMuted : TextKey.SystemControl_AudioDeviceInfo);
|
||||
|
||||
info = info.Replace("%%NAME%%", audio.DeviceShortName);
|
||||
info = info.Replace("%%VOLUME%%", Convert.ToString(Math.Round(volume * 100)));
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
private UIElement LoadIcon(double volume)
|
||||
{
|
||||
var icon = volume > 0.66 ? "100" : (volume > 0.33 ? "66" : "33");
|
||||
var uri = new Uri($"pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/Audio_{icon}.xaml");
|
||||
var resource = new XamlIconResource { Uri = uri };
|
||||
|
||||
return IconResourceLoader.Load(resource);
|
||||
}
|
||||
|
||||
private void Popup_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
|
||||
{
|
||||
if (e.Key == System.Windows.Input.Key.Escape)
|
||||
{
|
||||
Popup.IsOpen = false;
|
||||
Button.Focus();
|
||||
}
|
||||
}
|
||||
|
||||
private void Volume_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
|
||||
{
|
||||
if (e.Key == System.Windows.Input.Key.Enter)
|
||||
{
|
||||
Popup.IsOpen = false;
|
||||
Button.Focus();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,17 @@
|
||||
<UserControl x:Class="SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar.Clock" x:ClassModifier="internal"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop.Controls"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="300" d:DesignWidth="300">
|
||||
<Grid Background="Transparent" Margin="5,0" ToolTip="{Binding Path=ToolTip}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="1*" />
|
||||
<RowDefinition Height="1*" />
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock x:Name="TimeTextBlock" Grid.Row="0" Text="{Binding Path=Time}" FontWeight="Bold" HorizontalAlignment="Center" VerticalAlignment="Bottom" Focusable="True" AutomationProperties.Name="{Binding Path=Time}" />
|
||||
<TextBlock x:Name="DateTextBlock" Grid.Row="1" Text="{Binding Path=Date}" HorizontalAlignment="Center" VerticalAlignment="Top" Focusable="True" AutomationProperties.Name="{Binding Path=Date}" />
|
||||
</Grid>
|
||||
</UserControl>
|
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System.Windows.Controls;
|
||||
using SafeExamBrowser.UserInterface.Desktop.ViewModels;
|
||||
|
||||
namespace SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar
|
||||
{
|
||||
internal partial class Clock : UserControl
|
||||
{
|
||||
private DateTimeViewModel model;
|
||||
|
||||
public Clock()
|
||||
{
|
||||
InitializeComponent();
|
||||
InitializeControl();
|
||||
}
|
||||
|
||||
private void InitializeControl()
|
||||
{
|
||||
model = new DateTimeViewModel(false);
|
||||
DataContext = model;
|
||||
TimeTextBlock.DataContext = model;
|
||||
DateTextBlock.DataContext = model;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,35 @@
|
||||
<UserControl x:Class="SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar.KeyboardLayoutButton" x:ClassModifier="internal"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:fa="http://schemas.fontawesome.io/icons/"
|
||||
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop.Controls"
|
||||
mc:Ignorable="d" d:DesignHeight="40" d:DesignWidth="250">
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="../../Templates/Buttons.xaml" />
|
||||
<ResourceDictionary Source="../../Templates/Colors.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
<Button x:Name="Button" Background="Transparent" Height="40" Padding="10,0" Template="{StaticResource TaskbarButton}">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock x:Name="IsCurrentTextBlock" Grid.Column="0" FontSize="20" HorizontalAlignment="Center" VerticalAlignment="Center" Visibility="Hidden">•</TextBlock>
|
||||
<TextBlock x:Name="CultureCodeTextBlock" Grid.Column="1" FontWeight="Bold" HorizontalAlignment="Left" Margin="10,0,5,0" VerticalAlignment="Center" />
|
||||
<StackPanel Grid.Column="2" VerticalAlignment="Center">
|
||||
<TextBlock x:Name="CultureNameTextBlock" HorizontalAlignment="Left" Margin="5,0,10,0" TextDecorations="Underline" VerticalAlignment="Center" />
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<fa:ImageAwesome Foreground="Gray" Height="10" Icon="KeyboardOutline" Margin="5,0" />
|
||||
<TextBlock x:Name="LayoutNameTextBlock" Foreground="Gray" HorizontalAlignment="Left" Margin="0,0,10,0" VerticalAlignment="Center" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Button>
|
||||
</UserControl>
|
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Automation;
|
||||
using System.Windows.Controls;
|
||||
using SafeExamBrowser.SystemComponents.Contracts.Keyboard;
|
||||
|
||||
namespace SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar
|
||||
{
|
||||
internal partial class KeyboardLayoutButton : UserControl
|
||||
{
|
||||
private readonly IKeyboardLayout layout;
|
||||
|
||||
internal bool IsCurrent
|
||||
{
|
||||
set { IsCurrentTextBlock.Visibility = value ? Visibility.Visible : Visibility.Hidden; }
|
||||
}
|
||||
|
||||
internal Guid LayoutId
|
||||
{
|
||||
get { return layout.Id; }
|
||||
}
|
||||
|
||||
internal event EventHandler LayoutSelected;
|
||||
|
||||
internal KeyboardLayoutButton(IKeyboardLayout layout)
|
||||
{
|
||||
this.layout = layout;
|
||||
|
||||
InitializeComponent();
|
||||
InitializeLayoutButton();
|
||||
}
|
||||
|
||||
private void InitializeLayoutButton()
|
||||
{
|
||||
Button.Click += (o, args) => LayoutSelected?.Invoke(this, EventArgs.Empty);
|
||||
CultureCodeTextBlock.Text = layout.CultureCode;
|
||||
CultureNameTextBlock.Text = layout.CultureName;
|
||||
LayoutNameTextBlock.Text = layout.LayoutName;
|
||||
|
||||
AutomationProperties.SetName(Button, layout.CultureName);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,32 @@
|
||||
<UserControl x:Class="SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar.KeyboardLayoutControl" x:ClassModifier="internal"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:s="clr-namespace:System;assembly=mscorlib"
|
||||
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop.Controls"
|
||||
mc:Ignorable="d" d:DesignHeight="40" d:DesignWidth="40">
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="../../Templates/Buttons.xaml" />
|
||||
<ResourceDictionary Source="../../Templates/Colors.xaml" />
|
||||
<ResourceDictionary Source="../../Templates/ScrollViewers.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
<Grid>
|
||||
<Popup x:Name="Popup" IsOpen="False" Placement="Custom" PlacementTarget="{Binding ElementName=Button}" KeyUp="Popup_KeyUp">
|
||||
<Border Background="LightGray" BorderBrush="Gray" BorderThickness="1,1,1,0">
|
||||
<ScrollViewer x:Name="LayoutsScrollViewer" MaxHeight="250" VerticalScrollBarVisibility="Auto" Template="{StaticResource SmallBarScrollViewer}">
|
||||
<StackPanel x:Name="LayoutsStackPanel" />
|
||||
</ScrollViewer>
|
||||
</Border>
|
||||
</Popup>
|
||||
<Button x:Name="Button" Background="Transparent" Template="{StaticResource TaskbarButton}" Padding="5" Width="40">
|
||||
<Viewbox Stretch="Uniform">
|
||||
<TextBlock x:Name="LayoutCultureCode" FontWeight="Bold" Margin="2" TextAlignment="Center" VerticalAlignment="Center" />
|
||||
</Viewbox>
|
||||
</Button>
|
||||
</Grid>
|
||||
</UserControl>
|
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Automation;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Media;
|
||||
using SafeExamBrowser.I18n.Contracts;
|
||||
using SafeExamBrowser.SystemComponents.Contracts.Keyboard;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Shell;
|
||||
|
||||
namespace SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar
|
||||
{
|
||||
internal partial class KeyboardLayoutControl : UserControl, ISystemControl
|
||||
{
|
||||
private readonly IKeyboard keyboard;
|
||||
private readonly IText text;
|
||||
|
||||
internal KeyboardLayoutControl(IKeyboard keyboard, IText text)
|
||||
{
|
||||
this.keyboard = keyboard;
|
||||
this.text = text;
|
||||
|
||||
InitializeComponent();
|
||||
InitializeKeyboardLayoutControl();
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
Dispatcher.Invoke(() => Popup.IsOpen = false);
|
||||
}
|
||||
|
||||
private void InitializeKeyboardLayoutControl()
|
||||
{
|
||||
var originalBrush = Button.Background;
|
||||
|
||||
InitializeLayouts();
|
||||
|
||||
keyboard.LayoutChanged += Keyboard_LayoutChanged;
|
||||
Button.Click += (o, args) =>
|
||||
{
|
||||
Popup.IsOpen = !Popup.IsOpen;
|
||||
Task.Delay(200).ContinueWith(_ => this.Dispatcher.BeginInvoke((System.Action) (() =>
|
||||
{
|
||||
((LayoutsStackPanel.Children[0] as ContentControl).Content as UIElement).Focus();
|
||||
})));
|
||||
};
|
||||
var lastOpenedBySpacePress = false;
|
||||
Button.PreviewKeyDown += (o, args) =>
|
||||
{
|
||||
// For some reason, the popup immediately closes again if opened by a Space Bar key event - as a mitigation,
|
||||
// we record the space bar event and leave the popup open for at least 3 seconds.
|
||||
if (args.Key == System.Windows.Input.Key.Space)
|
||||
{
|
||||
lastOpenedBySpacePress = true;
|
||||
}
|
||||
};
|
||||
Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() =>
|
||||
{
|
||||
if (Popup.IsOpen && lastOpenedBySpacePress)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Popup.IsOpen = Popup.IsMouseOver;
|
||||
}));
|
||||
Popup.CustomPopupPlacementCallback = new CustomPopupPlacementCallback(Popup_PlacementCallback);
|
||||
Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() =>
|
||||
{
|
||||
if (Popup.IsOpen && lastOpenedBySpacePress)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Popup.IsOpen = IsMouseOver;
|
||||
}));
|
||||
|
||||
Popup.Opened += (o, args) =>
|
||||
{
|
||||
Background = Brushes.LightGray;
|
||||
Button.Background = Brushes.LightGray;
|
||||
};
|
||||
|
||||
Popup.Closed += (o, args) =>
|
||||
{
|
||||
Background = originalBrush;
|
||||
Button.Background = originalBrush;
|
||||
lastOpenedBySpacePress = false;
|
||||
};
|
||||
}
|
||||
|
||||
private void Keyboard_LayoutChanged(IKeyboardLayout layout)
|
||||
{
|
||||
Dispatcher.InvokeAsync(() => SetCurrent(layout));
|
||||
}
|
||||
|
||||
private CustomPopupPlacement[] Popup_PlacementCallback(Size popupSize, Size targetSize, Point offset)
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
new CustomPopupPlacement(new Point(targetSize.Width / 2 - popupSize.Width / 2, -popupSize.Height), PopupPrimaryAxis.None)
|
||||
};
|
||||
}
|
||||
|
||||
private void InitializeLayouts()
|
||||
{
|
||||
foreach (var layout in keyboard.GetLayouts())
|
||||
{
|
||||
var button = new KeyboardLayoutButton(layout);
|
||||
|
||||
button.LayoutSelected += (o, args) => ActivateLayout(layout);
|
||||
LayoutsStackPanel.Children.Add(button);
|
||||
|
||||
if (layout.IsCurrent)
|
||||
{
|
||||
SetCurrent(layout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ActivateLayout(IKeyboardLayout layout)
|
||||
{
|
||||
Popup.IsOpen = false;
|
||||
keyboard.ActivateLayout(layout.Id);
|
||||
}
|
||||
|
||||
private void SetCurrent(IKeyboardLayout layout)
|
||||
{
|
||||
var name = layout.CultureName?.Length > 3 ? String.Join(string.Empty, layout.CultureName.Split(' ').Where(s => Char.IsLetter(s.First())).Select(s => s.First())) : layout.CultureName;
|
||||
var tooltip = text.Get(TextKey.SystemControl_KeyboardLayoutTooltip).Replace("%%LAYOUT%%", layout.CultureName);
|
||||
|
||||
foreach (var child in LayoutsStackPanel.Children)
|
||||
{
|
||||
if (child is KeyboardLayoutButton layoutButton)
|
||||
{
|
||||
layoutButton.IsCurrent = layout.Id == layoutButton.LayoutId;
|
||||
}
|
||||
}
|
||||
|
||||
LayoutCultureCode.Text = layout.CultureCode;
|
||||
Button.ToolTip = tooltip;
|
||||
|
||||
AutomationProperties.SetName(Button, tooltip);
|
||||
}
|
||||
|
||||
private void Popup_KeyUp(object sender, System.Windows.Input.KeyEventArgs e)
|
||||
{
|
||||
if (e.Key == System.Windows.Input.Key.Enter || e.Key == System.Windows.Input.Key.Escape)
|
||||
{
|
||||
Popup.IsOpen = false;
|
||||
Button.Focus();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,30 @@
|
||||
<UserControl x:Class="SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar.NetworkButton" x:ClassModifier="internal"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop.Controls"
|
||||
mc:Ignorable="d" d:DesignHeight="40" d:DesignWidth="250">
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="../../Templates/Buttons.xaml" />
|
||||
<ResourceDictionary Source="../../Templates/Colors.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
<Grid>
|
||||
<Button x:Name="Button" Background="Transparent" Height="40" Padding="10,0" Template="{StaticResource TaskbarButton}">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock x:Name="IsCurrentTextBlock" Grid.Column="0" FontSize="20" HorizontalAlignment="Center" VerticalAlignment="Center" Visibility="Hidden">•</TextBlock>
|
||||
<TextBlock x:Name="SignalStrengthTextBlock" Grid.Column="1" Foreground="Gray" HorizontalAlignment="Left" Margin="10,0,5,0" VerticalAlignment="Center" />
|
||||
<TextBlock x:Name="NetworkNameTextBlock" Grid.Column="2" FontWeight="Bold" HorizontalAlignment="Left" Margin="5,0,10,0" VerticalAlignment="Center" />
|
||||
</Grid>
|
||||
</Button>
|
||||
</Grid>
|
||||
</UserControl>
|
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using SafeExamBrowser.SystemComponents.Contracts.Network;
|
||||
|
||||
namespace SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar
|
||||
{
|
||||
internal partial class NetworkButton : UserControl
|
||||
{
|
||||
private readonly IWirelessNetwork network;
|
||||
|
||||
internal event EventHandler NetworkSelected;
|
||||
|
||||
internal NetworkButton(IWirelessNetwork network)
|
||||
{
|
||||
this.network = network;
|
||||
|
||||
InitializeComponent();
|
||||
InitializeNetworkButton();
|
||||
}
|
||||
|
||||
private void InitializeNetworkButton()
|
||||
{
|
||||
Button.Click += (o, args) => NetworkSelected?.Invoke(this, EventArgs.Empty);
|
||||
IsCurrentTextBlock.Visibility = network.Status == ConnectionStatus.Connected ? Visibility.Visible : Visibility.Hidden;
|
||||
NetworkNameTextBlock.Text = network.Name;
|
||||
SignalStrengthTextBlock.Text = $"{network.SignalStrength}%";
|
||||
}
|
||||
|
||||
public void SetFocus()
|
||||
{
|
||||
Button.Focus();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,37 @@
|
||||
<UserControl x:Class="SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar.NetworkControl" x:ClassModifier="internal"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:fa="http://schemas.fontawesome.io/icons/"
|
||||
xmlns:s="clr-namespace:System;assembly=mscorlib"
|
||||
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop.Controls"
|
||||
mc:Ignorable="d" d:DesignHeight="40" d:DesignWidth="40">
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="../../Templates/Buttons.xaml" />
|
||||
<ResourceDictionary Source="../../Templates/Colors.xaml" />
|
||||
<ResourceDictionary Source="../../Templates/ScrollViewers.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
<Grid>
|
||||
<Popup x:Name="Popup" IsOpen="False" Placement="Custom" PlacementTarget="{Binding ElementName=Button}">
|
||||
<Border Background="LightGray" BorderBrush="Gray" BorderThickness="1,1,1,0">
|
||||
<ScrollViewer MaxHeight="250" VerticalScrollBarVisibility="Auto" Template="{StaticResource SmallBarScrollViewer}">
|
||||
<StackPanel x:Name="WirelessNetworksStackPanel" />
|
||||
</ScrollViewer>
|
||||
</Border>
|
||||
</Popup>
|
||||
<Button x:Name="Button" Background="Transparent" Padding="5" Template="{StaticResource TaskbarButton}" ToolTipService.ShowOnDisabled="True" Width="40">
|
||||
<Grid HorizontalAlignment="Center" VerticalAlignment="Center">
|
||||
<Viewbox x:Name="WirelessIcon" Stretch="Uniform" Width="Auto" Visibility="Collapsed" />
|
||||
<fa:ImageAwesome x:Name="WiredIcon" Icon="Tv" Margin="0,2,4,4" Visibility="Collapsed" />
|
||||
<Border Background="{StaticResource BackgroundBrush}" CornerRadius="6" Height="12" HorizontalAlignment="Right" Margin="0,0,-1,1" Panel.ZIndex="10" VerticalAlignment="Bottom">
|
||||
<fa:ImageAwesome x:Name="NetworkStatusIcon" />
|
||||
</Border>
|
||||
</Grid>
|
||||
</Button>
|
||||
</Grid>
|
||||
</UserControl>
|
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Media;
|
||||
using FontAwesome.WPF;
|
||||
using SafeExamBrowser.Core.Contracts.Resources.Icons;
|
||||
using SafeExamBrowser.I18n.Contracts;
|
||||
using SafeExamBrowser.SystemComponents.Contracts.Network;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Shell;
|
||||
using SafeExamBrowser.UserInterface.Shared.Utilities;
|
||||
|
||||
namespace SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar
|
||||
{
|
||||
internal partial class NetworkControl : UserControl, ISystemControl
|
||||
{
|
||||
private readonly INetworkAdapter adapter;
|
||||
private readonly IText text;
|
||||
|
||||
internal NetworkControl(INetworkAdapter adapter, IText text)
|
||||
{
|
||||
this.adapter = adapter;
|
||||
this.text = text;
|
||||
|
||||
InitializeComponent();
|
||||
InitializeWirelessNetworkControl();
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
Dispatcher.InvokeAsync(() => Popup.IsOpen = false);
|
||||
}
|
||||
|
||||
private void InitializeWirelessNetworkControl()
|
||||
{
|
||||
var lastOpenedBySpacePress = false;
|
||||
var originalBrush = Button.Background;
|
||||
|
||||
adapter.Changed += () => Dispatcher.InvokeAsync(Update);
|
||||
Button.PreviewKeyDown += (o, args) =>
|
||||
{
|
||||
// For some reason, the popup immediately closes again if opened by a Space Bar key event - as a mitigation,
|
||||
// we record the space bar event and leave the popup open for at least 3 seconds
|
||||
if (args.Key == System.Windows.Input.Key.Space)
|
||||
{
|
||||
lastOpenedBySpacePress = true;
|
||||
}
|
||||
};
|
||||
Button.Click += (o, args) => Popup.IsOpen = !Popup.IsOpen;
|
||||
Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() =>
|
||||
{
|
||||
if (Popup.IsOpen && lastOpenedBySpacePress)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Popup.IsOpen = Popup.IsMouseOver;
|
||||
}));
|
||||
Popup.Closed += (o, args) =>
|
||||
{
|
||||
adapter.StopWirelessNetworkScanning();
|
||||
Background = originalBrush;
|
||||
Button.Background = originalBrush;
|
||||
lastOpenedBySpacePress = false;
|
||||
};
|
||||
Popup.CustomPopupPlacementCallback = new CustomPopupPlacementCallback(Popup_PlacementCallback);
|
||||
Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() =>
|
||||
{
|
||||
if (Popup.IsOpen && lastOpenedBySpacePress)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Popup.IsOpen = IsMouseOver;
|
||||
}));
|
||||
Popup.Opened += (o, args) =>
|
||||
{
|
||||
adapter.StartWirelessNetworkScanning();
|
||||
Background = Brushes.LightGray;
|
||||
Button.Background = Brushes.LightGray;
|
||||
Task.Delay(100).ContinueWith((task) => Dispatcher.Invoke(() =>
|
||||
{
|
||||
if (WirelessNetworksStackPanel.Children.Count > 0)
|
||||
{
|
||||
(WirelessNetworksStackPanel.Children[0] as NetworkButton)?.SetFocus();
|
||||
}
|
||||
}));
|
||||
};
|
||||
WirelessIcon.Child = GetWirelessIcon(0);
|
||||
|
||||
Update();
|
||||
}
|
||||
|
||||
private CustomPopupPlacement[] Popup_PlacementCallback(Size popupSize, Size targetSize, Point offset)
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
new CustomPopupPlacement(new Point(targetSize.Width / 2 - popupSize.Width / 2, -popupSize.Height), PopupPrimaryAxis.None)
|
||||
};
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
switch (adapter.Type)
|
||||
{
|
||||
case ConnectionType.Wired:
|
||||
Button.IsEnabled = false;
|
||||
UpdateText(text.Get(TextKey.SystemControl_NetworkWiredConnected));
|
||||
WiredIcon.Visibility = Visibility.Visible;
|
||||
WirelessIcon.Visibility = Visibility.Collapsed;
|
||||
break;
|
||||
case ConnectionType.Wireless:
|
||||
Button.IsEnabled = true;
|
||||
WiredIcon.Visibility = Visibility.Collapsed;
|
||||
WirelessIcon.Visibility = Visibility.Visible;
|
||||
break;
|
||||
default:
|
||||
Button.IsEnabled = false;
|
||||
UpdateText(text.Get(TextKey.SystemControl_NetworkNotAvailable));
|
||||
WiredIcon.Visibility = Visibility.Visible;
|
||||
WirelessIcon.Visibility = Visibility.Collapsed;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (adapter.Status)
|
||||
{
|
||||
case ConnectionStatus.Connected:
|
||||
UpdateText(text.Get(TextKey.SystemControl_NetworkWiredConnected));
|
||||
NetworkStatusIcon.Rotation = 0;
|
||||
NetworkStatusIcon.Source = ImageAwesome.CreateImageSource(FontAwesomeIcon.Globe, Brushes.Green);
|
||||
NetworkStatusIcon.Spin = false;
|
||||
break;
|
||||
case ConnectionStatus.Connecting:
|
||||
UpdateText(text.Get(TextKey.SystemControl_NetworkWirelessConnecting));
|
||||
NetworkStatusIcon.Rotation = 0;
|
||||
NetworkStatusIcon.Source = ImageAwesome.CreateImageSource(FontAwesomeIcon.Cog, Brushes.DimGray);
|
||||
NetworkStatusIcon.Spin = true;
|
||||
NetworkStatusIcon.SpinDuration = 2;
|
||||
break;
|
||||
default:
|
||||
UpdateText(text.Get(TextKey.SystemControl_NetworkDisconnected));
|
||||
NetworkStatusIcon.Source = ImageAwesome.CreateImageSource(FontAwesomeIcon.Ban, Brushes.DarkOrange);
|
||||
NetworkStatusIcon.Spin = false;
|
||||
WirelessIcon.Child = GetWirelessIcon(0);
|
||||
break;
|
||||
}
|
||||
|
||||
WirelessNetworksStackPanel.Children.Clear();
|
||||
|
||||
foreach (var network in adapter.GetWirelessNetworks())
|
||||
{
|
||||
var button = new NetworkButton(network);
|
||||
|
||||
button.NetworkSelected += (o, args) => adapter.ConnectToWirelessNetwork(network.Name);
|
||||
|
||||
if (network.Status == ConnectionStatus.Connected)
|
||||
{
|
||||
WirelessIcon.Child = GetWirelessIcon(network.SignalStrength);
|
||||
UpdateText(text.Get(TextKey.SystemControl_NetworkWirelessConnected).Replace("%%NAME%%", network.Name));
|
||||
}
|
||||
|
||||
WirelessNetworksStackPanel.Children.Add(button);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateText(string text)
|
||||
{
|
||||
Button.ToolTip = text;
|
||||
Button.SetValue(System.Windows.Automation.AutomationProperties.NameProperty, text);
|
||||
}
|
||||
|
||||
private UIElement GetWirelessIcon(int signalStrength)
|
||||
{
|
||||
var icon = signalStrength > 66 ? "100" : (signalStrength > 33 ? "66" : (signalStrength > 0 ? "33" : "0"));
|
||||
var uri = new Uri($"pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/WiFi_{icon}.xaml");
|
||||
var resource = new XamlIconResource { Uri = uri };
|
||||
|
||||
return IconResourceLoader.Load(resource);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,20 @@
|
||||
<UserControl x:Class="SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar.NotificationButton" x:ClassModifier="internal"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop.Controls"
|
||||
mc:Ignorable="d" d:DesignHeight="40" d:DesignWidth="40">
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="../../Templates/Buttons.xaml" />
|
||||
<ResourceDictionary Source="../../Templates/Colors.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
<Grid>
|
||||
<Button x:Name="IconButton" Background="{StaticResource BackgroundBrush}" Click="IconButton_Click" Padding="7.5"
|
||||
Template="{StaticResource TaskbarButton}" ToolTipService.ShowOnDisabled="True" Width="40" />
|
||||
</Grid>
|
||||
</UserControl>
|
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System.Windows;
|
||||
using System.Windows.Automation;
|
||||
using System.Windows.Controls;
|
||||
using SafeExamBrowser.Core.Contracts.Notifications;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Shell;
|
||||
using SafeExamBrowser.UserInterface.Shared.Utilities;
|
||||
|
||||
namespace SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar
|
||||
{
|
||||
internal partial class NotificationButton : UserControl, INotificationControl
|
||||
{
|
||||
private readonly INotification notification;
|
||||
|
||||
internal NotificationButton(INotification notification)
|
||||
{
|
||||
this.notification = notification;
|
||||
|
||||
InitializeComponent();
|
||||
InitializeNotification();
|
||||
UpdateNotification();
|
||||
}
|
||||
|
||||
private void IconButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (notification.CanActivate)
|
||||
{
|
||||
notification.Activate();
|
||||
}
|
||||
}
|
||||
|
||||
private void InitializeNotification()
|
||||
{
|
||||
notification.NotificationChanged += () => Dispatcher.Invoke(UpdateNotification);
|
||||
}
|
||||
|
||||
private void UpdateNotification()
|
||||
{
|
||||
IconButton.Content = IconResourceLoader.Load(notification.IconResource);
|
||||
IconButton.IsEnabled = notification.CanActivate;
|
||||
IconButton.ToolTip = notification.Tooltip;
|
||||
|
||||
AutomationProperties.SetName(this, notification.Tooltip);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,63 @@
|
||||
<UserControl x:Class="SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar.PowerSupplyControl" x:ClassModifier="internal"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop.Controls"
|
||||
mc:Ignorable="d" d:DesignHeight="40" d:DesignWidth="40" Focusable="true" IsTabStop="True">
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="../../Templates/Buttons.xaml" />
|
||||
<ResourceDictionary Source="../../Templates/Colors.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
<Grid>
|
||||
<Popup x:Name="Popup" IsOpen="False" Placement="Custom" PlacementTarget="{Binding ElementName=Button}">
|
||||
<Border Background="LightGray" BorderBrush="Gray" BorderThickness="1,1,1,0">
|
||||
<Grid MaxWidth="250" Margin="20,10,20,20">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid Grid.Row="0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Button Grid.Column="1" Background="Transparent" BorderBrush="LightGray" Click="Button_Click" Cursor="Hand" FontWeight="Bold"
|
||||
Foreground="Gray" HorizontalAlignment="Center" Margin="0,0,0,5" Width="20">X</Button>
|
||||
</Grid>
|
||||
<TextBlock Grid.Row="1" x:Name="PopupText" TextWrapping="Wrap" />
|
||||
</Grid>
|
||||
</Border>
|
||||
</Popup>
|
||||
<Button x:Name="Button" Background="Transparent" IsEnabled="False" Padding="5" Template="{StaticResource TaskbarButton}" ToolTipService.ShowOnDisabled="True">
|
||||
<Viewbox Stretch="Uniform" Width="Auto">
|
||||
<Canvas Height="40" Width="40">
|
||||
<Viewbox Stretch="Uniform" Width="40" Panel.ZIndex="2">
|
||||
<Canvas Width="1024.000" Height="1024.000">
|
||||
<Canvas.LayoutTransform>
|
||||
<RotateTransform Angle="180" />
|
||||
</Canvas.LayoutTransform>
|
||||
<Canvas>
|
||||
<Path Data=" M 0.000,0.000 L 1024.000,0.000 L 1024.000,1024.000 L 0.000,1024.000 L 0.000,0.000 Z"/>
|
||||
<Path StrokeThickness="35.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 112.000,300.000 L 951.000,300.000 C 970.330,300.000 986.000,315.670 986.000,335.000 L 986.000,689.000 C 986.000,708.330 970.330,724.000 951.000,724.000 L 112.000,724.000 C 92.670,724.000 77.000,708.330 77.000,689.000 L 77.000,335.000 C 77.000,315.670 92.670,300.000 112.000,300.000 Z"/>
|
||||
<Path StrokeThickness="1.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Fill="#ff000000" Data=" M 25.000,462.500 L 50.000,462.500 C 52.760,462.500 55.000,464.740 55.000,467.500 L 55.000,557.500 C 55.000,560.260 52.760,562.500 50.000,562.500 L 25.000,562.500 C 22.240,562.500 20.000,560.260 20.000,557.500 L 20.000,467.500 C 20.000,464.740 22.240,462.500 25.000,462.500 Z"/>
|
||||
</Canvas>
|
||||
</Canvas>
|
||||
</Viewbox>
|
||||
<Rectangle x:Name="BatteryCharge" Canvas.Left="2" Canvas.Top="12" Fill="Green" Height="16" Width="35" Panel.ZIndex="1" />
|
||||
<Canvas x:Name="PowerPlug" Panel.ZIndex="3" Canvas.Left="4" Canvas.Top="-3">
|
||||
<Canvas.LayoutTransform>
|
||||
<ScaleTransform ScaleX="2" ScaleY="2" />
|
||||
</Canvas.LayoutTransform>
|
||||
<Path Stroke="Black" StrokeStartLineCap="Round" Fill="Black" Data="M2.5,17.5 V10 Q5,10 5,6 H4 V4 H4 V6 H1 V4 H1 V6 H0 Q0,10 2.5,10" />
|
||||
</Canvas>
|
||||
<TextBlock x:Name="Warning" FontSize="36" FontWeight="ExtraBold" Foreground="Red" Canvas.Left="13" Canvas.Top="-7" Panel.ZIndex="3">!</TextBlock>
|
||||
</Canvas>
|
||||
</Viewbox>
|
||||
</Button>
|
||||
</Grid>
|
||||
</UserControl>
|
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Threading;
|
||||
using SafeExamBrowser.I18n.Contracts;
|
||||
using SafeExamBrowser.SystemComponents.Contracts.PowerSupply;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Shell;
|
||||
|
||||
namespace SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar
|
||||
{
|
||||
internal partial class PowerSupplyControl : UserControl, ISystemControl
|
||||
{
|
||||
private Brush initialBrush;
|
||||
private bool infoShown, warningShown;
|
||||
private double maxWidth;
|
||||
private IPowerSupply powerSupply;
|
||||
private IText text;
|
||||
|
||||
internal PowerSupplyControl(IPowerSupply powerSupply, IText text)
|
||||
{
|
||||
this.powerSupply = powerSupply;
|
||||
this.text = text;
|
||||
|
||||
InitializeComponent();
|
||||
InitializePowerSupplyControl();
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
Dispatcher.InvokeAsync(ClosePopup);
|
||||
}
|
||||
|
||||
public void SetInformation(string text)
|
||||
{
|
||||
Dispatcher.InvokeAsync(() => PopupText.Text = text);
|
||||
}
|
||||
|
||||
private void InitializePowerSupplyControl()
|
||||
{
|
||||
initialBrush = BatteryCharge.Fill;
|
||||
maxWidth = BatteryCharge.Width;
|
||||
powerSupply.StatusChanged += PowerSupply_StatusChanged;
|
||||
Popup.CustomPopupPlacementCallback = new CustomPopupPlacementCallback(Popup_PlacementCallback);
|
||||
UpdateStatus(powerSupply.GetStatus());
|
||||
}
|
||||
|
||||
private void Button_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
ClosePopup();
|
||||
}
|
||||
|
||||
private CustomPopupPlacement[] Popup_PlacementCallback(Size popupSize, Size targetSize, Point offset)
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
new CustomPopupPlacement(new Point(targetSize.Width / 2 - popupSize.Width / 2, -popupSize.Height), PopupPrimaryAxis.None)
|
||||
};
|
||||
}
|
||||
|
||||
private void PowerSupply_StatusChanged(IPowerSupplyStatus status)
|
||||
{
|
||||
Dispatcher.InvokeAsync(() => UpdateStatus(status));
|
||||
}
|
||||
|
||||
private void UpdateStatus(IPowerSupplyStatus status)
|
||||
{
|
||||
var percentage = Math.Round(status.BatteryCharge * 100);
|
||||
var tooltip = string.Empty;
|
||||
|
||||
RenderCharge(status.BatteryCharge, status.BatteryChargeStatus);
|
||||
|
||||
if (status.IsOnline)
|
||||
{
|
||||
infoShown = false;
|
||||
warningShown = false;
|
||||
tooltip = text.Get(percentage == 100 ? TextKey.SystemControl_BatteryCharged : TextKey.SystemControl_BatteryCharging);
|
||||
tooltip = tooltip.Replace("%%CHARGE%%", percentage.ToString());
|
||||
|
||||
ClosePopup();
|
||||
}
|
||||
else
|
||||
{
|
||||
tooltip = text.Get(TextKey.SystemControl_BatteryRemainingCharge);
|
||||
tooltip = tooltip.Replace("%%CHARGE%%", percentage.ToString());
|
||||
tooltip = tooltip.Replace("%%HOURS%%", status.BatteryTimeRemaining.Hours.ToString());
|
||||
tooltip = tooltip.Replace("%%MINUTES%%", status.BatteryTimeRemaining.Minutes.ToString());
|
||||
|
||||
HandleBatteryStatus(status.BatteryChargeStatus);
|
||||
}
|
||||
|
||||
Button.ToolTip = tooltip;
|
||||
PowerPlug.Visibility = status.IsOnline ? Visibility.Visible : Visibility.Collapsed;
|
||||
Warning.Visibility = status.BatteryChargeStatus == BatteryChargeStatus.Critical ? Visibility.Visible : Visibility.Collapsed;
|
||||
this.SetValue(System.Windows.Automation.AutomationProperties.NameProperty, tooltip);
|
||||
}
|
||||
|
||||
private void RenderCharge(double charge, BatteryChargeStatus status)
|
||||
{
|
||||
var width = maxWidth * charge;
|
||||
|
||||
BatteryCharge.Width = width > maxWidth ? maxWidth : (width < 0 ? 0 : width);
|
||||
|
||||
switch (status)
|
||||
{
|
||||
case BatteryChargeStatus.Critical:
|
||||
BatteryCharge.Fill = Brushes.Red;
|
||||
break;
|
||||
case BatteryChargeStatus.Low:
|
||||
BatteryCharge.Fill = Brushes.Orange;
|
||||
break;
|
||||
default:
|
||||
BatteryCharge.Fill = initialBrush;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleBatteryStatus(BatteryChargeStatus chargeStatus)
|
||||
{
|
||||
if (chargeStatus == BatteryChargeStatus.Low && !infoShown)
|
||||
{
|
||||
ShowPopup(text.Get(TextKey.SystemControl_BatteryChargeLowInfo));
|
||||
infoShown = true;
|
||||
}
|
||||
|
||||
if (chargeStatus == BatteryChargeStatus.Critical && !warningShown)
|
||||
{
|
||||
ShowPopup(text.Get(TextKey.SystemControl_BatteryChargeCriticalWarning));
|
||||
warningShown = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void ShowPopup(string text)
|
||||
{
|
||||
Popup.IsOpen = true;
|
||||
PopupText.Text = text;
|
||||
Background = Brushes.LightGray;
|
||||
}
|
||||
|
||||
private void ClosePopup()
|
||||
{
|
||||
Popup.IsOpen = false;
|
||||
Background = Brushes.Transparent;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,22 @@
|
||||
<UserControl x:Class="SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar.QuitButton" x:ClassModifier="internal"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop.Controls"
|
||||
x:Name="root"
|
||||
mc:Ignorable="d" d:DesignHeight="40" d:DesignWidth="40">
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="../../Templates/Buttons.xaml" />
|
||||
<ResourceDictionary Source="../../Templates/Colors.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
<Grid>
|
||||
<Button x:Name="Button" Click="Button_Click" Background="{StaticResource BackgroundBrush}" HorizontalAlignment="Stretch"
|
||||
Template="{StaticResource TaskbarButton}" VerticalAlignment="Stretch"
|
||||
AutomationProperties.Name="{Binding Path=(AutomationProperties.Name), ElementName=root}"/>
|
||||
</Grid>
|
||||
</UserControl>
|
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using SafeExamBrowser.Core.Contracts.Resources.Icons;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Shell.Events;
|
||||
using SafeExamBrowser.UserInterface.Shared.Utilities;
|
||||
|
||||
namespace SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar
|
||||
{
|
||||
internal partial class QuitButton : UserControl
|
||||
{
|
||||
internal event QuitButtonClickedEventHandler Clicked;
|
||||
|
||||
public QuitButton()
|
||||
{
|
||||
InitializeComponent();
|
||||
LoadIcon();
|
||||
}
|
||||
|
||||
private void Button_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Clicked?.Invoke(new CancelEventArgs());
|
||||
}
|
||||
|
||||
private void LoadIcon()
|
||||
{
|
||||
var uri = new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/ShutDown.xaml");
|
||||
var resource = new XamlIconResource { Uri = uri };
|
||||
|
||||
Button.Content = IconResourceLoader.Load(resource);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,36 @@
|
||||
<UserControl x:Class="SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar.RaiseHandControl"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar"
|
||||
mc:Ignorable="d" d:DesignHeight="40" d:DesignWidth="40">
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="../../Templates/Buttons.xaml" />
|
||||
<ResourceDictionary Source="../../Templates/Colors.xaml" />
|
||||
<ResourceDictionary Source="../../Templates/ScrollViewers.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
<Grid>
|
||||
<Popup x:Name="Popup" IsOpen="False" Placement="Custom" PlacementTarget="{Binding ElementName=Button}">
|
||||
<Border Background="LightGray" BorderBrush="Gray" BorderThickness="1,1,1,0" >
|
||||
<StackPanel>
|
||||
<TextBox Name="Message" AcceptsReturn="True" Height="150" IsReadOnly="False" Margin="5,5,5,0" Width="350" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" />
|
||||
<Grid>
|
||||
<Button Name="HandButton" Background="Transparent" Height="30" Margin="5" Padding="5" Template="{StaticResource TaskbarButton}" Width="150">
|
||||
<Viewbox Stretch="Uniform">
|
||||
<TextBlock x:Name="HandButtonText" FontWeight="Bold" TextAlignment="Center" />
|
||||
</Viewbox>
|
||||
</Button>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Popup>
|
||||
<Button x:Name="NotificationButton" Background="Transparent" Template="{StaticResource TaskbarButton}" Padding="5" Width="40">
|
||||
<ContentControl Name="Icon" />
|
||||
</Button>
|
||||
</Grid>
|
||||
</UserControl>
|
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using SafeExamBrowser.Core.Contracts.Resources.Icons;
|
||||
using SafeExamBrowser.I18n.Contracts;
|
||||
using SafeExamBrowser.Proctoring.Contracts;
|
||||
using SafeExamBrowser.Settings.Proctoring;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Shell;
|
||||
using SafeExamBrowser.UserInterface.Shared.Utilities;
|
||||
|
||||
namespace SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar
|
||||
{
|
||||
public partial class RaiseHandControl : UserControl, INotificationControl
|
||||
{
|
||||
private readonly IProctoringController controller;
|
||||
private readonly ProctoringSettings settings;
|
||||
private readonly IText text;
|
||||
|
||||
private IconResource LoweredIcon;
|
||||
private IconResource RaisedIcon;
|
||||
|
||||
public RaiseHandControl(IProctoringController controller, ProctoringSettings settings, IText text)
|
||||
{
|
||||
this.controller = controller;
|
||||
this.settings = settings;
|
||||
this.text = text;
|
||||
|
||||
InitializeComponent();
|
||||
InitializeRaiseHandControl();
|
||||
}
|
||||
|
||||
private void InitializeRaiseHandControl()
|
||||
{
|
||||
var originalBrush = NotificationButton.Background;
|
||||
|
||||
controller.HandLowered += () => Dispatcher.Invoke(ShowLowered);
|
||||
controller.HandRaised += () => Dispatcher.Invoke(ShowRaised);
|
||||
|
||||
HandButton.Click += RaiseHandButton_Click;
|
||||
HandButtonText.Text = text.Get(TextKey.Notification_ProctoringRaiseHand);
|
||||
|
||||
LoweredIcon = new XamlIconResource { Uri = new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/Hand_Lowered.xaml") };
|
||||
RaisedIcon = new XamlIconResource { Uri = new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/Hand_Raised.xaml") };
|
||||
Icon.Content = IconResourceLoader.Load(LoweredIcon);
|
||||
|
||||
var lastOpenedBySpacePress = false;
|
||||
NotificationButton.PreviewKeyDown += (o, args) =>
|
||||
{
|
||||
if (args.Key == System.Windows.Input.Key.Space) // for some reason, the popup immediately closes again if opened by a Space Bar key event - as a mitigation, we record the space bar event and leave the popup open for at least 3 seconds
|
||||
{
|
||||
lastOpenedBySpacePress = true;
|
||||
}
|
||||
};
|
||||
NotificationButton.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() =>
|
||||
{
|
||||
if (Popup.IsOpen && lastOpenedBySpacePress)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Popup.IsOpen = Popup.IsMouseOver;
|
||||
}));
|
||||
NotificationButton.PreviewMouseLeftButtonUp += NotificationButton_PreviewMouseLeftButtonUp;
|
||||
NotificationButton.PreviewMouseRightButtonUp += NotificationButton_PreviewMouseRightButtonUp;
|
||||
NotificationButton.ToolTip = text.Get(TextKey.Notification_ProctoringHandLowered);
|
||||
|
||||
Popup.CustomPopupPlacementCallback = new CustomPopupPlacementCallback(Popup_PlacementCallback);
|
||||
Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() =>
|
||||
{
|
||||
if (Popup.IsOpen && lastOpenedBySpacePress)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Popup.IsOpen = IsMouseOver;
|
||||
}));
|
||||
Popup.Opened += (o, args) =>
|
||||
{
|
||||
Background = Brushes.LightGray;
|
||||
NotificationButton.Background = Brushes.LightGray;
|
||||
};
|
||||
Popup.Closed += (o, args) =>
|
||||
{
|
||||
Background = originalBrush;
|
||||
NotificationButton.Background = originalBrush;
|
||||
lastOpenedBySpacePress = false;
|
||||
};
|
||||
}
|
||||
|
||||
private void NotificationButton_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (settings.ForceRaiseHandMessage || Popup.IsOpen)
|
||||
{
|
||||
Popup.IsOpen = !Popup.IsOpen;
|
||||
}
|
||||
else
|
||||
{
|
||||
ToggleHand();
|
||||
}
|
||||
}
|
||||
|
||||
private void NotificationButton_PreviewMouseRightButtonUp(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
Popup.IsOpen = !Popup.IsOpen;
|
||||
}
|
||||
|
||||
private CustomPopupPlacement[] Popup_PlacementCallback(Size popupSize, Size targetSize, Point offset)
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
new CustomPopupPlacement(new Point(targetSize.Width / 2 - popupSize.Width / 2, -popupSize.Height), PopupPrimaryAxis.None)
|
||||
};
|
||||
}
|
||||
|
||||
private void RaiseHandButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
ToggleHand();
|
||||
}
|
||||
|
||||
private void ToggleHand()
|
||||
{
|
||||
if (controller.IsHandRaised)
|
||||
{
|
||||
controller.LowerHand();
|
||||
}
|
||||
else
|
||||
{
|
||||
controller.RaiseHand(Message.Text);
|
||||
Message.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
private void ShowLowered()
|
||||
{
|
||||
HandButtonText.Text = text.Get(TextKey.Notification_ProctoringRaiseHand);
|
||||
Icon.Content = IconResourceLoader.Load(LoweredIcon);
|
||||
Message.IsEnabled = true;
|
||||
NotificationButton.ToolTip = text.Get(TextKey.Notification_ProctoringHandLowered);
|
||||
Popup.IsOpen = false;
|
||||
}
|
||||
|
||||
private void ShowRaised()
|
||||
{
|
||||
HandButtonText.Text = text.Get(TextKey.Notification_ProctoringLowerHand);
|
||||
Icon.Content = IconResourceLoader.Load(RaisedIcon);
|
||||
Message.IsEnabled = false;
|
||||
NotificationButton.ToolTip = text.Get(TextKey.Notification_ProctoringHandRaised);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,30 @@
|
||||
<UserControl x:Class="SafeExamBrowser.UserInterface.Desktop.Controls.Taskview.WindowControl" x:ClassModifier="internal"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop.Controls">
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="../../Templates/Colors.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
<Grid Margin="5" Height="175" Width="250">
|
||||
<Border Name="Indicator" Background="{StaticResource BackgroundTransparentEmphasisBrush}" BorderThickness="0" Visibility="Hidden" />
|
||||
<Grid Margin="5">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<ContentControl Grid.Row="0" Grid.Column="0" Name="Icon" Margin="0,0,5,0" Height="16" />
|
||||
<TextBlock Grid.Row="0" Grid.Column="1" Name="Title" Foreground="{StaticResource PrimaryTextBrush}" VerticalAlignment="Center" TextTrimming="CharacterEllipsis" />
|
||||
<ContentControl Grid.Row="1" Grid.ColumnSpan="2" Name="Placeholder" Margin="0,5,0,0" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</UserControl>
|
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Threading;
|
||||
using SafeExamBrowser.Applications.Contracts;
|
||||
using SafeExamBrowser.Core.Contracts.Resources.Icons;
|
||||
using SafeExamBrowser.UserInterface.Shared.Utilities;
|
||||
|
||||
namespace SafeExamBrowser.UserInterface.Desktop.Controls.Taskview
|
||||
{
|
||||
internal partial class WindowControl : UserControl
|
||||
{
|
||||
private Windows.Taskview taskview;
|
||||
private IntPtr thumbnail;
|
||||
private IApplicationWindow window;
|
||||
|
||||
internal WindowControl(IApplicationWindow window, Windows.Taskview taskview)
|
||||
{
|
||||
this.window = window;
|
||||
this.taskview = taskview;
|
||||
|
||||
InitializeComponent();
|
||||
InitializeControl();
|
||||
}
|
||||
|
||||
internal void Activate()
|
||||
{
|
||||
window.Activate();
|
||||
}
|
||||
|
||||
internal void Deselect()
|
||||
{
|
||||
Indicator.Visibility = Visibility.Hidden;
|
||||
Title.FontWeight = FontWeights.Normal;
|
||||
}
|
||||
|
||||
internal void Destroy()
|
||||
{
|
||||
if (thumbnail != IntPtr.Zero)
|
||||
{
|
||||
Thumbnail.DwmUnregisterThumbnail(thumbnail);
|
||||
}
|
||||
}
|
||||
|
||||
internal void Select()
|
||||
{
|
||||
Indicator.Visibility = Visibility.Visible;
|
||||
Title.FontWeight = FontWeights.SemiBold;
|
||||
}
|
||||
|
||||
internal void Update()
|
||||
{
|
||||
if (!IsLoaded || !IsVisible)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (thumbnail == IntPtr.Zero && taskview.Handle != IntPtr.Zero && window.Handle != IntPtr.Zero)
|
||||
{
|
||||
Thumbnail.DwmRegisterThumbnail(taskview.Handle, window.Handle, out thumbnail);
|
||||
}
|
||||
|
||||
if (thumbnail != IntPtr.Zero)
|
||||
{
|
||||
Thumbnail.DwmQueryThumbnailSourceSize(thumbnail, out var size);
|
||||
|
||||
var destination = CalculatePhysicalDestination(size);
|
||||
var properties = new Thumbnail.Properties
|
||||
{
|
||||
Destination = destination,
|
||||
Flags = Thumbnail.DWM_TNP_RECTDESTINATION | Thumbnail.DWM_TNP_VISIBLE,
|
||||
Visible = true
|
||||
};
|
||||
|
||||
Thumbnail.DwmUpdateThumbnailProperties(thumbnail, ref properties);
|
||||
}
|
||||
}
|
||||
|
||||
private void TaskViewWindowControl_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.NewValue as bool? == true)
|
||||
{
|
||||
Update();
|
||||
}
|
||||
}
|
||||
|
||||
private void Window_TitleChanged(string title)
|
||||
{
|
||||
Dispatcher.InvokeAsync(() => Title.Text = title);
|
||||
}
|
||||
|
||||
private void Window_IconChanged(IconResource icon)
|
||||
{
|
||||
Dispatcher.InvokeAsync(() => Icon.Content = IconResourceLoader.Load(window.Icon));
|
||||
}
|
||||
|
||||
private Thumbnail.Rectangle CalculatePhysicalDestination(Thumbnail.Size size)
|
||||
{
|
||||
var controlToTaskview = TransformToVisual(taskview);
|
||||
var placeholderToControl = Placeholder.TransformToVisual(this);
|
||||
var placeholderLeft = placeholderToControl.Transform(new Point(0, 0)).X;
|
||||
var placeholderTop = placeholderToControl.Transform(new Point(0, 0)).Y;
|
||||
var placeholderRight = placeholderToControl.Transform(new Point(Placeholder.ActualWidth, 0)).X;
|
||||
var placeholderBottom = placeholderToControl.Transform(new Point(0, Placeholder.ActualHeight)).Y;
|
||||
|
||||
var physicalBounds = new Thumbnail.Rectangle
|
||||
{
|
||||
Left = (int) Math.Round(this.TransformToPhysical(controlToTaskview.Transform(new Point(placeholderLeft, 0)).X, 0).X),
|
||||
Top = (int) Math.Round(this.TransformToPhysical(0, controlToTaskview.Transform(new Point(0, placeholderTop)).Y).Y),
|
||||
Right = (int) Math.Round(this.TransformToPhysical(controlToTaskview.Transform(new Point(placeholderRight, 0)).X, 0).X),
|
||||
Bottom = (int) Math.Round(this.TransformToPhysical(0, controlToTaskview.Transform(new Point(0, placeholderBottom)).Y).Y)
|
||||
};
|
||||
|
||||
var scaleFactor = default(double);
|
||||
var thumbnailHeight = default(double);
|
||||
var thumbnailWidth = default(double);
|
||||
var maxWidth = (double) physicalBounds.Right - physicalBounds.Left;
|
||||
var maxHeight = (double) physicalBounds.Bottom - physicalBounds.Top;
|
||||
var placeholderRatio = maxWidth / maxHeight;
|
||||
var windowRatio = (double) size.X / size.Y;
|
||||
|
||||
if (windowRatio < placeholderRatio)
|
||||
{
|
||||
thumbnailHeight = maxHeight;
|
||||
scaleFactor = thumbnailHeight / size.Y;
|
||||
thumbnailWidth = size.X * scaleFactor;
|
||||
}
|
||||
else
|
||||
{
|
||||
thumbnailWidth = maxWidth;
|
||||
scaleFactor = thumbnailWidth / size.X;
|
||||
thumbnailHeight = size.Y * scaleFactor;
|
||||
}
|
||||
|
||||
var widthDifference = maxWidth - thumbnailWidth;
|
||||
var heightDifference = maxHeight - thumbnailHeight;
|
||||
|
||||
return new Thumbnail.Rectangle
|
||||
{
|
||||
Left = (int) Math.Round(physicalBounds.Left + (widthDifference / 2)),
|
||||
Top = (int) Math.Round(physicalBounds.Top + (heightDifference / 2)),
|
||||
Right = (int) Math.Round(physicalBounds.Right - (widthDifference / 2)),
|
||||
Bottom = (int) Math.Round(physicalBounds.Bottom - (heightDifference / 2))
|
||||
};
|
||||
}
|
||||
|
||||
private void InitializeControl()
|
||||
{
|
||||
Icon.Content = IconResourceLoader.Load(window.Icon);
|
||||
IsVisibleChanged += TaskViewWindowControl_IsVisibleChanged;
|
||||
Loaded += (o, args) => Update();
|
||||
Title.Text = window.Title;
|
||||
window.IconChanged += Window_IconChanged;
|
||||
window.TitleChanged += Window_TitleChanged;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System.Windows;
|
||||
using SafeExamBrowser.I18n.Contracts;
|
||||
using SafeExamBrowser.SystemComponents.Contracts;
|
||||
using SafeExamBrowser.UserInterface.Contracts.FileSystemDialog;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Windows;
|
||||
using SafeExamBrowser.UserInterface.Desktop.Windows;
|
||||
|
||||
namespace SafeExamBrowser.UserInterface.Desktop
|
||||
{
|
||||
public class FileSystemDialogFactory : IFileSystemDialog
|
||||
{
|
||||
private readonly ISystemInfo systemInfo;
|
||||
private readonly IText text;
|
||||
|
||||
public FileSystemDialogFactory(ISystemInfo systemInfo, IText text)
|
||||
{
|
||||
this.systemInfo = systemInfo;
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public FileSystemDialogResult Show(
|
||||
FileSystemElement element,
|
||||
FileSystemOperation operation,
|
||||
string initialPath = default,
|
||||
string message = default,
|
||||
string title = default,
|
||||
IWindow parent = default,
|
||||
bool restrictNavigation = false,
|
||||
bool showElementPath = true)
|
||||
{
|
||||
if (parent is Window window)
|
||||
{
|
||||
return window.Dispatcher.Invoke(() => new FileSystemDialog(element, operation, systemInfo, text, initialPath, message, title, parent, restrictNavigation, showElementPath).Show());
|
||||
}
|
||||
else
|
||||
{
|
||||
return new FileSystemDialog(element, operation, systemInfo, text, initialPath, message, title, restrictNavigation: restrictNavigation, showElementPath: showElementPath).Show();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,14 @@
|
||||
<Viewbox
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Canvas Width="1024.000" Height="1024.000">
|
||||
<Canvas>
|
||||
<Path Data=" M 0.000,0.000 L 1024.000,0.000 L 1024.000,1024.000 L 0.000,1024.000 L 0.000,0.000 Z"/>
|
||||
<Path StrokeThickness="70.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 117.000,512.000 C 117.000,293.840 293.840,117.000 512.000,117.000 C 730.160,117.000 907.000,293.840 907.000,512.000 C 907.000,730.160 730.160,907.000 512.000,907.000 C 293.840,907.000 117.000,730.160 117.000,512.000 Z"/>
|
||||
<Path StrokeThickness="70.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 619.210,298.700"/>
|
||||
<Path StrokeThickness="70.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 619.210,727.560"/>
|
||||
<Path StrokeThickness="70.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 512.000,458.096 L 512.000,741.560"/>
|
||||
<Path Fill="#ff000000" Data=" M 547.625,312.700 C 547.625,332.375 531.675,348.325 512.000,348.325 C 492.325,348.325 476.375,332.375 476.375,312.700 C 476.375,293.025 492.325,277.075 512.000,277.075 C 531.675,277.075 547.625,293.025 547.625,312.700 Z"/>
|
||||
</Canvas>
|
||||
</Canvas>
|
||||
</Viewbox>
|
13
SafeExamBrowser.UserInterface.Desktop/Images/Audio_100.xaml
Normal file
13
SafeExamBrowser.UserInterface.Desktop/Images/Audio_100.xaml
Normal file
@@ -0,0 +1,13 @@
|
||||
<Viewbox
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:fa="http://schemas.fontawesome.io/icons/"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Grid>
|
||||
<fa:ImageAwesome Icon="VolumeOff" HorizontalAlignment="Left" />
|
||||
<Canvas Width="100" Height="100">
|
||||
<Path StrokeThickness="5.0" Stroke="Black" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data="M 55,35 C 65,45 65,55 55,65"/>
|
||||
<Path StrokeThickness="5.0" Stroke="Black" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data="M 65,25 C 80,35 80,65 65,75"/>
|
||||
<Path StrokeThickness="5.0" Stroke="Black" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data="M 75,15 C 95,30 95,70 75,85"/>
|
||||
</Canvas>
|
||||
</Grid>
|
||||
</Viewbox>
|
13
SafeExamBrowser.UserInterface.Desktop/Images/Audio_33.xaml
Normal file
13
SafeExamBrowser.UserInterface.Desktop/Images/Audio_33.xaml
Normal file
@@ -0,0 +1,13 @@
|
||||
<Viewbox
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:fa="http://schemas.fontawesome.io/icons/"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Grid>
|
||||
<fa:ImageAwesome Icon="VolumeOff" HorizontalAlignment="Left" />
|
||||
<Canvas Width="100" Height="100">
|
||||
<Path StrokeThickness="5.0" Stroke="Black" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data="M 55,35 C 65,45 65,55 55,65"/>
|
||||
<Path StrokeThickness="5.0" Stroke="DarkGray" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data="M 65,25 C 80,35 80,65 65,75"/>
|
||||
<Path StrokeThickness="5.0" Stroke="DarkGray" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data="M 75,15 C 95,30 95,70 75,85"/>
|
||||
</Canvas>
|
||||
</Grid>
|
||||
</Viewbox>
|
13
SafeExamBrowser.UserInterface.Desktop/Images/Audio_66.xaml
Normal file
13
SafeExamBrowser.UserInterface.Desktop/Images/Audio_66.xaml
Normal file
@@ -0,0 +1,13 @@
|
||||
<Viewbox
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:fa="http://schemas.fontawesome.io/icons/"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Grid>
|
||||
<fa:ImageAwesome Icon="VolumeOff" HorizontalAlignment="Left" />
|
||||
<Canvas Width="100" Height="100">
|
||||
<Path StrokeThickness="5.0" Stroke="Black" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data="M 55,35 C 65,45 65,55 55,65"/>
|
||||
<Path StrokeThickness="5.0" Stroke="Black" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data="M 65,25 C 80,35 80,65 65,75"/>
|
||||
<Path StrokeThickness="5.0" Stroke="DarkGray" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data="M 75,15 C 95,30 95,70 75,85"/>
|
||||
</Canvas>
|
||||
</Grid>
|
||||
</Viewbox>
|
@@ -0,0 +1,13 @@
|
||||
<Viewbox
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:fa="http://schemas.fontawesome.io/icons/"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Grid>
|
||||
<fa:ImageAwesome Icon="VolumeOff" HorizontalAlignment="Left" />
|
||||
<Canvas Width="100" Height="100">
|
||||
<Path StrokeThickness="5.0" Stroke="Black" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data="M 55,35 C 65,45 65,55 55,65"/>
|
||||
<Path StrokeThickness="5.0" Stroke="Black" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data="M 65,25 C 80,35 80,65 65,75"/>
|
||||
<Path StrokeThickness="5.0" Stroke="Black" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data="M 75,15 C 95,30 95,70 75,85"/>
|
||||
</Canvas>
|
||||
</Grid>
|
||||
</Viewbox>
|
@@ -0,0 +1,13 @@
|
||||
<Viewbox
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:fa="http://schemas.fontawesome.io/icons/"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Grid>
|
||||
<fa:ImageAwesome Icon="VolumeOff" HorizontalAlignment="Left" />
|
||||
<Canvas Width="100" Height="100">
|
||||
<Path StrokeThickness="5.0" Stroke="Black" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data="M 55,35 C 65,45 65,55 55,65"/>
|
||||
<Path StrokeThickness="5.0" Stroke="#ffdddddd" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data="M 65,25 C 80,35 80,65 65,75"/>
|
||||
<Path StrokeThickness="5.0" Stroke="#ffdddddd" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data="M 75,15 C 95,30 95,70 75,85"/>
|
||||
</Canvas>
|
||||
</Grid>
|
||||
</Viewbox>
|
@@ -0,0 +1,13 @@
|
||||
<Viewbox
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:fa="http://schemas.fontawesome.io/icons/"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Grid>
|
||||
<fa:ImageAwesome Icon="VolumeOff" HorizontalAlignment="Left" />
|
||||
<Canvas Width="100" Height="100">
|
||||
<Path StrokeThickness="5.0" Stroke="Black" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data="M 55,35 C 65,45 65,55 55,65"/>
|
||||
<Path StrokeThickness="5.0" Stroke="Black" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data="M 65,25 C 80,35 80,65 65,75"/>
|
||||
<Path StrokeThickness="5.0" Stroke="#ffdddddd" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data="M 75,15 C 95,30 95,70 75,85"/>
|
||||
</Canvas>
|
||||
</Grid>
|
||||
</Viewbox>
|
@@ -0,0 +1,16 @@
|
||||
<Viewbox
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:fa="http://schemas.fontawesome.io/icons/"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Grid Margin="1">
|
||||
<Grid Margin="5,0,0,0">
|
||||
<fa:ImageAwesome Icon="VolumeOff" Foreground="#ffdddddd" HorizontalAlignment="Left" />
|
||||
<Canvas Width="100" Height="100">
|
||||
<Path StrokeThickness="5.0" Stroke="#ffdddddd" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data="M 55,35 C 65,45 65,55 55,65"/>
|
||||
<Path StrokeThickness="5.0" Stroke="#ffdddddd" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data="M 65,25 C 80,35 80,65 65,75"/>
|
||||
<Path StrokeThickness="5.0" Stroke="#ffdddddd" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data="M 75,15 C 95,30 95,70 75,85"/>
|
||||
</Canvas>
|
||||
</Grid>
|
||||
<fa:ImageAwesome Foreground="Red" Icon="Ban" Opacity="0.3" />
|
||||
</Grid>
|
||||
</Viewbox>
|
@@ -0,0 +1,12 @@
|
||||
<Viewbox
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:fa="http://schemas.fontawesome.io/icons/"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Grid>
|
||||
<fa:ImageAwesome Icon="VolumeOff" HorizontalAlignment="Left" />
|
||||
<Canvas Width="100" Height="100">
|
||||
<Path StrokeThickness="5.0" Stroke="Black" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data="M 60,35 L 90,65"/>
|
||||
<Path StrokeThickness="5.0" Stroke="Black" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data="M 60,65 L 90,35"/>
|
||||
</Canvas>
|
||||
</Grid>
|
||||
</Viewbox>
|
@@ -0,0 +1,16 @@
|
||||
<Viewbox
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:fa="http://schemas.fontawesome.io/icons/"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Grid Margin="1">
|
||||
<Grid Margin="5,0,0,0">
|
||||
<fa:ImageAwesome Icon="VolumeOff" Foreground="DarkGray" HorizontalAlignment="Left" />
|
||||
<Canvas Width="100" Height="100">
|
||||
<Path StrokeThickness="5.0" Stroke="DarkGray" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data="M 55,35 C 65,45 65,55 55,65"/>
|
||||
<Path StrokeThickness="5.0" Stroke="DarkGray" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data="M 65,25 C 80,35 80,65 65,75"/>
|
||||
<Path StrokeThickness="5.0" Stroke="DarkGray" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data="M 75,15 C 95,30 95,70 75,85"/>
|
||||
</Canvas>
|
||||
</Grid>
|
||||
<fa:ImageAwesome Foreground="Red" Icon="Ban" Opacity="0.3" />
|
||||
</Grid>
|
||||
</Viewbox>
|
11
SafeExamBrowser.UserInterface.Desktop/Images/Battery.xaml
Normal file
11
SafeExamBrowser.UserInterface.Desktop/Images/Battery.xaml
Normal file
@@ -0,0 +1,11 @@
|
||||
<Viewbox
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Canvas Width="1024.000" Height="1024.000">
|
||||
<Canvas>
|
||||
<Path Data=" M 0.000,0.000 L 1024.000,0.000 L 1024.000,1024.000 L 0.000,1024.000 L 0.000,0.000 Z"/>
|
||||
<Path StrokeThickness="35.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 112.000,300.000 L 951.000,300.000 C 970.330,300.000 986.000,315.670 986.000,335.000 L 986.000,689.000 C 986.000,708.330 970.330,724.000 951.000,724.000 L 112.000,724.000 C 92.670,724.000 77.000,708.330 77.000,689.000 L 77.000,335.000 C 77.000,315.670 92.670,300.000 112.000,300.000 Z"/>
|
||||
<Path StrokeThickness="1.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Fill="#ff000000" Data=" M 25.000,462.500 L 50.000,462.500 C 52.760,462.500 55.000,464.740 55.000,467.500 L 55.000,557.500 C 55.000,560.260 52.760,562.500 50.000,562.500 L 25.000,562.500 C 22.240,562.500 20.000,560.260 20.000,557.500 L 20.000,467.500 C 20.000,464.740 22.240,462.500 25.000,462.500 Z"/>
|
||||
</Canvas>
|
||||
</Canvas>
|
||||
</Viewbox>
|
@@ -0,0 +1,9 @@
|
||||
<Viewbox
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Grid>
|
||||
<Canvas Width="858.999" Height="862.000">
|
||||
<Path Fill="Black" Data="F1 M 425.701,794.995 C 379.929,794.995 340.560,785.583 307.594,766.759 C 274.629,747.934 249.228,720.533 231.394,684.556 C 213.560,648.578 204.643,605.004 204.643,553.835 L 204.643,232.478 C 204.643,225.177 206.828,219.235 211.200,214.654 C 215.571,210.074 221.301,207.783 228.391,207.783 C 235.437,207.783 241.250,210.074 245.831,214.654 C 250.412,219.235 252.702,225.177 252.702,232.478 L 252.702,429.758 C 252.702,437.762 255.532,444.401 261.193,449.677 C 266.854,454.952 273.347,457.590 280.672,457.590 C 288.464,457.590 295.231,454.952 300.971,449.677 C 306.712,444.401 309.582,437.762 309.582,429.758 L 309.582,134.006 C 309.582,126.704 311.704,120.710 315.947,116.024 C 320.191,111.337 325.860,108.994 332.954,108.994 C 340.047,108.994 345.884,111.337 350.465,116.024 C 355.046,120.710 357.336,126.704 357.336,134.006 L 357.336,409.800 C 357.336,417.804 360.153,424.443 365.788,429.719 C 371.423,434.994 378.033,437.632 385.618,437.632 C 393.198,437.632 399.848,434.994 405.566,429.719 C 411.285,424.443 414.145,417.804 414.145,409.800 L 414.145,85.449 C 414.145,78.195 416.435,72.173 421.015,67.383 C 425.596,62.593 431.434,60.198 438.527,60.198 C 445.410,60.198 451.088,62.593 455.563,67.383 C 460.038,72.173 462.276,78.195 462.276,85.449 L 462.276,405.459 C 462.276,413.203 465.042,419.777 470.575,425.180 C 476.108,430.583 482.770,433.285 490.563,433.285 C 498.308,433.285 504.998,430.583 510.635,425.180 C 516.271,419.777 519.089,413.203 519.089,405.459 L 519.089,134.006 C 519.089,126.704 521.304,120.710 525.733,116.024 C 530.163,111.337 535.924,108.994 543.017,108.994 C 550.111,108.994 555.908,111.337 560.407,116.024 C 564.906,120.710 567.155,126.704 567.155,134.006 L 567.155,515.518 C 567.155,526.396 570.239,534.828 576.407,540.814 C 582.574,546.800 590.147,549.793 599.125,549.793 C 606.758,549.749 613.863,547.732 620.440,543.742 C 627.016,539.752 632.568,532.671 637.095,522.500 L 692.280,399.003 C 695.582,391.355 700.202,386.286 706.142,383.797 C 712.082,381.308 718.005,381.203 723.909,383.483 C 730.492,386.062 734.788,390.327 736.798,396.279 C 738.808,402.231 738.336,409.407 735.382,417.806 L 664.082,614.392 C 640.346,679.569 608.514,725.963 568.587,753.576 C 528.659,781.189 481.030,794.995 425.701,794.995 Z M 427.827,859.330 C 498.493,859.330 558.389,840.488 607.515,802.806 C 656.640,765.124 694.482,709.031 721.040,634.529 L 789.323,442.896 C 794.241,429.083 796.700,415.750 796.700,402.896 C 796.700,381.287 789.469,363.388 775.007,349.199 C 760.550,335.009 742.647,327.914 721.298,327.914 C 707.645,327.914 694.945,331.775 683.196,339.498 C 671.448,347.220 662.334,358.505 655.855,373.351 L 635.083,424.458 C 634.364,426.107 633.285,426.932 631.844,426.932 C 630.147,426.932 629.298,425.874 629.298,423.758 L 629.298,128.275 C 629.298,104.087 622.123,84.794 607.772,70.395 C 593.421,55.996 574.457,48.796 550.880,48.796 C 543.511,48.796 536.562,49.966 530.033,52.305 C 523.504,54.645 517.625,58.024 512.395,62.443 C 508.739,43.046 500.446,27.789 487.518,16.674 C 474.590,5.558 458.374,0.000 438.868,0.000 C 419.667,0.000 403.510,5.610 390.396,16.830 C 377.282,28.049 368.767,43.020 364.851,61.742 C 355.210,53.112 343.534,48.796 329.821,48.796 C 307.913,48.796 290.190,55.788 276.651,69.772 C 263.112,83.756 256.343,102.040 256.343,124.622 L 256.343,160.747 C 251.556,156.209 245.815,152.730 239.118,150.310 C 232.422,147.891 225.401,146.682 218.056,146.682 C 196.148,146.682 178.245,153.968 164.347,168.541 C 150.448,183.114 143.499,202.087 143.499,225.460 L 143.499,560.451 C 143.499,622.072 155.334,675.223 179.002,719.906 C 202.671,764.588 235.828,798.996 278.474,823.130 C 321.121,847.263 370.905,859.330 427.827,859.330 Z"/>
|
||||
</Canvas>
|
||||
</Grid>
|
||||
</Viewbox>
|
@@ -0,0 +1,12 @@
|
||||
<Viewbox
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Grid>
|
||||
<Canvas Width="929.832" Height="936.000">
|
||||
<Canvas>
|
||||
<Path Fill="#ff000000" Data="F1 M 188.249,869.559 C 168.871,869.559 153.644,854.794 153.644,835.416 C 153.644,816.960 169.332,801.734 188.249,801.734 C 207.628,801.734 222.854,816.960 222.854,835.416 C 222.854,854.794 207.628,869.559 188.249,869.559 Z M 188.249,777.280 C 173.023,777.280 162.411,767.129 161.949,752.826 L 158.720,655.933 C 158.259,638.861 170.255,626.865 188.249,626.865 C 206.243,626.865 218.240,638.861 217.778,655.933 L 214.549,752.826 C 214.087,767.129 203.015,777.280 188.249,777.280 Z M 188.249,936.000 C 291.603,936.000 376.499,851.103 376.499,747.751 C 376.499,644.398 291.603,559.501 188.249,559.501 C 84.897,559.501 0.000,644.398 0.000,747.751 C 0.000,851.103 84.897,936.000 188.249,936.000 Z"/>
|
||||
<Path Fill="#ff000000" Data="F1 M 845.839,349.199 C 831.382,335.009 813.479,327.914 792.130,327.914 C 778.478,327.914 765.777,331.775 754.028,339.498 C 742.280,347.220 733.167,358.505 726.688,373.351 L 705.915,424.458 C 705.197,426.107 704.117,426.932 702.676,426.932 C 700.979,426.932 700.131,425.874 700.131,423.758 L 700.131,128.275 C 700.131,104.088 692.955,84.794 678.604,70.395 C 664.253,55.996 645.289,48.796 621.712,48.796 C 614.343,48.796 607.394,49.966 600.865,52.305 C 594.336,54.645 588.457,58.024 583.228,62.443 C 579.571,43.046 571.278,27.789 558.350,16.674 C 545.423,5.558 529.206,0.000 509.701,0.000 C 490.500,0.000 474.342,5.610 461.228,16.830 C 448.115,28.049 439.600,43.020 435.683,61.742 C 426.043,53.112 414.366,48.796 400.654,48.796 C 378.746,48.796 361.022,55.788 347.483,69.772 C 333.945,83.756 327.175,102.040 327.175,124.622 L 327.175,160.747 C 322.389,156.209 316.647,152.730 309.951,150.310 C 303.254,147.891 296.234,146.682 288.888,146.682 C 266.980,146.682 249.077,153.968 235.179,168.541 C 221.281,183.114 214.332,202.087 214.332,225.460 L 214.332,508.446 C 235.287,510.924 255.750,516.158 275.475,524.104 L 275.475,232.478 C 275.475,225.177 277.661,219.235 282.032,214.654 C 286.403,210.074 292.133,207.783 299.223,207.783 C 306.269,207.783 312.083,210.074 316.664,214.654 C 321.244,219.235 323.534,225.177 323.534,232.478 L 323.534,429.758 C 323.534,437.762 326.365,444.401 332.026,449.677 C 337.686,454.952 344.179,457.590 351.504,457.590 C 359.297,457.590 366.063,454.952 371.804,449.677 C 377.544,444.401 380.414,437.762 380.414,429.758 L 380.414,134.006 C 380.414,126.704 382.536,120.710 386.780,116.024 C 391.023,111.337 396.692,108.994 403.786,108.994 C 410.879,108.994 416.717,111.337 421.298,116.024 C 425.878,120.710 428.168,126.704 428.168,134.006 L 428.168,409.800 C 428.168,417.804 430.986,424.443 436.620,429.719 C 442.255,434.994 448.865,437.632 456.450,437.632 C 464.031,437.632 470.680,434.994 476.399,429.719 C 482.117,424.443 484.977,417.804 484.977,409.800 L 484.977,85.449 C 484.977,78.195 487.267,72.173 491.848,67.383 C 496.429,62.593 502.266,60.198 509.359,60.198 C 516.242,60.198 521.921,62.593 526.396,67.383 C 530.871,72.173 533.108,78.195 533.108,85.449 L 533.108,405.459 C 533.108,413.203 535.875,419.777 541.407,425.180 C 546.940,430.583 553.603,433.285 561.395,433.285 C 569.140,433.285 575.830,430.583 581.467,425.180 C 587.104,419.777 589.922,413.203 589.922,405.459 L 589.922,134.006 C 589.922,126.704 592.136,120.710 596.566,116.024 C 600.995,111.337 606.756,108.994 613.850,108.994 C 620.944,108.994 626.740,111.337 631.239,116.024 C 635.738,120.710 637.987,126.704 637.987,134.006 L 637.987,515.518 C 637.987,526.396 641.071,534.828 647.239,540.814 C 653.407,546.800 660.979,549.793 669.958,549.793 C 677.590,549.749 684.695,547.732 691.272,543.742 C 697.849,539.752 703.400,532.671 707.927,522.500 L 763.112,399.003 C 766.414,391.355 771.035,386.286 776.974,383.797 C 782.915,381.308 788.837,381.203 794.741,383.483 C 801.324,386.062 805.620,390.327 807.630,396.279 C 809.640,402.231 809.168,409.406 806.214,417.806 L 734.915,614.392 C 711.179,679.569 679.347,725.963 639.419,753.576 C 599.491,781.189 551.862,794.995 496.533,794.995 C 470.493,794.995 446.532,791.938 424.637,785.846 C 421.591,805.184 416.182,824.071 408.423,842.300 C 407.750,843.879 407.056,845.446 406.352,847.008 C 434.695,855.217 465.461,859.330 498.659,859.330 C 569.325,859.330 629.221,840.488 678.347,802.806 C 727.472,765.124 765.314,709.031 791.873,634.529 L 860.155,442.896 C 865.074,429.083 867.533,415.750 867.533,402.896 C 867.533,381.287 860.302,363.388 845.839,349.199 Z"/>
|
||||
</Canvas>
|
||||
</Canvas>
|
||||
</Grid>
|
||||
</Viewbox>
|
11
SafeExamBrowser.UserInterface.Desktop/Images/Home.xaml
Normal file
11
SafeExamBrowser.UserInterface.Desktop/Images/Home.xaml
Normal file
@@ -0,0 +1,11 @@
|
||||
<Viewbox
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Canvas Width="1024.000" Height="1024.000">
|
||||
<Canvas>
|
||||
<Path Data=" M 0.000,0.000 L 1024.000,0.000 L 1024.000,1024.000 L 0.000,1024.000 L 0.000,0.000 Z"/>
|
||||
<Path StrokeThickness="70.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 301.086,510.424 L 786.763,188.341 L 786.763,835.919 L 301.086,510.424 Z"/>
|
||||
<Path StrokeThickness="70.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data="F1 M 235.016,188.341 L 235.016,835.919"/>
|
||||
</Canvas>
|
||||
</Canvas>
|
||||
</Viewbox>
|
34
SafeExamBrowser.UserInterface.Desktop/Images/Keyboard.xaml
Normal file
34
SafeExamBrowser.UserInterface.Desktop/Images/Keyboard.xaml
Normal file
@@ -0,0 +1,34 @@
|
||||
<Viewbox
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Canvas Width="1024.000" Height="1024.000">
|
||||
<Canvas>
|
||||
<Path Data=" M 0.000,0.000 L 1024.000,0.000 L 1024.000,1024.000 L 0.000,1024.000 L 0.000,0.000 Z"/>
|
||||
<Path StrokeThickness="35.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 134.000,339.000 L 889.000,339.000 C 908.330,339.000 924.000,354.670 924.000,374.000 L 924.000,649.000 C 924.000,668.330 908.330,684.000 889.000,684.000 L 134.000,684.000 C 114.670,684.000 99.000,668.330 99.000,649.000 L 99.000,374.000 C 99.000,354.670 114.670,339.000 134.000,339.000 Z"/>
|
||||
<Path StrokeThickness="1.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Fill="#ff000000" Data=" M 152.000,582.000 L 192.000,582.000 C 194.760,582.000 197.000,584.240 197.000,587.000 L 197.000,627.000 C 197.000,629.760 194.760,632.000 192.000,632.000 L 152.000,632.000 C 149.240,632.000 147.000,629.760 147.000,627.000 L 147.000,587.000 C 147.000,584.240 149.240,582.000 152.000,582.000 Z"/>
|
||||
<Path StrokeThickness="1.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Fill="#ff000000" Data=" M 747.000,582.000 L 787.000,582.000 C 789.760,582.000 792.000,584.240 792.000,587.000 L 792.000,627.000 C 792.000,629.760 789.760,632.000 787.000,632.000 L 747.000,632.000 C 744.240,632.000 742.000,629.760 742.000,627.000 L 742.000,587.000 C 742.000,584.240 744.240,582.000 747.000,582.000 Z"/>
|
||||
<Path StrokeThickness="1.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Fill="#ff000000" Data=" M 152.000,487.000 L 192.000,487.000 C 194.760,487.000 197.000,489.240 197.000,492.000 L 197.000,532.000 C 197.000,534.760 194.760,537.000 192.000,537.000 L 152.000,537.000 C 149.240,537.000 147.000,534.760 147.000,532.000 L 147.000,492.000 C 147.000,489.240 149.240,487.000 152.000,487.000 Z"/>
|
||||
<Path StrokeThickness="1.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Fill="#ff000000" Data=" M 322.000,487.000 L 362.000,487.000 C 364.760,487.000 367.000,489.240 367.000,492.000 L 367.000,532.000 C 367.000,534.760 364.760,537.000 362.000,537.000 L 322.000,537.000 C 319.240,537.000 317.000,534.760 317.000,532.000 L 317.000,492.000 C 317.000,489.240 319.240,487.000 322.000,487.000 Z"/>
|
||||
<Path StrokeThickness="1.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Fill="#ff000000" Data=" M 492.000,487.000 L 532.000,487.000 C 534.760,487.000 537.000,489.240 537.000,492.000 L 537.000,532.000 C 537.000,534.760 534.760,537.000 532.000,537.000 L 492.000,537.000 C 489.240,537.000 487.000,534.760 487.000,532.000 L 487.000,492.000 C 487.000,489.240 489.240,487.000 492.000,487.000 Z"/>
|
||||
<Path StrokeThickness="1.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Fill="#ff000000" Data=" M 747.000,487.000 L 787.000,487.000 C 789.760,487.000 792.000,489.240 792.000,492.000 L 792.000,532.000 C 792.000,534.760 789.760,537.000 787.000,537.000 L 747.000,537.000 C 744.240,537.000 742.000,534.760 742.000,532.000 L 742.000,492.000 C 742.000,489.240 744.240,487.000 747.000,487.000 Z"/>
|
||||
<Path StrokeThickness="1.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Fill="#ff000000" Data=" M 152.000,392.000 L 192.000,392.000 C 194.760,392.000 197.000,394.240 197.000,397.000 L 197.000,437.000 C 197.000,439.760 194.760,442.000 192.000,442.000 L 152.000,442.000 C 149.240,442.000 147.000,439.760 147.000,437.000 L 147.000,397.000 C 147.000,394.240 149.240,392.000 152.000,392.000 Z"/>
|
||||
<Path StrokeThickness="1.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Fill="#ff000000" Data=" M 322.000,392.000 L 362.000,392.000 C 364.760,392.000 367.000,394.240 367.000,397.000 L 367.000,437.000 C 367.000,439.760 364.760,442.000 362.000,442.000 L 322.000,442.000 C 319.240,442.000 317.000,439.760 317.000,437.000 L 317.000,397.000 C 317.000,394.240 319.240,392.000 322.000,392.000 Z"/>
|
||||
<Path StrokeThickness="1.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Fill="#ff000000" Data=" M 492.000,392.000 L 532.000,392.000 C 534.760,392.000 537.000,394.240 537.000,397.000 L 537.000,437.000 C 537.000,439.760 534.760,442.000 532.000,442.000 L 492.000,442.000 C 489.240,442.000 487.000,439.760 487.000,437.000 L 487.000,397.000 C 487.000,394.240 489.240,392.000 492.000,392.000 Z"/>
|
||||
<Path StrokeThickness="1.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Fill="#ff000000" Data=" M 747.000,392.000 L 787.000,392.000 C 789.760,392.000 792.000,394.240 792.000,397.000 L 792.000,437.000 C 792.000,439.760 789.760,442.000 787.000,442.000 L 747.000,442.000 C 744.240,442.000 742.000,439.760 742.000,437.000 L 742.000,397.000 C 742.000,394.240 744.240,392.000 747.000,392.000 Z"/>
|
||||
<Path StrokeThickness="1.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Fill="#ff000000" Data=" M 237.000,582.000 L 277.000,582.000 C 279.760,582.000 282.000,584.240 282.000,587.000 L 282.000,627.000 C 282.000,629.760 279.760,632.000 277.000,632.000 L 237.000,632.000 C 234.240,632.000 232.000,629.760 232.000,627.000 L 232.000,587.000 C 232.000,584.240 234.240,582.000 237.000,582.000 Z"/>
|
||||
<Path StrokeThickness="1.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Fill="#ff000000" Data=" M 322.000,582.000 L 702.000,582.000 C 704.760,582.000 707.000,584.240 707.000,587.000 L 707.000,627.000 C 707.000,629.760 704.760,632.000 702.000,632.000 L 322.000,632.000 C 319.240,632.000 317.000,629.760 317.000,627.000 L 317.000,587.000 C 317.000,584.240 319.240,582.000 322.000,582.000 Z"/>
|
||||
<Path StrokeThickness="1.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Fill="#ff000000" Data=" M 832.000,582.000 L 872.000,582.000 C 874.760,582.000 877.000,584.240 877.000,587.000 L 877.000,627.000 C 877.000,629.760 874.760,632.000 872.000,632.000 L 832.000,632.000 C 829.240,632.000 827.000,629.760 827.000,627.000 L 827.000,587.000 C 827.000,584.240 829.240,582.000 832.000,582.000 Z"/>
|
||||
<Path StrokeThickness="1.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Fill="#ff000000" Data=" M 237.000,487.000 L 277.000,487.000 C 279.760,487.000 282.000,489.240 282.000,492.000 L 282.000,532.000 C 282.000,534.760 279.760,537.000 277.000,537.000 L 237.000,537.000 C 234.240,537.000 232.000,534.760 232.000,532.000 L 232.000,492.000 C 232.000,489.240 234.240,487.000 237.000,487.000 Z"/>
|
||||
<Path StrokeThickness="1.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Fill="#ff000000" Data=" M 407.000,487.000 L 447.000,487.000 C 449.760,487.000 452.000,489.240 452.000,492.000 L 452.000,532.000 C 452.000,534.760 449.760,537.000 447.000,537.000 L 407.000,537.000 C 404.240,537.000 402.000,534.760 402.000,532.000 L 402.000,492.000 C 402.000,489.240 404.240,487.000 407.000,487.000 Z"/>
|
||||
<Path StrokeThickness="1.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Fill="#ff000000" Data=" M 577.000,487.000 L 617.000,487.000 C 619.760,487.000 622.000,489.240 622.000,492.000 L 622.000,532.000 C 622.000,534.760 619.760,537.000 617.000,537.000 L 577.000,537.000 C 574.240,537.000 572.000,534.760 572.000,532.000 L 572.000,492.000 C 572.000,489.240 574.240,487.000 577.000,487.000 Z"/>
|
||||
<Path StrokeThickness="1.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Fill="#ff000000" Data=" M 662.000,487.000 L 702.000,487.000 C 704.760,487.000 707.000,489.240 707.000,492.000 L 707.000,532.000 C 707.000,534.760 704.760,537.000 702.000,537.000 L 662.000,537.000 C 659.240,537.000 657.000,534.760 657.000,532.000 L 657.000,492.000 C 657.000,489.240 659.240,487.000 662.000,487.000 Z"/>
|
||||
<Path StrokeThickness="1.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Fill="#ff000000" Data=" M 832.000,487.000 L 872.000,487.000 C 874.760,487.000 877.000,489.240 877.000,492.000 L 877.000,532.000 C 877.000,534.760 874.760,537.000 872.000,537.000 L 832.000,537.000 C 829.240,537.000 827.000,534.760 827.000,532.000 L 827.000,492.000 C 827.000,489.240 829.240,487.000 832.000,487.000 Z"/>
|
||||
<Path StrokeThickness="1.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Fill="#ff000000" Data=" M 237.000,392.000 L 277.000,392.000 C 279.760,392.000 282.000,394.240 282.000,397.000 L 282.000,437.000 C 282.000,439.760 279.760,442.000 277.000,442.000 L 237.000,442.000 C 234.240,442.000 232.000,439.760 232.000,437.000 L 232.000,397.000 C 232.000,394.240 234.240,392.000 237.000,392.000 Z"/>
|
||||
<Path StrokeThickness="1.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Fill="#ff000000" Data=" M 407.000,392.000 L 447.000,392.000 C 449.760,392.000 452.000,394.240 452.000,397.000 L 452.000,437.000 C 452.000,439.760 449.760,442.000 447.000,442.000 L 407.000,442.000 C 404.240,442.000 402.000,439.760 402.000,437.000 L 402.000,397.000 C 402.000,394.240 404.240,392.000 407.000,392.000 Z"/>
|
||||
<Path StrokeThickness="1.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Fill="#ff000000" Data=" M 577.000,392.000 L 617.000,392.000 C 619.760,392.000 622.000,394.240 622.000,397.000 L 622.000,437.000 C 622.000,439.760 619.760,442.000 617.000,442.000 L 577.000,442.000 C 574.240,442.000 572.000,439.760 572.000,437.000 L 572.000,397.000 C 572.000,394.240 574.240,392.000 577.000,392.000 Z"/>
|
||||
<Path StrokeThickness="1.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Fill="#ff000000" Data=" M 662.000,392.000 L 702.000,392.000 C 704.760,392.000 707.000,394.240 707.000,397.000 L 707.000,437.000 C 707.000,439.760 704.760,442.000 702.000,442.000 L 662.000,442.000 C 659.240,442.000 657.000,439.760 657.000,437.000 L 657.000,397.000 C 657.000,394.240 659.240,392.000 662.000,392.000 Z"/>
|
||||
<Path StrokeThickness="1.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Fill="#ff000000" Data=" M 832.000,392.000 L 872.000,392.000 C 874.760,392.000 877.000,394.240 877.000,397.000 L 877.000,437.000 C 877.000,439.760 874.760,442.000 872.000,442.000 L 832.000,442.000 C 829.240,442.000 827.000,439.760 827.000,437.000 L 827.000,397.000 C 827.000,394.240 829.240,392.000 832.000,392.000 Z"/>
|
||||
<Path StrokeThickness="35.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 668.000,201.000 L 512.000,90.000 L 668.000,201.000 Z M 356.000,201.000 L 512.000,90.000 L 356.000,201.000 Z"/>
|
||||
</Canvas>
|
||||
</Canvas>
|
||||
</Viewbox>
|
BIN
SafeExamBrowser.UserInterface.Desktop/Images/LogNotification.ico
Normal file
BIN
SafeExamBrowser.UserInterface.Desktop/Images/LogNotification.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 91 KiB |
7
SafeExamBrowser.UserInterface.Desktop/Images/Menu.xaml
Normal file
7
SafeExamBrowser.UserInterface.Desktop/Images/Menu.xaml
Normal file
@@ -0,0 +1,7 @@
|
||||
<Viewbox Stretch="Uniform"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:fa="http://schemas.fontawesome.io/icons/">
|
||||
<Canvas Height="120" Width="120">
|
||||
<Path Stroke="Black" StrokeLineJoin="Round" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeThickness="8" Data="M 20,30 L 100,30 M 20,60 L 100,60 M 20,90 L 100,90" />
|
||||
</Canvas>
|
||||
</Viewbox>
|
@@ -0,0 +1,12 @@
|
||||
<Viewbox
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Canvas Width="1024.000" Height="1024.000">
|
||||
<Canvas>
|
||||
<Path Data=" M 0.000,0.000 L 1024.000,0.000 L 1024.000,1024.000 L 0.000,1024.000 L 0.000,0.000 Z"/>
|
||||
<Path StrokeThickness="70.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 753.838,835.919 L 268.162,510.424 L 753.838,188.341"/>
|
||||
<Path StrokeThickness="70.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 766.763,835.919"/>
|
||||
<Path StrokeThickness="70.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 766.763,188.341"/>
|
||||
</Canvas>
|
||||
</Canvas>
|
||||
</Viewbox>
|
@@ -0,0 +1,12 @@
|
||||
<Viewbox
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Canvas Width="1024.000" Height="1024.000">
|
||||
<Canvas>
|
||||
<Path Data=" M 0.000,0.000 L 1024.000,0.000 L 1024.000,1024.000 L 0.000,1024.000 L 0.000,0.000 Z"/>
|
||||
<Path StrokeThickness="70.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 268.162,835.919 L 753.838,510.424 L 268.162,188.341"/>
|
||||
<Path StrokeThickness="70.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 766.763,835.919"/>
|
||||
<Path StrokeThickness="70.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 766.763,188.341"/>
|
||||
</Canvas>
|
||||
</Canvas>
|
||||
</Viewbox>
|
@@ -0,0 +1,9 @@
|
||||
<Viewbox
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Canvas Width="1024.000" Height="1024.000">
|
||||
<Canvas>
|
||||
<Path Fill="Green" Data="F1 M 511.000,587.189 C 600.504,588.389 671.387,512.101 671.387,411.785 C 671.387,317.474 600.504,239.984 511.000,239.984 C 421.496,239.984 350.614,317.474 351.215,411.785 C 351.816,512.101 421.496,585.987 511.000,587.189 Z M 511.000,665.880 C 342.805,665.880 223.266,745.773 170.404,856.302 C 155.987,843.687 148.178,823.263 148.178,796.232 L 148.178,227.369 C 148.178,175.709 175.810,148.677 225.669,148.677 L 796.333,148.677 C 845.590,148.677 873.823,175.709 873.823,227.369 L 873.823,796.232 C 873.823,823.263 866.014,843.086 851.597,856.302 C 799.336,745.173 683.401,665.880 511.000,665.880 Z M 224.467,941.000 L 797.535,941.000 C 893.045,941.000 940.500,893.545 940.500,799.835 L 940.500,223.765 C 940.500,130.057 893.045,82.000 797.535,82.000 L 224.467,82.000 C 129.557,82.000 81.501,129.455 81.501,223.765 L 81.501,799.835 C 81.501,893.545 129.557,941.000 224.467,941.000 Z"/>
|
||||
</Canvas>
|
||||
</Canvas>
|
||||
</Viewbox>
|
@@ -0,0 +1,9 @@
|
||||
<Viewbox
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Canvas Width="1024.000" Height="1024.000">
|
||||
<Canvas>
|
||||
<Path Fill="Black" Data="F1 M 511.000,587.189 C 600.504,588.389 671.387,512.101 671.387,411.785 C 671.387,317.474 600.504,239.984 511.000,239.984 C 421.496,239.984 350.614,317.474 351.215,411.785 C 351.816,512.101 421.496,585.987 511.000,587.189 Z M 511.000,665.880 C 342.805,665.880 223.266,745.773 170.404,856.302 C 155.987,843.687 148.178,823.263 148.178,796.232 L 148.178,227.369 C 148.178,175.709 175.810,148.677 225.669,148.677 L 796.333,148.677 C 845.590,148.677 873.823,175.709 873.823,227.369 L 873.823,796.232 C 873.823,823.263 866.014,843.086 851.597,856.302 C 799.336,745.173 683.401,665.880 511.000,665.880 Z M 224.467,941.000 L 797.535,941.000 C 893.045,941.000 940.500,893.545 940.500,799.835 L 940.500,223.765 C 940.500,130.057 893.045,82.000 797.535,82.000 L 224.467,82.000 C 129.557,82.000 81.501,129.455 81.501,223.765 L 81.501,799.835 C 81.501,893.545 129.557,941.000 224.467,941.000 Z"/>
|
||||
</Canvas>
|
||||
</Canvas>
|
||||
</Viewbox>
|
11
SafeExamBrowser.UserInterface.Desktop/Images/Reload.xaml
Normal file
11
SafeExamBrowser.UserInterface.Desktop/Images/Reload.xaml
Normal file
@@ -0,0 +1,11 @@
|
||||
<Viewbox
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Canvas Width="1024.000" Height="1024.000">
|
||||
<Canvas>
|
||||
<Path Data=" M 0.000,0.000 L 1024.000,0.000 L 1024.000,1024.000 L 0.000,1024.000 L 0.000,0.000 Z"/>
|
||||
<Path StrokeThickness="70.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 862.000,557.000 C 862.000,750.300 705.300,907.000 512.000,907.000 C 318.700,907.000 162.000,750.300 162.000,557.000 C 162.000,363.700 318.700,207.000 512.000,207.000"/>
|
||||
<Path Fill="#ff000000" Data="F1 M 471.000,67.000 L 712.500,207.000 L 471.000,345.000 L 471.000,67.000 Z"/>
|
||||
</Canvas>
|
||||
</Canvas>
|
||||
</Viewbox>
|
BIN
SafeExamBrowser.UserInterface.Desktop/Images/SafeExamBrowser.ico
Normal file
BIN
SafeExamBrowser.UserInterface.Desktop/Images/SafeExamBrowser.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 361 KiB |
@@ -0,0 +1,9 @@
|
||||
<Viewbox
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Canvas Width="996.513" Height="879.512">
|
||||
<Path Fill="Green" Data="F1 M 648.026,733.342 L 132.172,733.342 C 95.142,733.342 74.057,713.285 74.057,674.713 L 74.057,191.286 C 74.057,152.201 95.142,132.658 132.172,132.658 L 821.827,132.658 C 858.855,132.658 879.940,152.201 879.940,191.286 L 879.940,533.629 C 906.670,538.022 931.750,547.790 954.000,561.758 L 954.000,187.686 C 954.000,101.287 910.798,58.086 822.855,58.086 L 131.143,58.086 C 43.714,58.086 0.000,101.287 0.000,187.686 L 0.000,678.313 C 0.000,764.714 43.714,807.914 131.143,807.914 L 663.555,807.914 C 653.801,784.825 648.291,759.630 648.026,733.342 Z"/>
|
||||
<Path Fill="Green" Data="F1 M 819.770,533.037 L 819.770,225.230 C 819.770,204.657 808.455,192.315 788.398,192.315 L 165.600,192.315 C 146.057,192.315 134.229,204.657 134.229,225.230 L 134.229,640.771 C 134.229,661.342 146.057,673.685 165.600,673.685 L 656.640,673.685 C 679.042,600.500 742.705,544.204 819.770,533.037 Z"/>
|
||||
<Path Fill="Green" Data="F1 M 848.358,879.512 C 765.828,879.512 700.700,813.887 700.700,731.358 C 700.700,649.325 765.828,583.203 847.860,583.203 C 930.391,583.203 996.513,649.325 996.513,731.358 C 996.513,813.887 930.391,879.512 848.358,879.512 Z"/>
|
||||
</Canvas>
|
||||
</Viewbox>
|
@@ -0,0 +1,7 @@
|
||||
<Viewbox
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Canvas Width="996.513" Height="879.512">
|
||||
<Path Fill="Black" Data="F1 M 132.172,733.342 C 95.142,733.342 74.057,713.285 74.057,674.713 L 74.057,191.286 C 74.057,152.201 95.142,132.658 132.172,132.658 L 821.827,132.658 C 858.855,132.658 879.940,152.201 879.940,191.286 L 879.940,674.713 C 879.940,713.285 858.855,733.342 821.827,733.342 L 132.172,733.342 Z M 131.143,807.913 L 822.855,807.913 C 910.798,807.913 954.000,764.714 954.000,678.313 L 954.000,187.686 C 954.000,101.287 910.798,58.087 822.855,58.087 L 131.143,58.087 C 43.714,58.087 0.000,101.287 0.000,187.686 L 0.000,678.313 C 0.000,764.714 43.714,807.913 131.143,807.913 Z M 165.600,673.685 L 788.398,673.685 C 808.455,673.685 819.770,661.342 819.770,640.771 L 819.770,225.230 C 819.770,204.657 808.455,192.315 788.398,192.315 L 165.600,192.315 C 146.057,192.315 134.229,204.657 134.229,225.230 L 134.229,640.771 C 134.229,661.342 146.057,673.685 165.600,673.685 Z"/>
|
||||
</Canvas>
|
||||
</Viewbox>
|
12
SafeExamBrowser.UserInterface.Desktop/Images/ShutDown.xaml
Normal file
12
SafeExamBrowser.UserInterface.Desktop/Images/ShutDown.xaml
Normal file
@@ -0,0 +1,12 @@
|
||||
<Viewbox
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Canvas Width="1024.000" Height="1024.000">
|
||||
<Canvas>
|
||||
<Path StrokeThickness="79.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 512.000,902.000 C 296.610,902.000 122.000,727.280 122.000,511.740 C 122.000,388.110 179.450,277.910 269.090,206.400"/>
|
||||
<Path StrokeThickness="79.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 512.000,902.000 C 727.390,902.000 902.000,727.280 902.000,511.740 C 902.000,388.110 844.550,277.910 754.910,206.400"/>
|
||||
<Path StrokeThickness="79.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 512.560,112.000 L 512.560,494.460"/>
|
||||
<Path Data=" M 0.000,0.000 L 1024.000,0.000 L 1024.000,1024.000 L 0.000,1024.000 L 0.000,0.000 Z"/>
|
||||
</Canvas>
|
||||
</Canvas>
|
||||
</Viewbox>
|
BIN
SafeExamBrowser.UserInterface.Desktop/Images/SplashScreen.png
Normal file
BIN
SafeExamBrowser.UserInterface.Desktop/Images/SplashScreen.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 39 KiB |
16
SafeExamBrowser.UserInterface.Desktop/Images/WiFi_0.xaml
Normal file
16
SafeExamBrowser.UserInterface.Desktop/Images/WiFi_0.xaml
Normal file
@@ -0,0 +1,16 @@
|
||||
<Viewbox
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Canvas Width="1024.000" Height="1024.000">
|
||||
<Canvas>
|
||||
<Path Data=" M 0.000,0.000 L 1024.000,0.000 L 1024.000,1024.000 L 0.000,1024.000 L 0.000,0.000 Z"/>
|
||||
<Path StrokeThickness="1.0" Stroke="#ffaaaaaa" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Fill="#ffaaaaaa" Data=" M 467.000,811.000 C 467.000,786.150 487.150,766.000 512.000,766.000 C 536.850,766.000 557.000,786.150 557.000,811.000 C 557.000,835.850 536.850,856.000 512.000,856.000 C 487.150,856.000 467.000,835.850 467.000,811.000 Z"/>
|
||||
<Path StrokeThickness="35.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 82.530,352.000 C 191.500,240.330 343.650,171.000 512.000,171.000 C 680.350,171.000 832.500,240.330 941.470,352.000"/>
|
||||
<Path StrokeThickness="70.0" Stroke="#ffaaaaaa" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 82.530,352.000 C 191.500,240.330 343.650,171.000 512.000,171.000 C 680.350,171.000 832.500,240.330 941.470,352.000"/>
|
||||
<Path StrokeThickness="35.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 346.620,660.000 C 384.600,610.220 444.550,578.100 512.000,578.100 C 579.900,578.100 640.200,610.650 678.140,661.000"/>
|
||||
<Path StrokeThickness="70.0" Stroke="#ffaaaaaa" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 346.620,660.000 C 384.600,610.220 444.550,578.100 512.000,578.100 C 579.900,578.100 640.200,610.650 678.140,661.000"/>
|
||||
<Path StrokeThickness="35.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 213.050,505.000 C 288.650,426.810 394.650,378.200 512.000,378.200 C 629.350,378.200 735.350,426.810 810.950,505.000"/>
|
||||
<Path StrokeThickness="70.0" Stroke="#ffaaaaaa" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 213.050,505.000 C 288.650,426.810 394.650,378.200 512.000,378.200 C 629.350,378.200 735.350,426.810 810.950,505.000"/>
|
||||
</Canvas>
|
||||
</Canvas>
|
||||
</Viewbox>
|
16
SafeExamBrowser.UserInterface.Desktop/Images/WiFi_100.xaml
Normal file
16
SafeExamBrowser.UserInterface.Desktop/Images/WiFi_100.xaml
Normal file
@@ -0,0 +1,16 @@
|
||||
<Viewbox
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Canvas Width="1024.000" Height="1024.000">
|
||||
<Canvas>
|
||||
<Path Data=" M 0.000,0.000 L 1024.000,0.000 L 1024.000,1024.000 L 0.000,1024.000 L 0.000,0.000 Z"/>
|
||||
<Path StrokeThickness="1.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Fill="#ff000000" Data=" M 467.000,811.000 C 467.000,786.150 487.150,766.000 512.000,766.000 C 536.850,766.000 557.000,786.150 557.000,811.000 C 557.000,835.850 536.850,856.000 512.000,856.000 C 487.150,856.000 467.000,835.850 467.000,811.000 Z"/>
|
||||
<Path StrokeThickness="35.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 82.530,352.000 C 191.500,240.330 343.650,171.000 512.000,171.000 C 680.350,171.000 832.500,240.330 941.470,352.000"/>
|
||||
<Path StrokeThickness="70.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 82.530,352.000 C 191.500,240.330 343.650,171.000 512.000,171.000 C 680.350,171.000 832.500,240.330 941.470,352.000"/>
|
||||
<Path StrokeThickness="35.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 346.620,660.000 C 384.600,610.221 444.550,578.100 512.000,578.100 C 579.900,578.100 640.200,610.650 678.140,661.000"/>
|
||||
<Path StrokeThickness="70.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 346.620,660.000 C 384.600,610.221 444.550,578.100 512.000,578.100 C 579.900,578.100 640.200,610.650 678.140,661.000"/>
|
||||
<Path StrokeThickness="35.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 213.050,505.000 C 288.650,426.810 394.650,378.200 512.000,378.200 C 629.350,378.200 735.350,426.810 810.950,505.000"/>
|
||||
<Path StrokeThickness="70.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 213.050,505.000 C 288.650,426.810 394.650,378.200 512.000,378.200 C 629.350,378.200 735.350,426.810 810.950,505.000"/>
|
||||
</Canvas>
|
||||
</Canvas>
|
||||
</Viewbox>
|
16
SafeExamBrowser.UserInterface.Desktop/Images/WiFi_33.xaml
Normal file
16
SafeExamBrowser.UserInterface.Desktop/Images/WiFi_33.xaml
Normal file
@@ -0,0 +1,16 @@
|
||||
<Viewbox
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Canvas Width="1024.000" Height="1024.000">
|
||||
<Canvas>
|
||||
<Path Data=" M 0.000,0.000 L 1024.000,0.000 L 1024.000,1024.000 L 0.000,1024.000 L 0.000,0.000 Z"/>
|
||||
<Path StrokeThickness="1.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Fill="#ff000000" Data=" M 467.000,811.000 C 467.000,786.150 487.150,766.000 512.000,766.000 C 536.850,766.000 557.000,786.150 557.000,811.000 C 557.000,835.850 536.850,856.000 512.000,856.000 C 487.150,856.000 467.000,835.850 467.000,811.000 Z"/>
|
||||
<Path StrokeThickness="35.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 82.530,352.000 C 191.500,240.330 343.650,171.000 512.000,171.000 C 680.350,171.000 832.500,240.330 941.470,352.000"/>
|
||||
<Path StrokeThickness="70.0" Stroke="#ffaaaaaa" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 82.530,352.000 C 191.500,240.330 343.650,171.000 512.000,171.000 C 680.350,171.000 832.500,240.330 941.470,352.000"/>
|
||||
<Path StrokeThickness="35.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 346.620,660.000 C 384.600,610.220 444.550,578.100 512.000,578.100 C 579.900,578.100 640.200,610.650 678.140,661.000"/>
|
||||
<Path StrokeThickness="70.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 346.620,660.000 C 384.600,610.220 444.550,578.100 512.000,578.100 C 579.900,578.100 640.200,610.650 678.140,661.000"/>
|
||||
<Path StrokeThickness="35.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 213.050,505.000 C 288.650,426.810 394.650,378.200 512.000,378.200 C 629.350,378.200 735.350,426.810 810.950,505.000"/>
|
||||
<Path StrokeThickness="70.0" Stroke="#ffaaaaaa" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 213.050,505.000 C 288.650,426.810 394.650,378.200 512.000,378.200 C 629.350,378.200 735.350,426.810 810.950,505.000"/>
|
||||
</Canvas>
|
||||
</Canvas>
|
||||
</Viewbox>
|
16
SafeExamBrowser.UserInterface.Desktop/Images/WiFi_66.xaml
Normal file
16
SafeExamBrowser.UserInterface.Desktop/Images/WiFi_66.xaml
Normal file
@@ -0,0 +1,16 @@
|
||||
<Viewbox
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Canvas Width="1024.000" Height="1024.000">
|
||||
<Canvas>
|
||||
<Path Data=" M 0.000,0.000 L 1024.000,0.000 L 1024.000,1024.000 L 0.000,1024.000 L 0.000,0.000 Z"/>
|
||||
<Path StrokeThickness="1.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Fill="#ff000000" Data=" M 467.000,811.000 C 467.000,786.150 487.150,766.000 512.000,766.000 C 536.850,766.000 557.000,786.150 557.000,811.000 C 557.000,835.850 536.850,856.000 512.000,856.000 C 487.150,856.000 467.000,835.850 467.000,811.000 Z"/>
|
||||
<Path StrokeThickness="35.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 82.530,352.000 C 191.500,240.330 343.650,171.000 512.000,171.000 C 680.350,171.000 832.500,240.330 941.470,352.000"/>
|
||||
<Path StrokeThickness="70.0" Stroke="#ffaaaaaa" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 82.530,352.000 C 191.500,240.330 343.650,171.000 512.000,171.000 C 680.350,171.000 832.500,240.330 941.470,352.000"/>
|
||||
<Path StrokeThickness="35.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 346.620,660.000 C 384.600,610.220 444.550,578.100 512.000,578.100 C 579.900,578.100 640.200,610.650 678.140,661.000"/>
|
||||
<Path StrokeThickness="70.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 346.620,660.000 C 384.600,610.220 444.550,578.100 512.000,578.100 C 579.900,578.100 640.200,610.650 678.140,661.000"/>
|
||||
<Path StrokeThickness="35.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 213.050,505.000 C 288.650,426.810 394.650,378.200 512.000,378.200 C 629.350,378.200 735.350,426.810 810.950,505.000"/>
|
||||
<Path StrokeThickness="70.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 213.050,505.000 C 288.650,426.810 394.650,378.200 512.000,378.200 C 629.350,378.200 735.350,426.810 810.950,505.000"/>
|
||||
</Canvas>
|
||||
</Canvas>
|
||||
</Viewbox>
|
@@ -0,0 +1,16 @@
|
||||
<Viewbox
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Canvas Width="1024.000" Height="1024.000">
|
||||
<Canvas>
|
||||
<Path Data=" M 0.000,0.000 L 1024.000,0.000 L 1024.000,1024.000 L 0.000,1024.000 L 0.000,0.000 Z"/>
|
||||
<Path StrokeThickness="1.0" Stroke="#ffdddddd" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Fill="#ffdddddd" Data=" M 467.000,811.000 C 467.000,786.150 487.150,766.000 512.000,766.000 C 536.850,766.000 557.000,786.150 557.000,811.000 C 557.000,835.850 536.850,856.000 512.000,856.000 C 487.150,856.000 467.000,835.850 467.000,811.000 Z"/>
|
||||
<Path StrokeThickness="35.0" Stroke="#ffdddddd" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 82.530,352.000 C 191.500,240.330 343.650,171.000 512.000,171.000 C 680.350,171.000 832.500,240.330 941.470,352.000"/>
|
||||
<Path StrokeThickness="70.0" Stroke="#ffdddddd" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 82.530,352.000 C 191.500,240.330 343.650,171.000 512.000,171.000 C 680.350,171.000 832.500,240.330 941.470,352.000"/>
|
||||
<Path StrokeThickness="35.0" Stroke="#ffdddddd" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 346.620,660.000 C 384.600,610.220 444.550,578.100 512.000,578.100 C 579.900,578.100 640.200,610.650 678.140,661.000"/>
|
||||
<Path StrokeThickness="70.0" Stroke="#ffdddddd" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 346.620,660.000 C 384.600,610.220 444.550,578.100 512.000,578.100 C 579.900,578.100 640.200,610.650 678.140,661.000"/>
|
||||
<Path StrokeThickness="35.0" Stroke="#ffdddddd" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 213.050,505.000 C 288.650,426.810 394.650,378.200 512.000,378.200 C 629.350,378.200 735.350,426.810 810.950,505.000"/>
|
||||
<Path StrokeThickness="70.0" Stroke="#ffdddddd" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 213.050,505.000 C 288.650,426.810 394.650,378.200 512.000,378.200 C 629.350,378.200 735.350,426.810 810.950,505.000"/>
|
||||
</Canvas>
|
||||
</Canvas>
|
||||
</Viewbox>
|
@@ -0,0 +1,16 @@
|
||||
<Viewbox
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Canvas Width="1024.000" Height="1024.000">
|
||||
<Canvas>
|
||||
<Path Data=" M 0.000,0.000 L 1024.000,0.000 L 1024.000,1024.000 L 0.000,1024.000 L 0.000,0.000 Z"/>
|
||||
<Path StrokeThickness="1.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Fill="#ff000000" Data=" M 467.000,811.000 C 467.000,786.150 487.150,766.000 512.000,766.000 C 536.850,766.000 557.000,786.150 557.000,811.000 C 557.000,835.850 536.850,856.000 512.000,856.000 C 487.150,856.000 467.000,835.850 467.000,811.000 Z"/>
|
||||
<Path StrokeThickness="35.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 82.530,352.000 C 191.500,240.330 343.650,171.000 512.000,171.000 C 680.350,171.000 832.500,240.330 941.470,352.000"/>
|
||||
<Path StrokeThickness="70.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 82.530,352.000 C 191.500,240.330 343.650,171.000 512.000,171.000 C 680.350,171.000 832.500,240.330 941.470,352.000"/>
|
||||
<Path StrokeThickness="35.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 346.620,660.000 C 384.600,610.221 444.550,578.100 512.000,578.100 C 579.900,578.100 640.200,610.650 678.140,661.000"/>
|
||||
<Path StrokeThickness="70.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 346.620,660.000 C 384.600,610.221 444.550,578.100 512.000,578.100 C 579.900,578.100 640.200,610.650 678.140,661.000"/>
|
||||
<Path StrokeThickness="35.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 213.050,505.000 C 288.650,426.810 394.650,378.200 512.000,378.200 C 629.350,378.200 735.350,426.810 810.950,505.000"/>
|
||||
<Path StrokeThickness="70.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 213.050,505.000 C 288.650,426.810 394.650,378.200 512.000,378.200 C 629.350,378.200 735.350,426.810 810.950,505.000"/>
|
||||
</Canvas>
|
||||
</Canvas>
|
||||
</Viewbox>
|
@@ -0,0 +1,16 @@
|
||||
<Viewbox
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Canvas Width="1024.000" Height="1024.000">
|
||||
<Canvas>
|
||||
<Path Data=" M 0.000,0.000 L 1024.000,0.000 L 1024.000,1024.000 L 0.000,1024.000 L 0.000,0.000 Z"/>
|
||||
<Path StrokeThickness="1.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Fill="#ff000000" Data=" M 467.000,811.000 C 467.000,786.150 487.150,766.000 512.000,766.000 C 536.850,766.000 557.000,786.150 557.000,811.000 C 557.000,835.850 536.850,856.000 512.000,856.000 C 487.150,856.000 467.000,835.850 467.000,811.000 Z"/>
|
||||
<Path StrokeThickness="35.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 82.530,352.000 C 191.500,240.330 343.650,171.000 512.000,171.000 C 680.350,171.000 832.500,240.330 941.470,352.000"/>
|
||||
<Path StrokeThickness="70.0" Stroke="#ffdddddd" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 82.530,352.000 C 191.500,240.330 343.650,171.000 512.000,171.000 C 680.350,171.000 832.500,240.330 941.470,352.000"/>
|
||||
<Path StrokeThickness="35.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 346.620,660.000 C 384.600,610.220 444.550,578.100 512.000,578.100 C 579.900,578.100 640.200,610.650 678.140,661.000"/>
|
||||
<Path StrokeThickness="70.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 346.620,660.000 C 384.600,610.220 444.550,578.100 512.000,578.100 C 579.900,578.100 640.200,610.650 678.140,661.000"/>
|
||||
<Path StrokeThickness="35.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 213.050,505.000 C 288.650,426.810 394.650,378.200 512.000,378.200 C 629.350,378.200 735.350,426.810 810.950,505.000"/>
|
||||
<Path StrokeThickness="70.0" Stroke="#ffdddddd" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 213.050,505.000 C 288.650,426.810 394.650,378.200 512.000,378.200 C 629.350,378.200 735.350,426.810 810.950,505.000"/>
|
||||
</Canvas>
|
||||
</Canvas>
|
||||
</Viewbox>
|
@@ -0,0 +1,16 @@
|
||||
<Viewbox
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Canvas Width="1024.000" Height="1024.000">
|
||||
<Canvas>
|
||||
<Path Data=" M 0.000,0.000 L 1024.000,0.000 L 1024.000,1024.000 L 0.000,1024.000 L 0.000,0.000 Z"/>
|
||||
<Path StrokeThickness="1.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Fill="#ff000000" Data=" M 467.000,811.000 C 467.000,786.150 487.150,766.000 512.000,766.000 C 536.850,766.000 557.000,786.150 557.000,811.000 C 557.000,835.850 536.850,856.000 512.000,856.000 C 487.150,856.000 467.000,835.850 467.000,811.000 Z"/>
|
||||
<Path StrokeThickness="35.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 82.530,352.000 C 191.500,240.330 343.650,171.000 512.000,171.000 C 680.350,171.000 832.500,240.330 941.470,352.000"/>
|
||||
<Path StrokeThickness="70.0" Stroke="#ffdddddd" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 82.530,352.000 C 191.500,240.330 343.650,171.000 512.000,171.000 C 680.350,171.000 832.500,240.330 941.470,352.000"/>
|
||||
<Path StrokeThickness="35.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 346.620,660.000 C 384.600,610.220 444.550,578.100 512.000,578.100 C 579.900,578.100 640.200,610.650 678.140,661.000"/>
|
||||
<Path StrokeThickness="70.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 346.620,660.000 C 384.600,610.220 444.550,578.100 512.000,578.100 C 579.900,578.100 640.200,610.650 678.140,661.000"/>
|
||||
<Path StrokeThickness="35.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 213.050,505.000 C 288.650,426.810 394.650,378.200 512.000,378.200 C 629.350,378.200 735.350,426.810 810.950,505.000"/>
|
||||
<Path StrokeThickness="70.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 213.050,505.000 C 288.650,426.810 394.650,378.200 512.000,378.200 C 629.350,378.200 735.350,426.810 810.950,505.000"/>
|
||||
</Canvas>
|
||||
</Canvas>
|
||||
</Viewbox>
|
12
SafeExamBrowser.UserInterface.Desktop/Images/ZoomPageIn.xaml
Normal file
12
SafeExamBrowser.UserInterface.Desktop/Images/ZoomPageIn.xaml
Normal file
@@ -0,0 +1,12 @@
|
||||
<Viewbox
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Canvas Width="40.000" Height="40.000">
|
||||
<Canvas>
|
||||
<Path Data="F1 M 32.000,36.000 L 9.000,36.000 L 9.000,5.000 L 32.000,5.000 L 32.000,36.000 Z"/>
|
||||
</Canvas>
|
||||
<Canvas>
|
||||
<Path StrokeThickness="1.9" Stroke="#ff666666" StrokeLineJoin="Round" Data="F1 M 31.258,13.484 L 23.773,6.000 M 31.258,35.000 L 9.742,35.000 L 9.742,6.001 L 23.773,6.001 L 23.773,13.485 L 31.258,13.484 L 31.258,35.000 Z"/>
|
||||
</Canvas>
|
||||
</Canvas>
|
||||
</Viewbox>
|
@@ -0,0 +1,12 @@
|
||||
<Viewbox
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Canvas Width="40.000" Height="40.000">
|
||||
<Canvas>
|
||||
<Path Data="F1 M 32.000,36.000 L 9.000,36.000 L 9.000,5.000 L 32.000,5.000 L 32.000,36.000 Z"/>
|
||||
</Canvas>
|
||||
<Canvas>
|
||||
<Path StrokeThickness="2.0" Stroke="#ff666666" StrokeLineJoin="Round" Data="F1 M 27.000,14.870 L 22.129,10.000 M 27.000,28.869 L 13.000,28.869 L 13.000,10.000 L 22.129,10.000 L 22.129,14.870 L 27.000,14.870 L 27.000,28.869 Z"/>
|
||||
</Canvas>
|
||||
</Canvas>
|
||||
</Viewbox>
|
92
SafeExamBrowser.UserInterface.Desktop/MessageBoxFactory.cs
Normal file
92
SafeExamBrowser.UserInterface.Desktop/MessageBoxFactory.cs
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System.Windows;
|
||||
using SafeExamBrowser.I18n.Contracts;
|
||||
using SafeExamBrowser.UserInterface.Contracts.MessageBox;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Windows;
|
||||
using MessageBoxResult = SafeExamBrowser.UserInterface.Contracts.MessageBox.MessageBoxResult;
|
||||
|
||||
namespace SafeExamBrowser.UserInterface.Desktop
|
||||
{
|
||||
public class MessageBoxFactory : IMessageBox
|
||||
{
|
||||
private IText text;
|
||||
|
||||
public MessageBoxFactory(IText text)
|
||||
{
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public MessageBoxResult Show(string message, string title, MessageBoxAction action = MessageBoxAction.Ok, MessageBoxIcon icon = MessageBoxIcon.Information, IWindow parent = null)
|
||||
{
|
||||
var result = default(System.Windows.MessageBoxResult);
|
||||
|
||||
if (parent is Window window)
|
||||
{
|
||||
result = window.Dispatcher.Invoke(() => MessageBox.Show(window, message, title, ToButton(action), ToImage(icon)));
|
||||
}
|
||||
else
|
||||
{
|
||||
result = MessageBox.Show(message, title, ToButton(action), ToImage(icon));
|
||||
}
|
||||
|
||||
return ToResult(result);
|
||||
}
|
||||
|
||||
public MessageBoxResult Show(TextKey message, TextKey title, MessageBoxAction action = MessageBoxAction.Ok, MessageBoxIcon icon = MessageBoxIcon.Information, IWindow parent = null)
|
||||
{
|
||||
return Show(text.Get(message), text.Get(title), action, icon, parent);
|
||||
}
|
||||
|
||||
private MessageBoxButton ToButton(MessageBoxAction action)
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
case MessageBoxAction.OkCancel:
|
||||
return MessageBoxButton.OKCancel;
|
||||
case MessageBoxAction.YesNo:
|
||||
return MessageBoxButton.YesNo;
|
||||
default:
|
||||
return MessageBoxButton.OK;
|
||||
}
|
||||
}
|
||||
|
||||
private MessageBoxImage ToImage(MessageBoxIcon icon)
|
||||
{
|
||||
switch (icon)
|
||||
{
|
||||
case MessageBoxIcon.Error:
|
||||
return MessageBoxImage.Error;
|
||||
case MessageBoxIcon.Question:
|
||||
return MessageBoxImage.Question;
|
||||
case MessageBoxIcon.Warning:
|
||||
return MessageBoxImage.Warning;
|
||||
default:
|
||||
return MessageBoxImage.Information;
|
||||
}
|
||||
}
|
||||
|
||||
private MessageBoxResult ToResult(System.Windows.MessageBoxResult result)
|
||||
{
|
||||
switch (result)
|
||||
{
|
||||
case System.Windows.MessageBoxResult.Cancel:
|
||||
return MessageBoxResult.Cancel;
|
||||
case System.Windows.MessageBoxResult.No:
|
||||
return MessageBoxResult.No;
|
||||
case System.Windows.MessageBoxResult.OK:
|
||||
return MessageBoxResult.Ok;
|
||||
case System.Windows.MessageBoxResult.Yes:
|
||||
return MessageBoxResult.Yes;
|
||||
default:
|
||||
return MessageBoxResult.None;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,51 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("SafeExamBrowser.UserInterface.Desktop")]
|
||||
[assembly: AssemblyDescription("Safe Exam Browser")]
|
||||
[assembly: AssemblyCompany("ETH Zürich")]
|
||||
[assembly: AssemblyProduct("SafeExamBrowser.UserInterface.Desktop")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2024 ETH Zürich, IT Services")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
//In order to begin building localizable applications, set
|
||||
//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
|
||||
//inside a <PropertyGroup>. For example, if you are using US english
|
||||
//in your source files, set the <UICulture> to en-US. Then uncomment
|
||||
//the NeutralResourceLanguage attribute below. Update the "en-US" in
|
||||
//the line below to match the UICulture setting in the project file.
|
||||
|
||||
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
|
||||
|
||||
|
||||
[assembly: ThemeInfo(
|
||||
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
|
||||
//(used if a resource is not found in the page,
|
||||
// or application resource dictionaries)
|
||||
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
|
||||
//(used if a resource is not found in the page,
|
||||
// app, or any theme specific resource dictionaries)
|
||||
)]
|
||||
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("3.8.0.742")]
|
||||
[assembly: AssemblyFileVersion("3.8.0.742")]
|
||||
[assembly: AssemblyInformationalVersion("1.0.0.0")]
|
@@ -0,0 +1,589 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{A502DF54-7169-4647-94BD-18B192924866}</ProjectGuid>
|
||||
<OutputType>library</OutputType>
|
||||
<RootNamespace>SafeExamBrowser.UserInterface.Desktop</RootNamespace>
|
||||
<AssemblyName>SafeExamBrowser.UserInterface.Desktop</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\x86\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
|
||||
<OutputPath>bin\x86\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\x64\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||
<OutputPath>bin\x64\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="FontAwesome.WPF, Version=4.7.0.37774, Culture=neutral, PublicKeyToken=0758b07a11a4f466, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\FontAwesome.WPF.4.7.0.9\lib\net40\FontAwesome.WPF.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.Xaml">
|
||||
<RequiredTargetFramework>4.0</RequiredTargetFramework>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="WindowsBase" />
|
||||
<Reference Include="PresentationCore" />
|
||||
<Reference Include="PresentationFramework" />
|
||||
<Reference Include="WindowsFormsIntegration" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Controls\ActionCenter\RaiseHandControl.xaml.cs">
|
||||
<DependentUpon>RaiseHandControl.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Controls\Taskbar\RaiseHandControl.xaml.cs">
|
||||
<DependentUpon>RaiseHandControl.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Windows\AboutWindow.xaml.cs">
|
||||
<DependentUpon>AboutWindow.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Windows\ActionCenter.xaml.cs">
|
||||
<DependentUpon>ActionCenter.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Windows\BrowserWindow.xaml.cs">
|
||||
<DependentUpon>BrowserWindow.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Controls\ActionCenter\ApplicationControl.xaml.cs">
|
||||
<DependentUpon>ApplicationControl.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Controls\ActionCenter\ApplicationButton.xaml.cs">
|
||||
<DependentUpon>ApplicationButton.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Controls\ActionCenter\AudioControl.xaml.cs">
|
||||
<DependentUpon>AudioControl.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Controls\ActionCenter\Clock.xaml.cs">
|
||||
<DependentUpon>Clock.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Controls\ActionCenter\KeyboardLayoutButton.xaml.cs">
|
||||
<DependentUpon>KeyboardLayoutButton.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Controls\ActionCenter\KeyboardLayoutControl.xaml.cs">
|
||||
<DependentUpon>KeyboardLayoutControl.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Controls\ActionCenter\NotificationButton.xaml.cs">
|
||||
<DependentUpon>NotificationButton.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Controls\ActionCenter\PowerSupplyControl.xaml.cs">
|
||||
<DependentUpon>PowerSupplyControl.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Controls\ActionCenter\QuitButton.xaml.cs">
|
||||
<DependentUpon>QuitButton.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Controls\ActionCenter\NetworkButton.xaml.cs">
|
||||
<DependentUpon>NetworkButton.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Controls\ActionCenter\NetworkControl.xaml.cs">
|
||||
<DependentUpon>NetworkControl.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Controls\Browser\DownloadItemControl.xaml.cs">
|
||||
<DependentUpon>DownloadItemControl.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Controls\Taskbar\ApplicationControl.xaml.cs">
|
||||
<DependentUpon>ApplicationControl.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Controls\Taskbar\ApplicationWindowButton.xaml.cs">
|
||||
<DependentUpon>ApplicationWindowButton.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Controls\Taskbar\AudioControl.xaml.cs">
|
||||
<DependentUpon>AudioControl.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Controls\Taskbar\Clock.xaml.cs">
|
||||
<DependentUpon>Clock.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Controls\Taskbar\KeyboardLayoutButton.xaml.cs">
|
||||
<DependentUpon>KeyboardLayoutButton.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Controls\Taskbar\KeyboardLayoutControl.xaml.cs">
|
||||
<DependentUpon>KeyboardLayoutControl.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Controls\Taskbar\NotificationButton.xaml.cs">
|
||||
<DependentUpon>NotificationButton.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Controls\Taskbar\PowerSupplyControl.xaml.cs">
|
||||
<DependentUpon>PowerSupplyControl.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Controls\Taskbar\QuitButton.xaml.cs">
|
||||
<DependentUpon>QuitButton.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Controls\Taskbar\NetworkButton.xaml.cs">
|
||||
<DependentUpon>NetworkButton.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Controls\Taskbar\NetworkControl.xaml.cs">
|
||||
<DependentUpon>NetworkControl.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Controls\Taskview\WindowControl.xaml.cs">
|
||||
<DependentUpon>WindowControl.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Windows\ExamSelectionDialog.xaml.cs">
|
||||
<DependentUpon>ExamSelectionDialog.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Windows\FileSystemDialog.xaml.cs">
|
||||
<DependentUpon>FileSystemDialog.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="FileSystemDialogFactory.cs" />
|
||||
<Compile Include="Windows\LockScreen.xaml.cs">
|
||||
<DependentUpon>LockScreen.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Windows\LogWindow.xaml.cs">
|
||||
<DependentUpon>LogWindow.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="MessageBoxFactory.cs" />
|
||||
<Compile Include="Windows\CredentialsDialog.xaml.cs">
|
||||
<DependentUpon>CredentialsDialog.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Windows\PasswordDialog.xaml.cs">
|
||||
<DependentUpon>PasswordDialog.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Windows\ProctoringFinalizationDialog.xaml.cs">
|
||||
<DependentUpon>ProctoringFinalizationDialog.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Windows\ProctoringWindow.xaml.cs">
|
||||
<DependentUpon>ProctoringWindow.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Windows\RuntimeWindow.xaml.cs">
|
||||
<DependentUpon>RuntimeWindow.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Windows\ServerFailureDialog.xaml.cs">
|
||||
<DependentUpon>ServerFailureDialog.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Windows\SplashScreen.xaml.cs">
|
||||
<DependentUpon>SplashScreen.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Windows\Taskview.xaml.cs">
|
||||
<DependentUpon>Taskview.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="UserInterfaceFactory.cs" />
|
||||
<Compile Include="ViewModels\DateTimeViewModel.cs" />
|
||||
<Compile Include="ViewModels\LogViewModel.cs" />
|
||||
<Compile Include="ViewModels\ProgressIndicatorViewModel.cs" />
|
||||
<Compile Include="ViewModels\RuntimeWindowViewModel.cs" />
|
||||
<Resource Include="Images\Proctoring_Inactive.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Resource>
|
||||
<Resource Include="Images\Proctoring_Active.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Resource>
|
||||
<Page Include="Controls\ActionCenter\RaiseHandControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="Controls\Taskbar\RaiseHandControl.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Resource Include="Images\Hand_Lowered.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Resource>
|
||||
<Resource Include="Images\Hand_Raised.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Resource>
|
||||
<Resource Include="Images\ScreenProctoring_Inactive.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Resource>
|
||||
<Resource Include="Images\ScreenProctoring_Active.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Resource>
|
||||
<Page Include="Windows\AboutWindow.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Windows\ActionCenter.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Windows\BrowserWindow.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Controls\ActionCenter\ApplicationControl.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Controls\ActionCenter\ApplicationButton.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Controls\ActionCenter\AudioControl.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Controls\ActionCenter\Clock.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Controls\ActionCenter\KeyboardLayoutButton.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Controls\ActionCenter\KeyboardLayoutControl.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Controls\ActionCenter\NotificationButton.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Controls\ActionCenter\PowerSupplyControl.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Controls\ActionCenter\QuitButton.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Controls\ActionCenter\NetworkButton.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Controls\ActionCenter\NetworkControl.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Controls\Browser\DownloadItemControl.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Controls\Taskbar\ApplicationControl.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Controls\Taskbar\ApplicationWindowButton.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Controls\Taskbar\AudioControl.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Controls\Taskbar\Clock.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Controls\Taskbar\KeyboardLayoutButton.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Controls\Taskbar\KeyboardLayoutControl.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Controls\Taskbar\NotificationButton.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Controls\Taskbar\PowerSupplyControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="Controls\Taskbar\QuitButton.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Resource Include="Images\Menu.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Resource>
|
||||
<Resource Include="Images\WiFi_Light_66.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Resource>
|
||||
<Resource Include="Images\WiFi_Light_33.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Resource>
|
||||
<Resource Include="Images\WiFi_Light_100.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Resource>
|
||||
<Resource Include="Images\WiFi_Light_0.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Resource>
|
||||
<Resource Include="Images\Audio_NoDevice.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Resource>
|
||||
<Resource Include="Images\Audio_66.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Resource>
|
||||
<Resource Include="Images\Audio_33.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Resource>
|
||||
<Resource Include="Images\Audio_100.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Resource>
|
||||
<Resource Include="Images\Audio_Muted.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Resource>
|
||||
<Resource Include="Images\Audio_Light_66.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Resource>
|
||||
<Resource Include="Images\Audio_Light_33.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Resource>
|
||||
<Resource Include="Images\Audio_Light_100.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Resource>
|
||||
<Resource Include="Images\Audio_Light_NoDevice.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Resource>
|
||||
<Page Include="Controls\Taskview\WindowControl.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Windows\ExamSelectionDialog.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Windows\FileSystemDialog.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Windows\LockScreen.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Windows\CredentialsDialog.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Windows\ProctoringFinalizationDialog.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Windows\ProctoringWindow.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Windows\ServerFailureDialog.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Windows\Taskview.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Templates\ScrollViewers.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Resource Include="Images\Battery.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Resource>
|
||||
<Resource Include="Images\Keyboard.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Resource>
|
||||
<Resource Include="Images\NavigateBack.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Resource>
|
||||
<Resource Include="Images\NavigateForward.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Resource>
|
||||
<Resource Include="Images\Reload.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Resource>
|
||||
<Resource Include="Images\ShutDown.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Resource>
|
||||
<Resource Include="Images\Home.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Resource>
|
||||
<Resource Include="Images\WiFi_0.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Resource>
|
||||
<Resource Include="Images\WiFi_100.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Resource>
|
||||
<Resource Include="Images\WiFi_33.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Resource>
|
||||
<Resource Include="Images\WiFi_66.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Resource>
|
||||
<Resource Include="Images\ZoomPageIn.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Resource>
|
||||
<Resource Include="Images\ZoomPageOut.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Resource>
|
||||
<Page Include="Controls\Taskbar\NetworkButton.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Controls\Taskbar\NetworkControl.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Resource Include="Images\AboutNotification.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Resource>
|
||||
<Page Include="Windows\LogWindow.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Windows\PasswordDialog.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Windows\RuntimeWindow.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Windows\SplashScreen.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Windows\Taskbar.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Compile Include="Windows\Taskbar.xaml.cs">
|
||||
<DependentUpon>Taskbar.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Page Include="Templates\Buttons.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Templates\Colors.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Properties\AssemblyInfo.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<None Include="app.config" />
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\SafeExamBrowser.Applications.Contracts\SafeExamBrowser.Applications.Contracts.csproj">
|
||||
<Project>{ac77745d-3b41-43e2-8e84-d40e5a4ee77f}</Project>
|
||||
<Name>SafeExamBrowser.Applications.Contracts</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\SafeExamBrowser.Browser.Contracts\SafeExamBrowser.Browser.Contracts.csproj">
|
||||
<Project>{5fb5273d-277c-41dd-8593-a25ce1aff2e9}</Project>
|
||||
<Name>SafeExamBrowser.Browser.Contracts</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\SafeExamBrowser.Configuration.Contracts\SafeExamBrowser.Configuration.Contracts.csproj">
|
||||
<Project>{7d74555e-63e1-4c46-bd0a-8580552368c8}</Project>
|
||||
<Name>SafeExamBrowser.Configuration.Contracts</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\SafeExamBrowser.Core.Contracts\SafeExamBrowser.Core.Contracts.csproj">
|
||||
<Project>{fe0e1224-b447-4b14-81e7-ed7d84822aa0}</Project>
|
||||
<Name>SafeExamBrowser.Core.Contracts</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\SafeExamBrowser.I18n.Contracts\SafeExamBrowser.I18n.Contracts.csproj">
|
||||
<Project>{1858ddf3-bc2a-4bff-b663-4ce2ffeb8b7d}</Project>
|
||||
<Name>SafeExamBrowser.I18n.Contracts</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\SafeExamBrowser.Logging.Contracts\SafeExamBrowser.Logging.Contracts.csproj">
|
||||
<Project>{64ea30fb-11d4-436a-9c2b-88566285363e}</Project>
|
||||
<Name>SafeExamBrowser.Logging.Contracts</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\SafeExamBrowser.Proctoring.Contracts\SafeExamBrowser.Proctoring.Contracts.csproj">
|
||||
<Project>{8e52bd1c-0540-4f16-b181-6665d43f7a7b}</Project>
|
||||
<Name>SafeExamBrowser.Proctoring.Contracts</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\SafeExamBrowser.Server.Contracts\SafeExamBrowser.Server.Contracts.csproj">
|
||||
<Project>{DB701E6F-BDDC-4CEC-B662-335A9DC11809}</Project>
|
||||
<Name>SafeExamBrowser.Server.Contracts</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\SafeExamBrowser.Settings\SafeExamBrowser.Settings.csproj">
|
||||
<Project>{30b2d907-5861-4f39-abad-c4abf1b3470e}</Project>
|
||||
<Name>SafeExamBrowser.Settings</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\SafeExamBrowser.SystemComponents.Contracts\SafeExamBrowser.SystemComponents.Contracts.csproj">
|
||||
<Project>{903129c6-e236-493b-9ad6-c6a57f647a3a}</Project>
|
||||
<Name>SafeExamBrowser.SystemComponents.Contracts</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\SafeExamBrowser.UserInterface.Contracts\SafeExamBrowser.UserInterface.Contracts.csproj">
|
||||
<Project>{c7889e97-6ff6-4a58-b7cb-521ed276b316}</Project>
|
||||
<Name>SafeExamBrowser.UserInterface.Contracts</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\SafeExamBrowser.UserInterface.Shared\SafeExamBrowser.UserInterface.Shared.csproj">
|
||||
<Project>{38525928-87ba-4f8c-8010-4eb97bfaae13}</Project>
|
||||
<Name>SafeExamBrowser.UserInterface.Shared</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Images\LogNotification.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Images\SafeExamBrowser.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Images\SplashScreen.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
61
SafeExamBrowser.UserInterface.Desktop/Templates/Buttons.xaml
Normal file
61
SafeExamBrowser.UserInterface.Desktop/Templates/Buttons.xaml
Normal file
@@ -0,0 +1,61 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="../Templates/Colors.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
<ControlTemplate x:Key="ActionCenterButton" TargetType="Button">
|
||||
<Border x:Name="ButtonContent" Background="Transparent" BorderBrush="Transparent" BorderThickness="1" Cursor="Hand" Padding="{TemplateBinding Padding}">
|
||||
<ContentPresenter ContentSource="Content" HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
|
||||
RenderOptions.BitmapScalingMode="HighQuality" VerticalAlignment="{TemplateBinding VerticalAlignment}" />
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter TargetName="ButtonContent" Property="Background" Value="#AAADD8E6" />
|
||||
<Setter TargetName="ButtonContent" Property="BorderBrush" Value="DodgerBlue" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter TargetName="ButtonContent" Property="BorderBrush" Value="#AA87CEEB" />
|
||||
<Setter TargetName="ButtonContent" Property="BorderThickness" Value="2" />
|
||||
<Setter Property="Cursor" Value="Hand" />
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
<ControlTemplate x:Key="BrowserButton" TargetType="Button">
|
||||
<Border x:Name="ButtonContent" Background="Transparent" BorderBrush="Transparent" BorderThickness="1" Cursor="Hand" Padding="{TemplateBinding Padding}">
|
||||
<ContentPresenter ContentSource="Content" HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
|
||||
RenderOptions.BitmapScalingMode="HighQuality" VerticalAlignment="{TemplateBinding VerticalAlignment}" />
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter TargetName="ButtonContent" Property="Opacity" Value="0.25" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter TargetName="ButtonContent" Property="Background" Value="LightBlue" />
|
||||
<Setter TargetName="ButtonContent" Property="BorderBrush" Value="DodgerBlue" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter TargetName="ButtonContent" Property="BorderBrush" Value="SkyBlue" />
|
||||
<Setter TargetName="ButtonContent" Property="BorderThickness" Value="2" />
|
||||
<Setter Property="Cursor" Value="Hand" />
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
<ControlTemplate x:Key="TaskbarButton" TargetType="Button">
|
||||
<Border x:Name="ButtonContent" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding Background}"
|
||||
BorderThickness="1" Cursor="Hand" Padding="{TemplateBinding Padding}">
|
||||
<ContentPresenter ContentSource="Content" HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
|
||||
RenderOptions.BitmapScalingMode="HighQuality" VerticalAlignment="{TemplateBinding VerticalAlignment}" />
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter TargetName="ButtonContent" Property="Background" Value="LightBlue" />
|
||||
<Setter TargetName="ButtonContent" Property="BorderBrush" Value="DodgerBlue" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter TargetName="ButtonContent" Property="BorderBrush" Value="SkyBlue" />
|
||||
<Setter TargetName="ButtonContent" Property="BorderThickness" Value="2" />
|
||||
<Setter Property="Cursor" Value="Hand" />
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</ResourceDictionary>
|
@@ -0,0 +1,9 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<SolidColorBrush x:Key="ActionCenterDarkBrush">#AA808080</SolidColorBrush>
|
||||
<SolidColorBrush x:Key="BackgroundBrush">#FFF0F0F0</SolidColorBrush>
|
||||
<SolidColorBrush x:Key="BackgroundTransparentBrush">#EEF0F0F0</SolidColorBrush>
|
||||
<SolidColorBrush x:Key="BackgroundTransparentEmphasisBrush">#99D3D3D3</SolidColorBrush>
|
||||
<SolidColorBrush x:Key="PrimaryTextBrush">Black</SolidColorBrush>
|
||||
<SolidColorBrush x:Key="SecondaryTextBrush">DimGray</SolidColorBrush>
|
||||
</ResourceDictionary>
|
@@ -0,0 +1,59 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<ControlTemplate x:Key="Thumb" TargetType="{x:Type Thumb}">
|
||||
<Rectangle x:Name="Rectangle" Fill="DarkGray" Height="Auto" Width="Auto" />
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsDragging" Value="True">
|
||||
<Setter TargetName="Rectangle" Property="Fill" Value="DimGray" />
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
<ControlTemplate x:Key="RepeatButton" TargetType="RepeatButton">
|
||||
<Rectangle Fill="DarkGray" Height="Auto" Width="Auto" />
|
||||
</ControlTemplate>
|
||||
<ControlTemplate x:Key="VerticalScrollBar" TargetType="{x:Type ScrollBar}">
|
||||
<Track Name="PART_Track" Height="Auto" IsDirectionReversed="True" Width="10">
|
||||
<Track.DecreaseRepeatButton>
|
||||
<RepeatButton Margin="4.5,0" Template="{StaticResource RepeatButton}" />
|
||||
</Track.DecreaseRepeatButton>
|
||||
<Track.Thumb>
|
||||
<Thumb Cursor="ScrollNS" Focusable="False" Margin="2.5,0" OverridesDefaultStyle="True" SnapsToDevicePixels="True" Template="{StaticResource Thumb}" />
|
||||
</Track.Thumb>
|
||||
<Track.IncreaseRepeatButton>
|
||||
<RepeatButton Margin="4.5,0" Template="{StaticResource RepeatButton}" />
|
||||
</Track.IncreaseRepeatButton>
|
||||
</Track>
|
||||
</ControlTemplate>
|
||||
<ControlTemplate x:Key="HorizontalScrollBar" TargetType="{x:Type ScrollBar}">
|
||||
<Track Name="PART_Track" Height="10" IsDirectionReversed="False" Width="Auto">
|
||||
<Track.DecreaseRepeatButton>
|
||||
<RepeatButton Margin="0,4.5" Template="{StaticResource RepeatButton}" />
|
||||
</Track.DecreaseRepeatButton>
|
||||
<Track.Thumb>
|
||||
<Thumb Cursor="ScrollWE" Focusable="False" Margin="0,2.5" OverridesDefaultStyle="True" SnapsToDevicePixels="True" Template="{StaticResource Thumb}" />
|
||||
</Track.Thumb>
|
||||
<Track.IncreaseRepeatButton>
|
||||
<RepeatButton Margin="0,4.5" Template="{StaticResource RepeatButton}" />
|
||||
</Track.IncreaseRepeatButton>
|
||||
</Track>
|
||||
</ControlTemplate>
|
||||
<ControlTemplate x:Key="SmallBarScrollViewer" TargetType="{x:Type ScrollViewer}">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<ScrollContentPresenter Grid.Column="0" Grid.Row="0" />
|
||||
<ScrollBar Name="PART_VerticalScrollBar" Grid.Column="1" Grid.Row="0" Background="LightGray" OverridesDefaultStyle="True"
|
||||
Value="{TemplateBinding VerticalOffset}" Maximum="{TemplateBinding ScrollableHeight}" Template="{StaticResource VerticalScrollBar}"
|
||||
ViewportSize="{TemplateBinding ViewportHeight}" Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" />
|
||||
<ScrollBar Name="PART_HorizontalScrollBar" Grid.Column="0" Grid.Row="1" Background="LightGray" OverridesDefaultStyle="True" Orientation="Horizontal"
|
||||
Value="{TemplateBinding HorizontalOffset}" Maximum="{TemplateBinding ScrollableWidth}" Template="{StaticResource HorizontalScrollBar}"
|
||||
ViewportSize="{TemplateBinding ViewportWidth}" Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" />
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</ResourceDictionary>
|
259
SafeExamBrowser.UserInterface.Desktop/UserInterfaceFactory.cs
Normal file
259
SafeExamBrowser.UserInterface.Desktop/UserInterfaceFactory.cs
Normal file
@@ -0,0 +1,259 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using FontAwesome.WPF;
|
||||
using SafeExamBrowser.Applications.Contracts;
|
||||
using SafeExamBrowser.Configuration.Contracts;
|
||||
using SafeExamBrowser.Core.Contracts.Notifications;
|
||||
using SafeExamBrowser.I18n.Contracts;
|
||||
using SafeExamBrowser.Logging.Contracts;
|
||||
using SafeExamBrowser.Proctoring.Contracts;
|
||||
using SafeExamBrowser.Server.Contracts.Data;
|
||||
using SafeExamBrowser.Settings.Browser;
|
||||
using SafeExamBrowser.Settings.Proctoring;
|
||||
using SafeExamBrowser.Settings.UserInterface;
|
||||
using SafeExamBrowser.SystemComponents.Contracts.Audio;
|
||||
using SafeExamBrowser.SystemComponents.Contracts.Keyboard;
|
||||
using SafeExamBrowser.SystemComponents.Contracts.Network;
|
||||
using SafeExamBrowser.SystemComponents.Contracts.PowerSupply;
|
||||
using SafeExamBrowser.UserInterface.Contracts;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Browser;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Proctoring;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Shell;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Windows;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Windows.Data;
|
||||
using SafeExamBrowser.UserInterface.Desktop.Windows;
|
||||
using SplashScreen = SafeExamBrowser.UserInterface.Desktop.Windows.SplashScreen;
|
||||
|
||||
namespace SafeExamBrowser.UserInterface.Desktop
|
||||
{
|
||||
public class UserInterfaceFactory : IUserInterfaceFactory
|
||||
{
|
||||
private readonly IText text;
|
||||
|
||||
public UserInterfaceFactory(IText text)
|
||||
{
|
||||
this.text = text;
|
||||
|
||||
InitializeFontAwesome();
|
||||
}
|
||||
|
||||
public IWindow CreateAboutWindow(AppConfig appConfig)
|
||||
{
|
||||
return new AboutWindow(appConfig, text);
|
||||
}
|
||||
|
||||
public IActionCenter CreateActionCenter()
|
||||
{
|
||||
return new ActionCenter();
|
||||
}
|
||||
|
||||
public IApplicationControl CreateApplicationControl(IApplication<IApplicationWindow> application, Location location)
|
||||
{
|
||||
if (location == Location.ActionCenter)
|
||||
{
|
||||
return new Controls.ActionCenter.ApplicationControl(application);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new Controls.Taskbar.ApplicationControl(application);
|
||||
}
|
||||
}
|
||||
|
||||
public ISystemControl CreateAudioControl(IAudio audio, Location location)
|
||||
{
|
||||
if (location == Location.ActionCenter)
|
||||
{
|
||||
return new Controls.ActionCenter.AudioControl(audio, text);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new Controls.Taskbar.AudioControl(audio, text);
|
||||
}
|
||||
}
|
||||
|
||||
public IBrowserWindow CreateBrowserWindow(IBrowserControl control, BrowserSettings settings, bool isMainWindow, ILogger logger)
|
||||
{
|
||||
return Application.Current.Dispatcher.Invoke(() => new BrowserWindow(control, settings, isMainWindow, text, logger));
|
||||
}
|
||||
|
||||
public ICredentialsDialog CreateCredentialsDialog(CredentialsDialogPurpose purpose, string message, string title)
|
||||
{
|
||||
return Application.Current.Dispatcher.Invoke(() => new CredentialsDialog(purpose, message, title, text));
|
||||
}
|
||||
|
||||
public IExamSelectionDialog CreateExamSelectionDialog(IEnumerable<Exam> exams)
|
||||
{
|
||||
return Application.Current.Dispatcher.Invoke(() => new ExamSelectionDialog(exams, text));
|
||||
}
|
||||
|
||||
public ISystemControl CreateKeyboardLayoutControl(IKeyboard keyboard, Location location)
|
||||
{
|
||||
if (location == Location.ActionCenter)
|
||||
{
|
||||
return new Controls.ActionCenter.KeyboardLayoutControl(keyboard, text);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new Controls.Taskbar.KeyboardLayoutControl(keyboard, text);
|
||||
}
|
||||
}
|
||||
|
||||
public ILockScreen CreateLockScreen(string message, string title, IEnumerable<LockScreenOption> options, LockScreenSettings settings)
|
||||
{
|
||||
return Application.Current.Dispatcher.Invoke(() => new LockScreen(message, title, settings, text, options));
|
||||
}
|
||||
|
||||
public IWindow CreateLogWindow(ILogger logger)
|
||||
{
|
||||
var window = default(LogWindow);
|
||||
var windowReadyEvent = new AutoResetEvent(false);
|
||||
var windowThread = new Thread(() =>
|
||||
{
|
||||
window = new LogWindow(logger, text);
|
||||
window.Closed += (o, args) => window.Dispatcher.InvokeShutdown();
|
||||
window.Show();
|
||||
|
||||
windowReadyEvent.Set();
|
||||
|
||||
System.Windows.Threading.Dispatcher.Run();
|
||||
});
|
||||
|
||||
windowThread.SetApartmentState(ApartmentState.STA);
|
||||
windowThread.IsBackground = true;
|
||||
windowThread.Start();
|
||||
|
||||
windowReadyEvent.WaitOne();
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
public ISystemControl CreateNetworkControl(INetworkAdapter adapter, Location location)
|
||||
{
|
||||
if (location == Location.ActionCenter)
|
||||
{
|
||||
return new Controls.ActionCenter.NetworkControl(adapter, text);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new Controls.Taskbar.NetworkControl(adapter, text);
|
||||
}
|
||||
}
|
||||
|
||||
public INotificationControl CreateNotificationControl(INotification notification, Location location)
|
||||
{
|
||||
if (location == Location.ActionCenter)
|
||||
{
|
||||
return new Controls.ActionCenter.NotificationButton(notification);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new Controls.Taskbar.NotificationButton(notification);
|
||||
}
|
||||
}
|
||||
|
||||
public IPasswordDialog CreatePasswordDialog(string message, string title)
|
||||
{
|
||||
return Application.Current.Dispatcher.Invoke(() => new PasswordDialog(message, title, text));
|
||||
}
|
||||
|
||||
public IPasswordDialog CreatePasswordDialog(TextKey message, TextKey title)
|
||||
{
|
||||
return Application.Current.Dispatcher.Invoke(() => new PasswordDialog(text.Get(message), text.Get(title), text));
|
||||
}
|
||||
|
||||
public ISystemControl CreatePowerSupplyControl(IPowerSupply powerSupply, Location location)
|
||||
{
|
||||
if (location == Location.ActionCenter)
|
||||
{
|
||||
return new Controls.ActionCenter.PowerSupplyControl(powerSupply, text);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new Controls.Taskbar.PowerSupplyControl(powerSupply, text);
|
||||
}
|
||||
}
|
||||
|
||||
public IProctoringFinalizationDialog CreateProctoringFinalizationDialog()
|
||||
{
|
||||
return Application.Current.Dispatcher.Invoke(() => new ProctoringFinalizationDialog(text));
|
||||
}
|
||||
|
||||
public IProctoringWindow CreateProctoringWindow(IProctoringControl control)
|
||||
{
|
||||
return Application.Current.Dispatcher.Invoke(() => new ProctoringWindow(control));
|
||||
}
|
||||
|
||||
public INotificationControl CreateRaiseHandControl(IProctoringController controller, Location location, ProctoringSettings settings)
|
||||
{
|
||||
if (location == Location.ActionCenter)
|
||||
{
|
||||
return new Controls.ActionCenter.RaiseHandControl(controller, settings, text);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new Controls.Taskbar.RaiseHandControl(controller, settings, text);
|
||||
}
|
||||
}
|
||||
|
||||
public IRuntimeWindow CreateRuntimeWindow(AppConfig appConfig)
|
||||
{
|
||||
return Application.Current.Dispatcher.Invoke(() => new RuntimeWindow(appConfig, text));
|
||||
}
|
||||
|
||||
public IServerFailureDialog CreateServerFailureDialog(string info, bool showFallback)
|
||||
{
|
||||
return Application.Current.Dispatcher.Invoke(() => new ServerFailureDialog(info, showFallback, text));
|
||||
}
|
||||
|
||||
public ISplashScreen CreateSplashScreen(AppConfig appConfig = null)
|
||||
{
|
||||
var window = default(SplashScreen);
|
||||
var windowReadyEvent = new AutoResetEvent(false);
|
||||
var windowThread = new Thread(() =>
|
||||
{
|
||||
window = new SplashScreen(text, appConfig);
|
||||
window.Closed += (o, args) => window.Dispatcher.InvokeShutdown();
|
||||
window.Show();
|
||||
|
||||
windowReadyEvent.Set();
|
||||
|
||||
System.Windows.Threading.Dispatcher.Run();
|
||||
});
|
||||
|
||||
windowThread.SetApartmentState(ApartmentState.STA);
|
||||
windowThread.IsBackground = true;
|
||||
windowThread.Start();
|
||||
|
||||
windowReadyEvent.WaitOne();
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
public ITaskbar CreateTaskbar(ILogger logger)
|
||||
{
|
||||
return new Taskbar(logger);
|
||||
}
|
||||
|
||||
public ITaskview CreateTaskview()
|
||||
{
|
||||
return new Taskview();
|
||||
}
|
||||
|
||||
private void InitializeFontAwesome()
|
||||
{
|
||||
// To be able to use FontAwesome in XAML icon resources, we need to make sure that the FontAwesome.WPF assembly is loaded into
|
||||
// the AppDomain before attempting to load an icon resource - thus the creation of an unused image below...
|
||||
ImageAwesome.CreateImageSource(FontAwesomeIcon.FontAwesome, Brushes.Black);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Windows.Threading;
|
||||
|
||||
namespace SafeExamBrowser.UserInterface.Desktop.ViewModels
|
||||
{
|
||||
internal class DateTimeViewModel : INotifyPropertyChanged
|
||||
{
|
||||
private DispatcherTimer timer;
|
||||
private readonly bool showSeconds;
|
||||
|
||||
public string Date { get; private set; }
|
||||
public string Time { get; private set; }
|
||||
public string ToolTip { get; private set; }
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
public DateTimeViewModel(bool showSeconds)
|
||||
{
|
||||
this.showSeconds = showSeconds;
|
||||
this.timer = new DispatcherTimer();
|
||||
this.timer.Interval = TimeSpan.FromMilliseconds(250);
|
||||
this.timer.Tick += Timer_Tick;
|
||||
this.timer.Start();
|
||||
}
|
||||
|
||||
private void Timer_Tick(object sender, EventArgs e)
|
||||
{
|
||||
var date = DateTime.Now;
|
||||
|
||||
Date = date.ToShortDateString();
|
||||
Time = showSeconds ? date.ToLongTimeString() : date.ToShortTimeString();
|
||||
ToolTip = $"{date.ToLongDateString()} {date.ToLongTimeString()}";
|
||||
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Time)));
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Date)));
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ToolTip)));
|
||||
}
|
||||
}
|
||||
}
|
109
SafeExamBrowser.UserInterface.Desktop/ViewModels/LogViewModel.cs
Normal file
109
SafeExamBrowser.UserInterface.Desktop/ViewModels/LogViewModel.cs
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Media;
|
||||
using SafeExamBrowser.I18n.Contracts;
|
||||
using SafeExamBrowser.Logging.Contracts;
|
||||
using SafeExamBrowser.Settings.Logging;
|
||||
|
||||
namespace SafeExamBrowser.UserInterface.Desktop.ViewModels
|
||||
{
|
||||
internal class LogViewModel : ILogObserver
|
||||
{
|
||||
private IText text;
|
||||
private ScrollViewer scrollViewer;
|
||||
private TextBlock textBlock;
|
||||
|
||||
public bool AutoScroll { get; set; } = true;
|
||||
public string AutoScrollTitle => text.Get(TextKey.LogWindow_AutoScroll);
|
||||
public string TopmostTitle => text.Get(TextKey.LogWindow_AlwaysOnTop);
|
||||
public string WindowTitle => text.Get(TextKey.LogWindow_Title);
|
||||
|
||||
public LogViewModel(IText text, ScrollViewer scrollViewer, TextBlock textBlock)
|
||||
{
|
||||
this.text = text;
|
||||
this.scrollViewer = scrollViewer;
|
||||
this.textBlock = textBlock;
|
||||
}
|
||||
|
||||
public void Notify(ILogContent content)
|
||||
{
|
||||
switch (content)
|
||||
{
|
||||
case ILogText text:
|
||||
AppendLogText(text);
|
||||
break;
|
||||
case ILogMessage message:
|
||||
AppendLogMessage(message);
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException($"The log window is not yet implemented for log content of type {content.GetType()}!");
|
||||
}
|
||||
}
|
||||
|
||||
private void AppendLogText(ILogText logText)
|
||||
{
|
||||
textBlock.Dispatcher.InvokeAsync(() =>
|
||||
{
|
||||
var isHeader = logText.Text.StartsWith("/* ");
|
||||
var isComment = logText.Text.StartsWith("# ");
|
||||
var brush = isHeader || isComment ? Brushes.LimeGreen : textBlock.Foreground;
|
||||
var fontWeight = isHeader ? FontWeights.Bold : FontWeights.Normal;
|
||||
|
||||
textBlock.Inlines.Add(new Run($"{logText.Text}{Environment.NewLine}") { FontWeight = fontWeight, Foreground = brush });
|
||||
ScrollToEnd();
|
||||
});
|
||||
}
|
||||
|
||||
private void AppendLogMessage(ILogMessage message)
|
||||
{
|
||||
textBlock.Dispatcher.InvokeAsync(() =>
|
||||
{
|
||||
var date = message.DateTime.ToString("HH:mm:ss.fff");
|
||||
var severity = message.Severity.ToString().ToUpper();
|
||||
var threadId = message.ThreadInfo.Id < 10 ? $"0{message.ThreadInfo.Id}" : message.ThreadInfo.Id.ToString();
|
||||
var threadName = message.ThreadInfo.HasName ? ": " + message.ThreadInfo.Name : string.Empty;
|
||||
var threadInfo = $"[{threadId}{threadName}]";
|
||||
|
||||
var infoRun = new Run($"{date} {threadInfo} - ") { Foreground = Brushes.DarkGray };
|
||||
var messageRun = new Run($"{severity}: {message.Message}{Environment.NewLine}") { Foreground = GetBrushFor(message.Severity) };
|
||||
|
||||
textBlock.Inlines.Add(infoRun);
|
||||
textBlock.Inlines.Add(messageRun);
|
||||
ScrollToEnd();
|
||||
});
|
||||
}
|
||||
|
||||
private Brush GetBrushFor(LogLevel severity)
|
||||
{
|
||||
switch (severity)
|
||||
{
|
||||
case LogLevel.Debug:
|
||||
return Brushes.DarkGray;
|
||||
case LogLevel.Error:
|
||||
return Brushes.Red;
|
||||
case LogLevel.Warning:
|
||||
return Brushes.Orange;
|
||||
default:
|
||||
return Brushes.White;
|
||||
}
|
||||
}
|
||||
|
||||
private void ScrollToEnd()
|
||||
{
|
||||
if (AutoScroll)
|
||||
{
|
||||
scrollViewer.ScrollToEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System.ComponentModel;
|
||||
using System.Timers;
|
||||
|
||||
namespace SafeExamBrowser.UserInterface.Desktop.ViewModels
|
||||
{
|
||||
internal class ProgressIndicatorViewModel : INotifyPropertyChanged
|
||||
{
|
||||
private readonly object @lock = new object();
|
||||
|
||||
private Timer busyTimer;
|
||||
private int currentProgress;
|
||||
private bool isIndeterminate;
|
||||
private int maxProgress;
|
||||
private string status;
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
public bool BusyIndication
|
||||
{
|
||||
set
|
||||
{
|
||||
HandleBusyIndication(value);
|
||||
}
|
||||
}
|
||||
|
||||
public int CurrentProgress
|
||||
{
|
||||
get
|
||||
{
|
||||
return currentProgress;
|
||||
}
|
||||
set
|
||||
{
|
||||
currentProgress = value;
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(CurrentProgress)));
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsIndeterminate
|
||||
{
|
||||
get
|
||||
{
|
||||
return isIndeterminate;
|
||||
}
|
||||
set
|
||||
{
|
||||
isIndeterminate = value;
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsIndeterminate)));
|
||||
}
|
||||
}
|
||||
|
||||
public int MaxProgress
|
||||
{
|
||||
get
|
||||
{
|
||||
return maxProgress;
|
||||
}
|
||||
set
|
||||
{
|
||||
maxProgress = value;
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(MaxProgress)));
|
||||
}
|
||||
}
|
||||
|
||||
public string Status
|
||||
{
|
||||
get
|
||||
{
|
||||
return status;
|
||||
}
|
||||
set
|
||||
{
|
||||
status = value;
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Status)));
|
||||
}
|
||||
}
|
||||
|
||||
protected void OnPropertyChanged(string propertyName)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
|
||||
private void HandleBusyIndication(bool start)
|
||||
{
|
||||
lock (@lock)
|
||||
{
|
||||
if (busyTimer != null)
|
||||
{
|
||||
busyTimer.Elapsed -= BusyTimer_Elapsed;
|
||||
busyTimer.Stop();
|
||||
busyTimer.Close();
|
||||
}
|
||||
|
||||
if (start)
|
||||
{
|
||||
busyTimer = new Timer
|
||||
{
|
||||
AutoReset = true,
|
||||
Interval = 1500,
|
||||
};
|
||||
busyTimer.Elapsed += BusyTimer_Elapsed;
|
||||
busyTimer.Start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void BusyTimer_Elapsed(object sender, ElapsedEventArgs e)
|
||||
{
|
||||
var next = Status ?? string.Empty;
|
||||
|
||||
if (next.EndsWith("..."))
|
||||
{
|
||||
next = Status.Substring(0, Status.Length - 3);
|
||||
}
|
||||
else
|
||||
{
|
||||
next += ".";
|
||||
}
|
||||
|
||||
Status = next;
|
||||
busyTimer.Interval = 750;
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user