Removed P/Invokes, now uses native ContextMenu handling.

This commit is contained in:
Mark Lopez 2014-11-02 13:00:02 -07:00
parent 1cce51d66d
commit 013fa89ce4
3 changed files with 306 additions and 462 deletions

View file

@ -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;
}
}

View file

@ -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">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aa_bb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=Parameters/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aa_bb" /&gt;</s:String></wpf:ResourceDictionary>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=Parameters/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aa_bb" /&gt;</s:String>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

View file

@ -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);
}
}
}