Merge branch 'dev' into handle-icon-urls

This commit is contained in:
Jeremy Wu 2022-11-22 20:06:47 +11:00
commit e5948a70c4
14 changed files with 282 additions and 27297 deletions

View file

@ -64,16 +64,5 @@
<PackageReference Include="ToolGood.Words.Pinyin" Version="3.0.1.4" /> <PackageReference Include="ToolGood.Words.Pinyin" Version="3.0.1.4" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<None Update="pinyindb\pinyin_gwoyeu_mapping.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="pinyindb\pinyin_mapping.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="pinyindb\unicode_to_hanyu_pinyin.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project> </Project>

View file

@ -15,7 +15,7 @@ namespace Flow.Launcher.Infrastructure
private List<int> originalIndexs = new List<int>(); private List<int> originalIndexs = new List<int>();
private List<int> translatedIndexs = new List<int>(); private List<int> translatedIndexs = new List<int>();
private int translaedLength = 0; private int translatedLength = 0;
public string key { get; private set; } public string key { get; private set; }
@ -32,13 +32,13 @@ namespace Flow.Launcher.Infrastructure
originalIndexs.Add(originalIndex); originalIndexs.Add(originalIndex);
translatedIndexs.Add(translatedIndex); translatedIndexs.Add(translatedIndex);
translatedIndexs.Add(translatedIndex + length); translatedIndexs.Add(translatedIndex + length);
translaedLength += length - 1; translatedLength += length - 1;
} }
public int MapToOriginalIndex(int translatedIndex) public int MapToOriginalIndex(int translatedIndex)
{ {
if (translatedIndex > translatedIndexs.Last()) if (translatedIndex > translatedIndexs.Last())
return translatedIndex - translaedLength - 1; return translatedIndex - translatedLength - 1;
int lowerBound = 0; int lowerBound = 0;
int upperBound = originalIndexs.Count - 1; int upperBound = originalIndexs.Count - 1;
@ -102,9 +102,24 @@ namespace Flow.Launcher.Infrastructure
} }
} }
/// <summary>
/// Translate a language to English letters using a given rule.
/// </summary>
public interface IAlphabet public interface IAlphabet
{ {
/// <summary>
/// Translate a string to English letters, using a given rule.
/// </summary>
/// <param name="stringToTranslate">String to translate.</param>
/// <returns></returns>
public (string translation, TranslationMapping map) Translate(string stringToTranslate); public (string translation, TranslationMapping map) Translate(string stringToTranslate);
/// <summary>
/// Determine if a string can be translated to English letter with this Alphabet.
/// </summary>
/// <param name="stringToTranslate">String to translate.</param>
/// <returns></returns>
public bool CanBeTranslated(string stringToTranslate);
} }
public class PinyinAlphabet : IAlphabet public class PinyinAlphabet : IAlphabet
@ -119,59 +134,66 @@ namespace Flow.Launcher.Infrastructure
_settings = settings ?? throw new ArgumentNullException(nameof(settings)); _settings = settings ?? throw new ArgumentNullException(nameof(settings));
} }
public bool CanBeTranslated(string stringToTranslate)
{
return WordsHelper.HasChinese(stringToTranslate);
}
public (string translation, TranslationMapping map) Translate(string content) public (string translation, TranslationMapping map) Translate(string content)
{ {
if (_settings.ShouldUsePinyin) if (_settings.ShouldUsePinyin)
{ {
if (!_pinyinCache.ContainsKey(content)) if (!_pinyinCache.ContainsKey(content))
{ {
if (WordsHelper.HasChinese(content)) return BuildCacheFromContent(content);
{
var resultList = WordsHelper.GetPinyinList(content);
StringBuilder resultBuilder = new StringBuilder();
TranslationMapping map = new TranslationMapping();
bool pre = false;
for (int i = 0; i < resultList.Length; i++)
{
if (content[i] >= 0x3400 && content[i] <= 0x9FD5)
{
map.AddNewIndex(i, resultBuilder.Length, resultList[i].Length + 1);
resultBuilder.Append(' ');
resultBuilder.Append(resultList[i]);
pre = true;
}
else
{
if (pre)
{
pre = false;
resultBuilder.Append(' ');
}
resultBuilder.Append(resultList[i]);
}
}
map.endConstruct();
var key = resultBuilder.ToString();
map.setKey(key);
return _pinyinCache[content] = (key, map);
}
else
{
return (content, null);
}
} }
else else
{ {
return _pinyinCache[content]; return _pinyinCache[content];
} }
} }
return (content, null);
}
private (string translation, TranslationMapping map) BuildCacheFromContent(string content)
{
if (WordsHelper.HasChinese(content))
{
var resultList = WordsHelper.GetPinyinList(content);
StringBuilder resultBuilder = new StringBuilder();
TranslationMapping map = new TranslationMapping();
bool pre = false;
for (int i = 0; i < resultList.Length; i++)
{
if (content[i] >= 0x3400 && content[i] <= 0x9FD5)
{
map.AddNewIndex(i, resultBuilder.Length, resultList[i].Length + 1);
resultBuilder.Append(' ');
resultBuilder.Append(resultList[i]);
pre = true;
}
else
{
if (pre)
{
pre = false;
resultBuilder.Append(' ');
}
resultBuilder.Append(resultList[i]);
}
}
map.endConstruct();
var key = resultBuilder.ToString();
map.setKey(key);
return _pinyinCache[content] = (key, map);
}
else else
{ {
return (content, null); return (content, null);

View file

@ -1,4 +1,4 @@
using Flow.Launcher.Plugin.SharedModels; using Flow.Launcher.Plugin.SharedModels;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@ -60,8 +60,13 @@ namespace Flow.Launcher.Infrastructure
return new MatchResult(false, UserSettingSearchPrecision); return new MatchResult(false, UserSettingSearchPrecision);
query = query.Trim(); query = query.Trim();
TranslationMapping translationMapping; TranslationMapping translationMapping = null;
(stringToCompare, translationMapping) = _alphabet?.Translate(stringToCompare) ?? (stringToCompare, null); if (_alphabet is not null && !_alphabet.CanBeTranslated(query))
{
// We assume that if a query can be translated (containing characters of a language, like Chinese)
// it actually means user doesn't want it to be translated to English letters.
(stringToCompare, translationMapping) = _alphabet.Translate(stringToCompare);
}
var currentAcronymQueryIndex = 0; var currentAcronymQueryIndex = 0;
var acronymMatchData = new List<int>(); var acronymMatchData = new List<int>();

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,4 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;

View file

@ -1,5 +1,4 @@
<Window <Window x:Class="Flow.Launcher.MainWindow"
x:Class="Flow.Launcher.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="clr-namespace:Flow.Launcher.Converters" xmlns:converters="clr-namespace:Flow.Launcher.Converters"
@ -40,164 +39,145 @@
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" /> <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
</Window.Resources> </Window.Resources>
<Window.InputBindings> <Window.InputBindings>
<KeyBinding Key="Escape" Command="{Binding EscCommand}" /> <KeyBinding Key="Escape"
<KeyBinding Key="F1" Command="{Binding StartHelpCommand}" /> Command="{Binding EscCommand}" />
<KeyBinding Key="F5" Command="{Binding ReloadPluginDataCommand}" /> <KeyBinding Key="F1"
<KeyBinding Key="Tab" Command="{Binding AutocompleteQueryCommand}" /> Command="{Binding StartHelpCommand}" />
<KeyBinding <KeyBinding Key="F5"
Key="Tab" Command="{Binding ReloadPluginDataCommand}" />
<KeyBinding Key="Tab"
Command="{Binding AutocompleteQueryCommand}" />
<KeyBinding Key="Tab"
Command="{Binding AutocompleteQueryCommand}" Command="{Binding AutocompleteQueryCommand}"
Modifiers="Shift" /> Modifiers="Shift" />
<KeyBinding <KeyBinding Key="I"
Key="I"
Command="{Binding OpenSettingCommand}" Command="{Binding OpenSettingCommand}"
Modifiers="Ctrl" /> Modifiers="Ctrl" />
<KeyBinding <KeyBinding Key="N"
Key="N"
Command="{Binding SelectNextItemCommand}" Command="{Binding SelectNextItemCommand}"
Modifiers="Ctrl" /> Modifiers="Ctrl" />
<KeyBinding <KeyBinding Key="J"
Key="J"
Command="{Binding SelectNextItemCommand}" Command="{Binding SelectNextItemCommand}"
Modifiers="Ctrl" /> Modifiers="Ctrl" />
<KeyBinding <KeyBinding Key="D"
Key="D"
Command="{Binding SelectNextPageCommand}" Command="{Binding SelectNextPageCommand}"
Modifiers="Ctrl" /> Modifiers="Ctrl" />
<KeyBinding <KeyBinding Key="P"
Key="P"
Command="{Binding SelectPrevItemCommand}" Command="{Binding SelectPrevItemCommand}"
Modifiers="Ctrl" /> Modifiers="Ctrl" />
<KeyBinding <KeyBinding Key="K"
Key="K"
Command="{Binding SelectPrevItemCommand}" Command="{Binding SelectPrevItemCommand}"
Modifiers="Ctrl" /> Modifiers="Ctrl" />
<KeyBinding <KeyBinding Key="U"
Key="U"
Command="{Binding SelectPrevPageCommand}" Command="{Binding SelectPrevPageCommand}"
Modifiers="Ctrl" /> Modifiers="Ctrl" />
<KeyBinding <KeyBinding Key="Home"
Key="Home"
Command="{Binding SelectFirstResultCommand}" Command="{Binding SelectFirstResultCommand}"
Modifiers="Alt" /> Modifiers="Alt" />
<KeyBinding <KeyBinding Key="O"
Key="O"
Command="{Binding LoadContextMenuCommand}" Command="{Binding LoadContextMenuCommand}"
Modifiers="Ctrl" /> Modifiers="Ctrl" />
<KeyBinding Key="Right" Command="{Binding LoadContextMenuCommand}" /> <KeyBinding Key="Right"
<KeyBinding Key="Left" Command="{Binding EscCommand}" /> Command="{Binding LoadContextMenuCommand}" />
<KeyBinding <KeyBinding Key="Left"
Key="H" Command="{Binding EscCommand}" />
<KeyBinding Key="H"
Command="{Binding LoadHistoryCommand}" Command="{Binding LoadHistoryCommand}"
Modifiers="Ctrl" /> Modifiers="Ctrl" />
<KeyBinding Key="Right" Command="{Binding LoadContextMenuCommand}" /> <KeyBinding Key="Right"
<KeyBinding Key="Left" Command="{Binding EscCommand}" /> Command="{Binding LoadContextMenuCommand}" />
<KeyBinding <KeyBinding Key="Left"
Key="OemCloseBrackets" Command="{Binding EscCommand}" />
<KeyBinding Key="OemCloseBrackets"
Command="{Binding IncreaseWidthCommand}" Command="{Binding IncreaseWidthCommand}"
Modifiers="Control" /> Modifiers="Control" />
<KeyBinding <KeyBinding Key="OemOpenBrackets"
Key="OemOpenBrackets"
Command="{Binding DecreaseWidthCommand}" Command="{Binding DecreaseWidthCommand}"
Modifiers="Control" /> Modifiers="Control" />
<KeyBinding <KeyBinding Key="OemPlus"
Key="OemPlus"
Command="{Binding IncreaseMaxResultCommand}" Command="{Binding IncreaseMaxResultCommand}"
Modifiers="Control" /> Modifiers="Control" />
<KeyBinding <KeyBinding Key="OemMinus"
Key="OemMinus"
Command="{Binding DecreaseMaxResultCommand}" Command="{Binding DecreaseMaxResultCommand}"
Modifiers="Control" /> Modifiers="Control" />
<KeyBinding <KeyBinding Key="H"
Key="H"
Command="{Binding LoadHistoryCommand}" Command="{Binding LoadHistoryCommand}"
Modifiers="Ctrl" /> Modifiers="Ctrl" />
<KeyBinding <KeyBinding Key="Enter"
Key="Enter"
Command="{Binding OpenResultCommand}" Command="{Binding OpenResultCommand}"
Modifiers="Ctrl+Shift" /> Modifiers="Ctrl+Shift" />
<KeyBinding <KeyBinding Key="Enter"
Key="Enter"
Command="{Binding LoadContextMenuCommand}" Command="{Binding LoadContextMenuCommand}"
Modifiers="Shift" /> Modifiers="Shift" />
<KeyBinding Key="Enter" Command="{Binding OpenResultCommand}" /> <KeyBinding Key="Enter"
<KeyBinding Command="{Binding OpenResultCommand}" />
Key="Enter" <KeyBinding Key="Enter"
Command="{Binding OpenResultCommand}" Command="{Binding OpenResultCommand}"
Modifiers="Ctrl" /> Modifiers="Ctrl" />
<KeyBinding <KeyBinding Key="Enter"
Key="Enter"
Command="{Binding OpenResultCommand}" Command="{Binding OpenResultCommand}"
Modifiers="Alt" /> Modifiers="Alt" />
<KeyBinding <KeyBinding Key="D1"
Key="D1"
Command="{Binding OpenResultCommand}" Command="{Binding OpenResultCommand}"
CommandParameter="0" CommandParameter="0"
Modifiers="{Binding OpenResultCommandModifiers}" /> Modifiers="{Binding OpenResultCommandModifiers}" />
<KeyBinding <KeyBinding Key="D2"
Key="D2"
Command="{Binding OpenResultCommand}" Command="{Binding OpenResultCommand}"
CommandParameter="1" CommandParameter="1"
Modifiers="{Binding OpenResultCommandModifiers}" /> Modifiers="{Binding OpenResultCommandModifiers}" />
<KeyBinding <KeyBinding Key="D3"
Key="D3"
Command="{Binding OpenResultCommand}" Command="{Binding OpenResultCommand}"
CommandParameter="2" CommandParameter="2"
Modifiers="{Binding OpenResultCommandModifiers}" /> Modifiers="{Binding OpenResultCommandModifiers}" />
<KeyBinding <KeyBinding Key="D4"
Key="D4"
Command="{Binding OpenResultCommand}" Command="{Binding OpenResultCommand}"
CommandParameter="3" CommandParameter="3"
Modifiers="{Binding OpenResultCommandModifiers}" /> Modifiers="{Binding OpenResultCommandModifiers}" />
<KeyBinding <KeyBinding Key="D5"
Key="D5"
Command="{Binding OpenResultCommand}" Command="{Binding OpenResultCommand}"
CommandParameter="4" CommandParameter="4"
Modifiers="{Binding OpenResultCommandModifiers}" /> Modifiers="{Binding OpenResultCommandModifiers}" />
<KeyBinding <KeyBinding Key="D6"
Key="D6"
Command="{Binding OpenResultCommand}" Command="{Binding OpenResultCommand}"
CommandParameter="5" CommandParameter="5"
Modifiers="{Binding OpenResultCommandModifiers}" /> Modifiers="{Binding OpenResultCommandModifiers}" />
<KeyBinding <KeyBinding Key="D7"
Key="D7"
Command="{Binding OpenResultCommand}" Command="{Binding OpenResultCommand}"
CommandParameter="6" CommandParameter="6"
Modifiers="{Binding OpenResultCommandModifiers}" /> Modifiers="{Binding OpenResultCommandModifiers}" />
<KeyBinding <KeyBinding Key="D8"
Key="D8"
Command="{Binding OpenResultCommand}" Command="{Binding OpenResultCommand}"
CommandParameter="7" CommandParameter="7"
Modifiers="{Binding OpenResultCommandModifiers}" /> Modifiers="{Binding OpenResultCommandModifiers}" />
<KeyBinding <KeyBinding Key="D9"
Key="D9"
Command="{Binding OpenResultCommand}" Command="{Binding OpenResultCommand}"
CommandParameter="8" CommandParameter="8"
Modifiers="{Binding OpenResultCommandModifiers}" /> Modifiers="{Binding OpenResultCommandModifiers}" />
<KeyBinding <KeyBinding Key="D0"
Key="D0"
Command="{Binding OpenResultCommand}" Command="{Binding OpenResultCommand}"
CommandParameter="9" CommandParameter="9"
Modifiers="{Binding OpenResultCommandModifiers}" /> Modifiers="{Binding OpenResultCommandModifiers}" />
</Window.InputBindings> </Window.InputBindings>
<Grid> <Grid>
<Border MouseDown="OnMouseDown" Style="{DynamicResource WindowBorderStyle}"> <Border MouseDown="OnMouseDown"
Style="{DynamicResource WindowBorderStyle}">
<StackPanel Orientation="Vertical"> <StackPanel Orientation="Vertical">
<Grid> <Grid>
<TextBox <TextBox x:Name="QueryTextSuggestionBox"
x:Name="QueryTextSuggestionBox"
IsEnabled="False" IsEnabled="False"
Style="{DynamicResource QuerySuggestionBoxStyle}"> Style="{DynamicResource QuerySuggestionBoxStyle}">
<TextBox.Text> <TextBox.Text>
<MultiBinding Converter="{StaticResource QuerySuggestionBoxConverter}"> <MultiBinding Converter="{StaticResource QuerySuggestionBoxConverter}">
<Binding ElementName="QueryTextBox" Mode="OneTime" /> <Binding ElementName="QueryTextBox"
<Binding ElementName="ResultListBox" Path="SelectedItem" /> Mode="OneTime" />
<Binding ElementName="QueryTextBox" Path="Text" /> <Binding ElementName="ResultListBox"
Path="SelectedItem" />
<Binding ElementName="QueryTextBox"
Path="Text" />
</MultiBinding> </MultiBinding>
</TextBox.Text> </TextBox.Text>
</TextBox> </TextBox>
<TextBox <TextBox x:Name="QueryTextBox"
x:Name="QueryTextBox"
AllowDrop="True" AllowDrop="True"
Background="Transparent" Background="Transparent"
PreviewDragOver="OnPreviewDragOver" PreviewDragOver="OnPreviewDragOver"
@ -206,35 +186,40 @@
Text="{Binding QueryText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Text="{Binding QueryText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Visibility="Visible"> Visibility="Visible">
<TextBox.CommandBindings> <TextBox.CommandBindings>
<CommandBinding Command="ApplicationCommands.Copy" Executed="OnCopy" /> <CommandBinding Command="ApplicationCommands.Copy"
Executed="OnCopy" />
</TextBox.CommandBindings> </TextBox.CommandBindings>
<TextBox.ContextMenu> <TextBox.ContextMenu>
<ContextMenu> <ContextMenu>
<MenuItem Command="ApplicationCommands.Cut" Header="{DynamicResource cut}"> <MenuItem Command="ApplicationCommands.Cut"
Header="{DynamicResource cut}">
<MenuItem.Icon> <MenuItem.Icon>
<ui:FontIcon Glyph="&#xe8c6;" /> <ui:FontIcon Glyph="&#xe8c6;" />
</MenuItem.Icon> </MenuItem.Icon>
</MenuItem> </MenuItem>
<MenuItem Command="ApplicationCommands.Copy" Header="{DynamicResource copy}"> <MenuItem Command="ApplicationCommands.Copy"
Header="{DynamicResource copy}">
<MenuItem.Icon> <MenuItem.Icon>
<ui:FontIcon Glyph="&#xe8c8;" /> <ui:FontIcon Glyph="&#xe8c8;" />
</MenuItem.Icon> </MenuItem.Icon>
</MenuItem> </MenuItem>
<MenuItem Command="ApplicationCommands.Paste" Header="{DynamicResource paste}"> <MenuItem Command="ApplicationCommands.Paste"
Header="{DynamicResource paste}">
<MenuItem.Icon> <MenuItem.Icon>
<ui:FontIcon Glyph="&#xe77f;" /> <ui:FontIcon Glyph="&#xe77f;" />
</MenuItem.Icon> </MenuItem.Icon>
</MenuItem> </MenuItem>
<Separator <Separator Margin="0"
Margin="0"
Padding="0,4,0,4" Padding="0,4,0,4"
Background="{DynamicResource ContextSeparator}" /> Background="{DynamicResource ContextSeparator}" />
<MenuItem Click="OnContextMenusForSettingsClick" Header="{DynamicResource flowlauncher_settings}"> <MenuItem Click="OnContextMenusForSettingsClick"
Header="{DynamicResource flowlauncher_settings}">
<MenuItem.Icon> <MenuItem.Icon>
<ui:FontIcon Glyph="&#xe713;" /> <ui:FontIcon Glyph="&#xe713;" />
</MenuItem.Icon> </MenuItem.Icon>
</MenuItem> </MenuItem>
<MenuItem Command="{Binding EscCommand}" Header="{DynamicResource closeWindow}"> <MenuItem Command="{Binding EscCommand}"
Header="{DynamicResource closeWindow}">
<MenuItem.Icon> <MenuItem.Icon>
<ui:FontIcon Glyph="&#xe711;" /> <ui:FontIcon Glyph="&#xe711;" />
</MenuItem.Icon> </MenuItem.Icon>
@ -243,23 +228,19 @@
</TextBox.ContextMenu> </TextBox.ContextMenu>
</TextBox> </TextBox>
<StackPanel <StackPanel x:Name="ClockPanel"
x:Name="ClockPanel"
IsHitTestVisible="False" IsHitTestVisible="False"
Style="{DynamicResource ClockPanel}"> Style="{DynamicResource ClockPanel}">
<TextBlock <TextBlock Style="{DynamicResource DateBox}"
Style="{DynamicResource DateBox}"
Text="{Binding DateText}" Text="{Binding DateText}"
Visibility="{Binding Settings.UseDate, Converter={StaticResource BooleanToVisibilityConverter}}" /> Visibility="{Binding Settings.UseDate, Converter={StaticResource BooleanToVisibilityConverter}}" />
<TextBlock <TextBlock Style="{DynamicResource ClockBox}"
Style="{DynamicResource ClockBox}"
Text="{Binding ClockText}" Text="{Binding ClockText}"
Visibility="{Binding Settings.UseClock, Converter={StaticResource BooleanToVisibilityConverter}}" /> Visibility="{Binding Settings.UseClock, Converter={StaticResource BooleanToVisibilityConverter}}" />
</StackPanel> </StackPanel>
<Canvas Style="{DynamicResource SearchIconPosition}"> <Canvas Style="{DynamicResource SearchIconPosition}">
<Image <Image x:Name="PluginActivationIcon"
x:Name="PluginActivationIcon"
Width="32" Width="32"
Height="32" Height="32"
Margin="0,0,0,0" Margin="0,0,0,0"
@ -270,8 +251,7 @@
Source="{Binding PluginIconPath}" Source="{Binding PluginIconPath}"
Stretch="Uniform" Stretch="Uniform"
Style="{DynamicResource PluginActivationIcon}" /> Style="{DynamicResource PluginActivationIcon}" />
<Path <Path Name="SearchIcon"
Name="SearchIcon"
Margin="0" Margin="0"
Data="{DynamicResource SearchIconImg}" Data="{DynamicResource SearchIconImg}"
Stretch="Fill" Stretch="Fill"
@ -284,27 +264,32 @@
<ContentControl> <ContentControl>
<ContentControl.Style> <ContentControl.Style>
<Style TargetType="ContentControl"> <Style TargetType="ContentControl">
<Setter Property="Visibility" Value="Collapsed" /> <Setter Property="Visibility"
Value="Collapsed" />
<Style.Triggers> <Style.Triggers>
<DataTrigger Binding="{Binding ElementName=ResultListBox, Path=Visibility}" Value="Visible"> <DataTrigger Binding="{Binding ElementName=ResultListBox, Path=Visibility}"
<Setter Property="Visibility" Value="Visible" /> Value="Visible">
<Setter Property="Visibility"
Value="Visible" />
</DataTrigger> </DataTrigger>
<DataTrigger Binding="{Binding ElementName=ContextMenu, Path=Visibility}" Value="Visible"> <DataTrigger Binding="{Binding ElementName=ContextMenu, Path=Visibility}"
<Setter Property="Visibility" Value="Visible" /> Value="Visible">
<Setter Property="Visibility"
Value="Visible" />
</DataTrigger> </DataTrigger>
<DataTrigger Binding="{Binding ElementName=History, Path=Visibility}" Value="Visible"> <DataTrigger Binding="{Binding ElementName=History, Path=Visibility}"
<Setter Property="Visibility" Value="Visible" /> Value="Visible">
<Setter Property="Visibility"
Value="Visible" />
</DataTrigger> </DataTrigger>
</Style.Triggers> </Style.Triggers>
</Style> </Style>
</ContentControl.Style> </ContentControl.Style>
<Rectangle <Rectangle Width="Auto"
Width="Auto"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
Style="{DynamicResource SeparatorStyle}" /> Style="{DynamicResource SeparatorStyle}" />
</ContentControl> </ContentControl>
<Line <Line x:Name="ProgressBar"
x:Name="ProgressBar"
Width="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Grid}}, Path=ActualWidth}" Width="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Grid}}, Path=ActualWidth}"
Height="2" Height="2"
HorizontalAlignment="Right" HorizontalAlignment="Right"
@ -320,46 +305,55 @@
<Border Style="{DynamicResource WindowRadius}"> <Border Style="{DynamicResource WindowRadius}">
<Border.Clip> <Border.Clip>
<MultiBinding Converter="{StaticResource BorderClipConverter}"> <MultiBinding Converter="{StaticResource BorderClipConverter}">
<Binding Path="ActualWidth" RelativeSource="{RelativeSource Self}" /> <Binding Path="ActualWidth"
<Binding Path="ActualHeight" RelativeSource="{RelativeSource Self}" /> RelativeSource="{RelativeSource Self}" />
<Binding Path="CornerRadius" RelativeSource="{RelativeSource Self}" /> <Binding Path="ActualHeight"
RelativeSource="{RelativeSource Self}" />
<Binding Path="CornerRadius"
RelativeSource="{RelativeSource Self}" />
</MultiBinding> </MultiBinding>
</Border.Clip> </Border.Clip>
<ContentControl> <ContentControl>
<flowlauncher:ResultListBox <flowlauncher:ResultListBox x:Name="ResultListBox"
x:Name="ResultListBox"
DataContext="{Binding Results}" DataContext="{Binding Results}"
PreviewMouseLeftButtonUp="OnPreviewMouseButtonDown" /> LeftClickResultCommand="{Binding LeftClickResultCommand}"
RightClickResultCommand="{Binding RightClickResultCommand}" />
</ContentControl> </ContentControl>
</Border> </Border>
<Border Style="{DynamicResource WindowRadius}"> <Border Style="{DynamicResource WindowRadius}">
<Border.Clip> <Border.Clip>
<MultiBinding Converter="{StaticResource BorderClipConverter}"> <MultiBinding Converter="{StaticResource BorderClipConverter}">
<Binding Path="ActualWidth" RelativeSource="{RelativeSource Self}" /> <Binding Path="ActualWidth"
<Binding Path="ActualHeight" RelativeSource="{RelativeSource Self}" /> RelativeSource="{RelativeSource Self}" />
<Binding Path="CornerRadius" RelativeSource="{RelativeSource Self}" /> <Binding Path="ActualHeight"
RelativeSource="{RelativeSource Self}" />
<Binding Path="CornerRadius"
RelativeSource="{RelativeSource Self}" />
</MultiBinding> </MultiBinding>
</Border.Clip> </Border.Clip>
<ContentControl> <ContentControl>
<flowlauncher:ResultListBox <flowlauncher:ResultListBox x:Name="ContextMenu"
x:Name="ContextMenu"
DataContext="{Binding ContextMenu}" DataContext="{Binding ContextMenu}"
PreviewMouseDown="OnPreviewMouseButtonDown" /> LeftClickResultCommand="{Binding LeftClickResultCommand}"
RightClickResultCommand="{Binding RightClickResultCommand}" />
</ContentControl> </ContentControl>
</Border> </Border>
<Border Style="{DynamicResource WindowRadius}"> <Border Style="{DynamicResource WindowRadius}">
<Border.Clip> <Border.Clip>
<MultiBinding Converter="{StaticResource BorderClipConverter}"> <MultiBinding Converter="{StaticResource BorderClipConverter}">
<Binding Path="ActualWidth" RelativeSource="{RelativeSource Self}" /> <Binding Path="ActualWidth"
<Binding Path="ActualHeight" RelativeSource="{RelativeSource Self}" /> RelativeSource="{RelativeSource Self}" />
<Binding Path="CornerRadius" RelativeSource="{RelativeSource Self}" /> <Binding Path="ActualHeight"
RelativeSource="{RelativeSource Self}" />
<Binding Path="CornerRadius"
RelativeSource="{RelativeSource Self}" />
</MultiBinding> </MultiBinding>
</Border.Clip> </Border.Clip>
<ContentControl> <ContentControl>
<flowlauncher:ResultListBox <flowlauncher:ResultListBox x:Name="History"
x:Name="History"
DataContext="{Binding History}" DataContext="{Binding History}"
PreviewMouseDown="OnPreviewMouseButtonDown" /> LeftClickResultCommand="{Binding LeftClickResultCommand}"
RightClickResultCommand="{Binding RightClickResultCommand}" />
</ContentControl> </ContentControl>
</Border> </Border>
</StackPanel> </StackPanel>

View file

@ -405,28 +405,6 @@ namespace Flow.Launcher
if (e.ChangedButton == MouseButton.Left) DragMove(); if (e.ChangedButton == MouseButton.Left) DragMove();
} }
private void OnPreviewMouseButtonDown(object sender, MouseButtonEventArgs e)
{
if (sender != null && e.OriginalSource != null)
{
var r = (ResultListBox)sender;
var d = (DependencyObject)e.OriginalSource;
var item = ItemsControl.ContainerFromElement(r, d) as ListBoxItem;
var result = (ResultViewModel)item?.DataContext;
if (result != null)
{
if (e.ChangedButton == MouseButton.Left)
{
_viewModel.OpenResultCommand.Execute(null);
}
else if (e.ChangedButton == MouseButton.Right)
{
_viewModel.LoadContextMenuCommand.Execute(null);
}
}
}
}
private void OnPreviewDragOver(object sender, DragEventArgs e) private void OnPreviewDragOver(object sender, DragEventArgs e)
{ {
e.Handled = true; e.Handled = true;

View file

@ -27,7 +27,9 @@
Visibility="{Binding Visbility}" Visibility="{Binding Visbility}"
mc:Ignorable="d" mc:Ignorable="d"
PreviewMouseMove="ResultList_MouseMove" PreviewMouseMove="ResultList_MouseMove"
PreviewMouseLeftButtonDown="ResultList_PreviewMouseLeftButtonDown"> PreviewMouseLeftButtonDown="ResultList_PreviewMouseLeftButtonDown"
PreviewMouseLeftButtonUp="ResultListBox_OnPreviewMouseUp"
PreviewMouseRightButtonDown="ResultListBox_OnPreviewMouseRightButtonDown">
<!-- IsSynchronizedWithCurrentItem: http://stackoverflow.com/a/7833798/2833083 --> <!-- IsSynchronizedWithCurrentItem: http://stackoverflow.com/a/7833798/2833083 -->
<ListBox.ItemTemplate> <ListBox.ItemTemplate>
@ -137,10 +139,11 @@
x:Name="Title" x:Name="Title"
VerticalAlignment="Center" VerticalAlignment="Center"
DockPanel.Dock="Left" DockPanel.Dock="Left"
IsHitTestVisible="False"
Style="{DynamicResource ItemTitleStyle}" Style="{DynamicResource ItemTitleStyle}"
Text="{Binding Result.Title}" Text="{Binding Result.Title}"
ToolTip="{Binding ShowTitleToolTip}"> ToolTip="{Binding ShowTitleToolTip}"
ToolTipService.ShowOnDisabled="True"
IsEnabled="False">
<vm:ResultsViewModel.FormattedText> <vm:ResultsViewModel.FormattedText>
<MultiBinding Converter="{StaticResource HighlightTextConverter}"> <MultiBinding Converter="{StaticResource HighlightTextConverter}">
<Binding Path="Result.Title" /> <Binding Path="Result.Title" />
@ -151,11 +154,11 @@
<TextBlock <TextBlock
x:Name="SubTitle" x:Name="SubTitle"
Grid.Row="1" Grid.Row="1"
IsHitTestVisible="False" IsEnabled="False"
ToolTipService.ShowOnDisabled="True"
Style="{DynamicResource ItemSubTitleStyle}" Style="{DynamicResource ItemSubTitleStyle}"
Text="{Binding Result.SubTitle}" Text="{Binding Result.SubTitle}"
ToolTip="{Binding ShowSubTitleToolTip}" /> ToolTip="{Binding ShowSubTitleToolTip}"/>
</Grid> </Grid>
</Grid> </Grid>

View file

@ -17,6 +17,36 @@ namespace Flow.Launcher
InitializeComponent(); InitializeComponent();
} }
public static readonly DependencyProperty RightClickResultCommandProperty =
DependencyProperty.Register("RightClickResultCommand", typeof(ICommand), typeof(ResultListBox), new UIPropertyMetadata(null));
public ICommand RightClickResultCommand
{
get
{
return (ICommand)GetValue(RightClickResultCommandProperty);
}
set
{
SetValue(RightClickResultCommandProperty, value);
}
}
public static readonly DependencyProperty LeftClickResultCommandProperty =
DependencyProperty.Register("LeftClickResultCommand", typeof(ICommand), typeof(ResultListBox), new UIPropertyMetadata(null));
public ICommand LeftClickResultCommand
{
get
{
return (ICommand)GetValue(LeftClickResultCommandProperty);
}
set
{
SetValue(LeftClickResultCommandProperty, value);
}
}
private void OnSelectionChanged(object sender, SelectionChangedEventArgs e) private void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{ {
if (e.AddedItems.Count > 0 && e.AddedItems[0] != null) if (e.AddedItems.Count > 0 && e.AddedItems[0] != null)
@ -103,5 +133,19 @@ namespace Flow.Launcher
e.Handled = true; e.Handled = true;
} }
private void ResultListBox_OnPreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
if (Mouse.DirectlyOver is not FrameworkElement { DataContext: ResultViewModel result })
return;
RightClickResultCommand?.Execute(result.Result);
}
private void ResultListBox_OnPreviewMouseUp(object sender, MouseButtonEventArgs e)
{
if (Mouse.DirectlyOver is not FrameworkElement { DataContext: ResultViewModel result })
return;
LeftClickResultCommand?.Execute(null);
}
} }
} }

View file

@ -77,12 +77,22 @@ namespace Flow.Launcher.ViewModel
_userSelectedRecord = _userSelectedRecordStorage.Load(); _userSelectedRecord = _userSelectedRecordStorage.Load();
_topMostRecord = _topMostRecordStorage.Load(); _topMostRecord = _topMostRecordStorage.Load();
ContextMenu = new ResultsViewModel(Settings); InitializeKeyCommands();
Results = new ResultsViewModel(Settings);
History = new ResultsViewModel(Settings); ContextMenu = new ResultsViewModel(Settings)
{
LeftClickResultCommand = OpenResultCommand, RightClickResultCommand = LoadContextMenuCommand
};
Results = new ResultsViewModel(Settings)
{
LeftClickResultCommand = OpenResultCommand, RightClickResultCommand = LoadContextMenuCommand
};
History = new ResultsViewModel(Settings)
{
LeftClickResultCommand = OpenResultCommand, RightClickResultCommand = LoadContextMenuCommand
};
_selectedResults = Results; _selectedResults = Results;
InitializeKeyCommands();
RegisterViewUpdate(); RegisterViewUpdate();
RegisterResultsUpdatedEvent(); RegisterResultsUpdatedEvent();
@ -199,15 +209,10 @@ namespace Flow.Launcher.ViewModel
PluginManager.API.OpenUrl("https://github.com/Flow-Launcher/Flow.Launcher/wiki/Flow-Launcher/"); PluginManager.API.OpenUrl("https://github.com/Flow-Launcher/Flow.Launcher/wiki/Flow-Launcher/");
}); });
OpenSettingCommand = new RelayCommand(_ => { App.API.OpenSettingDialog(); }); OpenSettingCommand = new RelayCommand(_ => { App.API.OpenSettingDialog(); });
OpenResultCommand = new RelayCommand(async index => OpenResultCommand = new AsyncRelayCommand(async _ =>
{ {
var results = SelectedResults; var results = SelectedResults;
if (index != null)
{
results.SelectedIndex = int.Parse(index.ToString()!);
}
var result = results.SelectedItem?.Result; var result = results.SelectedItem?.Result;
if (result == null) if (result == null)
{ {

View file

@ -8,6 +8,8 @@ using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Data; using System.Windows.Data;
using System.Windows.Documents; using System.Windows.Documents;
using System.Windows.Input;
using JetBrains.Annotations;
namespace Flow.Launcher.ViewModel namespace Flow.Launcher.ViewModel
{ {
@ -50,6 +52,9 @@ namespace Flow.Launcher.ViewModel
public Thickness Margin { get; set; } public Thickness Margin { get; set; }
public Visibility Visbility { get; set; } = Visibility.Collapsed; public Visibility Visbility { get; set; } = Visibility.Collapsed;
public ICommand RightClickResultCommand { get; init; }
public ICommand LeftClickResultCommand { get; init; }
#endregion #endregion
#region Private Methods #region Private Methods

View file

@ -37,7 +37,6 @@ namespace Flow.Launcher.Plugin.Program.Programs
/// Path of the actual executable file. /// Path of the actual executable file.
/// </summary> /// </summary>
public string ExecutablePath => LnkResolvedPath ?? FullPath; public string ExecutablePath => LnkResolvedPath ?? FullPath;
public string WorkingDir => Directory.GetParent(ExecutablePath)?.FullName ?? string.Empty;
public string ParentDirectory { get; set; } public string ParentDirectory { get; set; }
public string ExecutableName { get; set; } public string ExecutableName { get; set; }
public string Description { get; set; } public string Description { get; set; }
@ -140,8 +139,8 @@ namespace Flow.Launcher.Plugin.Program.Programs
var info = new ProcessStartInfo var info = new ProcessStartInfo
{ {
FileName = ExecutablePath, FileName = FullPath,
WorkingDirectory = WorkingDir, WorkingDirectory = ParentDirectory,
UseShellExecute = true, UseShellExecute = true,
Verb = runAsAdmin ? "runas" : null Verb = runAsAdmin ? "runas" : null
}; };
@ -167,8 +166,8 @@ namespace Flow.Launcher.Plugin.Program.Programs
{ {
var info = new ProcessStartInfo var info = new ProcessStartInfo
{ {
FileName = ExecutablePath, FileName = FullPath,
WorkingDirectory = WorkingDir, WorkingDirectory = ParentDirectory,
UseShellExecute = true UseShellExecute = true
}; };
@ -187,7 +186,7 @@ namespace Flow.Launcher.Plugin.Program.Programs
var info = new ProcessStartInfo var info = new ProcessStartInfo
{ {
FileName = ExecutablePath, FileName = ExecutablePath,
WorkingDirectory = WorkingDir, WorkingDirectory = ParentDirectory,
Verb = "runas", Verb = "runas",
UseShellExecute = true UseShellExecute = true
}; };
@ -221,8 +220,7 @@ namespace Flow.Launcher.Plugin.Program.Programs
return Name; return Name;
} }
public static List<FileSystemWatcher> Watchers = new List<FileSystemWatcher>(); private static List<FileSystemWatcher> Watchers = new List<FileSystemWatcher>();
private static Win32 Win32Program(string path) private static Win32 Win32Program(string path)
{ {
@ -573,6 +571,7 @@ namespace Flow.Launcher.Plugin.Program.Programs
private static IEnumerable<Win32> ProgramsHasher(IEnumerable<Win32> programs) private static IEnumerable<Win32> ProgramsHasher(IEnumerable<Win32> programs)
{ {
// TODO: Unable to distinguish multiple lnks to the same excutable but with different params
return programs.GroupBy(p => p.ExecutablePath.ToLowerInvariant()) return programs.GroupBy(p => p.ExecutablePath.ToLowerInvariant())
.AsParallel() .AsParallel()
.SelectMany(g => .SelectMany(g =>