diff --git a/WinAlfred.Plugin.System/BaseSystemPlugin.cs b/WinAlfred.Plugin.System/BaseSystemPlugin.cs index 997261ca24..548196a30e 100644 --- a/WinAlfred.Plugin.System/BaseSystemPlugin.cs +++ b/WinAlfred.Plugin.System/BaseSystemPlugin.cs @@ -12,6 +12,7 @@ namespace WinAlfred.Plugin.System public List Query(Query query) { + if (string.IsNullOrEmpty(query.RawQuery) || query.RawQuery.EndsWith(" ")) return new List(); return QueryInternal(query); } diff --git a/WinAlfred.Plugin.System/Setting.cs b/WinAlfred.Plugin.System/Setting.cs new file mode 100644 index 0000000000..59b90c168f --- /dev/null +++ b/WinAlfred.Plugin.System/Setting.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace WinAlfred.Plugin.System +{ + public class Setting : BaseSystemPlugin + { + private PluginInitContext context; + protected override List QueryInternal(Query query) + { + List results = new List(); + if ("setting".Contains(query.RawQuery.ToLower())) + { + results.Add(new Result() + { + Title = "WinAlfred Setting Dialog", + Score = 100, + IcoPath = "Images/app.png", + Action = () => context.OpenSettingDialog() + }); + } + + return results; + } + + protected override void InitInternal(PluginInitContext context) + { + this.context = context; + } + } +} diff --git a/WinAlfred.Plugin.System/Sys.cs b/WinAlfred.Plugin.System/Sys.cs index 6b3b6fd2d0..edcdffe7c5 100644 --- a/WinAlfred.Plugin.System/Sys.cs +++ b/WinAlfred.Plugin.System/Sys.cs @@ -70,7 +70,7 @@ namespace WinAlfred.Plugin.System Title = "Exit", SubTitle = "Close this app", Score = 110, - IcoPath = "Images\\ico.png", + IcoPath = "Images\\app.png", Action = () => context.CloseApp() }); } diff --git a/WinAlfred.Plugin.System/WinAlfred.Plugin.System.csproj b/WinAlfred.Plugin.System/WinAlfred.Plugin.System.csproj index 14b1c7ec18..cfccceaa14 100644 --- a/WinAlfred.Plugin.System/WinAlfred.Plugin.System.csproj +++ b/WinAlfred.Plugin.System/WinAlfred.Plugin.System.csproj @@ -52,6 +52,7 @@ + diff --git a/WinAlfred.Plugin/PluginInitContext.cs b/WinAlfred.Plugin/PluginInitContext.cs index 1e25a60b8e..3f23bba3dc 100644 --- a/WinAlfred.Plugin/PluginInitContext.cs +++ b/WinAlfred.Plugin/PluginInitContext.cs @@ -15,5 +15,6 @@ namespace WinAlfred.Plugin public Action HideApp { get; set; } public Action ShowApp { get; set; } public Action ShowMsg { get; set; } + public Action OpenSettingDialog { get; set; } } } diff --git a/WinAlfred/App.xaml b/WinAlfred/App.xaml index 43657b4414..e9810181ff 100644 --- a/WinAlfred/App.xaml +++ b/WinAlfred/App.xaml @@ -4,56 +4,9 @@ > - - - + + + diff --git a/WinAlfred/Helper/Settings.cs b/WinAlfred/Helper/Settings.cs new file mode 100644 index 0000000000..3d58177b32 --- /dev/null +++ b/WinAlfred/Helper/Settings.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; + +namespace WinAlfred.Helper +{ + public class Settings + { + private string configPath = Directory.GetCurrentDirectory() + "\\config.ini"; + private static readonly Settings settings = new Settings(); + IniParser parser = new IniParser("config.ini"); + + public string Theme { get; set; } + + private Settings() + { + LoadSettings(); + } + + private void LoadSettings() + { + if (!File.Exists(configPath)) File.Create(configPath); + Theme = parser.GetSetting("ui", "theme"); + } + + public void SaveSettings() + { + parser.AddSetting("ui", "theme", Theme); + parser.SaveSettings(); + } + + public static Settings Instance + { + get + { + return settings; + } + } + + + } +} diff --git a/WinAlfred/Images/app.png b/WinAlfred/Images/app.png new file mode 100644 index 0000000000..d24f3550dd Binary files /dev/null and b/WinAlfred/Images/app.png differ diff --git a/WinAlfred/Images/ico.png b/WinAlfred/Images/ico.png deleted file mode 100644 index 64196dec7c..0000000000 Binary files a/WinAlfred/Images/ico.png and /dev/null differ diff --git a/WinAlfred/MainWindow.xaml b/WinAlfred/MainWindow.xaml index bb69c1e6b7..5d9ee64dd3 100644 --- a/WinAlfred/MainWindow.xaml +++ b/WinAlfred/MainWindow.xaml @@ -1,8 +1,7 @@  - + - + - - - + + + - - + \ No newline at end of file diff --git a/WinAlfred/MainWindow.xaml.cs b/WinAlfred/MainWindow.xaml.cs index 2abe99c93e..a75a10912d 100644 --- a/WinAlfred/MainWindow.xaml.cs +++ b/WinAlfred/MainWindow.xaml.cs @@ -11,6 +11,7 @@ using WinAlfred.Commands; using WinAlfred.Helper; using WinAlfred.Plugin; using WinAlfred.PluginLoader; +using Application = System.Windows.Application; using KeyEventArgs = System.Windows.Input.KeyEventArgs; using MessageBox = System.Windows.MessageBox; @@ -34,6 +35,8 @@ namespace WinAlfred resultCtrl.resultItemChangedEvent += resultCtrl_resultItemChangedEvent; ThreadPool.SetMaxThreads(30, 10); InitProgressbarAnimation(); + + ChangeStyles(Settings.Instance.Theme); } private void WakeupApp() @@ -50,7 +53,7 @@ namespace WinAlfred double oldLeft = Left; Left = 20000; ShowWinAlfred(); - cmdDispatcher.DispatchCommand(new Query("qq"),false); + cmdDispatcher.DispatchCommand(new Query("qq"), false); HideWinAlfred(); Left = oldLeft; } @@ -84,8 +87,8 @@ namespace WinAlfred private void resultCtrl_resultItemChangedEvent() { - Height = resultCtrl.pnlContainer.ActualHeight + tbQuery.Height + tbQuery.Margin.Top + tbQuery.Margin.Bottom; - resultCtrl.Margin = resultCtrl.GetCurrentResultCount() > 0 ? new Thickness { Bottom = 10, Left = 10, Right = 10 } : new Thickness { Bottom = 0, Left = 10, Right = 10 }; + //Height = resultCtrl.pnlContainer.ActualHeight + tbQuery.Height + tbQuery.Margin.Top + tbQuery.Margin.Bottom; + resultCtrl.Margin = resultCtrl.GetCurrentResultCount() > 0 ? new Thickness { Top = 10 } : new Thickness { Top = 0 }; } private void OnHotKey(object sender, KeyPressedEventArgs e) @@ -250,7 +253,7 @@ namespace WinAlfred //todo:this used be opened to users, it's they choise use it or not in thier workflows list.ForEach(o => { - if(o.AutoAjustScore) o.Score += selectedRecords.GetSelectedCount(o); + if (o.AutoAjustScore) o.Score += selectedRecords.GetSelectedCount(o); }); resultCtrl.Dispatcher.Invoke(new Action(() => { @@ -260,6 +263,17 @@ namespace WinAlfred } } + public void ChangeStyles(string themeName) + { + ResourceDictionary dict = new ResourceDictionary + { + Source = new Uri("pack://application:,,,/Themes/" + themeName + ".xaml") + }; + + Application.Current.Resources.MergedDictionaries.Clear(); + Application.Current.Resources.MergedDictionaries.Add(dict); + } + #region Public API //Those method can be invoked by plugins @@ -292,7 +306,14 @@ namespace WinAlfred m.Show(title, subTitle, iconPath); } + public void OpenSettingDialog() + { + SettingWidow s = new SettingWidow(this); + s.Show(); + } + #endregion + } } \ No newline at end of file diff --git a/WinAlfred/PluginLoader/Plugins.cs b/WinAlfred/PluginLoader/Plugins.cs index 19745be993..62d9a6dd4f 100644 --- a/WinAlfred/PluginLoader/Plugins.cs +++ b/WinAlfred/PluginLoader/Plugins.cs @@ -34,7 +34,8 @@ namespace WinAlfred.PluginLoader CloseApp = window.CloseApp, HideApp = window.HideApp, ShowApp = () => window.ShowApp(), - ShowMsg = (title, subTitle, iconPath) => window.ShowMsg(title, subTitle, iconPath) + ShowMsg = (title, subTitle, iconPath) => window.ShowMsg(title, subTitle, iconPath), + OpenSettingDialog = ()=> window.OpenSettingDialog() })); } } diff --git a/WinAlfred/Properties/Annotations.cs b/WinAlfred/Properties/Annotations.cs new file mode 100644 index 0000000000..03f2d06e6d --- /dev/null +++ b/WinAlfred/Properties/Annotations.cs @@ -0,0 +1,577 @@ +using System; + +#pragma warning disable 1591 +// ReSharper disable UnusedMember.Global +// ReSharper disable MemberCanBePrivate.Global +// ReSharper disable UnusedAutoPropertyAccessor.Global +// ReSharper disable IntroduceOptionalParameters.Global +// ReSharper disable MemberCanBeProtected.Global +// ReSharper disable InconsistentNaming + +namespace WinAlfred.Annotations +{ + /// + /// Indicates that the value of the marked element could be null sometimes, + /// so the check for null is necessary before its usage + /// + /// + /// [CanBeNull] public object Test() { return null; } + /// public void UseTest() { + /// var p = Test(); + /// var s = p.ToString(); // Warning: Possible 'System.NullReferenceException' + /// } + /// + [AttributeUsage( + AttributeTargets.Method | AttributeTargets.Parameter | + AttributeTargets.Property | AttributeTargets.Delegate | + AttributeTargets.Field, AllowMultiple = false, Inherited = true)] + public sealed class CanBeNullAttribute : Attribute { } + + /// + /// Indicates that the value of the marked element could never be null + /// + /// + /// [NotNull] public object Foo() { + /// return null; // Warning: Possible 'null' assignment + /// } + /// + [AttributeUsage( + AttributeTargets.Method | AttributeTargets.Parameter | + AttributeTargets.Property | AttributeTargets.Delegate | + AttributeTargets.Field, AllowMultiple = false, Inherited = true)] + public sealed class NotNullAttribute : Attribute { } + + /// + /// Indicates that the marked method builds string by format pattern and (optional) arguments. + /// Parameter, which contains format string, should be given in constructor. The format string + /// should be in -like form + /// + /// + /// [StringFormatMethod("message")] + /// public void ShowError(string message, params object[] args) { /* do something */ } + /// public void Foo() { + /// ShowError("Failed: {0}"); // Warning: Non-existing argument in format string + /// } + /// + [AttributeUsage( + AttributeTargets.Constructor | AttributeTargets.Method, + AllowMultiple = false, Inherited = true)] + public sealed class StringFormatMethodAttribute : Attribute + { + /// + /// Specifies which parameter of an annotated method should be treated as format-string + /// + public StringFormatMethodAttribute(string formatParameterName) + { + FormatParameterName = formatParameterName; + } + + public string FormatParameterName { get; private set; } + } + + /// + /// Indicates that the function argument should be string literal and match one + /// of the parameters of the caller function. For example, ReSharper annotates + /// the parameter of + /// + /// + /// public void Foo(string param) { + /// if (param == null) + /// throw new ArgumentNullException("par"); // Warning: Cannot resolve symbol + /// } + /// + [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)] + public sealed class InvokerParameterNameAttribute : Attribute { } + + /// + /// Indicates that the method is contained in a type that implements + /// interface + /// and this method is used to notify that some property value changed + /// + /// + /// The method should be non-static and conform to one of the supported signatures: + /// + /// NotifyChanged(string) + /// NotifyChanged(params string[]) + /// NotifyChanged{T}(Expression{Func{T}}) + /// NotifyChanged{T,U}(Expression{Func{T,U}}) + /// SetProperty{T}(ref T, T, string) + /// + /// + /// + /// public class Foo : INotifyPropertyChanged { + /// public event PropertyChangedEventHandler PropertyChanged; + /// [NotifyPropertyChangedInvocator] + /// protected virtual void NotifyChanged(string propertyName) { ... } + /// + /// private string _name; + /// public string Name { + /// get { return _name; } + /// set { _name = value; NotifyChanged("LastName"); /* Warning */ } + /// } + /// } + /// + /// Examples of generated notifications: + /// + /// NotifyChanged("Property") + /// NotifyChanged(() => Property) + /// NotifyChanged((VM x) => x.Property) + /// SetProperty(ref myField, value, "Property") + /// + /// + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)] + public sealed class NotifyPropertyChangedInvocatorAttribute : Attribute + { + public NotifyPropertyChangedInvocatorAttribute() { } + public NotifyPropertyChangedInvocatorAttribute(string parameterName) + { + ParameterName = parameterName; + } + + public string ParameterName { get; private set; } + } + + /// + /// Describes dependency between method input and output + /// + /// + ///

Function Definition Table syntax:

+ /// + /// FDT ::= FDTRow [;FDTRow]* + /// FDTRow ::= Input => Output | Output <= Input + /// Input ::= ParameterName: Value [, Input]* + /// Output ::= [ParameterName: Value]* {halt|stop|void|nothing|Value} + /// Value ::= true | false | null | notnull | canbenull + /// + /// If method has single input parameter, it's name could be omitted.
+ /// Using halt (or void/nothing, which is the same) + /// for method output means that the methos doesn't return normally.
+ /// canbenull annotation is only applicable for output parameters.
+ /// You can use multiple [ContractAnnotation] for each FDT row, + /// or use single attribute with rows separated by semicolon.
+ ///
+ /// + /// + /// [ContractAnnotation("=> halt")] + /// public void TerminationMethod() + /// + /// + /// [ContractAnnotation("halt <= condition: false")] + /// public void Assert(bool condition, string text) // regular assertion method + /// + /// + /// [ContractAnnotation("s:null => true")] + /// public bool IsNullOrEmpty(string s) // string.IsNullOrEmpty() + /// + /// + /// // A method that returns null if the parameter is null, and not null if the parameter is not null + /// [ContractAnnotation("null => null; notnull => notnull")] + /// public object Transform(object data) + /// + /// + /// [ContractAnnotation("s:null=>false; =>true,result:notnull; =>false, result:null")] + /// public bool TryParse(string s, out Person result) + /// + /// + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)] + public sealed class ContractAnnotationAttribute : Attribute + { + public ContractAnnotationAttribute([NotNull] string contract) + : this(contract, false) { } + + public ContractAnnotationAttribute([NotNull] string contract, bool forceFullStates) + { + Contract = contract; + ForceFullStates = forceFullStates; + } + + public string Contract { get; private set; } + public bool ForceFullStates { get; private set; } + } + + /// + /// Indicates that marked element should be localized or not + /// + /// + /// [LocalizationRequiredAttribute(true)] + /// public class Foo { + /// private string str = "my string"; // Warning: Localizable string + /// } + /// + [AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = true)] + public sealed class LocalizationRequiredAttribute : Attribute + { + public LocalizationRequiredAttribute() : this(true) { } + public LocalizationRequiredAttribute(bool required) + { + Required = required; + } + + public bool Required { get; private set; } + } + + /// + /// Indicates that the value of the marked type (or its derivatives) + /// cannot be compared using '==' or '!=' operators and Equals() + /// should be used instead. However, using '==' or '!=' for comparison + /// with null is always permitted. + /// + /// + /// [CannotApplyEqualityOperator] + /// class NoEquality { } + /// class UsesNoEquality { + /// public void Test() { + /// var ca1 = new NoEquality(); + /// var ca2 = new NoEquality(); + /// if (ca1 != null) { // OK + /// bool condition = ca1 == ca2; // Warning + /// } + /// } + /// } + /// + [AttributeUsage( + AttributeTargets.Interface | AttributeTargets.Class | + AttributeTargets.Struct, AllowMultiple = false, Inherited = true)] + public sealed class CannotApplyEqualityOperatorAttribute : Attribute { } + + /// + /// When applied to a target attribute, specifies a requirement for any type marked + /// with the target attribute to implement or inherit specific type or types. + /// + /// + /// [BaseTypeRequired(typeof(IComponent)] // Specify requirement + /// public class ComponentAttribute : Attribute { } + /// [Component] // ComponentAttribute requires implementing IComponent interface + /// public class MyComponent : IComponent { } + /// + [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)] + [BaseTypeRequired(typeof(Attribute))] + public sealed class BaseTypeRequiredAttribute : Attribute + { + public BaseTypeRequiredAttribute([NotNull] Type baseType) + { + BaseType = baseType; + } + + [NotNull] public Type BaseType { get; private set; } + } + + /// + /// Indicates that the marked symbol is used implicitly + /// (e.g. via reflection, in external library), so this symbol + /// will not be marked as unused (as well as by other usage inspections) + /// + [AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = true)] + public sealed class UsedImplicitlyAttribute : Attribute + { + public UsedImplicitlyAttribute() + : this(ImplicitUseKindFlags.Default, ImplicitUseTargetFlags.Default) { } + + public UsedImplicitlyAttribute(ImplicitUseKindFlags useKindFlags) + : this(useKindFlags, ImplicitUseTargetFlags.Default) { } + + public UsedImplicitlyAttribute(ImplicitUseTargetFlags targetFlags) + : this(ImplicitUseKindFlags.Default, targetFlags) { } + + public UsedImplicitlyAttribute( + ImplicitUseKindFlags useKindFlags, ImplicitUseTargetFlags targetFlags) + { + UseKindFlags = useKindFlags; + TargetFlags = targetFlags; + } + + public ImplicitUseKindFlags UseKindFlags { get; private set; } + public ImplicitUseTargetFlags TargetFlags { get; private set; } + } + + /// + /// Should be used on attributes and causes ReSharper + /// to not mark symbols marked with such attributes as unused + /// (as well as by other usage inspections) + /// + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)] + public sealed class MeansImplicitUseAttribute : Attribute + { + public MeansImplicitUseAttribute() + : this(ImplicitUseKindFlags.Default, ImplicitUseTargetFlags.Default) { } + + public MeansImplicitUseAttribute(ImplicitUseKindFlags useKindFlags) + : this(useKindFlags, ImplicitUseTargetFlags.Default) { } + + public MeansImplicitUseAttribute(ImplicitUseTargetFlags targetFlags) + : this(ImplicitUseKindFlags.Default, targetFlags) { } + + public MeansImplicitUseAttribute( + ImplicitUseKindFlags useKindFlags, ImplicitUseTargetFlags targetFlags) + { + UseKindFlags = useKindFlags; + TargetFlags = targetFlags; + } + + [UsedImplicitly] public ImplicitUseKindFlags UseKindFlags { get; private set; } + [UsedImplicitly] public ImplicitUseTargetFlags TargetFlags { get; private set; } + } + + [Flags] + public enum ImplicitUseKindFlags + { + Default = Access | Assign | InstantiatedWithFixedConstructorSignature, + /// Only entity marked with attribute considered used + Access = 1, + /// Indicates implicit assignment to a member + Assign = 2, + /// + /// Indicates implicit instantiation of a type with fixed constructor signature. + /// That means any unused constructor parameters won't be reported as such. + /// + InstantiatedWithFixedConstructorSignature = 4, + /// Indicates implicit instantiation of a type + InstantiatedNoFixedConstructorSignature = 8, + } + + /// + /// Specify what is considered used implicitly + /// when marked with + /// or + /// + [Flags] + public enum ImplicitUseTargetFlags + { + Default = Itself, + Itself = 1, + /// Members of entity marked with attribute are considered used + Members = 2, + /// Entity marked with attribute and all its members considered used + WithMembers = Itself | Members + } + + /// + /// This attribute is intended to mark publicly available API + /// which should not be removed and so is treated as used + /// + [MeansImplicitUse] + public sealed class PublicAPIAttribute : Attribute + { + public PublicAPIAttribute() { } + public PublicAPIAttribute([NotNull] string comment) + { + Comment = comment; + } + + [NotNull] public string Comment { get; private set; } + } + + /// + /// Tells code analysis engine if the parameter is completely handled + /// when the invoked method is on stack. If the parameter is a delegate, + /// indicates that delegate is executed while the method is executed. + /// If the parameter is an enumerable, indicates that it is enumerated + /// while the method is executed + /// + [AttributeUsage(AttributeTargets.Parameter, Inherited = true)] + public sealed class InstantHandleAttribute : Attribute { } + + /// + /// Indicates that a method does not make any observable state changes. + /// The same as System.Diagnostics.Contracts.PureAttribute + /// + /// + /// [Pure] private int Multiply(int x, int y) { return x * y; } + /// public void Foo() { + /// const int a = 2, b = 2; + /// Multiply(a, b); // Waring: Return value of pure method is not used + /// } + /// + [AttributeUsage(AttributeTargets.Method, Inherited = true)] + public sealed class PureAttribute : Attribute { } + + /// + /// Indicates that a parameter is a path to a file or a folder + /// within a web project. Path can be relative or absolute, + /// starting from web root (~) + /// + [AttributeUsage(AttributeTargets.Parameter)] + public class PathReferenceAttribute : Attribute + { + public PathReferenceAttribute() { } + public PathReferenceAttribute([PathReference] string basePath) + { + BasePath = basePath; + } + + [NotNull] public string BasePath { get; private set; } + } + + // ASP.NET MVC attributes + + /// + /// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter + /// is an MVC action. If applied to a method, the MVC action name is calculated + /// implicitly from the context. Use this attribute for custom wrappers similar to + /// System.Web.Mvc.Html.ChildActionExtensions.RenderAction(HtmlHelper, String) + /// + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method)] + public sealed class AspMvcActionAttribute : Attribute + { + public AspMvcActionAttribute() { } + public AspMvcActionAttribute([NotNull] string anonymousProperty) + { + AnonymousProperty = anonymousProperty; + } + + [NotNull] public string AnonymousProperty { get; private set; } + } + + /// + /// ASP.NET MVC attribute. Indicates that a parameter is an MVC area. + /// Use this attribute for custom wrappers similar to + /// System.Web.Mvc.Html.ChildActionExtensions.RenderAction(HtmlHelper, String) + /// + [AttributeUsage(AttributeTargets.Parameter)] + public sealed class AspMvcAreaAttribute : PathReferenceAttribute + { + public AspMvcAreaAttribute() { } + public AspMvcAreaAttribute([NotNull] string anonymousProperty) + { + AnonymousProperty = anonymousProperty; + } + + [NotNull] public string AnonymousProperty { get; private set; } + } + + /// + /// ASP.NET MVC attribute. If applied to a parameter, indicates that + /// the parameter is an MVC controller. If applied to a method, + /// the MVC controller name is calculated implicitly from the context. + /// Use this attribute for custom wrappers similar to + /// System.Web.Mvc.Html.ChildActionExtensions.RenderAction(HtmlHelper, String, String) + /// + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method)] + public sealed class AspMvcControllerAttribute : Attribute + { + public AspMvcControllerAttribute() { } + public AspMvcControllerAttribute([NotNull] string anonymousProperty) + { + AnonymousProperty = anonymousProperty; + } + + [NotNull] public string AnonymousProperty { get; private set; } + } + + /// + /// ASP.NET MVC attribute. Indicates that a parameter is an MVC Master. + /// Use this attribute for custom wrappers similar to + /// System.Web.Mvc.Controller.View(String, String) + /// + [AttributeUsage(AttributeTargets.Parameter)] + public sealed class AspMvcMasterAttribute : Attribute { } + + /// + /// ASP.NET MVC attribute. Indicates that a parameter is an MVC model type. + /// Use this attribute for custom wrappers similar to + /// System.Web.Mvc.Controller.View(String, Object) + /// + [AttributeUsage(AttributeTargets.Parameter)] + public sealed class AspMvcModelTypeAttribute : Attribute { } + + /// + /// ASP.NET MVC attribute. If applied to a parameter, indicates that + /// the parameter is an MVC partial view. If applied to a method, + /// the MVC partial view name is calculated implicitly from the context. + /// Use this attribute for custom wrappers similar to + /// System.Web.Mvc.Html.RenderPartialExtensions.RenderPartial(HtmlHelper, String) + /// + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method)] + public sealed class AspMvcPartialViewAttribute : PathReferenceAttribute { } + + /// + /// ASP.NET MVC attribute. Allows disabling all inspections + /// for MVC views within a class or a method. + /// + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] + public sealed class AspMvcSupressViewErrorAttribute : Attribute { } + + /// + /// ASP.NET MVC attribute. Indicates that a parameter is an MVC display template. + /// Use this attribute for custom wrappers similar to + /// System.Web.Mvc.Html.DisplayExtensions.DisplayForModel(HtmlHelper, String) + /// + [AttributeUsage(AttributeTargets.Parameter)] + public sealed class AspMvcDisplayTemplateAttribute : Attribute { } + + /// + /// ASP.NET MVC attribute. Indicates that a parameter is an MVC editor template. + /// Use this attribute for custom wrappers similar to + /// System.Web.Mvc.Html.EditorExtensions.EditorForModel(HtmlHelper, String) + /// + [AttributeUsage(AttributeTargets.Parameter)] + public sealed class AspMvcEditorTemplateAttribute : Attribute { } + + /// + /// ASP.NET MVC attribute. Indicates that a parameter is an MVC template. + /// Use this attribute for custom wrappers similar to + /// System.ComponentModel.DataAnnotations.UIHintAttribute(System.String) + /// + [AttributeUsage(AttributeTargets.Parameter)] + public sealed class AspMvcTemplateAttribute : Attribute { } + + /// + /// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter + /// is an MVC view. If applied to a method, the MVC view name is calculated implicitly + /// from the context. Use this attribute for custom wrappers similar to + /// System.Web.Mvc.Controller.View(Object) + /// + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method)] + public sealed class AspMvcViewAttribute : PathReferenceAttribute { } + + /// + /// ASP.NET MVC attribute. When applied to a parameter of an attribute, + /// indicates that this parameter is an MVC action name + /// + /// + /// [ActionName("Foo")] + /// public ActionResult Login(string returnUrl) { + /// ViewBag.ReturnUrl = Url.Action("Foo"); // OK + /// return RedirectToAction("Bar"); // Error: Cannot resolve action + /// } + /// + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property)] + public sealed class AspMvcActionSelectorAttribute : Attribute { } + + [AttributeUsage( + AttributeTargets.Parameter | AttributeTargets.Property | + AttributeTargets.Field, Inherited = true)] + public sealed class HtmlElementAttributesAttribute : Attribute + { + public HtmlElementAttributesAttribute() { } + public HtmlElementAttributesAttribute([NotNull] string name) + { + Name = name; + } + + [NotNull] public string Name { get; private set; } + } + + [AttributeUsage( + AttributeTargets.Parameter | AttributeTargets.Field | + AttributeTargets.Property, Inherited = true)] + public sealed class HtmlAttributeValueAttribute : Attribute + { + public HtmlAttributeValueAttribute([NotNull] string name) + { + Name = name; + } + + [NotNull] public string Name { get; private set; } + } + + // Razor attributes + + /// + /// Razor attribute. Indicates that a parameter or a method is a Razor section. + /// Use this attribute for custom wrappers similar to + /// System.Web.WebPages.WebPageBase.RenderSection(String) + /// + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method, Inherited = true)] + public sealed class RazorSectionAttribute : Attribute { } +} \ No newline at end of file diff --git a/WinAlfred/ResultItem.xaml b/WinAlfred/ResultItem.xaml index 34d3ef4d25..a664b124ae 100644 --- a/WinAlfred/ResultItem.xaml +++ b/WinAlfred/ResultItem.xaml @@ -5,8 +5,9 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" mc:Ignorable="d" d:DesignWidth="400" + Style="{DynamicResource ItemStyle}" Height="50"> - + @@ -18,8 +19,8 @@ - Title - sdfdsf + Title + sub title diff --git a/WinAlfred/ResultItem.xaml.cs b/WinAlfred/ResultItem.xaml.cs index 389ee3af3a..c2b22f18e6 100644 --- a/WinAlfred/ResultItem.xaml.cs +++ b/WinAlfred/ResultItem.xaml.cs @@ -1,16 +1,18 @@ using System; +using System.ComponentModel; using System.Drawing; using System.IO; using System.Windows; using System.Windows.Controls; using System.Windows.Media; using System.Windows.Media.Imaging; +using WinAlfred.Annotations; using WinAlfred.Plugin; using Brush = System.Windows.Media.Brush; namespace WinAlfred { - public partial class ResultItem : UserControl + public partial class ResultItem : UserControl, INotifyPropertyChanged { private bool selected; @@ -25,17 +27,16 @@ namespace WinAlfred set { selected = value; - BrushConverter bc = new BrushConverter(); - Background = selected ? (Brush)(bc.ConvertFrom("#d1d1d1")) : (Brush)(bc.ConvertFrom("#ebebeb")); if (selected) { img.Visibility = Visibility.Visible; - img.Source = new BitmapImage(new Uri(Directory.GetCurrentDirectory()+"\\Images\\enter.png")); + img.Source = new BitmapImage(new Uri(Directory.GetCurrentDirectory() + "\\Images\\enter.png")); } else { img.Visibility = Visibility.Hidden; } + OnPropertyChanged("Selected"); } } @@ -75,7 +76,7 @@ namespace WinAlfred } } - public static ImageSource GetIcon(string fileName) + private static ImageSource GetIcon(string fileName) { Icon icon = Icon.ExtractAssociatedIcon(fileName); return System.Windows.Interop.Imaging.CreateBitmapSourceFromHIcon( @@ -83,5 +84,14 @@ namespace WinAlfred new Int32Rect(0, 0, icon.Width, icon.Height), BitmapSizeOptions.FromEmptyOptions()); } + + public event PropertyChangedEventHandler PropertyChanged; + + [NotifyPropertyChangedInvocator] + protected virtual void OnPropertyChanged(string propertyName) + { + PropertyChangedEventHandler handler = PropertyChanged; + if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName)); + } } } diff --git a/WinAlfred/ResultPanel.xaml.cs b/WinAlfred/ResultPanel.xaml.cs index 0551a09425..e7e1dbc5ce 100644 --- a/WinAlfred/ResultPanel.xaml.cs +++ b/WinAlfred/ResultPanel.xaml.cs @@ -153,6 +153,7 @@ namespace WinAlfred double scrollPosition = 0; Point newItemBottomPoint = resultItemControl.TranslatePoint(new Point(0, resultItemControl.ActualHeight), pnlContainer); + scrollPosition = newItemBottomPoint.Y; if (index == 0) { sv.ScrollToTop(); @@ -167,7 +168,9 @@ namespace WinAlfred if (index < oldIndex) { //move up and old item is at the top of the scroll view - if (newItemBottomPoint.Y - sv.VerticalOffset == 0) + var scrollPostionY = sv.VerticalOffset - sv.VerticalOffset%resultItemControl.ActualHeight + + resultItemControl.ActualHeight; + if (newItemBottomPoint.Y - scrollPostionY == 0) { scrollPosition = sv.VerticalOffset - resultItemControl.ActualHeight; } @@ -179,7 +182,8 @@ namespace WinAlfred else { //move down and old item is at the bottom of scroll view - if (sv.ActualHeight + sv.VerticalOffset == newItemBottomPoint.Y - resultItemControl.ActualHeight) + double scrollPostionY = (sv.ActualHeight + sv.VerticalOffset) - (sv.ActualHeight + sv.VerticalOffset)%resultItemControl.ActualHeight; + if (scrollPostionY == newItemBottomPoint.Y - resultItemControl.ActualHeight) { scrollPosition = newItemBottomPoint.Y - sv.ActualHeight; } diff --git a/WinAlfred/SettingWindow.xaml b/WinAlfred/SettingWindow.xaml new file mode 100644 index 0000000000..dab9c17916 --- /dev/null +++ b/WinAlfred/SettingWindow.xaml @@ -0,0 +1,13 @@ + + + + + + diff --git a/WinAlfred/SettingWindow.xaml.cs b/WinAlfred/SettingWindow.xaml.cs new file mode 100644 index 0000000000..ec62008bec --- /dev/null +++ b/WinAlfred/SettingWindow.xaml.cs @@ -0,0 +1,46 @@ +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Windows; +using System.Windows.Controls; +using WinAlfred.Helper; + +namespace WinAlfred +{ + public partial class SettingWidow : Window + { + private MainWindow mainWindow; + + public SettingWidow(MainWindow mainWindow) + { + this.mainWindow = mainWindow; + InitializeComponent(); + Loaded += Setting_Loaded; + } + + private void Setting_Loaded(object sender, RoutedEventArgs e) + { + foreach (string theme in LoadAvailableThemes()) + { + string themeName = theme.Substring(theme.LastIndexOf('\\') + 1).Replace(".xaml", ""); + themeComboBox.Items.Add(themeName); + } + + themeComboBox.SelectedItem = Settings.Instance.Theme; + } + + private List LoadAvailableThemes() + { + string themePath = Directory.GetCurrentDirectory() + "\\Themes\\"; + return Directory.GetFiles(themePath).Where(filePath => filePath.EndsWith(".xaml")).ToList(); + } + + private void ThemeComboBox_OnSelectionChanged(object sender, SelectionChangedEventArgs e) + { + string themeName = themeComboBox.SelectedItem.ToString(); + mainWindow.ChangeStyles(themeName); + Settings.Instance.Theme = themeName; + Settings.Instance.SaveSettings(); + } + } +} diff --git a/WinAlfred/Themes/Default.xaml b/WinAlfred/Themes/Default.xaml new file mode 100644 index 0000000000..92a27bc5e1 --- /dev/null +++ b/WinAlfred/Themes/Default.xaml @@ -0,0 +1,43 @@ + + + + + + + + + + + diff --git a/WinAlfred/Themes/Light.xaml b/WinAlfred/Themes/Light.xaml new file mode 100644 index 0000000000..085bfac034 --- /dev/null +++ b/WinAlfred/Themes/Light.xaml @@ -0,0 +1,43 @@ + + + + + + + + + + + diff --git a/WinAlfred/WinAlfred.csproj b/WinAlfred/WinAlfred.csproj index d827c0ec48..79fdf839e1 100644 --- a/WinAlfred/WinAlfred.csproj +++ b/WinAlfred/WinAlfred.csproj @@ -116,6 +116,7 @@ + Msg.xaml @@ -126,6 +127,7 @@ + ResultPanel.xaml @@ -133,6 +135,9 @@ ResultItem.xaml + + SettingWindow.xaml + MSBuild:Compile Designer @@ -157,6 +162,18 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + @@ -200,9 +217,6 @@ WinAlfred.Plugin - - - @@ -235,11 +249,24 @@ true + + + + + + + + + + + + - xcopy /Y $(ProjectDir)Images\*.* $(SolutionDir)WinAlfred\bin\Debug\Images\ -xcopy /Y $(ProjectDir)app.ico $(SolutionDir)WinAlfred\bin\Debug\ + xcopy /Y $(ProjectDir)Images\*.* $(TargetDir)Images\ +xcopy /Y $(ProjectDir)app.ico $(TargetDir) +xcopy /Y $(ProjectDir)Themes\*.* $(TargetDir)Themes\