diff --git a/Plugins/Wox.Plugin.Calculator/DecimalSeparator.cs b/Plugins/Wox.Plugin.Calculator/DecimalSeparator.cs new file mode 100644 index 000000000..5aad9b39a --- /dev/null +++ b/Plugins/Wox.Plugin.Calculator/DecimalSeparator.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Wox.Core; + +namespace Wox.Plugin.Caculator +{ + [TypeConverter(typeof(LocalizationConverter))] + public enum DecimalSeparator + { + [LocalizedDescription("wox_plugin_calculator_decimal_seperator_use_system_locale")] + UseSystemLocale, + + [LocalizedDescription("wox_plugin_calculator_decimal_seperator_dot")] + Dot, + + [LocalizedDescription("wox_plugin_calculator_decimal_seperator_comma")] + Comma + } +} \ No newline at end of file diff --git a/Plugins/Wox.Plugin.Calculator/Languages/de.xaml b/Plugins/Wox.Plugin.Calculator/Languages/de.xaml index 286e4bc9b..fe85d42e5 100644 --- a/Plugins/Wox.Plugin.Calculator/Languages/de.xaml +++ b/Plugins/Wox.Plugin.Calculator/Languages/de.xaml @@ -1,4 +1,4 @@ - @@ -7,4 +7,10 @@ Keine Zahl (NaN) Ausdruck falsch oder nicht vollständig (Klammern vergessen?) Diese Zahl in die Zwischenablage kopieren + Dezimaltrennzeichen + Das Dezimaltrennzeichen, welches bei der Ausgabe verwendet werden soll. + Systemeinstellung nutzen + Komma (,) + Punkt (.) + Max. Nachkommastellen \ No newline at end of file diff --git a/Plugins/Wox.Plugin.Calculator/Languages/en.xaml b/Plugins/Wox.Plugin.Calculator/Languages/en.xaml index 3b5fa32b3..ef33ecb9c 100644 --- a/Plugins/Wox.Plugin.Calculator/Languages/en.xaml +++ b/Plugins/Wox.Plugin.Calculator/Languages/en.xaml @@ -1,4 +1,4 @@ - @@ -7,4 +7,10 @@ Not a number (NaN) Expression wrong or incomplete (Did you forget some parentheses?) Copy this number to the clipboard + Decimal separator + The decimal separator to be used in the output. + Use system locale + Comma (,) + Dot (.) + Max. decimal places \ No newline at end of file diff --git a/Plugins/Wox.Plugin.Calculator/Main.cs b/Plugins/Wox.Plugin.Calculator/Main.cs index fab0b8e03..195138c0a 100644 --- a/Plugins/Wox.Plugin.Calculator/Main.cs +++ b/Plugins/Wox.Plugin.Calculator/Main.cs @@ -1,12 +1,18 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.Globalization; using System.Runtime.InteropServices; using System.Text.RegularExpressions; using System.Windows; +using System.Windows.Controls; using Mages.Core; +using Wox.Infrastructure.Storage; +using Wox.Plugin.Caculator.ViewModels; +using Wox.Plugin.Caculator.Views; namespace Wox.Plugin.Caculator { - public class Main : IPlugin, IPluginI18n + public class Main : IPlugin, IPluginI18n, ISavable, ISettingProvider { private static readonly Regex RegValidExpressChar = new Regex( @"^(" + @@ -21,20 +27,33 @@ namespace Wox.Plugin.Caculator private static readonly Engine MagesEngine; private PluginInitContext Context { get; set; } + private static Settings _settings; + private static SettingsViewModel _viewModel; + static Main() { MagesEngine = new Engine(); } + + public void Init(PluginInitContext context) + { + Context = context; + + _viewModel = new SettingsViewModel(); + _settings = _viewModel.Settings; + } public List Query(Query query) { - if (query.Search.Length <= 2 // don't affect when user only input "e" or "i" keyword - || !RegValidExpressChar.IsMatch(query.Search) - || !IsBracketComplete(query.Search)) return new List(); + if (!CanCalculate(query)) + { + return new List(); + } try { - var result = MagesEngine.Interpret(query.Search); + var expression = query.Search.Replace(",", "."); + var result = MagesEngine.Interpret(expression); if (result.ToString() == "NaN") result = Context.API.GetTranslation("wox_plugin_calculator_not_a_number"); @@ -42,14 +61,16 @@ namespace Wox.Plugin.Caculator if (result is Function) result = Context.API.GetTranslation("wox_plugin_calculator_expression_not_complete"); - if (!string.IsNullOrEmpty(result?.ToString())) { + decimal roundedResult = Math.Round(Convert.ToDecimal(result), _settings.MaxDecimalPlaces, MidpointRounding.AwayFromZero); + string newResult = ChangeDecimalSeparator(roundedResult, GetDecimalSeparator()); + return new List { new Result { - Title = result.ToString(), + Title = newResult, IcoPath = "Images/calculator.png", Score = 300, SubTitle = Context.API.GetTranslation("wox_plugin_calculator_copy_number_to_clipboard"), @@ -57,7 +78,7 @@ namespace Wox.Plugin.Caculator { try { - Clipboard.SetText(result.ToString()); + Clipboard.SetText(newResult); return true; } catch (ExternalException) @@ -78,6 +99,53 @@ namespace Wox.Plugin.Caculator return new List(); } + private bool CanCalculate(Query query) + { + // Don't execute when user only input "e" or "i" keyword + if (query.Search.Length < 2) + { + return false; + } + + if (!RegValidExpressChar.IsMatch(query.Search)) + { + return false; + } + + if (!IsBracketComplete(query.Search)) + { + return false; + } + + return true; + } + + private string ChangeDecimalSeparator(decimal value, string newDecimalSeparator) + { + if (String.IsNullOrEmpty(newDecimalSeparator)) + { + return value.ToString(); + } + + var numberFormatInfo = new NumberFormatInfo + { + NumberDecimalSeparator = newDecimalSeparator + }; + return value.ToString(numberFormatInfo); + } + + private string GetDecimalSeparator() + { + string systemDecimalSeperator = CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator; + switch (_settings.DecimalSeparator) + { + case DecimalSeparator.UseSystemLocale: return systemDecimalSeperator; + case DecimalSeparator.Dot: return "."; + case DecimalSeparator.Comma: return ","; + default: return systemDecimalSeperator; + } + } + private bool IsBracketComplete(string query) { var matchs = RegBrackets.Matches(query); @@ -96,12 +164,7 @@ namespace Wox.Plugin.Caculator return leftBracketCount == 0; } - - public void Init(PluginInitContext context) - { - Context = context; - } - + public string GetTranslatedPluginTitle() { return Context.API.GetTranslation("wox_plugin_caculator_plugin_name"); @@ -111,5 +174,15 @@ namespace Wox.Plugin.Caculator { return Context.API.GetTranslation("wox_plugin_caculator_plugin_description"); } + + public Control CreateSettingPanel() + { + return new CalculatorSettings(_viewModel); + } + + public void Save() + { + _viewModel.Save(); + } } } diff --git a/Plugins/Wox.Plugin.Calculator/Settings.cs b/Plugins/Wox.Plugin.Calculator/Settings.cs new file mode 100644 index 000000000..ce01f2da0 --- /dev/null +++ b/Plugins/Wox.Plugin.Calculator/Settings.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Wox.Plugin.Caculator +{ + public class Settings + { + public DecimalSeparator DecimalSeparator { get; set; } = DecimalSeparator.UseSystemLocale; + public int MaxDecimalPlaces { get; set; } = 10; + } +} diff --git a/Plugins/Wox.Plugin.Calculator/ViewModels/SettingsViewModel.cs b/Plugins/Wox.Plugin.Calculator/ViewModels/SettingsViewModel.cs new file mode 100644 index 000000000..8550f47a5 --- /dev/null +++ b/Plugins/Wox.Plugin.Calculator/ViewModels/SettingsViewModel.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Wox.Infrastructure.Storage; +using Wox.Infrastructure.UserSettings; + +namespace Wox.Plugin.Caculator.ViewModels +{ + public class SettingsViewModel : BaseModel, ISavable + { + private readonly PluginJsonStorage _storage; + + public SettingsViewModel() + { + _storage = new PluginJsonStorage(); + Settings = _storage.Load(); + } + + public Settings Settings { get; set; } + + public IEnumerable MaxDecimalPlacesRange => Enumerable.Range(1, 20); + + public void Save() + { + _storage.Save(); + } + } +} diff --git a/Plugins/Wox.Plugin.Calculator/Views/CalculatorSettings.xaml b/Plugins/Wox.Plugin.Calculator/Views/CalculatorSettings.xaml new file mode 100644 index 000000000..b7bd188e6 --- /dev/null +++ b/Plugins/Wox.Plugin.Calculator/Views/CalculatorSettings.xaml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Plugins/Wox.Plugin.Calculator/Views/CalculatorSettings.xaml.cs b/Plugins/Wox.Plugin.Calculator/Views/CalculatorSettings.xaml.cs new file mode 100644 index 000000000..c5f4b76f0 --- /dev/null +++ b/Plugins/Wox.Plugin.Calculator/Views/CalculatorSettings.xaml.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; +using Wox.Plugin.Caculator.ViewModels; + +namespace Wox.Plugin.Caculator.Views +{ + /// + /// Interaction logic for CalculatorSettings.xaml + /// + public partial class CalculatorSettings : UserControl + { + private readonly SettingsViewModel _viewModel; + private readonly Settings _settings; + + public CalculatorSettings(SettingsViewModel viewModel) + { + _viewModel = viewModel; + _settings = viewModel.Settings; + DataContext = viewModel; + InitializeComponent(); + } + + private void CalculatorSettings_Loaded(object sender, RoutedEventArgs e) + { + DecimalSeparatorComboBox.SelectedItem = _settings.DecimalSeparator; + MaxDecimalPlaces.SelectedItem = _settings.MaxDecimalPlaces; + } + } + + +} diff --git a/Plugins/Wox.Plugin.Calculator/Wox.Plugin.Calculator.csproj b/Plugins/Wox.Plugin.Calculator/Wox.Plugin.Calculator.csproj index bb841fd3c..e0c7ce3bd 100644 --- a/Plugins/Wox.Plugin.Calculator/Wox.Plugin.Calculator.csproj +++ b/Plugins/Wox.Plugin.Calculator/Wox.Plugin.Calculator.csproj @@ -1,4 +1,4 @@ - + netcoreapp3.1 @@ -6,6 +6,7 @@ Properties Wox.Plugin.Caculator Wox.Plugin.Caculator + true false false @@ -38,8 +39,7 @@ - - + @@ -95,15 +95,17 @@ PreserveNewest - + + + + + + + - - - - \ No newline at end of file diff --git a/Plugins/Wox.Plugin.WebSearch/Main.cs b/Plugins/Wox.Plugin.WebSearch/Main.cs index 429e51cc0..d8c6ccafb 100644 --- a/Plugins/Wox.Plugin.WebSearch/Main.cs +++ b/Plugins/Wox.Plugin.WebSearch/Main.cs @@ -72,6 +72,7 @@ namespace Wox.Plugin.WebSearch SubTitle = subtitle, Score = 6, IcoPath = searchSource.IconPath, + ActionKeywordAssigned = searchSource.ActionKeyword == SearchSourceGlobalPluginWildCardSign ? string.Empty : searchSource.ActionKeyword, Action = c => { if (_settings.OpenInNewBrowser) @@ -137,6 +138,7 @@ namespace Wox.Plugin.WebSearch SubTitle = subtitle, Score = 5, IcoPath = searchSource.IconPath, + ActionKeywordAssigned = searchSource.ActionKeyword == SearchSourceGlobalPluginWildCardSign ? string.Empty : searchSource.ActionKeyword, Action = c => { if (_settings.OpenInNewBrowser) diff --git a/README.md b/README.md index 00069024a..732dd242f 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,7 @@ Features **New from this fork:** - Portable mode - Drastically improved search experience +- Auto-complete text suggestion - Search all subfolders and files - Option to always run CMD or Powershell as administrator - Run CMD, Powershell and programs as a different user @@ -78,17 +79,7 @@ Contribution Build ----- -Install Visual Studio 2015/2017/2019 - -This project requires Windows 10 SDK: - - VS 2015: - - Tick all Windows 10 sdk options - - VS 2017/2019 and later: - - Last Windows 10 SDK which [supported](https://github.com/Wox-launcher/Wox/pull/1827#commitcomment-26475392) UwpDesktop is version 10.0.14393.795. It is needed to compile "Programs" Plugin (UWP.cs), you will see the "References" of Plugin.Programs as broken if you use a later SDK version. - - This SDK cannot be installed via VS 2019 installer. - - Download and install [Windows 10 SDK version 10.0.14393.795](https://go.microsoft.com/fwlink/p/?LinkId=838916). +Install Visual Studio 2017/2019 Documentation ------------- diff --git a/Wox.Core/Plugin/PluginManager.cs b/Wox.Core/Plugin/PluginManager.cs index 0166690b7..3d1450648 100644 --- a/Wox.Core/Plugin/PluginManager.cs +++ b/Wox.Core/Plugin/PluginManager.cs @@ -191,6 +191,11 @@ namespace Wox.Core.Plugin r.PluginDirectory = metadata.PluginDirectory; r.PluginID = metadata.ID; r.OriginQuery = query; + + // ActionKeywordAssigned is used for constructing MainViewModel's query text auto-complete suggestions + // Plugins may have multi-actionkeywords eg. WebSearches. In this scenario it needs to be overriden on the plugin level + if (metadata.ActionKeywords.Count == 1) + r.ActionKeywordAssigned = query.ActionKeyword; } } diff --git a/Wox.Core/Resource/Internationalization.cs b/Wox.Core/Resource/Internationalization.cs index 9f865cb53..53cce9174 100644 --- a/Wox.Core/Resource/Internationalization.cs +++ b/Wox.Core/Resource/Internationalization.cs @@ -99,6 +99,22 @@ namespace Wox.Core.Resource } + public bool PromptShouldUsePinyin(string languageCodeToSet) + { + var languageToSet = GetLanguageByLanguageCode(languageCodeToSet); + + if (Settings.ShouldUsePinyin) + return false; + + if (languageToSet != AvailableLanguages.Chinese && languageToSet != AvailableLanguages.Chinese_TW) + return false; + + if (MessageBox.Show("Do you want to turn on search with Pinyin?", string.Empty, MessageBoxButton.YesNo) == MessageBoxResult.No) + return false; + + return true; + } + private void RemoveOldLanguageFiles() { var dicts = Application.Current.Resources.MergedDictionaries; diff --git a/Wox.Core/Resource/LocalizationConverter.cs b/Wox.Core/Resource/LocalizationConverter.cs new file mode 100644 index 000000000..d86bf5f7e --- /dev/null +++ b/Wox.Core/Resource/LocalizationConverter.cs @@ -0,0 +1,37 @@ +using System; +using System.ComponentModel; +using System.Globalization; +using System.Reflection; +using System.Windows.Data; + +namespace Wox.Core +{ + public class LocalizationConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (targetType == typeof(string) && value != null) + { + FieldInfo fi = value.GetType().GetField(value.ToString()); + if (fi != null) + { + string localizedDescription = string.Empty; + var attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false); + if ((attributes.Length > 0) && (!String.IsNullOrEmpty(attributes[0].Description))) + { + localizedDescription = attributes[0].Description; + } + + return (!String.IsNullOrEmpty(localizedDescription)) ? localizedDescription : value.ToString(); + } + } + + return string.Empty; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/Wox.Core/Resource/LocalizedDescriptionAttribute.cs b/Wox.Core/Resource/LocalizedDescriptionAttribute.cs new file mode 100644 index 000000000..ef1257220 --- /dev/null +++ b/Wox.Core/Resource/LocalizedDescriptionAttribute.cs @@ -0,0 +1,27 @@ +using System.ComponentModel; +using Wox.Core.Resource; + +namespace Wox.Core +{ + public class LocalizedDescriptionAttribute : DescriptionAttribute + { + private readonly Internationalization _translator; + private readonly string _resourceKey; + + public LocalizedDescriptionAttribute(string resourceKey) + { + _translator = InternationalizationManager.Instance; + _resourceKey = resourceKey; + } + + public override string Description + { + get + { + string description = _translator.GetTranslation(_resourceKey); + return string.IsNullOrWhiteSpace(description) ? + string.Format("[[{0}]]", _resourceKey) : description; + } + } + } +} diff --git a/Wox.Core/Resource/Theme.cs b/Wox.Core/Resource/Theme.cs index 4b8c37ccf..fc5d55046 100644 --- a/Wox.Core/Resource/Theme.cs +++ b/Wox.Core/Resource/Theme.cs @@ -124,6 +124,12 @@ namespace Wox.Core.Resource queryBoxStyle.Setters.Add(new Setter(TextBox.FontStyleProperty, FontHelper.GetFontStyleFromInvariantStringOrNormal(Settings.QueryBoxFontStyle))); queryBoxStyle.Setters.Add(new Setter(TextBox.FontWeightProperty, FontHelper.GetFontWeightFromInvariantStringOrNormal(Settings.QueryBoxFontWeight))); queryBoxStyle.Setters.Add(new Setter(TextBox.FontStretchProperty, FontHelper.GetFontStretchFromInvariantStringOrNormal(Settings.QueryBoxFontStretch))); + + var caretBrushPropertyValue = queryBoxStyle.Setters.OfType().Any(x => x.Property.Name == "CaretBrush"); + var foregroundPropertyValue = queryBoxStyle.Setters.OfType().Where(x => x.Property.Name == "Foreground") + .Select(x => x.Value).FirstOrDefault(); + if (!caretBrushPropertyValue && foregroundPropertyValue != null) //otherwise BaseQueryBoxStyle will handle styling + queryBoxStyle.Setters.Add(new Setter(TextBox.CaretBrushProperty, foregroundPropertyValue)); } Style resultItemStyle = dict["ItemTitleStyle"] as Style; diff --git a/Wox.Infrastructure/Alphabet.cs b/Wox.Infrastructure/Alphabet.cs index c67fbbdf1..e366ad034 100644 --- a/Wox.Infrastructure/Alphabet.cs +++ b/Wox.Infrastructure/Alphabet.cs @@ -172,7 +172,7 @@ namespace Wox.Infrastructure if (word.Length > 40) { - Log.Debug($"|Wox.Infrastructure.StringMatcher.ScoreForPinyin|skip too long string: {word}"); + //Skip strings that are too long string for Pinyin conversion. return false; } diff --git a/Wox.Infrastructure/UI/EnumBindingSource.cs b/Wox.Infrastructure/UI/EnumBindingSource.cs new file mode 100644 index 000000000..c23aacd81 --- /dev/null +++ b/Wox.Infrastructure/UI/EnumBindingSource.cs @@ -0,0 +1,57 @@ +using System; +using System.Windows.Markup; + +namespace Wox.Infrastructure.UI +{ + public class EnumBindingSourceExtension : MarkupExtension + { + private Type _enumType; + public Type EnumType + { + get { return _enumType; } + set + { + if (value != _enumType) + { + if (value != null) + { + Type enumType = Nullable.GetUnderlyingType(value) ?? value; + if (!enumType.IsEnum) + { + throw new ArgumentException("Type must represent an enum."); + } + } + + _enumType = value; + } + } + } + + public EnumBindingSourceExtension() { } + + public EnumBindingSourceExtension(Type enumType) + { + EnumType = enumType; + } + + public override object ProvideValue(IServiceProvider serviceProvider) + { + if (_enumType == null) + { + throw new InvalidOperationException("The EnumType must be specified."); + } + + Type actualEnumType = Nullable.GetUnderlyingType(_enumType) ?? _enumType; + Array enumValues = Enum.GetValues(actualEnumType); + + if (actualEnumType == _enumType) + { + return enumValues; + } + + Array tempArray = Array.CreateInstance(actualEnumType, enumValues.Length + 1); + enumValues.CopyTo(tempArray, 1); + return tempArray; + } + } +} diff --git a/Wox.Infrastructure/UserSettings/Settings.cs b/Wox.Infrastructure/UserSettings/Settings.cs index 7714768f0..94a1639d6 100644 --- a/Wox.Infrastructure/UserSettings/Settings.cs +++ b/Wox.Infrastructure/UserSettings/Settings.cs @@ -25,8 +25,7 @@ namespace Wox.Infrastructure.UserSettings /// /// when false Alphabet static service will always return empty results /// - public bool ShouldUsePinyin { get; set; } = true; - + public bool ShouldUsePinyin { get; set; } = false; internal StringMatcher.SearchPrecisionScore QuerySearchPrecision { get; private set; } = StringMatcher.SearchPrecisionScore.Regular; diff --git a/Wox.Plugin/IPublicAPI.cs b/Wox.Plugin/IPublicAPI.cs index 754b76d36..3c5b34277 100644 --- a/Wox.Plugin/IPublicAPI.cs +++ b/Wox.Plugin/IPublicAPI.cs @@ -81,7 +81,16 @@ namespace Wox.Plugin /// Message title /// Message subtitle /// Message icon path (relative path to your plugin folder) - void ShowMsg(string title, string subTitle = "", string iconPath = "", bool useMainWindowAsOwner = true); + void ShowMsg(string title, string subTitle = "", string iconPath = ""); + + /// + /// Show message box + /// + /// Message title + /// Message subtitle + /// Message icon path (relative path to your plugin folder) + /// when true will use main windows as the owner + void ShowMsg(string title, string subTitle, string iconPath, bool useMainWindowAsOwner = true); /// /// Open setting dialog diff --git a/Wox.Plugin/Result.cs b/Wox.Plugin/Result.cs index 6e0559d35..4c8f2b1ed 100644 --- a/Wox.Plugin/Result.cs +++ b/Wox.Plugin/Result.cs @@ -14,6 +14,12 @@ namespace Wox.Plugin public string Title { get; set; } public string SubTitle { get; set; } + /// + /// This holds the action keyword that triggered the result. + /// If result is triggered by global keyword: *, this should be empty. + /// + public string ActionKeywordAssigned { get; set; } + public string IcoPath { get { return _icoPath; } @@ -53,7 +59,7 @@ namespace Wox.Plugin public IList SubTitleHighlightData { get; set; } /// - /// Only resulsts that originQuery match with curren query will be displayed in the panel + /// Only results that originQuery match with current query will be displayed in the panel /// internal Query OriginQuery { get; set; } @@ -98,13 +104,14 @@ namespace Wox.Plugin return Title + SubTitle; } - [Obsolete("Use IContextMenu instead")] + /// /// Context menus associate with this result /// + [Obsolete("Use IContextMenu instead")] public List ContextMenu { get; set; } - [Obsolete("Use Object initializers instead")] + [Obsolete("Use Object initializer instead")] public Result(string Title, string IcoPath, string SubTitle = null) { this.Title = Title; diff --git a/Wox.sln b/Wox.sln index 711ef1f72..1dd69c3da 100644 --- a/Wox.sln +++ b/Wox.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.29806.167 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wox.Test", "Wox.Test\Wox.Test.csproj", "{FF742965-9A80-41A5-B042-D6C7D3A21708}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wox.Test", "Wox.Test\Wox.Test.csproj", "{FF742965-9A80-41A5-B042-D6C7D3A21708}" ProjectSection(ProjectDependencies) = postProject {DB90F671-D861-46BB-93A3-F1304F5BA1C5} = {DB90F671-D861-46BB-93A3-F1304F5BA1C5} EndProjectSection @@ -69,10 +69,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HelloWorldCSharp", "Plugins EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wox.Plugin.Shell", "Plugins\Wox.Plugin.Shell\Wox.Plugin.Shell.csproj", "{C21BFF9C-2C99-4B5F-B7C9-A5E6DDDB37B0}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wox.Plugin.Calculator", "Plugins\Wox.Plugin.Calculator\Wox.Plugin.Calculator.csproj", "{59BD9891-3837-438A-958D-ADC7F91F6F7E}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wox.Plugin.BrowserBookmark", "Plugins\Wox.Plugin.BrowserBookmark\Wox.Plugin.BrowserBookmark.csproj", "{9B130CC5-14FB-41FF-B310-0A95B6894C37}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wox.Plugin.Calculator", "Plugins\Wox.Plugin.Calculator\Wox.Plugin.Calculator.csproj", "{59BD9891-3837-438A-958D-ADC7F91F6F7E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -288,18 +288,6 @@ Global {C21BFF9C-2C99-4B5F-B7C9-A5E6DDDB37B0}.Release|x64.Build.0 = Release|Any CPU {C21BFF9C-2C99-4B5F-B7C9-A5E6DDDB37B0}.Release|x86.ActiveCfg = Release|Any CPU {C21BFF9C-2C99-4B5F-B7C9-A5E6DDDB37B0}.Release|x86.Build.0 = Release|Any CPU - {59BD9891-3837-438A-958D-ADC7F91F6F7E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {59BD9891-3837-438A-958D-ADC7F91F6F7E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {59BD9891-3837-438A-958D-ADC7F91F6F7E}.Debug|x64.ActiveCfg = Debug|Any CPU - {59BD9891-3837-438A-958D-ADC7F91F6F7E}.Debug|x64.Build.0 = Debug|Any CPU - {59BD9891-3837-438A-958D-ADC7F91F6F7E}.Debug|x86.ActiveCfg = Debug|Any CPU - {59BD9891-3837-438A-958D-ADC7F91F6F7E}.Debug|x86.Build.0 = Debug|Any CPU - {59BD9891-3837-438A-958D-ADC7F91F6F7E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {59BD9891-3837-438A-958D-ADC7F91F6F7E}.Release|Any CPU.Build.0 = Release|Any CPU - {59BD9891-3837-438A-958D-ADC7F91F6F7E}.Release|x64.ActiveCfg = Release|Any CPU - {59BD9891-3837-438A-958D-ADC7F91F6F7E}.Release|x64.Build.0 = Release|Any CPU - {59BD9891-3837-438A-958D-ADC7F91F6F7E}.Release|x86.ActiveCfg = Release|Any CPU - {59BD9891-3837-438A-958D-ADC7F91F6F7E}.Release|x86.Build.0 = Release|Any CPU {9B130CC5-14FB-41FF-B310-0A95B6894C37}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {9B130CC5-14FB-41FF-B310-0A95B6894C37}.Debug|Any CPU.Build.0 = Debug|Any CPU {9B130CC5-14FB-41FF-B310-0A95B6894C37}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -312,6 +300,18 @@ Global {9B130CC5-14FB-41FF-B310-0A95B6894C37}.Release|x64.Build.0 = Release|Any CPU {9B130CC5-14FB-41FF-B310-0A95B6894C37}.Release|x86.ActiveCfg = Release|Any CPU {9B130CC5-14FB-41FF-B310-0A95B6894C37}.Release|x86.Build.0 = Release|Any CPU + {59BD9891-3837-438A-958D-ADC7F91F6F7E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {59BD9891-3837-438A-958D-ADC7F91F6F7E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {59BD9891-3837-438A-958D-ADC7F91F6F7E}.Debug|x64.ActiveCfg = Debug|Any CPU + {59BD9891-3837-438A-958D-ADC7F91F6F7E}.Debug|x64.Build.0 = Debug|Any CPU + {59BD9891-3837-438A-958D-ADC7F91F6F7E}.Debug|x86.ActiveCfg = Debug|Any CPU + {59BD9891-3837-438A-958D-ADC7F91F6F7E}.Debug|x86.Build.0 = Debug|Any CPU + {59BD9891-3837-438A-958D-ADC7F91F6F7E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {59BD9891-3837-438A-958D-ADC7F91F6F7E}.Release|Any CPU.Build.0 = Release|Any CPU + {59BD9891-3837-438A-958D-ADC7F91F6F7E}.Release|x64.ActiveCfg = Release|Any CPU + {59BD9891-3837-438A-958D-ADC7F91F6F7E}.Release|x64.Build.0 = Release|Any CPU + {59BD9891-3837-438A-958D-ADC7F91F6F7E}.Release|x86.ActiveCfg = Release|Any CPU + {59BD9891-3837-438A-958D-ADC7F91F6F7E}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -329,8 +329,8 @@ Global {230AE83F-E92E-4E69-8355-426B305DA9C0} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87} {03FFA443-5F50-48D5-8869-F3DF316803AA} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87} {C21BFF9C-2C99-4B5F-B7C9-A5E6DDDB37B0} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87} - {59BD9891-3837-438A-958D-ADC7F91F6F7E} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87} {9B130CC5-14FB-41FF-B310-0A95B6894C37} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87} + {59BD9891-3837-438A-958D-ADC7F91F6F7E} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {F26ACB50-3F6C-4907-B0C9-1ADACC1D0DED} diff --git a/Wox/Converters/QuerySuggestionBoxConverter.cs b/Wox/Converters/QuerySuggestionBoxConverter.cs new file mode 100644 index 000000000..68b891ce6 --- /dev/null +++ b/Wox/Converters/QuerySuggestionBoxConverter.cs @@ -0,0 +1,61 @@ +using System; +using System.Globalization; +using System.Windows.Data; +using Wox.Infrastructure.Logger; +using Wox.ViewModel; + +namespace Wox.Converters +{ + public class QuerySuggestionBoxConverter : IMultiValueConverter + { + public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) + { + if (values.Length != 2) + { + return string.Empty; + } + + // first prop is the current query string + var queryText = (string)values[0]; + + if (string.IsNullOrEmpty(queryText)) + return "Type here to search"; + + // second prop is the current selected item result + var val = values[1]; + if (val == null) + { + return string.Empty; + } + if (!(val is ResultViewModel)) + { + return System.Windows.Data.Binding.DoNothing; + } + + try + { + var selectedItem = (ResultViewModel)val; + + var selectedResult = selectedItem.Result; + var selectedResultActionKeyword = string.IsNullOrEmpty(selectedResult.ActionKeywordAssigned) ? "" : selectedResult.ActionKeywordAssigned + " "; + var selectedResultPossibleSuggestion = selectedResultActionKeyword + selectedResult.Title; + + if (!selectedResultPossibleSuggestion.StartsWith(queryText, StringComparison.CurrentCultureIgnoreCase)) + return string.Empty; + + // When user typed lower case and result title is uppercase, we still want to display suggestion + return queryText + selectedResultPossibleSuggestion.Substring(queryText.Length); + } + catch (Exception e) + { + Log.Exception(nameof(QuerySuggestionBoxConverter), "fail to convert text for suggestion box", e); + return string.Empty; + } + } + + public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/Wox/MainWindow.xaml b/Wox/MainWindow.xaml index b3e2aba25..a93305453 100644 --- a/Wox/MainWindow.xaml +++ b/Wox/MainWindow.xaml @@ -4,7 +4,9 @@ xmlns:wox="clr-namespace:Wox" xmlns:vm="clr-namespace:Wox.ViewModel" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" - xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" + xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:converters="clr-namespace:Wox.Converters" + mc:Ignorable="d" Title="Wox" Topmost="True" SizeToContent="Height" @@ -25,6 +27,9 @@ PreviewKeyDown="OnKeyDown" Visibility="{Binding MainWindowVisibility, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" d:DataContext="{d:DesignInstance vm:MainViewModel}"> + + + @@ -55,29 +60,43 @@ - + + + + + + + + + - - - - - - - - - - + Background="Transparent"> + + + + + + + + + + + - + diff --git a/Wox/PublicAPIInstance.cs b/Wox/PublicAPIInstance.cs index 58915f87b..6c17be5c5 100644 --- a/Wox/PublicAPIInstance.cs +++ b/Wox/PublicAPIInstance.cs @@ -97,7 +97,12 @@ namespace Wox _mainVM.MainWindowVisibility = Visibility.Visible; } - public void ShowMsg(string title, string subTitle = "", string iconPath = "", bool useMainWindowAsOwner = true) + public void ShowMsg(string title, string subTitle = "", string iconPath = "") + { + ShowMsg(title, subTitle, iconPath, true); + } + + public void ShowMsg(string title, string subTitle, string iconPath, bool useMainWindowAsOwner = true) { Application.Current.Dispatcher.Invoke(() => { diff --git a/Wox/SettingWindow.xaml b/Wox/SettingWindow.xaml index 1eddd8ab6..7fe6d8750 100644 --- a/Wox/SettingWindow.xaml +++ b/Wox/SettingWindow.xaml @@ -55,7 +55,7 @@ - + @@ -72,8 +72,8 @@ - diff --git a/Wox/SettingWindow.xaml.cs b/Wox/SettingWindow.xaml.cs index 52addf362..df3b363d5 100644 --- a/Wox/SettingWindow.xaml.cs +++ b/Wox/SettingWindow.xaml.cs @@ -40,12 +40,6 @@ namespace Wox #region General - void OnLanguageChanged(object sender, SelectionChangedEventArgs e) - { - var language = (Language)e.AddedItems[0]; - InternationalizationManager.Instance.ChangeLanguage(language); - } - private void OnAutoStartupChecked(object sender, RoutedEventArgs e) { SetStartup(); diff --git a/Wox/Themes/Base.xaml b/Wox/Themes/Base.xaml index ae195feaa..6f6083035 100644 --- a/Wox/Themes/Base.xaml +++ b/Wox/Themes/Base.xaml @@ -8,6 +8,7 @@ + diff --git a/Wox/ViewModel/MainViewModel.cs b/Wox/ViewModel/MainViewModel.cs index acdd7c040..c2a277963 100644 --- a/Wox/ViewModel/MainViewModel.cs +++ b/Wox/ViewModel/MainViewModel.cs @@ -1,5 +1,6 @@ -using System; +using System; using System.Collections.Generic; +using System.ComponentModel; using System.Diagnostics; using System.Linq; using System.Threading; @@ -210,7 +211,7 @@ namespace Wox.ViewModel Query(); } } - + /// /// we need move cursor to end when we manually changed query /// but we don't want to move cursor to end when query is updated from TextBox @@ -455,7 +456,6 @@ namespace Wox.ViewModel } } - private Result ContextMenuTopMost(Result result) { Result menu; diff --git a/Wox/ViewModel/SettingWindowViewModel.cs b/Wox/ViewModel/SettingWindowViewModel.cs index 504e7bdfa..f9160df9f 100644 --- a/Wox/ViewModel/SettingWindowViewModel.cs +++ b/Wox/ViewModel/SettingWindowViewModel.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -77,6 +77,33 @@ namespace Wox.ViewModel } } + public string Language + { + get + { + return Settings.Language; + } + set + { + InternationalizationManager.Instance.ChangeLanguage(value); + + if (InternationalizationManager.Instance.PromptShouldUsePinyin(value)) + ShouldUsePinyin = true; + } + } + + public bool ShouldUsePinyin + { + get + { + return Settings.ShouldUsePinyin; + } + set + { + Settings.ShouldUsePinyin = value; + } + } + public List QuerySearchPrecisionStrings { get