<Compile Include="KeyModifier.cs" />
<Compile Include="MetroPopupWindowAction.cs" />
<Compile Include="NeuQuant.cs" />
+ <Compile Include="NotifyIconWrapper.cs" />
<Compile Include="OptionContent.cs" />
<Compile Include="OptionView.xaml.cs">
<DependentUpon>OptionView.xaml</DependentUpon>
private static readonly string BaseDir = AppDomain.CurrentDomain.BaseDirectory;
public Point Location { get; set; } = new Point(double.MinValue, double.MinValue);
public bool TopMost { get; set; }
+ public bool ResideInSystemTray { get; set; }
+ public WindowState WindowState { get; set; }
public int Interval { get; set; } = 200;
public int RingBuffer { get; set; } = 25;
xmlns:properties="clr-namespace:BurageSnap.Properties"
mc:Ignorable="d"
Style="{StaticResource WindowStyle}"
- Title="BurageSnap" Height="114" Width="169" ResizeMode="CanMinimize" Icon="app.ico">
+ Title="BurageSnap" Height="114" Width="169" ResizeMode="CanMinimize" Icon="app.ico"
+ ShowInTaskbar="{Binding ShowInTaskbar}" WindowState="{Binding WindowState}">
<controls:MetroWindow.DataContext>
<local:MainWindowViewModel/>
</controls:MetroWindow.DataContext>
<Style TargetType="Button" BasedOn="{StaticResource ButtonStyle}"/>
</Window.Resources>
<Grid>
+ <local:NotifyIconWrapper Text="BurageSnap">
+ <i:Interaction.Triggers>
+ <i:EventTrigger EventName="OpenSelected">
+ <i:InvokeCommandAction Command="{Binding NotifyIconOpenCommand}"/>
+ </i:EventTrigger>
+ <i:EventTrigger EventName="ExitSelected">
+ <i:InvokeCommandAction Command="{Binding NotifyIconExitCommand}"/>
+ </i:EventTrigger>
+ </i:Interaction.Triggers>
+ </local:NotifyIconWrapper>
<Button x:Name="buttonCapture" Content="{Binding CaptureButtonText}" HorizontalAlignment="Left" Margin="8,8,0,0" VerticalAlignment="Top" Width="77" Height="51" FontSize="12" Command="{Binding CaptureCommand}"/>
<Button x:Name="buttonBrowse" HorizontalAlignment="Left" Margin="93,9,0,0" VerticalAlignment="Top" Width="31" Height="31" Command="{Binding BrowseCommand}">
<Image Source="folder_open.ico"/>
</Grid>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
- <i:InvokeCommandAction Command="{Binding LoadedCommand}"/>
+ <prism:InvokeCommandAction Command="{Binding LoadedCommand}"/>
</i:EventTrigger>
<i:EventTrigger EventName="Closing">
- <i:InvokeCommandAction Command="{Binding ClosingCommand}"/>
+ <prism:InvokeCommandAction Command="{Binding ClosingCommand}"/>
</i:EventTrigger>
<prism:InteractionRequestTrigger SourceObject="{Binding ConfirmationRequest, Mode=OneWay}">
<local:MetroPopupWindowAction IsModal="True" CenterOverAssociatedObject="True" Owner="{Binding ElementName=mainWindow}">
InitializeComponent();
}
}
-}
+}
\ No newline at end of file
// limitations under the License.
using System.Reflection;
+using System.ComponentModel;
using System.Windows;
using System.Windows.Input;
using BurageSnap.Properties;
public ICommand CaptureCommand { get; private set; }
public InteractionRequest<IConfirmation> ConfirmationRequest { get; } = new InteractionRequest<IConfirmation>();
public InteractionRequest<IConfirmation> OptionViewRequest { get; } = new InteractionRequest<IConfirmation>();
+ public ICommand NotifyIconOpenCommand { get; private set; }
+ public ICommand NotifyIconExitCommand { get; private set; }
public bool BurstMode
{
: Resources.MainWindow_Start
: Resources.MainWindow_Capture;
+ public bool ShowInTaskbar => !(WindowState == WindowState.Minimized && Main.Config.ResideInSystemTray);
+
+ public WindowState WindowState
+ {
+ get { return Main.Config.WindowState; }
+ set
+ {
+ if (Main.Config.WindowState == value)
+ return;
+ Main.Config.WindowState = value;
+ OnPropertyChanged(() => WindowState);
+ OnPropertyChanged(() => ShowInTaskbar);
+ }
+ }
+
public MainWindowViewModel()
{
Main = new Main();
}
};
LoadedCommand = new DelegateCommand(Loaded);
- ClosingCommand = new DelegateCommand(Closing);
+ ClosingCommand = new DelegateCommand<CancelEventArgs>(Closing);
BrowseCommand = new DelegateCommand(Main.OpenPictureFolder);
OptionCommand = new DelegateCommand(SelectOption);
CaptureCommand = new DelegateCommand(Capture);
+ NotifyIconOpenCommand = new DelegateCommand(() => { WindowState = WindowState.Normal; });
+ NotifyIconExitCommand = new DelegateCommand(() =>
+ {
+ Terminate();
+ Application.Current.Shutdown();
+ });
}
private void Loaded()
_globelHotKey.Register(Application.Current.MainWindow, config.HotKeyModifier, config.HotKey);
}
- private void Closing()
+ private void Closing(CancelEventArgs e)
+ {
+ if (Main.Config.ResideInSystemTray)
+ {
+ e.Cancel = true;
+ WindowState = WindowState.Minimized;
+ }
+ else
+ {
+ Terminate();
+ }
+ }
+
+ public void Terminate()
+ {
+ SaveConfig();
+ _globelHotKey.Unregister();
+ }
+
+ private void SaveConfig()
{
var config = Main.Config;
var main = Application.Current.MainWindow;
? new Point(main.Left, main.Top)
: new Point(main.RestoreBounds.Left, main.RestoreBounds.Top);
config.Save();
- _globelHotKey.Unregister();
}
public static bool IsVisibleOnScreen(Rect rect)
private void ConfirmSaveBuffer()
{
- Application.Current.MainWindow.WindowState = WindowState.Normal;
+ WindowState = WindowState.Normal;
ConfirmationRequest.Raise(new Confirmation {Title = Resources.ConfirmView_Title}, c =>
{
if (c.Confirmed)
--- /dev/null
+// Copyright (C) 2016 Kazuhiro Fujieda <fujieda@users.osdn.me>
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using System;
+using System.ComponentModel;
+using System.Drawing;
+using System.Reflection;
+using System.Windows;
+using System.Windows.Forms;
+using Application = System.Windows.Application;
+
+namespace BurageSnap
+{
+ public class NotifyIconWrapper : FrameworkElement
+ {
+ private readonly NotifyIcon _notifyIcon;
+
+ public static readonly DependencyProperty TextProperty =
+ DependencyProperty.Register("Text", typeof(string), typeof(NotifyIconWrapper), new PropertyMetadata(
+ (d, e) =>
+ {
+ if (((NotifyIconWrapper)d)._notifyIcon == null)
+ return;
+ ((NotifyIconWrapper)d)._notifyIcon.Text = (string)e.NewValue;
+ }));
+
+ public string Text
+ {
+ get { return (string)GetValue(TextProperty); }
+ set { SetValue(TextProperty, value); }
+ }
+
+ public static readonly RoutedEvent OpenSelectedEvent = EventManager.RegisterRoutedEvent("OpenSelected",
+ RoutingStrategy.Direct, typeof(RoutedEventHandler), typeof(NotifyIconWrapper));
+
+ public event RoutedEventHandler OpenSelected
+ {
+ add { AddHandler(OpenSelectedEvent, value);}
+ remove { RemoveHandler(OpenSelectedEvent, value);}
+ }
+
+ public static readonly RoutedEvent ExitSelectedEvent = EventManager.RegisterRoutedEvent("ExitSelected",
+ RoutingStrategy.Direct, typeof(RoutedEventHandler), typeof(NotifyIconWrapper));
+
+ public event RoutedEventHandler ExitSelected
+ {
+ add { AddHandler(ExitSelectedEvent, value); }
+ remove { RemoveHandler(ExitSelectedEvent, value); }
+ }
+
+ public NotifyIconWrapper()
+ {
+ if (DesignerProperties.GetIsInDesignMode(new DependencyObject()))
+ return;
+ _notifyIcon = new NotifyIcon
+ {
+ // ReSharper disable once AssignNullToNotNullAttribute
+ Icon = Icon.ExtractAssociatedIcon(Assembly.GetExecutingAssembly().Location),
+ Visible = true,
+ ContextMenuStrip = CreateContextMenu()
+ };
+ _notifyIcon.DoubleClick += OpenItemOnClick;
+ Application.Current.Exit += (obj, args) => { _notifyIcon.Dispose(); };
+ }
+
+ private ContextMenuStrip CreateContextMenu()
+ {
+ var contextMenu = new ContextMenuStrip();
+ var openItem = new ToolStripMenuItem(Properties.Resources.NotifyIcon_Open);
+ openItem.Click += OpenItemOnClick;
+ var exitItem = new ToolStripMenuItem(Properties.Resources.NotifyIcon_Exit);
+ exitItem.Click += ExitItemOnClick;
+ contextMenu.Items.Add(openItem);
+ contextMenu.Items.Add(exitItem);
+ return contextMenu;
+ }
+
+ private void OpenItemOnClick(object sender, EventArgs eventArgs)
+ {
+ var args = new RoutedEventArgs(OpenSelectedEvent);
+ RaiseEvent(args);
+ }
+
+ private void ExitItemOnClick(object sender, EventArgs eventArgs)
+ {
+ var args = new RoutedEventArgs(ExitSelectedEvent);
+ RaiseEvent(args);
+ }
+
+ public void Dispose()
+ {
+ _notifyIcon.Dispose();
+ }
+ }
+}
\ No newline at end of file
public class OptionContent
{
public bool TopMost { get; set; }
+ public bool ResideInSystemTray { get; set; }
public int Interval { get; set; }
public int RingBuffer { get; set; }
public ObservableCollection<string> WindowTitles { get; set; }
<TextBox x:Name="textBoxRingBuffer" HorizontalAlignment="Left" Text="{Binding Options.RingBuffer}" VerticalAlignment="Center" Width="41" TextAlignment="Right" Margin="0 0 5 0"/>
<Label x:Name="labelFrames" Content="{x:Static proprties:Resources.OptionView_Frames}" HorizontalAlignment="Left" VerticalAlignment="Center"/>
</StackPanel>
- <StackPanel Orientation="Horizontal" Margin="0 0 0 15">
- <Label x:Name="labelWindow" Content="{x:Static proprties:Resources.OptionView_Window}" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="0 0 5 0"/>
- <CheckBox x:Name="checkBoxTopMost" Content="{x:Static proprties:Resources.OptionView_Top_most}" HorizontalAlignment="Left" VerticalAlignment="Center" IsChecked="{Binding Options.TopMost}"/>
- </StackPanel>
+ <Grid Margin="0 0 0 15">
+ <Grid.RowDefinitions>
+ <RowDefinition/>
+ <RowDefinition/>
+ </Grid.RowDefinitions>
+ <Grid.ColumnDefinitions>
+ <ColumnDefinition Width="Auto"/>
+ <ColumnDefinition/>
+ </Grid.ColumnDefinitions>
+ <Label x:Name="labelWindow" Content="{x:Static proprties:Resources.OptionView_Window}" Margin="0 0 5 0"/>
+ <CheckBox x:Name="checkBoxTopMost" Content="{x:Static proprties:Resources.OptionView_Top_most}" Grid.Row="0" Grid.Column="1" Margin="0 0 0 5" IsChecked="{Binding Options.TopMost}"/>
+ <CheckBox x:Name="checkBoxHideOnMinimize" Content="{x:Static proprties:Resources.OptionView_Reside_in_system_tray}" Grid.Row="1" Grid.Column="1" IsChecked="{Binding Options.ResideInSystemTray}"/>
+ </Grid>
<Grid HorizontalAlignment="Left" VerticalAlignment="Top" Margin="0 0 0 0">
<Grid.RowDefinitions>
<RowDefinition/>
}
/// <summary>
+ /// Exit に類似しているローカライズされた文字列を検索します。
+ /// </summary>
+ public static string NotifyIcon_Exit {
+ get {
+ return ResourceManager.GetString("NotifyIcon_Exit", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Open に類似しているローカライズされた文字列を検索します。
+ /// </summary>
+ public static string NotifyIcon_Open {
+ get {
+ return ResourceManager.GetString("NotifyIcon_Open", resourceCulture);
+ }
+ }
+
+ /// <summary>
/// Add に類似しているローカライズされた文字列を検索します。
/// </summary>
public static string OptionView_Add {
}
/// <summary>
+ /// Reside in system tray に類似しているローカライズされた文字列を検索します。
+ /// </summary>
+ public static string OptionView_Reside_in_system_tray {
+ get {
+ return ResourceManager.GetString("OptionView_Reside_in_system_tray", resourceCulture);
+ }
+ }
+
+ /// <summary>
/// Ring buffer: に類似しているローカライズされた文字列を検索します。
/// </summary>
public static string OptionView_Ring_buffer {
<data name="OptionView_Option" xml:space="preserve">
<value>オプション</value>
</data>
+ <data name="NotifyIcon_Exit" xml:space="preserve">
+ <value>終了</value>
+ </data>
+ <data name="NotifyIcon_Open" xml:space="preserve">
+ <value>開く</value>
+ </data>
+ <data name="OptionView_Reside_in_system_tray" xml:space="preserve">
+ <value>システムトレイに常駐する</value>
+ </data>
</root>
\ No newline at end of file
<data name="OptionView_Option" xml:space="preserve">
<value>Option</value>
</data>
+ <data name="NotifyIcon_Open" xml:space="preserve">
+ <value>Open</value>
+ </data>
+ <data name="NotifyIcon_Exit" xml:space="preserve">
+ <value>Exit</value>
+ </data>
+ <data name="OptionView_Reside_in_system_tray" xml:space="preserve">
+ <value>Reside in system tray</value>
+ </data>
</root>
\ No newline at end of file