Merge pull request #1567 from Silvenga/master
Improved Icon Menu Handling
This commit is contained in:
commit
9432644e45
|
@ -17,12 +17,9 @@
|
|||
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Markup;
|
||||
|
||||
|
@ -33,330 +30,158 @@ namespace SparkleShare {
|
|||
|
||||
[ContentProperty("Text")]
|
||||
[DefaultEvent("MouseDoubleClick")]
|
||||
public class SparkleNotifyIcon : FrameworkElement, IAddChild {
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
|
||||
private static extern IntPtr GetModuleHandle(string module_name);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
|
||||
private static extern int CallNextHookEx (int hook_id, int code, int param, IntPtr data_pointer);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
|
||||
private static extern int SetWindowsHookEx (int hook_id, HookProc function, IntPtr instance, int thread_id);
|
||||
public class SparkleNotifyIcon : UIElement, IAddChild {
|
||||
|
||||
[DllImport("user32.dll", EntryPoint = "DestroyIcon")]
|
||||
static extern bool DestroyIcon (IntPtr hIcon);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
|
||||
private static extern int UnhookWindowsHookEx (int hook_id);
|
||||
static extern bool DestroyIcon(IntPtr h_icon);
|
||||
|
||||
[StructLayout (LayoutKind.Sequential)]
|
||||
private struct MouseLLHook
|
||||
{
|
||||
internal int X;
|
||||
internal int Y;
|
||||
internal int MouseData;
|
||||
internal int Flags;
|
||||
internal int Time;
|
||||
internal int Info;
|
||||
}
|
||||
|
||||
|
||||
public Drawing.Bitmap Icon {
|
||||
set {
|
||||
this.notify_icon.Icon = GetIconFromBitmap (value);
|
||||
NotifyIcon.Icon = GetIconFromBitmap(value);
|
||||
}
|
||||
}
|
||||
|
||||
public string Text {
|
||||
get {
|
||||
return (string) GetValue(TextProperty);
|
||||
}
|
||||
set {
|
||||
var text = value;
|
||||
|
||||
if(!string.IsNullOrEmpty(HeaderText))
|
||||
text = HeaderText + "\n" + text;
|
||||
|
||||
SetValue(TextProperty, text);
|
||||
}
|
||||
}
|
||||
|
||||
public ContextMenu ContextMenu {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public string HeaderText {
|
||||
get {
|
||||
return header_text;
|
||||
}
|
||||
|
||||
set {
|
||||
header_text = value;
|
||||
}
|
||||
}
|
||||
|
||||
public string Text {
|
||||
get {
|
||||
return (string) GetValue (TextProperty);
|
||||
}
|
||||
|
||||
set {
|
||||
string text = value;
|
||||
|
||||
if (!string.IsNullOrEmpty (header_text))
|
||||
text = header_text + "\n" + text;
|
||||
|
||||
SetValue (TextProperty, text);
|
||||
}
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public event MouseButtonEventHandler MouseClick {
|
||||
add {
|
||||
AddHandler (MouseClickEvent, value);
|
||||
}
|
||||
|
||||
remove {
|
||||
RemoveHandler (MouseClickEvent, value);
|
||||
}
|
||||
private Forms.NotifyIcon NotifyIcon {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public event MouseButtonEventHandler MouseDoubleClick {
|
||||
add {
|
||||
AddHandler (MouseDoubleClickEvent, value);
|
||||
}
|
||||
|
||||
remove {
|
||||
RemoveHandler (MouseDoubleClickEvent, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public readonly RoutedEvent MouseClickEvent = EventManager.RegisterRoutedEvent (
|
||||
"MouseClick", RoutingStrategy.Bubble, typeof (MouseButtonEventHandler), typeof (SparkleNotifyIcon));
|
||||
public readonly RoutedEvent MouseClickEvent = EventManager.RegisterRoutedEvent(
|
||||
"MouseClick", RoutingStrategy.Bubble, typeof(MouseButtonEventHandler), typeof(SparkleNotifyIcon));
|
||||
|
||||
public readonly RoutedEvent MouseDoubleClickEvent = EventManager.RegisterRoutedEvent(
|
||||
"MouseDoubleClick", RoutingStrategy.Bubble, typeof (MouseButtonEventHandler), typeof (SparkleNotifyIcon));
|
||||
"MouseDoubleClick", RoutingStrategy.Bubble, typeof(MouseButtonEventHandler), typeof(SparkleNotifyIcon));
|
||||
|
||||
public readonly DependencyProperty TextProperty = DependencyProperty.Register(
|
||||
"Text", typeof(string), typeof (SparkleNotifyIcon), new PropertyMetadata (OnTextChanged));
|
||||
"Text", typeof(string), typeof(SparkleNotifyIcon), new PropertyMetadata(OnTextChanged));
|
||||
|
||||
|
||||
private string header_text;
|
||||
private Forms.NotifyIcon notify_icon;
|
||||
private HookProc hook_proc_ref;
|
||||
private int mouse_hook_handle;
|
||||
private delegate int HookProc (int code, int param, IntPtr struct_pointer);
|
||||
|
||||
|
||||
public SparkleNotifyIcon ()
|
||||
{
|
||||
VisibilityProperty.OverrideMetadata (typeof (SparkleNotifyIcon),
|
||||
new PropertyMetadata (OnVisibilityChanged));
|
||||
|
||||
this.notify_icon = new Forms.NotifyIcon () {
|
||||
Text = Text,
|
||||
Visible = true
|
||||
public SparkleNotifyIcon() {
|
||||
VisibilityProperty.OverrideMetadata(typeof(SparkleNotifyIcon), new PropertyMetadata(OnVisibilityChanged));
|
||||
|
||||
NotifyIcon = new Forms.NotifyIcon {
|
||||
Text = Text,
|
||||
Visible = true,
|
||||
ContextMenu = new Forms.ContextMenu()
|
||||
};
|
||||
|
||||
this.notify_icon.MouseDown += OnMouseDown;
|
||||
this.notify_icon.MouseUp += OnMouseUp;
|
||||
this.notify_icon.MouseClick += OnMouseClick;
|
||||
this.notify_icon.MouseDoubleClick += OnMouseDoubleClick;
|
||||
|
||||
this.hook_proc_ref = OnMouseEventProc;
|
||||
NotifyIcon.MouseDown += OnMouseDown;
|
||||
NotifyIcon.MouseUp += OnMouseUp;
|
||||
NotifyIcon.MouseClick += OnMouseClick;
|
||||
NotifyIcon.MouseDoubleClick += OnMouseDoubleClick;
|
||||
}
|
||||
|
||||
|
||||
public void ShowBalloonTip (string title, string subtext, string image_path)
|
||||
{
|
||||
|
||||
public void ShowBalloonTip(string title, string subtext, string image_path) {
|
||||
// TODO:
|
||||
// - Use the image pointed to by image_path
|
||||
// - Find a way to use the prettier (Win7?) balloons
|
||||
this.notify_icon.ShowBalloonTip (5 * 1000, title, subtext, Forms.ToolTipIcon.Info);
|
||||
NotifyIcon.ShowBalloonTip(5 * 1000, title, subtext, Forms.ToolTipIcon.Info);
|
||||
}
|
||||
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
this.notify_icon.Dispose();
|
||||
public void Dispose() {
|
||||
NotifyIcon.Dispose();
|
||||
}
|
||||
|
||||
|
||||
void IAddChild.AddChild (object value)
|
||||
{
|
||||
throw new InvalidOperationException ();
|
||||
void IAddChild.AddChild(object value) {
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
|
||||
void IAddChild.AddText (string text)
|
||||
{
|
||||
if (text == null)
|
||||
throw new ArgumentNullException ();
|
||||
void IAddChild.AddText(string text) {
|
||||
if(text == null)
|
||||
throw new ArgumentNullException();
|
||||
|
||||
Text = text;
|
||||
}
|
||||
|
||||
|
||||
private static MouseButtonEventArgs CreateMouseButtonEventArgs(
|
||||
RoutedEvent handler, Forms.MouseButtons button)
|
||||
{
|
||||
private static MouseButtonEventArgs CreateMouseButtonEventArgs(RoutedEvent handler, Forms.MouseButtons button) {
|
||||
MouseButton mouse_button;
|
||||
|
||||
if (button == Forms.MouseButtons.Left) {
|
||||
if(button == Forms.MouseButtons.Left) {
|
||||
mouse_button = MouseButton.Left;
|
||||
|
||||
} else if (button == Forms.MouseButtons.Right) {
|
||||
|
||||
} else if(button == Forms.MouseButtons.Right) {
|
||||
mouse_button = MouseButton.Right;
|
||||
|
||||
} else if (button == Forms.MouseButtons.Middle) {
|
||||
|
||||
} else if(button == Forms.MouseButtons.Middle) {
|
||||
mouse_button = MouseButton.Middle;
|
||||
|
||||
} else if (button == Forms.MouseButtons.XButton1) {
|
||||
|
||||
} else if(button == Forms.MouseButtons.XButton1) {
|
||||
mouse_button = MouseButton.XButton1;
|
||||
|
||||
} else if (button == Forms.MouseButtons.XButton2) {
|
||||
|
||||
} else if(button == Forms.MouseButtons.XButton2) {
|
||||
mouse_button = MouseButton.XButton2;
|
||||
|
||||
|
||||
} else {
|
||||
throw new InvalidOperationException ();
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
return new MouseButtonEventArgs (InputManager.Current.PrimaryMouseDevice, 0, mouse_button) {
|
||||
return new MouseButtonEventArgs(InputManager.Current.PrimaryMouseDevice, 0, mouse_button) {
|
||||
RoutedEvent = handler
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
private void ShowContextMenu ()
|
||||
{
|
||||
if (ContextMenu != null) {
|
||||
ContextMenu.Opened += OnContextMenuOpened;
|
||||
ContextMenu.Closed += OnContextMenuClosed;
|
||||
|
||||
ContextMenu.Placement = PlacementMode.Mouse;
|
||||
ContextMenu.IsOpen = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private Rect GetContextMenuRect (ContextMenu menu)
|
||||
{
|
||||
var source = PresentationSource.FromVisual (menu);
|
||||
if (source != null) {
|
||||
Point start_point = menu.PointToScreen(new Point(0, 0));
|
||||
Point end_point = menu.PointToScreen(new Point(menu.ActualWidth, menu.ActualHeight));
|
||||
|
||||
return new Rect(start_point, end_point);
|
||||
}
|
||||
|
||||
return new Rect();
|
||||
}
|
||||
|
||||
|
||||
private Point GetHitPoint (IntPtr struct_pointer)
|
||||
{
|
||||
MouseLLHook mouse_hook = (MouseLLHook) Marshal.PtrToStructure (
|
||||
struct_pointer, typeof (MouseLLHook));
|
||||
|
||||
return new Point (mouse_hook.X, mouse_hook.Y);
|
||||
}
|
||||
|
||||
|
||||
private int OnMouseEventProc (int code, int button, IntPtr data_pointer)
|
||||
{
|
||||
int left_button_down = 0x201;
|
||||
int right_button_down = 0x204;
|
||||
|
||||
int ret;
|
||||
try {
|
||||
if (button == left_button_down || button == right_button_down)
|
||||
{
|
||||
Rect context_menu_rect = GetContextMenuRect (ContextMenu);
|
||||
Point hit_point = GetHitPoint (data_pointer);
|
||||
|
||||
if (!context_menu_rect.Contains(hit_point)) {
|
||||
new Thread (() => {
|
||||
Thread.Sleep (750);
|
||||
|
||||
Dispatcher.BeginInvoke ((Action) delegate {
|
||||
ContextMenu.IsOpen = false;
|
||||
});
|
||||
}).Start ();
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
ret = CallNextHookEx(this.mouse_hook_handle, code, button, data_pointer);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
private void OnContextMenuOpened (object sender, RoutedEventArgs args)
|
||||
{
|
||||
using (Process process = Process.GetCurrentProcess ())
|
||||
using (ProcessModule module = process.MainModule)
|
||||
{
|
||||
this.mouse_hook_handle = SetWindowsHookEx (14, this.hook_proc_ref,
|
||||
GetModuleHandle (module.ModuleName), 0);
|
||||
}
|
||||
|
||||
if (this.mouse_hook_handle == 0)
|
||||
throw new Win32Exception (Marshal.GetLastWin32Error ());
|
||||
}
|
||||
|
||||
|
||||
private void OnContextMenuClosed (object sender, RoutedEventArgs args)
|
||||
{
|
||||
UnhookWindowsHookEx (this.mouse_hook_handle);
|
||||
|
||||
ContextMenu.Opened -= OnContextMenuOpened;
|
||||
ContextMenu.Closed -= OnContextMenuClosed;
|
||||
}
|
||||
|
||||
|
||||
private void OnVisibilityChanged (DependencyObject target,
|
||||
DependencyPropertyChangedEventArgs args)
|
||||
{
|
||||
SparkleNotifyIcon control = (SparkleNotifyIcon) target;
|
||||
control.notify_icon.Visible = (control.Visibility == Visibility.Visible);
|
||||
}
|
||||
|
||||
|
||||
private void OnMouseDown(object sender, Forms.MouseEventArgs args)
|
||||
{
|
||||
RaiseEvent (CreateMouseButtonEventArgs (MouseDownEvent, args.Button));
|
||||
}
|
||||
|
||||
|
||||
private void OnMouseClick (object sender, Forms.MouseEventArgs args)
|
||||
{
|
||||
RaiseEvent (CreateMouseButtonEventArgs (MouseClickEvent, args.Button));
|
||||
}
|
||||
|
||||
|
||||
private void OnMouseDoubleClick (object sender, Forms.MouseEventArgs args)
|
||||
{
|
||||
RaiseEvent (CreateMouseButtonEventArgs (MouseDoubleClickEvent, args.Button));
|
||||
}
|
||||
|
||||
|
||||
private void OnMouseUp (object sender, Forms.MouseEventArgs args)
|
||||
{
|
||||
if (args.Button == Forms.MouseButtons.Left ||
|
||||
args.Button == Forms.MouseButtons.Right) {
|
||||
|
||||
ShowContextMenu ();
|
||||
}
|
||||
|
||||
RaiseEvent (CreateMouseButtonEventArgs (MouseUpEvent, args.Button));
|
||||
}
|
||||
|
||||
|
||||
protected override void OnVisualParentChanged (DependencyObject parent)
|
||||
{
|
||||
base.OnVisualParentChanged (parent);
|
||||
}
|
||||
|
||||
|
||||
private static void OnTextChanged (DependencyObject target,
|
||||
DependencyPropertyChangedEventArgs args)
|
||||
{
|
||||
private void OnVisibilityChanged(DependencyObject target, DependencyPropertyChangedEventArgs args) {
|
||||
SparkleNotifyIcon control = (SparkleNotifyIcon) target;
|
||||
control.notify_icon.Text = control.Text;
|
||||
control.NotifyIcon.Visible = (control.Visibility == Visibility.Visible);
|
||||
}
|
||||
|
||||
|
||||
private Drawing.Icon GetIconFromBitmap (Drawing.Bitmap bitmap)
|
||||
{
|
||||
IntPtr unmanaged_icon = bitmap.GetHicon ();
|
||||
Drawing.Icon icon = (Drawing.Icon) Drawing.Icon.FromHandle (unmanaged_icon).Clone ();
|
||||
DestroyIcon (unmanaged_icon);
|
||||
|
||||
private void OnMouseDown(object sender, Forms.MouseEventArgs args) {
|
||||
RaiseEvent(CreateMouseButtonEventArgs(MouseDownEvent, args.Button));
|
||||
}
|
||||
|
||||
private void OnMouseClick(object sender, Forms.MouseEventArgs args) {
|
||||
RaiseEvent(CreateMouseButtonEventArgs(MouseClickEvent, args.Button));
|
||||
}
|
||||
|
||||
private void OnMouseDoubleClick(object sender, Forms.MouseEventArgs args) {
|
||||
RaiseEvent(CreateMouseButtonEventArgs(MouseDoubleClickEvent, args.Button));
|
||||
}
|
||||
|
||||
private void OnMouseUp(object sender, Forms.MouseEventArgs args) {
|
||||
|
||||
if(args.Button == Forms.MouseButtons.Right) {
|
||||
|
||||
ContextMenu.IsOpen = true;
|
||||
ContextMenu.StaysOpen = false;
|
||||
}
|
||||
|
||||
RaiseEvent(CreateMouseButtonEventArgs(MouseUpEvent, args.Button));
|
||||
}
|
||||
|
||||
private static void OnTextChanged(DependencyObject target, DependencyPropertyChangedEventArgs args) {
|
||||
SparkleNotifyIcon control = (SparkleNotifyIcon) target;
|
||||
control.NotifyIcon.Text = control.Text;
|
||||
}
|
||||
|
||||
|
||||
private static Drawing.Icon GetIconFromBitmap(Drawing.Bitmap bitmap) {
|
||||
IntPtr unmanaged_icon = bitmap.GetHicon();
|
||||
Drawing.Icon icon = (Drawing.Icon) Drawing.Icon.FromHandle(unmanaged_icon).Clone();
|
||||
DestroyIcon(unmanaged_icon);
|
||||
|
||||
return icon;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,4 +14,5 @@
|
|||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_BEFORE_METHOD_CALL_PARENTHESES/@EntryValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_BEFORE_METHOD_PARENTHESES/@EntryValue">True</s:Boolean>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=Locals/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="aa_bb" /></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=Parameters/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="aa_bb" /></s:String></wpf:ResourceDictionary>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=Parameters/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="aa_bb" /></s:String>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
|
@ -17,291 +17,309 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows;
|
||||
using System.Windows.Interop;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
|
||||
using Drawing = System.Drawing;
|
||||
using Forms = System.Windows.Forms;
|
||||
|
||||
namespace SparkleShare {
|
||||
|
||||
public class SparkleStatusIcon : Control {
|
||||
|
||||
|
||||
public SparkleStatusIconController Controller = new SparkleStatusIconController();
|
||||
|
||||
private Drawing.Bitmap syncing_idle_image = SparkleUIHelpers.GetBitmap ("process-syncing-idle");
|
||||
private Drawing.Bitmap syncing_up_image = SparkleUIHelpers.GetBitmap ("process-syncing-up");
|
||||
private Drawing.Bitmap syncing_down_image = SparkleUIHelpers.GetBitmap ("process-syncing-down");
|
||||
private Drawing.Bitmap syncing_image = SparkleUIHelpers.GetBitmap ("process-syncing");
|
||||
private Drawing.Bitmap syncing_error_image = SparkleUIHelpers.GetBitmap ("process-syncing-error");
|
||||
|
||||
private readonly Drawing.Bitmap syncing_idle_image = SparkleUIHelpers.GetBitmap("process-syncing-idle");
|
||||
private readonly Drawing.Bitmap syncing_up_image = SparkleUIHelpers.GetBitmap("process-syncing-up");
|
||||
private readonly Drawing.Bitmap syncing_down_image = SparkleUIHelpers.GetBitmap("process-syncing-down");
|
||||
private readonly Drawing.Bitmap syncing_image = SparkleUIHelpers.GetBitmap("process-syncing");
|
||||
private readonly Drawing.Bitmap syncing_error_image = SparkleUIHelpers.GetBitmap("process-syncing-error");
|
||||
|
||||
private ContextMenu context_menu;
|
||||
|
||||
private SparkleMenuItem log_item;
|
||||
private SparkleMenuItem state_item;
|
||||
private SparkleMenuItem exit_item;
|
||||
private SparkleMenuItem [] state_menu_items;
|
||||
private SparkleMenuItem[] state_menu_items;
|
||||
|
||||
private SparkleNotifyIcon notify_icon = new SparkleNotifyIcon ();
|
||||
private readonly SparkleNotifyIcon notify_icon = new SparkleNotifyIcon();
|
||||
|
||||
|
||||
public SparkleStatusIcon ()
|
||||
{
|
||||
public SparkleStatusIcon() {
|
||||
this.notify_icon.HeaderText = "SparkleShare";
|
||||
this.notify_icon.Icon = this.syncing_idle_image;
|
||||
this.notify_icon.Icon = this.syncing_idle_image;
|
||||
|
||||
CreateMenu ();
|
||||
|
||||
Controller.UpdateIconEvent += delegate (IconState state) {
|
||||
Dispatcher.BeginInvoke ((Action) delegate {
|
||||
switch (state) {
|
||||
case IconState.Idle: {
|
||||
this.notify_icon.Icon = this.syncing_idle_image;
|
||||
break;
|
||||
CreateMenu();
|
||||
|
||||
Controller.UpdateIconEvent += delegate(IconState state) {
|
||||
Dispatcher.BeginInvoke(
|
||||
(Action) delegate {
|
||||
switch(state) {
|
||||
case IconState.Idle: {
|
||||
this.notify_icon.Icon = this.syncing_idle_image;
|
||||
break;
|
||||
}
|
||||
case IconState.SyncingUp: {
|
||||
this.notify_icon.Icon = this.syncing_up_image;
|
||||
break;
|
||||
}
|
||||
case IconState.SyncingDown: {
|
||||
this.notify_icon.Icon = this.syncing_down_image;
|
||||
break;
|
||||
}
|
||||
case IconState.Syncing: {
|
||||
this.notify_icon.Icon = this.syncing_image;
|
||||
break;
|
||||
}
|
||||
case IconState.Error: {
|
||||
this.notify_icon.Icon = this.syncing_error_image;
|
||||
break;
|
||||
}
|
||||
}
|
||||
case IconState.SyncingUp: {
|
||||
this.notify_icon.Icon = this.syncing_up_image;
|
||||
break;
|
||||
}
|
||||
case IconState.SyncingDown: {
|
||||
this.notify_icon.Icon = this.syncing_down_image;
|
||||
break;
|
||||
}
|
||||
case IconState.Syncing: {
|
||||
this.notify_icon.Icon = this.syncing_image;
|
||||
break;
|
||||
}
|
||||
case IconState.Error: {
|
||||
this.notify_icon.Icon = this.syncing_error_image;
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
Controller.UpdateStatusItemEvent += delegate (string state_text) {
|
||||
Dispatcher.BeginInvoke ((Action) delegate {
|
||||
this.state_item.Header = state_text;
|
||||
this.state_item.UpdateLayout ();
|
||||
|
||||
if (Controller.Projects.Length == this.state_menu_items.Length) {
|
||||
for (int i = 0; i < Controller.Projects.Length; i++)
|
||||
this.state_menu_items [i].Header = Controller.Projects [i].StatusMessage;
|
||||
Controller.UpdateStatusItemEvent += delegate(string state_text) {
|
||||
Dispatcher.BeginInvoke(
|
||||
(Action) delegate {
|
||||
this.state_item.Header = state_text;
|
||||
this.state_item.UpdateLayout();
|
||||
|
||||
if(Controller.Projects.Length == state_menu_items.Length) {
|
||||
for(int i = 0; i < Controller.Projects.Length; i++)
|
||||
state_menu_items[i].Header = Controller.Projects[i].StatusMessage;
|
||||
}
|
||||
|
||||
this.notify_icon.HeaderText = "SparkleShare\n" + state_text;
|
||||
});
|
||||
};
|
||||
|
||||
Controller.UpdateMenuEvent += delegate (IconState state) {
|
||||
Dispatcher.BeginInvoke ((Action) delegate {
|
||||
CreateMenu ();
|
||||
});
|
||||
|
||||
Controller.UpdateMenuEvent += delegate {
|
||||
Dispatcher.BeginInvoke((Action) CreateMenu);
|
||||
};
|
||||
|
||||
Controller.UpdateQuitItemEvent += delegate (bool item_enabled) {
|
||||
Dispatcher.BeginInvoke ((Action) delegate {
|
||||
|
||||
Controller.UpdateQuitItemEvent += delegate(bool item_enabled) {
|
||||
Dispatcher.BeginInvoke((Action) delegate {
|
||||
this.exit_item.IsEnabled = item_enabled;
|
||||
this.exit_item.UpdateLayout ();
|
||||
this.exit_item.UpdateLayout();
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
public void CreateMenu ()
|
||||
{
|
||||
this.context_menu = new ContextMenu ();
|
||||
public void CreateMenu() {
|
||||
this.context_menu = new ContextMenu();
|
||||
|
||||
this.state_item = new SparkleMenuItem () {
|
||||
Header = Controller.StateText,
|
||||
this.state_item = new SparkleMenuItem {
|
||||
Header = Controller.StateText,
|
||||
IsEnabled = false
|
||||
};
|
||||
|
||||
Image folder_image = new Image () {
|
||||
Source = SparkleUIHelpers.GetImageSource ("sparkleshare-folder"),
|
||||
Width = 16,
|
||||
|
||||
Image folder_image = new Image {
|
||||
Source = SparkleUIHelpers.GetImageSource("sparkleshare-folder"),
|
||||
Width = 16,
|
||||
Height = 16
|
||||
};
|
||||
|
||||
SparkleMenuItem folder_item = new SparkleMenuItem () {
|
||||
|
||||
SparkleMenuItem folder_item = new SparkleMenuItem {
|
||||
Header = "SparkleShare",
|
||||
Icon = folder_image
|
||||
Icon = folder_image
|
||||
};
|
||||
|
||||
SparkleMenuItem add_item = new SparkleMenuItem () { Header = "Add hosted project…" };
|
||||
|
||||
this.log_item = new SparkleMenuItem () {
|
||||
Header = "Recent changes…",
|
||||
|
||||
SparkleMenuItem add_item = new SparkleMenuItem {
|
||||
Header = "Add hosted project…"
|
||||
};
|
||||
|
||||
this.log_item = new SparkleMenuItem {
|
||||
Header = "Recent changes…",
|
||||
IsEnabled = Controller.RecentEventsItemEnabled
|
||||
};
|
||||
|
||||
SparkleMenuItem link_code_item = new SparkleMenuItem () { Header = "Client ID" };
|
||||
|
||||
if (Controller.LinkCodeItemEnabled) {
|
||||
SparkleMenuItem code_item = new SparkleMenuItem ();
|
||||
code_item.Header = Program.Controller.CurrentUser.PublicKey.Substring (0, 20) + "...";
|
||||
|
||||
SparkleMenuItem copy_item = new SparkleMenuItem () { Header = "Copy to Clipboard" };
|
||||
copy_item.Click += delegate { Controller.CopyToClipboardClicked (); };
|
||||
|
||||
link_code_item.Items.Add (code_item);
|
||||
link_code_item.Items.Add (new Separator());
|
||||
link_code_item.Items.Add (copy_item);
|
||||
SparkleMenuItem link_code_item = new SparkleMenuItem {
|
||||
Header = "Client ID"
|
||||
};
|
||||
|
||||
if(Controller.LinkCodeItemEnabled) {
|
||||
SparkleMenuItem code_item = new SparkleMenuItem {
|
||||
Header = Program.Controller.CurrentUser.PublicKey.Substring(0, 20) + "..."
|
||||
};
|
||||
|
||||
SparkleMenuItem copy_item = new SparkleMenuItem {
|
||||
Header = "Copy to Clipboard"
|
||||
};
|
||||
copy_item.Click += delegate {
|
||||
Controller.CopyToClipboardClicked();
|
||||
};
|
||||
|
||||
link_code_item.Items.Add(code_item);
|
||||
link_code_item.Items.Add(new Separator());
|
||||
link_code_item.Items.Add(copy_item);
|
||||
}
|
||||
|
||||
CheckBox notify_check_box = new CheckBox () {
|
||||
Margin = new Thickness (6, 0, 0, 0),
|
||||
CheckBox notify_check_box = new CheckBox {
|
||||
Margin = new Thickness(6, 0, 0, 0),
|
||||
IsChecked = Program.Controller.NotificationsEnabled
|
||||
};
|
||||
|
||||
SparkleMenuItem notify_item = new SparkleMenuItem () { Header = "Notifications" };
|
||||
notify_item.Icon = notify_check_box;
|
||||
|
||||
SparkleMenuItem about_item = new SparkleMenuItem () { Header = "About SparkleShare" };
|
||||
this.exit_item = new SparkleMenuItem () { Header = "Exit" };
|
||||
|
||||
|
||||
add_item.Click += delegate { Controller.AddHostedProjectClicked (); };
|
||||
this.log_item.Click += delegate { Controller.RecentEventsClicked (); };
|
||||
about_item.Click += delegate { Controller.AboutClicked (); };
|
||||
|
||||
SparkleMenuItem notify_item = new SparkleMenuItem {
|
||||
Header = "Notifications",
|
||||
Icon = notify_check_box
|
||||
};
|
||||
|
||||
SparkleMenuItem about_item = new SparkleMenuItem {
|
||||
Header = "About SparkleShare"
|
||||
};
|
||||
this.exit_item = new SparkleMenuItem {
|
||||
Header = "Exit"
|
||||
};
|
||||
|
||||
|
||||
add_item.Click += delegate {
|
||||
Controller.AddHostedProjectClicked();
|
||||
};
|
||||
this.log_item.Click += delegate {
|
||||
Controller.RecentEventsClicked();
|
||||
};
|
||||
about_item.Click += delegate {
|
||||
Controller.AboutClicked();
|
||||
};
|
||||
|
||||
notify_check_box.Click += delegate {
|
||||
this.context_menu.IsOpen = false;
|
||||
Program.Controller.ToggleNotifications ();
|
||||
Program.Controller.ToggleNotifications();
|
||||
notify_check_box.IsChecked = Program.Controller.NotificationsEnabled;
|
||||
};
|
||||
|
||||
|
||||
notify_item.Click += delegate {
|
||||
Program.Controller.ToggleNotifications ();
|
||||
Program.Controller.ToggleNotifications();
|
||||
notify_check_box.IsChecked = Program.Controller.NotificationsEnabled;
|
||||
};
|
||||
|
||||
|
||||
this.exit_item.Click += delegate {
|
||||
this.notify_icon.Dispose ();
|
||||
Controller.QuitClicked ();
|
||||
this.notify_icon.Dispose();
|
||||
Controller.QuitClicked();
|
||||
};
|
||||
|
||||
|
||||
this.context_menu.Items.Add (this.state_item);
|
||||
this.context_menu.Items.Add (new Separator ());
|
||||
this.context_menu.Items.Add (folder_item);
|
||||
|
||||
this.state_menu_items = new SparkleMenuItem [Controller.Projects.Length];
|
||||
|
||||
// FIXME Add event handlers for pausing
|
||||
if (Controller.Projects.Length > 0) {
|
||||
this.context_menu.Items.Add(this.state_item);
|
||||
this.context_menu.Items.Add(new Separator());
|
||||
this.context_menu.Items.Add(folder_item);
|
||||
|
||||
state_menu_items = new SparkleMenuItem[Controller.Projects.Length];
|
||||
|
||||
if(Controller.Projects.Length > 0) {
|
||||
int i = 0;
|
||||
foreach (ProjectInfo project in Controller.Projects) {
|
||||
SparkleMenuItem item = new SparkleMenuItem () {
|
||||
Header = project.Name.Replace ("_", "__")
|
||||
foreach(ProjectInfo project in Controller.Projects) {
|
||||
|
||||
SparkleMenuItem subfolder_item = new SparkleMenuItem {
|
||||
Header = project.Name.Replace("_", "__"),
|
||||
Icon = new Image {
|
||||
Source = SparkleUIHelpers.GetImageSource("folder"),
|
||||
Width = 16,
|
||||
Height = 16
|
||||
}
|
||||
};
|
||||
|
||||
item.Icon = new Image () {
|
||||
Source = SparkleUIHelpers.GetImageSource ("folder"),
|
||||
Width = 16,
|
||||
Height = 16
|
||||
};
|
||||
|
||||
this.state_menu_items [i] = new SparkleMenuItem () {
|
||||
state_menu_items[i] = new SparkleMenuItem {
|
||||
Header = project.StatusMessage,
|
||||
IsEnabled = false
|
||||
};
|
||||
|
||||
item.Items.Add (this.state_menu_items [i]);
|
||||
item.Items.Add (new Separator ());
|
||||
subfolder_item.Items.Add(state_menu_items[i]);
|
||||
subfolder_item.Items.Add(new Separator());
|
||||
|
||||
if (project.IsPaused) {
|
||||
if(project.IsPaused) {
|
||||
SparkleMenuItem resume_item;
|
||||
|
||||
if (project.UnsyncedChangesInfo.Count > 0) {
|
||||
foreach (KeyValuePair<string, string> pair in project.UnsyncedChangesInfo)
|
||||
item.Items.Add (new SparkleMenuItem () {
|
||||
|
||||
if(project.UnsyncedChangesInfo.Count > 0) {
|
||||
foreach(KeyValuePair<string, string> pair in project.UnsyncedChangesInfo)
|
||||
subfolder_item.Items.Add(new SparkleMenuItem {
|
||||
Header = pair.Key,
|
||||
// TODO image
|
||||
IsEnabled = false
|
||||
});
|
||||
|
||||
if (!string.IsNullOrEmpty (project.MoreUnsyncedChanges)) {
|
||||
item.Items.Add (new SparkleMenuItem () {
|
||||
if(!string.IsNullOrEmpty(project.MoreUnsyncedChanges)) {
|
||||
subfolder_item.Items.Add(new SparkleMenuItem {
|
||||
Header = project.MoreUnsyncedChanges,
|
||||
IsEnabled = false
|
||||
});
|
||||
}
|
||||
|
||||
item.Items.Add (new Separator ());
|
||||
resume_item = new SparkleMenuItem () { Header = "Sync and Resume…" };
|
||||
|
||||
} else {
|
||||
resume_item = new SparkleMenuItem () { Header = "Resume" };
|
||||
}
|
||||
|
||||
//resume_item.Click += Controller.ResumeDelegate (project.Name);
|
||||
item.Items.Add (resume_item);
|
||||
|
||||
} else {
|
||||
if (Controller.Projects [i].HasError) {
|
||||
item.Icon = new Image () {
|
||||
Source = (BitmapSource) Imaging.CreateBitmapSourceFromHIcon (
|
||||
System.Drawing.SystemIcons.Exclamation.Handle, Int32Rect.Empty,
|
||||
BitmapSizeOptions.FromWidthAndHeight (16,16))
|
||||
subfolder_item.Items.Add(new Separator());
|
||||
resume_item = new SparkleMenuItem {
|
||||
Header = "Sync and Resume…"
|
||||
};
|
||||
|
||||
SparkleMenuItem try_again_item = new SparkleMenuItem () { Header = "Try Again" };
|
||||
//try_again_item.Click += Controller.TryAgainDelegate (project.Name);
|
||||
item.Items.Add (try_again_item);
|
||||
|
||||
} else {
|
||||
SparkleMenuItem pause_item = new SparkleMenuItem () { Header = "Pause" };
|
||||
//pause_item.Click += Controller.PauseDelegate (project.Name);
|
||||
item.Items.Add (pause_item);
|
||||
resume_item = new SparkleMenuItem {
|
||||
Header = "Resume"
|
||||
};
|
||||
}
|
||||
|
||||
resume_item.Click += (sender, e) => Controller.ResumeDelegate(project.Name)(sender, e);
|
||||
subfolder_item.Items.Add(resume_item);
|
||||
|
||||
} else {
|
||||
if(Controller.Projects[i].HasError) {
|
||||
subfolder_item.Icon = new Image {
|
||||
Source = Imaging.CreateBitmapSourceFromHIcon(
|
||||
Drawing.SystemIcons.Exclamation.Handle, Int32Rect.Empty,
|
||||
BitmapSizeOptions.FromWidthAndHeight(16, 16))
|
||||
};
|
||||
|
||||
SparkleMenuItem try_again_item = new SparkleMenuItem {
|
||||
Header = "Try Again"
|
||||
};
|
||||
try_again_item.Click += (sender, e) => Controller.TryAgainDelegate(project.Name)(sender, e);
|
||||
subfolder_item.Items.Add(try_again_item);
|
||||
|
||||
} else {
|
||||
SparkleMenuItem pause_item = new SparkleMenuItem {
|
||||
Header = "Pause"
|
||||
};
|
||||
pause_item.Click +=
|
||||
(sender, e) => Controller.PauseDelegate(project.Name)(sender, e);
|
||||
subfolder_item.Items.Add(pause_item);
|
||||
}
|
||||
}
|
||||
|
||||
this.context_menu.Items.Add (item);
|
||||
|
||||
this.context_menu.Items.Add(subfolder_item);
|
||||
i++;
|
||||
};
|
||||
}
|
||||
|
||||
folder_item.Items.Add(this.log_item);
|
||||
folder_item.Items.Add(add_item);
|
||||
folder_item.Items.Add(new Separator());
|
||||
folder_item.Items.Add(notify_item);
|
||||
folder_item.Items.Add(new Separator());
|
||||
folder_item.Items.Add(link_code_item);
|
||||
folder_item.Items.Add(new Separator());
|
||||
folder_item.Items.Add(about_item);
|
||||
|
||||
folder_item.Items.Add (this.log_item);
|
||||
folder_item.Items.Add (add_item);
|
||||
folder_item.Items.Add (new Separator ());
|
||||
folder_item.Items.Add (notify_item);
|
||||
folder_item.Items.Add (new Separator ());
|
||||
folder_item.Items.Add (link_code_item);
|
||||
folder_item.Items.Add (new Separator ());
|
||||
folder_item.Items.Add (about_item);
|
||||
this.context_menu.Items.Add(new Separator());
|
||||
this.context_menu.Items.Add(this.exit_item);
|
||||
|
||||
this.context_menu.Items.Add (new Separator ());
|
||||
this.context_menu.Items.Add (this.exit_item);
|
||||
|
||||
this.notify_icon.ContextMenu = this.context_menu;
|
||||
}
|
||||
|
||||
|
||||
public void ShowBalloon (string title, string subtext, string image_path)
|
||||
{
|
||||
this.notify_icon.ShowBalloonTip (title, subtext, image_path);
|
||||
}
|
||||
|
||||
|
||||
public void Dispose ()
|
||||
{
|
||||
this.notify_icon.Dispose ();
|
||||
public void ShowBalloon(string title, string subtext, string image_path) {
|
||||
this.notify_icon.ShowBalloonTip(title, subtext, image_path);
|
||||
}
|
||||
|
||||
|
||||
public void Dispose() {
|
||||
this.notify_icon.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public class SparkleMenuItem : MenuItem {
|
||||
|
||||
public SparkleMenuItem () : base ()
|
||||
{
|
||||
Padding = new Thickness (6, 3, 4, 0);
|
||||
|
||||
public SparkleMenuItem() {
|
||||
Padding = new Thickness(6, 3, 4, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue