From 71b5d4fe5a7a38bb5ed0a16944d84480d3706eb7 Mon Sep 17 00:00:00 2001 From: qianlifeng Date: Sat, 25 Jan 2014 18:00:13 +0800 Subject: [PATCH] add theme function. And provide two themes default. --- WinAlfred.Plugin.System/BaseSystemPlugin.cs | 1 + WinAlfred.Plugin.System/Setting.cs | 33 + WinAlfred.Plugin.System/Sys.cs | 2 +- .../WinAlfred.Plugin.System.csproj | 1 + WinAlfred.Plugin/PluginInitContext.cs | 1 + WinAlfred/App.xaml | 53 +- WinAlfred/Helper/Settings.cs | 44 ++ WinAlfred/Images/app.png | Bin 0 -> 8880 bytes WinAlfred/Images/ico.png | Bin 4884 -> 0 bytes WinAlfred/MainWindow.xaml | 19 +- WinAlfred/MainWindow.xaml.cs | 29 +- WinAlfred/PluginLoader/Plugins.cs | 3 +- WinAlfred/Properties/Annotations.cs | 577 ++++++++++++++++++ WinAlfred/ResultItem.xaml | 7 +- WinAlfred/ResultItem.xaml.cs | 20 +- WinAlfred/ResultPanel.xaml.cs | 8 +- WinAlfred/SettingWindow.xaml | 13 + WinAlfred/SettingWindow.xaml.cs | 46 ++ WinAlfred/Themes/Default.xaml | 43 ++ WinAlfred/Themes/Light.xaml | 43 ++ WinAlfred/WinAlfred.csproj | 37 +- 21 files changed, 899 insertions(+), 81 deletions(-) create mode 100644 WinAlfred.Plugin.System/Setting.cs create mode 100644 WinAlfred/Helper/Settings.cs create mode 100644 WinAlfred/Images/app.png delete mode 100644 WinAlfred/Images/ico.png create mode 100644 WinAlfred/Properties/Annotations.cs create mode 100644 WinAlfred/SettingWindow.xaml create mode 100644 WinAlfred/SettingWindow.xaml.cs create mode 100644 WinAlfred/Themes/Default.xaml create mode 100644 WinAlfred/Themes/Light.xaml 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 0000000000000000000000000000000000000000..d24f3550dd6456961e904b5ff8f493a4f7977380 GIT binary patch literal 8880 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%0Dj$XAnKnn@1v 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 - + - + - - - + + + - - + \ 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\