diff options
11 files changed, 1111 insertions, 2 deletions
diff --git a/main/Main.sln b/main/Main.sln index ecc2763a1d..cf95e9be00 100644 --- a/main/Main.sln +++ b/main/Main.sln @@ -392,6 +392,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EditorOptionsImpl", "extern EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EditorPrimitivesImpl", "external\vs-editor-core\src\Editor\Text\Impl\EditorPrimitives\EditorPrimitivesImpl.csproj", "{9B8B470A-5455-45B5-A5D1-8619ED174257}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Find", "external\vs-editor-core\src\Editor\Text\Impl\Find\Find.csproj", "{645985FC-FDD7-4D6F-9A90-79E9F96AF0FB}"
+EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NavigationImpl", "external\vs-editor-core\src\Editor\Text\Impl\Navigation\NavigationImpl.csproj", "{726E446E-2E8D-4B48-A47B-923C6CEC4556}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TextSearchImpl", "external\vs-editor-core\src\Editor\Text\Impl\TextSearch\TextSearchImpl.csproj", "{F713D37D-70A4-49BB-ADAE-B7007C880E57}"
@@ -2410,6 +2412,18 @@ Global {9B8B470A-5455-45B5-A5D1-8619ED174257}.ReleaseMac|Any CPU.ActiveCfg = Release|Any CPU
{9B8B470A-5455-45B5-A5D1-8619ED174257}.ReleaseMac|Any CPU.Build.0 = Release|Any CPU
{9B8B470A-5455-45B5-A5D1-8619ED174257}.ReleaseWin32|Any CPU.ActiveCfg = Release|Any CPU
+ {645985FC-FDD7-4D6F-9A90-79E9F96AF0FB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {645985FC-FDD7-4D6F-9A90-79E9F96AF0FB}.DebugGnome|Any CPU.ActiveCfg = Debug|Any CPU
+ {645985FC-FDD7-4D6F-9A90-79E9F96AF0FB}.DebugMac|Any CPU.ActiveCfg = Debug|Any CPU
+ {645985FC-FDD7-4D6F-9A90-79E9F96AF0FB}.DebugMac|Any CPU.Build.0 = Debug|Any CPU
+ {645985FC-FDD7-4D6F-9A90-79E9F96AF0FB}.DebugWin32|Any CPU.ActiveCfg = Debug|Any CPU
+ {645985FC-FDD7-4D6F-9A90-79E9F96AF0FB}.DebugWin32|Any CPU.Build.0 = Debug|Any CPU
+ {645985FC-FDD7-4D6F-9A90-79E9F96AF0FB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {645985FC-FDD7-4D6F-9A90-79E9F96AF0FB}.ReleaseGnome|Any CPU.ActiveCfg = Release|Any CPU
+ {645985FC-FDD7-4D6F-9A90-79E9F96AF0FB}.ReleaseMac|Any CPU.ActiveCfg = Release|Any CPU
+ {645985FC-FDD7-4D6F-9A90-79E9F96AF0FB}.ReleaseMac|Any CPU.Build.0 = Release|Any CPU
+ {645985FC-FDD7-4D6F-9A90-79E9F96AF0FB}.ReleaseWin32|Any CPU.ActiveCfg = Release|Any CPU
+ {645985FC-FDD7-4D6F-9A90-79E9F96AF0FB}.ReleaseWin32|Any CPU.Build.0 = Release|Any CPU
{726E446E-2E8D-4B48-A47B-923C6CEC4556}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{726E446E-2E8D-4B48-A47B-923C6CEC4556}.DebugGnome|Any CPU.ActiveCfg = Debug|Any CPU
{726E446E-2E8D-4B48-A47B-923C6CEC4556}.DebugMac|Any CPU.ActiveCfg = Debug|Any CPU
@@ -2966,6 +2980,7 @@ Global {E0561832-1C54-41A8-A30A-97E8E81DBCA7} = {32539734-6484-4451-9EF3-61610CA25BBF}
{CB978906-1945-4BB6-AAA5-1FA2E60C22EF} = {32539734-6484-4451-9EF3-61610CA25BBF}
{9B8B470A-5455-45B5-A5D1-8619ED174257} = {32539734-6484-4451-9EF3-61610CA25BBF}
+ {645985FC-FDD7-4D6F-9A90-79E9F96AF0FB} = {32539734-6484-4451-9EF3-61610CA25BBF}
{726E446E-2E8D-4B48-A47B-923C6CEC4556} = {32539734-6484-4451-9EF3-61610CA25BBF}
{F713D37D-70A4-49BB-ADAE-B7007C880E57} = {32539734-6484-4451-9EF3-61610CA25BBF}
{B5C85F1D-38B8-4A57-A763-F390D58BD4D5} = {32539734-6484-4451-9EF3-61610CA25BBF}
diff --git a/main/external/vs-editor-core b/main/external/vs-editor-core -Subproject d89ec5fcf29bf7090cc44d8fbc77d80f1e5f75f +Subproject b4a89409e7c14920a5a806c9056e1ed999b4faa diff --git a/main/msbuild/ReferencesVSEditor.Windows.props b/main/msbuild/ReferencesVSEditor.Windows.props index d81354673f..4390e5af52 100644 --- a/main/msbuild/ReferencesVSEditor.Windows.props +++ b/main/msbuild/ReferencesVSEditor.Windows.props @@ -9,6 +9,7 @@ </PropertyGroup>
<ItemGroup>
+ <PackageReference Include="Microsoft.VisualStudio.Imaging" Version="16.0.27828" PrivateAssets="$(ReferencesVSEditorPrivateAssets)" ExcludeAssets="$(ReferencesVSEditorExcludeAssets)" />
<PackageReference Include="Microsoft.VisualStudio.Language.NavigateTo.Interfaces" Version="$(NuGetVersionVSEditor)" PrivateAssets="$(ReferencesVSEditorPrivateAssets)" ExcludeAssets="$(ReferencesVSEditorExcludeAssets)" />
<PackageReference Include="Microsoft.VisualStudio.Platform.VSEditor" Version="$(NuGetVersionVSEditor)" PrivateAssets="$(ReferencesVSEditorPrivateAssets)" ExcludeAssets="$(ReferencesVSEditorExcludeAssets)" />
<PackageReference Include="Microsoft.CodeAnalysis.EditorFeatures.Wpf" Version="$(NuGetVersionRoslyn)" PrivateAssets="$(ReferencesVSEditorPrivateAssets)" ExcludeAssets="$(ReferencesVSEditorExcludeAssets)" />
diff --git a/main/src/addins/MonoDevelop.TextEditor/MonoDevelop.TextEditor.Wpf/Find/FindUI.xaml b/main/src/addins/MonoDevelop.TextEditor/MonoDevelop.TextEditor.Wpf/Find/FindUI.xaml new file mode 100644 index 0000000000..96d1edbb21 --- /dev/null +++ b/main/src/addins/MonoDevelop.TextEditor/MonoDevelop.TextEditor.Wpf/Find/FindUI.xaml @@ -0,0 +1,460 @@ +<UserControl x:Class="MonoDevelop.TextEditor.Wpf.Find.FindUI" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:c="clr-namespace:System.Windows.Controls;assembly=PresentationFramework" Cursor="Arrow" + x:Name="FindControl" + Background="#EEEEF2" + MinWidth="350" + Width="500" + KeyboardNavigation.TabNavigation="Cycle" + KeyboardNavigation.DirectionalNavigation="Cycle" + MouseDown="OnMouseDown" + MouseUp="OnMouseUp" + GotKeyboardFocus="OnGotKeyboardFocus" + LostKeyboardFocus="OnLostKeyboardFocus" + AutomationProperties.Name="FindControl" + AutomationProperties.AutomationId="FindControl"> + + <UserControl.Resources> + <ResourceDictionary> + + <!-- Toggle button style that is used to expand/collapse to/from replace mode --> + <Style x:Key="ToggleButtonStyle" TargetType="{x:Type ToggleButton}"> + <Setter Property="FocusVisualStyle" Value="{x:Null}" /> + <Setter Property="Control.Template"> + <Setter.Value> + <ControlTemplate TargetType="{x:Type ToggleButton}"> + <Border Background="Transparent" Width="{TemplateBinding Width}" Height="{TemplateBinding Height}"> + <Grid SnapsToDevicePixels="False" Background="Transparent" HorizontalAlignment="Center" VerticalAlignment="Center"> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="19" /> + </Grid.ColumnDefinitions> + <Path Data="M1,1.5L4.5,5 8,1.5" Stroke="#717171" StrokeThickness="2" Name="arrow" HorizontalAlignment="Center" VerticalAlignment="Center" SnapsToDevicePixels="False" /> + </Grid> + </Border> + <ControlTemplate.Triggers> + <Trigger Property="ToggleButton.IsChecked" Value="True"> + <Setter TargetName="arrow" Property="Path.Data"> + <Setter.Value> + <StreamGeometry>M1,4.5L4.5,1 8,4.5</StreamGeometry> + </Setter.Value> + </Setter> + </Trigger> + </ControlTemplate.Triggers> + </ControlTemplate> + </Setter.Value> + </Setter> + </Style> + + <Style x:Key="ButtonStyle" TargetType="{x:Type Button}"> + <Setter Property="Background" Value="Transparent" /> + <Setter Property="BorderBrush" Value="Transparent" /> + <Setter Property="BorderThickness" Value="0" /> + <Setter Property="MinWidth" Value="20" /> + <Setter Property="MinHeight" Value="20" /> + </Style> + + <!-- Search Options Toggle button Style--> + <Style x:Key="SearchOptionToggleButtonStyle" + TargetType="{x:Type ToggleButton}"> + <Setter Property="IsTabStop" Value="true"/> + <Setter Property="Focusable" Value="true"/> + <Setter Property="ClickMode" Value="Press"/> + <Setter Property="FocusVisualStyle" Value="{x:Null}" /> + <Setter Property="Template"> + <Setter.Value> + <ControlTemplate TargetType="{x:Type ToggleButton}"> + <Border x:Name="Border" + Width="20" + Height="20" + Background="Transparent" + BorderThickness="{TemplateBinding BorderThickness}" + BorderBrush="{TemplateBinding BorderBrush}" + SnapsToDevicePixels="True"> + <Border.Child> + <ContentPresenter Name="Image" + Margin="0" + Visibility="Visible" + RecognizesAccessKey="True" /> + </Border.Child> + </Border> + <ControlTemplate.Triggers> + <Trigger Property="IsChecked" Value="False"> + <Setter TargetName="Border" + Property="BorderThickness" + Value="0" /> + </Trigger> + <Trigger Property="IsChecked" Value="True"> + <Setter TargetName="Border" + Property="BorderThickness" + Value="1" /> + <Setter TargetName="Border" + Property="BorderBrush" + Value="#3399FF" /> + <Setter TargetName="Border" Property="Background" Value="#EEEEF2" /> + </Trigger> + <Trigger Property="IsPressed" Value="True"> + <Setter TargetName="Border" + Property="BorderThickness" + Value="1" /> + <Setter TargetName="Border" + Property="BorderBrush" + Value="#007ACC" /> + </Trigger> + <Trigger Property="IsMouseOver" Value="true"> + <Setter TargetName="Border" Property="BorderThickness" Value="1" /> + <Setter TargetName="Border" Property="BorderBrush" Value="#3399FF" /> + <Setter TargetName="Border" Property="Background" Value="#C9DEF5" /> + </Trigger> + <Trigger Property="IsEnabled" Value="false"> + <Setter TargetName="Border" Property="Background" Value="#EEEEF2" /> + </Trigger> + </ControlTemplate.Triggers> + </ControlTemplate> + </Setter.Value> + </Setter> + </Style> + + <Path x:Key="ArrowPath" Fill="{Binding Path=(TextElement.Foreground), RelativeSource={RelativeSource Self}}" Data="M 0 4 L 7 4 L 3.5 0 Z" /> + + <Path x:Key="DownArrowPath" Fill="{Binding Path=(TextElement.Foreground), RelativeSource={RelativeSource Self}}" + Width="8" + Height="4" + Data="F1 M 0,0L 4,4L 8,0L 0,0 Z" + SnapsToDevicePixels="True"/> + + <Path x:Key="XShapePath" + Width="10" + Height="8" + Fill="{Binding Path=(TextElement.Foreground), RelativeSource={RelativeSource Self}}" + Stretch="Uniform" + Data="F1 M 0,0L 2,0L 5,3L 8,0L 10,0L 6,4L 10,8L 8,8L 5,5L 2,8L 0,8L 4,4L 0,0 Z" /> + + </ResourceDictionary> + </UserControl.Resources> + + <UserControl.Content> + <Grid Margin="0,3,0,0"> + <Grid.RowDefinitions> + <RowDefinition Height="Auto"/> + <RowDefinition Height="Auto"/> + <RowDefinition Height="8px"/> + </Grid.RowDefinitions> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="Auto"/> + <ColumnDefinition /> + <ColumnDefinition Width="Auto"/> + </Grid.ColumnDefinitions> + <Grid.Children> + + <ToggleButton Name="FindReplaceToggleButton" + KeyboardNavigation.TabNavigation="Once" + VerticalAlignment="Center" + Padding="0" + Margin="12,0,4,0" + HorizontalAlignment="Center" + HorizontalContentAlignment="Center" + KeyboardNavigation.TabIndex="9" + VerticalContentAlignment="Center" + Background="Transparent" + ToolTip="Toggle to switch between find and replace modes" + Style="{StaticResource ResourceKey=ToggleButtonStyle}" + Width="21" + Height="21" + AutomationProperties.AutomationId="FindReplaceToggleButton" + AutomationProperties.Name="FindReplaceToggleButton"/> + + <ResizeGrip Grid.RowSpan="3" + Name="Resizer" + VerticalAlignment="Bottom" + HorizontalAlignment="Left" + Cursor="SizeWE" + MouseLeftButtonDown="OnResizerMouseLeftButtonDown" + MouseLeftButtonUp="OnResizerMouseLeftButtonUp" + MouseMove="OnResizerMouseMove" + Width="7" + Height="7" + IsTabStop="False" + AutomationProperties.AutomationId="Resizer" AutomationProperties.Name="Resizer"> + <ResizeGrip.Template> + <ControlTemplate TargetType="{x:Type ResizeGrip}"> + <Grid Background="Transparent" Margin="2,2,2,6" VerticalAlignment="{TemplateBinding VerticalAlignment}" HorizontalAlignment="{TemplateBinding HorizontalAlignment}"> + <Path Fill="#717171" Data="F1 M 0,1 L 0,0 L 1,0 L 1,1 L 0,1 Z"/> + <Path Fill="#717171" Data="F1 M 3,4 L 3,3 L 4,3 L 4,4 L 3,4 Z"/> + <Path Fill="#717171" Data="F1 M 0,4 L 0,3 L 1,3 L 1,4 L 0,4 Z"/> + <Path Fill="#717171" Data="F1 M 3,7 L 3,6 L 4,6 L 4,7 L 3,7 Z"/> + <Path Fill="#717171" Data="F1 M 0,7 L 0,6 L 1,6 L 1,7 L 0,7 Z"/> + <Path Fill="#717171" Data="F1 M 6,7 L 6,6 L 7,6 L 7,7 L 6,7 Z"/> + </Grid> + </ControlTemplate> + </ResizeGrip.Template> + </ResizeGrip> + + <Border Grid.Column="1" + Name="FindControlGroup" + HorizontalAlignment="Stretch"> + <Border Name="InvalidSearchBorder" + BorderThickness="1" + BorderBrush="Transparent"> + <TextBox x:Name="SearchControl" + Padding="3" + FontSize="12" + MinHeight="23" + HorizontalContentAlignment="Stretch" + KeyboardNavigation.TabIndex="0" + AutomationProperties.Name="SearchControl" + AutomationProperties.AutomationId="SearchControl"/> + </Border> + </Border> + + <Border Grid.Column="1" + Grid.Row="1" + Name="ReplaceControlGroup" + Padding="1,3,1,0" + HorizontalAlignment="Stretch" + BorderThickness="0"> + <TextBox x:Name="ReplaceControl" + MinHeight="23" + Padding="3" + FontSize="12" + KeyboardNavigation.TabIndex="1" + HorizontalAlignment="Stretch" + HorizontalContentAlignment="Stretch" + AutomationProperties.Name="ReplaceControl" + AutomationProperties.AutomationId="ReplaceControl"/> + </Border> + + <StackPanel Orientation="Horizontal" Grid.Column="2" VerticalAlignment="Center"> + <ToggleButton x:Name="MatchCaseToggleButton" + Margin="2,0,2,0" + Style="{StaticResource SearchOptionToggleButtonStyle}" + ToolTip="Match case (Alt+C)" + KeyboardNavigation.TabIndex="5" + KeyboardNavigation.TabNavigation="Local" + AutomationProperties.Name="MatchCaseToggleButton" + AutomationProperties.AutomationId="MatchCaseToggleButton"> + <ToggleButton.Content> + <Image Margin="0" Stretch="None" Width="17" Height="17"> + <Image.Source> + <DrawingImage> + <DrawingImage.Drawing> + <DrawingGroup> + <DrawingGroup.Children> + <GeometryDrawing Brush="Transparent" Geometry="F1 M 15.80,5.97 C 15.66,5.55 15.44,5.19 15.15,4.88 C 14.85,4.58 14.48,4.35 14.05,4.20 C 13.66,4.07 13.20,4.00 12.69,4.00 C 12.44,4.00 12.18,4.02 11.91,4.06 C 11.67,4.10 11.43,4.15 11.21,4.20 C 10.98,4.26 10.77,4.33 10.57,4.40 C 10.35,4.49 10.17,4.58 10.04,4.66 L 9.58,4.95 L 9.58,7.53 C 9.40,7.75 9.26,8.01 9.16,8.29 C 9.16,8.29 9.16,8.30 9.15,8.31 L 6.38,0.00 L 3.61,0.00 L 0.00,10.83 L 0.00,12.00 L 3.22,12.00 L 3.88,10.00 L 6.11,10.00 L 6.77,12.00 L 10.38,12.00 L 10.24,11.58 C 10.40,11.67 10.57,11.75 10.75,11.81 C 11.09,11.93 11.47,12.00 11.89,12.00 C 12.16,12.00 12.42,11.97 12.67,11.91 L 12.67,12.00 L 16.00,12.00 L 16.00,7.23 C 16.00,6.76 15.93,6.34 15.80,5.97 Z"/> + <DrawingGroup> + <DrawingGroup.Children> + <GeometryDrawing Brush="#424242" Geometry="F1 M 3.66,7.50 L 5.00,3.50 L 6.33,7.50 L 3.66,7.50 Z M 4.33,1.00 L 1.00,11.00 L 2.50,11.00 L 3.16,9.00 L 6.83,9.00 L 7.50,11.00 L 9.00,11.00 L 5.66,1.00 L 4.33,1.00 Z"/> + <GeometryDrawing Brush="#424242" Geometry="F1 M 13.68,8.59 C 13.68,8.78 13.65,8.96 13.58,9.13 C 13.52,9.30 13.42,9.44 13.30,9.57 C 13.18,9.69 13.04,9.79 12.87,9.86 C 12.70,9.94 12.51,9.97 12.30,9.97 C 12.15,9.97 12.02,9.95 11.89,9.91 C 11.77,9.87 11.67,9.81 11.58,9.74 C 11.50,9.67 11.43,9.59 11.39,9.49 C 11.34,9.39 11.32,9.28 11.32,9.16 C 11.32,9.03 11.33,8.92 11.36,8.82 C 11.39,8.72 11.45,8.63 11.53,8.55 C 11.61,8.47 11.72,8.41 11.85,8.35 C 12.00,8.30 12.18,8.26 12.40,8.24 L 13.68,8.07 L 13.68,8.59 Z M 14.85,6.29 C 14.76,6.01 14.62,5.78 14.43,5.59 C 14.25,5.39 14.01,5.25 13.72,5.15 C 13.43,5.05 13.09,5.00 12.69,5.00 C 12.49,5.00 12.28,5.01 12.07,5.05 C 11.86,5.08 11.65,5.12 11.46,5.17 C 11.27,5.22 11.09,5.28 10.94,5.34 C 10.78,5.40 10.66,5.45 10.58,5.50 L 10.58,6.64 C 10.85,6.45 11.15,6.30 11.50,6.18 C 11.84,6.06 12.19,6.01 12.55,6.01 C 12.91,6.01 13.19,6.10 13.39,6.28 C 13.58,6.47 13.68,6.77 13.68,7.17 L 11.94,7.40 C 11.60,7.44 11.30,7.52 11.06,7.63 C 10.81,7.74 10.61,7.88 10.45,8.04 C 10.29,8.21 10.18,8.40 10.10,8.61 C 10.03,8.82 10.00,9.05 10.00,9.30 C 10.00,9.55 10.04,9.78 10.12,9.98 C 10.20,10.19 10.33,10.37 10.48,10.52 C 10.64,10.67 10.84,10.79 11.08,10.87 C 11.31,10.95 11.58,11.00 11.89,11.00 C 12.27,11.00 12.61,10.92 12.91,10.76 C 13.20,10.60 13.45,10.37 13.65,10.07 L 13.67,10.07 L 13.67,11.00 L 15.00,11.00 L 15.00,7.23 C 15.00,6.88 14.95,6.56 14.85,6.29 Z"/> + </DrawingGroup.Children> + </DrawingGroup> + </DrawingGroup.Children> + </DrawingGroup> + </DrawingImage.Drawing> + </DrawingImage> + </Image.Source> + </Image> + </ToggleButton.Content> + </ToggleButton> + <ToggleButton x:Name="MatchWholeWordToggleButton" + Margin="2,0,2,0" + Style="{StaticResource ResourceKey=SearchOptionToggleButtonStyle}" + ToolTip="Match whole word (Alt+W)" + KeyboardNavigation.TabIndex="6" + KeyboardNavigation.TabNavigation="Local" + AutomationProperties.Name="MatchWholeWordToggleButton" + AutomationProperties.AutomationId="MatchWholeWordToggleButton"> + <ToggleButton.Content> + <Image Margin="0" Stretch="None" Width="17" Height="17"> + <Image.Source> + <DrawingImage> + <DrawingImage.Drawing> + <DrawingGroup> + <DrawingGroup.Children> + <GeometryDrawing Brush="Transparent" Geometry="F1 M 12.03,5.00 L 10.00,5.00 L 10.00,3.00 L 12.04,3.00 L 12.03,5.00 Z M 7.00,6.83 L 5.72,3.00 L 7.00,3.00 L 7.00,6.83 Z M 3.05,10.00 L 3.38,9.00 L 4.61,9.00 L 4.94,10.00 L 3.05,10.00 Z M 15.00,0.01 L 0.00,0.00 L 0.00,3.00 L 2.28,3.00 L 0.00,9.83 L 0.00,11.00 L 0.00,12.00 L 0.00,13.00 L 15.00,12.98 L 15.00,0.01 Z"/> + <DrawingGroup> + <DrawingGroup.Children> + <GeometryDrawing Brush="#424242" Geometry="F1 M 11.00,7.00 L 11.00,9.00 L 9.00,9.00 L 9.00,7.00 L 11.00,7.00 Z M 8.00,3.00 L 8.00,10.00 L 12.00,10.00 L 12.00,6.00 L 9.00,6.00 L 9.00,3.00 L 8.00,3.00 Z"/> + <GeometryDrawing Brush="#424242" Geometry="F1 M 13.00,10.00 L 14.00,10.00 L 14.00,3.00 L 13.04,3.00 L 13.00,10.00 Z"/> + <GeometryDrawing Brush="#424242" Geometry="F1 M 4.00,4.00 L 5.00,7.00 L 3.00,7.00 L 4.00,4.00 Z M 5.33,8.00 L 6.00,10.00 L 7.00,10.00 L 4.66,3.00 L 3.33,3.00 L 1.00,10.00 L 2.00,10.00 L 2.66,8.00 L 5.33,8.00 Z"/> + <GeometryDrawing Brush="#424242" Geometry="F1 M 1.00,1.00 L 1.00,2.00 L 14.00,2.00 L 14.00,1.00 L 1.00,1.00 Z"/> + <GeometryDrawing Brush="#424242" Geometry="F1 M 1.00,12.00 L 14.00,12.00 L 14.00,11.00 L 1.00,11.00 L 1.00,12.00 Z"/> + </DrawingGroup.Children> + </DrawingGroup> + </DrawingGroup.Children> + </DrawingGroup> + </DrawingImage.Drawing> + </DrawingImage> + </Image.Source> + </Image> + </ToggleButton.Content> + </ToggleButton> + <ToggleButton x:Name="RegularExpressionToggleButton" + Margin="2,0,2,0" + Style="{StaticResource ResourceKey=SearchOptionToggleButtonStyle}" + ToolTip="Use Regular Expressions" + KeyboardNavigation.TabIndex="7" + KeyboardNavigation.TabNavigation="Local" + AutomationProperties.Name="RegularExpressionToggleButton" + AutomationProperties.AutomationId="RegularExpressionToggleButton"> + <ToggleButton.Content> + <Image Margin="0" Stretch="None" Width="17" Height="17"> + <Image.Source> + <DrawingImage> + <DrawingImage.Drawing> + <DrawingGroup> + <DrawingGroup.Children> + <GeometryDrawing Brush="Transparent" Geometry="F1 M 14.34,5.70 L 12.94,1.79 L 10.81,2.68 L 11.09,0.00 L 6.90,0.00 L 7.18,2.68 L 5.05,1.79 L 3.65,5.70 L 6.06,6.11 L 5.33,6.99 L 0.00,6.99 L 0.00,12.99 L 6.00,12.99 L 6.00,9.22 L 7.78,10.45 L 9.00,8.22 L 10.24,10.45 L 13.58,8.11 L 11.95,6.11 L 14.34,5.70 Z"/> + <DrawingGroup> + <DrawingGroup.Children> + <GeometryDrawing Brush="#424242" Geometry="F1 M 13.00,4.91 L 12.35,3.11 L 9.64,4.25 L 9.98,1.00 L 8.01,1.00 L 8.35,4.25 L 5.64,3.11 L 5.00,4.91 L 7.93,5.41 L 5.86,7.91 L 7.44,9.00 L 8.99,6.16 L 10.58,9.00 L 12.13,7.91 L 10.09,5.41 L 13.00,4.91 Z"/> + <GeometryDrawing Brush="#424242" Geometry="F1 M 1.00,11.99 L 5.00,11.99 L 5.00,7.99 L 1.00,7.99 L 1.00,11.99 Z"/> + </DrawingGroup.Children> + </DrawingGroup> + </DrawingGroup.Children> + </DrawingGroup> + </DrawingImage.Drawing> + </DrawingImage> + </Image.Source> + </Image> + </ToggleButton.Content> + </ToggleButton> + + <TextBlock x:Name="ResultIndexAndCount" + MinWidth="60" + FontSize="12" + VerticalAlignment="Center" + Margin="8,0,8,0" /> + + <Button x:Name="FindPreviousButton" + Margin="4,0,2,0" + ToolTip="Find Previous (Shift+F3)" + Click="OnFindPreviousClick" + Style="{StaticResource ButtonStyle}"> + <Path Data="M5,1 L1,5 L5,9" Stroke="#717171" StrokeThickness="2" HorizontalAlignment="Center" VerticalAlignment="Center" /> + </Button> + <Button x:Name="FindNextButton" + Margin="4,0,2,0" + ToolTip="Find Next (F3)" + Click="OnFindNextClick" + Style="{StaticResource ButtonStyle}"> + <Path Data="M3,1 L7,5 L3,9" Stroke="#717171" StrokeThickness="2" HorizontalAlignment="Center" VerticalAlignment="Center" /> + </Button> + + <Button Name="CloseButton" + Style="{StaticResource ButtonStyle}" + Margin="12,0,0,0" + Padding="2" + Click="OnHide" + Content="{StaticResource ResourceKey=XShapePath}" + KeyboardNavigation.TabIndex="10" + ToolTip="Close" + TextElement.Foreground="#717171" + AutomationProperties.Name="CloseButton" + AutomationProperties.AutomationId="CloseButton"> + </Button> + + </StackPanel> + + <StackPanel Name="ReplaceButtons" + Orientation="Horizontal" + HorizontalAlignment="Left" + VerticalAlignment="Center" + Grid.Column="2" + Grid.Row="1"> + <Button Name="ReplaceNextButton" + Click="OnReplaceNext" + Margin="2,0,2,0" + Style="{StaticResource ButtonStyle}" + ToolTip="Replace next (Alt+R)" + KeyboardNavigation.TabIndex="3" + AutomationProperties.Name="ReplaceNextButton" + AutomationProperties.AutomationId="ReplaceNextButton"> + <Button.Content> + <Image Margin="0" + Stretch="None" + AutomationProperties.Name="ReplaceNextImage" + AutomationProperties.AutomationId="ReplaceNextImage" + Width="17" + Height="17"> + <Image.Source> + <DrawingImage> + <DrawingImage.Drawing> + <DrawingGroup> + <GeometryDrawing Brush="Transparent" + Geometry="F1 M 6.00,5.00 L 6.00,4.00 L 8.00,4.00 L 8.00,8.00 L 4.91,8.00 L 6.00,6.91 L 6.00,5.00 M 11.00,2.00 L 11.00,0.00 L 8.00,0.00 L 8.00,1.00 L 4.47,1.00 C 3.10,1.00 1.97,2.12 1.97,3.50 L 1.97,3.56 L 1.00,2.58 L 1.00,6.91 L 2.08,8.00 L 0.00,8.00 L 0.00,16.00 L 9.00,16.00 L 9.00,8.00 L 14.00,8.00 L 14.00,2.00 L 11.00,2.00 Z"/> + <GeometryDrawing Brush="#424242" + Geometry="F1 M 12.00,6.00 L 10.00,6.00 L 10.00,4.00 L 12.00,4.00 L 12.00,6.00 Z M 10.00,3.00 L 10.00,1.00 L 9.00,1.00 L 9.00,6.00 L 9.00,7.00 L 10.00,7.00 L 12.00,7.00 L 13.00,7.00 L 13.00,4.00 L 13.00,3.00 L 10.00,3.00 Z"/> + <GeometryDrawing Brush="#424242" + Geometry="F1 M 3.00,10.00 L 6.00,10.00 L 6.00,11.00 L 4.00,11.00 L 4.00,13.00 L 6.00,13.00 L 6.00,14.00 L 3.00,14.00 L 3.00,10.00 Z M 1.00,15.00 L 8.00,15.00 L 8.00,9.00 L 1.00,9.00 L 1.00,15.00 Z"/> + <GeometryDrawing Brush="#424242" + Geometry="F1 M 2.97,3.50 L 3.00,6.00 L 2.00,5.00 L 2.00,6.50 L 3.50,8.00 L 5.00,6.50 L 5.00,5.00 L 4.00,6.00 L 3.97,3.50 C 3.97,3.22 4.20,3.00 4.47,3.00 L 8.00,3.00 L 8.00,2.00 L 4.47,2.00 C 3.65,2.00 2.97,2.67 2.97,3.50 Z"/> + </DrawingGroup> + </DrawingImage.Drawing> + </DrawingImage> + </Image.Source> + </Image> + </Button.Content> + </Button> + <Button Name="ReplaceAllButton" + Click="OnReplaceAll" + Margin="2,0,2,0" + Style="{StaticResource ButtonStyle}" + ToolTip="Replace all (Alt+A)" + KeyboardNavigation.TabIndex="4" + AutomationProperties.Name="ReplaceAllButton" + AutomationProperties.AutomationId="ReplaceAllButton"> + <Button.Content> + <Image Margin="0" + Stretch="None" + AutomationProperties.Name="ReplaceAllImage" + AutomationProperties.AutomationId="ReplaceAllImage" + Width="17" + Height="17"> + <Image.Source> + <DrawingImage> + <DrawingImage.Drawing> + <DrawingGroup> + <DrawingGroup.Children> + <DrawingGroup> + <DrawingGroup.Children> + <GeometryDrawing Brush="Transparent" Geometry="F1 M 6.97,4.00 L 6.97,6.00 L 5.00,6.00 L 5.00,4.00 L 6.97,4.00 Z M 15.97,1.00 L 13.97,1.00 L 13.97,0.00 L 10.97,0.00 L 10.97,1.00 L 8.00,1.00 L 6.97,1.00 L 3.50,1.00 C 2.12,1.00 1.00,2.12 1.00,3.50 L 1.00,3.58 L 0.00,2.58 L 0.00,6.91 L 1.08,8.00 L 0.00,8.00 L 0.00,16.00 L 12.00,16.00 L 12.00,14.00 L 13.97,14.00 L 13.97,7.00 L 15.97,7.00 L 15.97,1.00 Z"/> + <GeometryDrawing Brush="#424242" Geometry="F1 M 13.97,5.00 L 12.97,5.00 L 12.97,3.00 L 13.97,3.00 L 13.97,5.00 Z M 12.97,2.00 L 12.97,1.00 L 11.97,1.00 L 11.97,6.00 L 14.97,6.00 L 14.97,2.00 L 12.97,2.00 Z"/> + <GeometryDrawing Brush="#424242" Geometry="F1 M 10.97,2.00 L 7.97,2.00 L 7.97,3.00 L 8.97,3.00 L 8.97,4.00 L 9.97,4.00 L 9.97,5.00 L 8.97,5.00 L 8.97,4.00 L 7.97,4.00 L 7.97,6.00 L 10.97,6.00 L 10.97,2.00 Z"/> + <GeometryDrawing Brush="#424242" Geometry="F1 M 4.97,8.00 L 11.97,8.00 L 11.97,13.00 L 12.97,13.00 L 12.97,8.00 L 12.97,7.00 L 4.97,7.00 L 4.97,8.00 Z"/> + <DrawingGroup> + <DrawingGroup.Children> + <GeometryDrawing Brush="#424242" Geometry="F1 M 3.97,13.00 L 3.97,12.00 L 2.97,12.00 L 2.97,13.00 L 3.97,13.00 Z"/> + <GeometryDrawing Brush="#424242" Geometry="F1 M 9.97,11.00 L 7.97,11.00 L 7.97,13.00 L 9.97,13.00 L 9.97,14.00 L 6.97,14.00 L 6.97,10.00 L 9.97,10.00 L 9.97,11.00 Z M 4.97,14.00 L 1.97,14.00 L 1.97,12.00 L 2.97,12.00 L 2.97,11.00 L 1.97,11.00 L 1.97,10.00 L 4.97,10.00 L 4.97,14.00 Z M 1.00,9.00 L 1.00,15.00 L 11.00,15.00 L 11.00,9.00 L 1.00,9.00 Z"/> + </DrawingGroup.Children> + </DrawingGroup> + <GeometryDrawing Brush="#00529B" Geometry="F1 M 4.00,6.50 L 4.00,5.00 L 3.00,6.00 L 3.00,3.50 C 3.00,3.22 3.22,3.00 3.50,3.00 L 7.00,3.00 L 7.00,2.00 L 3.50,2.00 C 2.67,2.00 2.00,2.67 2.00,3.50 L 2.00,6.00 L 1.00,5.00 L 1.00,6.50 L 2.50,8.00 L 4.00,6.50 Z"/> + </DrawingGroup.Children> + </DrawingGroup> + </DrawingGroup.Children> + </DrawingGroup> + </DrawingImage.Drawing> + </DrawingImage> + </Image.Source> + </Image> + </Button.Content> + </Button> + </StackPanel> + + <Rectangle Margin="0,4,0,0" Grid.ColumnSpan="3" Grid.Row="2" Name="Find_Focus_Border"> + <Rectangle.Style> + <Style TargetType="{x:Type Rectangle}"> + <Style.Setters> + <Setter Property="Fill" Value="#007ACC"/> + </Style.Setters> + <Style.Triggers> + <DataTrigger Binding="{Binding Path=IsKeyboardFocusWithin, ElementName=FindControl}" Value="False"> + <Setter Property="Fill" Value="#CCCEDB"/> + </DataTrigger> + </Style.Triggers> + </Style> + </Rectangle.Style> + </Rectangle> + </Grid.Children> + </Grid> + </UserControl.Content> + +</UserControl> diff --git a/main/src/addins/MonoDevelop.TextEditor/MonoDevelop.TextEditor.Wpf/Find/FindUI.xaml.cs b/main/src/addins/MonoDevelop.TextEditor/MonoDevelop.TextEditor.Wpf/Find/FindUI.xaml.cs new file mode 100644 index 0000000000..a3b4988a0c --- /dev/null +++ b/main/src/addins/MonoDevelop.TextEditor/MonoDevelop.TextEditor.Wpf/Find/FindUI.xaml.cs @@ -0,0 +1,363 @@ +// +// Copyright (c) Microsoft Corp. (https://www.microsoft.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +using System; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Input; +using System.Windows.Threading; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.Text.Operations; + +namespace MonoDevelop.TextEditor.Wpf.Find +{ + public partial class FindUI : UserControl + { + private IWpfTextView currentTextView; // The text view on which the UI is being displayed at any given time + + /// <summary> + /// Used for resizing of the control + /// </summary> + double _resizingBaselineWidth; + double _resizingBaselinePoint; + + public event Action<string> SearchTextChanged; + public event Action<string> ReplaceTextChanged; + public event Action<FindOptions> FindOptionsChanged; + public event Action FindPrevious; + public event Action FindNext; + public event Action Replace; + public event Action ReplaceAll; + public event Action CloseRequested; + + public const string FindUIAdornmentLayer = nameof (FindUIAdornmentLayer); + + public FindUI () + { + InitializeComponent (); + + Visibility = Visibility.Collapsed; + + SearchControl.TextChanged += OnSearchTextChanged; + ReplaceControl.TextChanged += OnReplaceTextChanged; + + FindReplaceToggleButton.Checked += (s, e) => IsInReplaceMode = true; + FindReplaceToggleButton.Unchecked += (s, e) => IsInReplaceMode = false; + MatchCaseToggleButton.Checked += RaiseFindOptionsChanged; + MatchCaseToggleButton.Unchecked += RaiseFindOptionsChanged; + MatchWholeWordToggleButton.Checked += RaiseFindOptionsChanged; + MatchWholeWordToggleButton.Unchecked += RaiseFindOptionsChanged; + RegularExpressionToggleButton.Checked += RaiseFindOptionsChanged; + RegularExpressionToggleButton.Unchecked += RaiseFindOptionsChanged; + + UpdateReplaceVisibility (false); + } + + public void ShowAdornment (IWpfTextView view) + { + IAdornmentLayer adornmentLayer = view.GetAdornmentLayer (FindUIAdornmentLayer); + + // Make sure anti-aliasing doesn't cause trouble + ((UIElement)adornmentLayer).SnapsToDevicePixels = true; + + currentTextView = view; + + if (adornmentLayer.Elements.Count == 0) { + adornmentLayer.AddAdornment (AdornmentPositioningBehavior.OwnerControlled, null, this, this, null); + } + + Position (); + + Visibility = Visibility.Visible; + + view.VisualElement.SizeChanged += OnViewSizeChanged; + view.Closed += OnViewClosed; + + FocusFindBox (); + } + + public void HideAdornment () + { + IWpfTextView textView = currentTextView; + + // Send the focus back to the editor. + if (textView != null && !textView.IsClosed) { + textView.VisualElement.Focus (); + } + + // Hide the adornment (Note that this calls DetachFromView on us) + // This has to be done after the focus transfer because the FindAdornmentManager + // needs to respond to the focus transfer before it disconnects itself from the view. + Visibility = Visibility.Collapsed; + + if (textView != null) { + if (this.IsKeyboardFocusWithin) { + // This method will remove the Find UI adornment from the visual tree but that on its own + // won't move the focus from the Find UI. WPF would later get around to restoring a valid focus. + // There is a problematic case when the adornment is being hidden while doing a FindNext to + // a document in a different top-level floating window frame because when we do try to focus + // the other top-level window frame, WPF will detect that focus is still "disconnected" + // and will restore focus to this editor instead of moving it as we request. + // By manually moving focus here, it will not get into this "disconnected" state. + textView.VisualElement.Focus (); + } + + currentTextView = null; + + textView.GetAdornmentLayer (FindUIAdornmentLayer).RemoveAllAdornments (); + textView.VisualElement.SizeChanged -= OnViewSizeChanged; + textView.Closed -= OnViewClosed; + textView = null; + } + } + + private void RaiseFindOptionsChanged (object sender, EventArgs args) + { + FindOptionsChanged?.Invoke (FindOptions); + } + + public FindOptions FindOptions { + get { + var options = FindOptions.None; + if (MatchCaseToggleButton.IsChecked == true) { + options |= FindOptions.MatchCase; + } + + if (MatchWholeWordToggleButton.IsChecked == true) { + options |= FindOptions.WholeWord; + } + + if (RegularExpressionToggleButton.IsChecked == true) { + options |= FindOptions.UseRegularExpressions; + } + + return options; + } + set { + MatchCaseToggleButton.IsChecked = (value & FindOptions.MatchCase) != 0; + MatchWholeWordToggleButton.IsChecked = (value & FindOptions.WholeWord) != 0; + RegularExpressionToggleButton.IsChecked = (value & FindOptions.UseRegularExpressions) != 0; + } + } + + private bool isInReplaceMode; + public bool IsInReplaceMode { + get => isInReplaceMode; + set { + if (isInReplaceMode == value) { + return; + } + + isInReplaceMode = value; + FindReplaceToggleButton.IsChecked = value; + UpdateReplaceVisibility (value); + } + } + + private void UpdateReplaceVisibility (bool value) + { + var visibility = value ? Visibility.Visible : Visibility.Collapsed; + ReplaceControlGroup.Visibility = visibility; + ReplaceButtons.Visibility = visibility; + } + + private void OnSearchTextChanged (object sender, TextChangedEventArgs e) + { + SearchTextChanged?.Invoke (SearchControl.Text); + } + + private void OnReplaceTextChanged (object sender, TextChangedEventArgs e) + { + ReplaceTextChanged?.Invoke (ReplaceControl.Text); + } + + private void OnFindPreviousClick (object sender, RoutedEventArgs args) + { + FindPrevious?.Invoke (); + } + + private void OnFindNextClick (object sender, RoutedEventArgs args) + { + FindNext?.Invoke (); + } + + private void OnReplaceNext (object sender, RoutedEventArgs e) + { + Replace?.Invoke (); + e.Handled = true; + } + + private void OnReplaceAll (object sender, RoutedEventArgs e) + { + ReplaceAll?.Invoke (); + e.Handled = true; + } + + private void OnMouseDown (object sender, MouseButtonEventArgs e) + { + // We don't want to allow the mouse click to go through to the editor. + e.Handled = true; + } + + private void OnMouseUp (object sender, MouseButtonEventArgs e) + { + // We don't want to allow the mouse click to go through to the editor. + e.Handled = true; + } + + private void OnGotKeyboardFocus (object sender, KeyboardFocusChangedEventArgs e) + { + // Don't let the GotKeyboardFocus event propagate to the parent. The text view, upon receipt of this event, + // does some processing (among which is IME) and causes issues. + e.Handled = true; + } + + private void OnLostKeyboardFocus (object sender, KeyboardFocusChangedEventArgs e) + { + // Don't let the LostKeyboardFocus event propagate to the parent. The text view, upon receipt of this event, + // does some processing (among which is IME) and causes issues. + e.Handled = true; + } + + private void OnResizerMouseLeftButtonDown (object sender, MouseButtonEventArgs e) + { + if (!this.Resizer.IsMouseCaptured) { + _resizingBaselinePoint = this.PointToScreen (e.GetPosition (this)).X; + _resizingBaselineWidth = this.ActualWidth; + + // While in the CaptureMouse call we can reentrantly get the MouseMove event so we + // have to have initialized the point and width fields above before the call. + if (!this.Resizer.CaptureMouse ()) { + _resizingBaselinePoint = .0; + _resizingBaselineWidth = .0; + } + + e.Handled = true; + } + } + + private void OnResizerMouseLeftButtonUp (object sender, MouseButtonEventArgs e) + { + if (this.Resizer.IsMouseCaptured) { + this.Resizer.ReleaseMouseCapture (); + _resizingBaselinePoint = .0; + _resizingBaselineWidth = .0; + e.Handled = true; + } + } + + private void OnResizerMouseMove (object sender, MouseEventArgs e) + { + if (this.Resizer.IsMouseCaptured && e.LeftButton == MouseButtonState.Pressed) { + Point mouseLocation = e.GetPosition (this); + Point anchorPoint = this.PointFromScreen (new Point (_resizingBaselinePoint, .0)); + double delta = anchorPoint.X > mouseLocation.X ? anchorPoint.X - mouseLocation.X : -(mouseLocation.X - anchorPoint.X); + this.Width = Math.Min (Math.Max (this.MinWidth, _resizingBaselineWidth + delta), this.MaxWidth); + + Canvas.SetTop (this, 0.0); + Canvas.SetLeft (this, currentTextView.ViewportWidth - this.Width); + + e.Handled = true; + } + } + + private void OnHide (object sender, RoutedEventArgs e) + { + CloseRequested?.Invoke (); + e.Handled = true; + } + + private void OnViewClosed (object sender, EventArgs args) + { + this.HideAdornment (); + } + + private void OnViewSizeChanged (object sender, SizeChangedEventArgs e) + { + if (e.WidthChanged) { + Position (); + } + } + + public void Position () + { + if (currentTextView != null) { + this.MaxWidth = currentTextView.ViewportWidth; + this.Width = Math.Min (Math.Max (this.Width, this.MinWidth), this.MaxWidth); + + Canvas.SetTop (this, 0.0); + Canvas.SetLeft (this, currentTextView.ViewportWidth - this.Width); + } + } + + protected override void OnPreviewKeyDown (KeyEventArgs e) + { + if (e == null || e.Handled) { + return; + } + + // We handle the Escape key on preview so that we have the chance of handling it before any of the controls inside + // the find adornment since we want to always dismiss the UI when escape is pressed irrespective of the state of + // the child controls. + base.OnPreviewKeyDown (e); + + if (e.Handled) { + return; + } + + if (e.Key == Key.Escape) { + // If the search or replace controls have their pop up open, we want to let Escape take its normal + // route so that it dismisses the popups. Also check whether a dropdown button has its context menu open. + if (!InputManager.Current.IsInMenuMode) { + CloseRequested?.Invoke (); + e.Handled = true; + } + } else if (e.Key == Key.F3) { + if (e.KeyboardDevice.Modifiers == ModifierKeys.None) { + FindNext?.Invoke (); + e.Handled = true; + } else if (e.KeyboardDevice.Modifiers == ModifierKeys.Shift) { + FindPrevious?.Invoke (); + e.Handled = true; + } + } else if (e.Key == Key.A && e.KeyboardDevice.Modifiers == ModifierKeys.Alt) { + ReplaceAll?.Invoke (); + e.Handled = true; + } else if (e.Key == Key.R && e.KeyboardDevice.Modifiers == ModifierKeys.Alt) { + Replace?.Invoke (); + e.Handled = true; + } + } + + private void OnIsVisibleChanged (object sender, DependencyPropertyChangedEventArgs e) + { + if ((bool)e.NewValue) { + this.Position (); + } + } + + public void FocusFindBox () + { + Dispatcher.BeginInvoke (new Action (() => this.SearchControl.Focus ()), DispatcherPriority.Input); + } + } +} + diff --git a/main/src/addins/MonoDevelop.TextEditor/MonoDevelop.TextEditor.Wpf/Find/WpfFindPresenter.cs b/main/src/addins/MonoDevelop.TextEditor/MonoDevelop.TextEditor.Wpf/Find/WpfFindPresenter.cs new file mode 100644 index 0000000000..4dc15a5225 --- /dev/null +++ b/main/src/addins/MonoDevelop.TextEditor/MonoDevelop.TextEditor.Wpf/Find/WpfFindPresenter.cs @@ -0,0 +1,170 @@ +// +// Copyright (c) Microsoft Corp. (https://www.microsoft.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +using System; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.Text.Operations; +using Microsoft.VisualStudio.Text.Find; +using Microsoft.VisualStudio.Text.Find.Implementation; +using Microsoft.VisualStudio.Text.Editor.Commanding; +using Microsoft.VisualStudio.Text.Editor.Commanding.Commands; + +namespace MonoDevelop.TextEditor.Wpf.Find +{ + class WpfFindPresenter : IFindPresenter + { + readonly WpfFindPresenterFactory factory; + readonly ITextView textView; + readonly FindUI findUI; + readonly IEditorCommandHandlerService commandHandlerService; + FindController controller; + + static Action Noop { get; } = () => { }; + FindBroker Broker => factory.FindBroker; + + public WpfFindPresenter (WpfFindPresenterFactory factory, ITextView textView) + { + this.factory = factory; + this.textView = textView; + this.findUI = new FindUI (); + this.commandHandlerService = factory.EditorCommandHandlerServiceFactory.GetService (textView); + + SubscribeToUIEvents (); + } + + /// <summary> + /// Controller is lazy to avoid a MEF loop + /// </summary> + FindController Controller { + get { + if (controller == null) { + controller = Broker.GetFindController (textView); + SubscribeToControllerEvents (); + } + + return controller; + } + } + + public bool IsVisible => findUI.IsVisible; + + public void ShowFind () + { + findUI.ShowAdornment ((IWpfTextView)textView); + findUI.IsInReplaceMode = false; + Controller.UpdateSearchTextFromCurrentWord (); + } + + public void ShowReplace () + { + findUI.ShowAdornment ((IWpfTextView)textView); + findUI.IsInReplaceMode = true; + Controller.UpdateSearchTextFromCurrentWord (); + } + + public void Hide () + { + findUI.HideAdornment (); + Controller.ClearTags (); + } + + void SubscribeToUIEvents () + { + findUI.CloseRequested += Hide; + findUI.SearchTextChanged += OnSearchTextChangedInUI; + findUI.ReplaceTextChanged += OnReplaceTextChangedInUI; + findUI.FindOptionsChanged += OnFindOptionsChangedInUI; + findUI.FindPrevious += OnFindPreviousClicked; + findUI.FindNext += OnFindNextClicked; + findUI.Replace += OnReplaceClicked; + findUI.ReplaceAll += OnReplaceAllClicked; + } + + void SubscribeToControllerEvents () + { + controller.ResultsAvailable += OnResultsAvailable; + controller.FindOptionsChanged += OnFindOptionsChanged; + controller.SearchTextChanged += OnSearchTextChanged; + } + + void OnSearchTextChanged () + { + if (findUI.SearchControl.Text != controller.SearchText) { + findUI.SearchControl.Text = controller.SearchText; + findUI.SearchControl.SelectAll (); + } + } + + void OnResultsAvailable ((int index, int count) args) + { + string summaryText = null; + if (args.count == 0) { + summaryText = "No results"; + } else { + summaryText = $"{args.index + 1} of {args.count}"; + } + + findUI.Dispatcher.InvokeAsync (() => { + findUI.ResultIndexAndCount.Text = summaryText; + }); + } + + void OnFindOptionsChanged () + { + findUI.FindOptions = Broker.FindOptions; + } + + void OnFindPreviousClicked () + { + commandHandlerService.Execute ((v, b) => new FindPreviousCommandArgs (v, b), Noop); + } + + void OnFindNextClicked () + { + commandHandlerService.Execute ((v, b) => new FindNextCommandArgs (v, b), Noop); + } + + void OnReplaceClicked () + { + commandHandlerService.Execute ((v, b) => new ReplaceNextCommandArgs (v, b), Noop); + } + + void OnReplaceAllClicked () + { + commandHandlerService.Execute ((v, b) => new ReplaceAllCommandArgs (v, b), Noop); + } + + void OnFindOptionsChangedInUI (FindOptions findOptions) + { + Broker.FindOptions = findOptions; + } + + void OnSearchTextChangedInUI (string text) + { + Controller.SearchText = text; + } + + void OnReplaceTextChangedInUI (string text) + { + Controller.ReplaceText = text; + } + } +}
\ No newline at end of file diff --git a/main/src/addins/MonoDevelop.TextEditor/MonoDevelop.TextEditor.Wpf/Find/WpfFindPresenterFactory.cs b/main/src/addins/MonoDevelop.TextEditor/MonoDevelop.TextEditor.Wpf/Find/WpfFindPresenterFactory.cs new file mode 100644 index 0000000000..4f6b1e7cc2 --- /dev/null +++ b/main/src/addins/MonoDevelop.TextEditor/MonoDevelop.TextEditor.Wpf/Find/WpfFindPresenterFactory.cs @@ -0,0 +1,55 @@ +// +// Copyright (c) Microsoft Corp. (https://www.microsoft.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +using System.ComponentModel.Composition; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.Text.Editor.Commanding; +using Microsoft.VisualStudio.Text.Find; +using Microsoft.VisualStudio.Text.Find.Implementation; +using Microsoft.VisualStudio.Utilities; + +namespace MonoDevelop.TextEditor.Wpf.Find +{ + [Export (typeof (IFindPresenterFactory))] + class WpfFindPresenterFactory : IFindPresenterFactory + { + [Import] + public FindBroker FindBroker { get; set; } + + [Import] + public IEditorCommandHandlerServiceFactory EditorCommandHandlerServiceFactory { get; set; } + + public IFindPresenter TryGetFindPresenter (ITextView textView) + { + return textView.Properties.GetOrCreateSingletonProperty<IFindPresenter> (() => + { + var presenter = new WpfFindPresenter (this, textView); + return presenter; + }); + } + + [Export] + [Name (FindUI.FindUIAdornmentLayer)] + [Order (After = PredefinedAdornmentLayers.Caret)] + [IsOverlayLayer (true)] + private AdornmentLayerDefinition adornmentLayerDefinition; + } +}
\ No newline at end of file diff --git a/main/src/addins/MonoDevelop.TextEditor/MonoDevelop.TextEditor.Wpf/KeyProcessor/DefaultKeyProcessor.cs b/main/src/addins/MonoDevelop.TextEditor/MonoDevelop.TextEditor.Wpf/KeyProcessor/DefaultKeyProcessor.cs index bcad36717e..daea6c8986 100644 --- a/main/src/addins/MonoDevelop.TextEditor/MonoDevelop.TextEditor.Wpf/KeyProcessor/DefaultKeyProcessor.cs +++ b/main/src/addins/MonoDevelop.TextEditor/MonoDevelop.TextEditor.Wpf/KeyProcessor/DefaultKeyProcessor.cs @@ -236,6 +236,12 @@ namespace MonoDevelop.Ide.Text case Key.A: QueryAndExecute ((v, b) => new SelectAllCommandArgs (v, b)); break; + case Key.F: + QueryAndExecute ((v, b) => new FindCommandArgs (v, b)); + break; + case Key.H: + QueryAndExecute ((v, b) => new ReplaceCommandArgs (v, b)); + break; case Key.W: _editorOperations.SelectCurrentWord (); break; diff --git a/main/src/addins/MonoDevelop.TextEditor/MonoDevelop.TextEditor.Wpf/MonoDevelop.TextEditor.Wpf.csproj b/main/src/addins/MonoDevelop.TextEditor/MonoDevelop.TextEditor.Wpf/MonoDevelop.TextEditor.Wpf.csproj index f75ebc2b94..ea1118d62d 100644 --- a/main/src/addins/MonoDevelop.TextEditor/MonoDevelop.TextEditor.Wpf/MonoDevelop.TextEditor.Wpf.csproj +++ b/main/src/addins/MonoDevelop.TextEditor/MonoDevelop.TextEditor.Wpf/MonoDevelop.TextEditor.Wpf.csproj @@ -10,8 +10,17 @@ </PropertyGroup> <ItemGroup> <PackageReference Include="DiagnosticMargin" Version="1.0.1" PrivateAssets="all" /> + <PackageReference Include="Microsoft.VisualStudio.CoreUtility" Version="$(NuGetVersionVSEditor)" PrivateAssets="all" ExcludeAssets="runtime" /> + <PackageReference Include="Microsoft.VisualStudio.Imaging" Version="16.0.27828" PrivateAssets="all" ExcludeAssets="runtime" /> + <PackageReference Include="Microsoft.VisualStudio.Text.Data" Version="$(NuGetVersionVSEditor)" PrivateAssets="all" ExcludeAssets="runtime" /> + <PackageReference Include="Microsoft.VisualStudio.Text.Internal" Version="$(NuGetVersionVSEditor)" PrivateAssets="all" ExcludeAssets="runtime" /> + <PackageReference Include="Microsoft.VisualStudio.Text.Logic" Version="$(NuGetVersionVSEditor)" PrivateAssets="all" ExcludeAssets="runtime" /> + <PackageReference Include="Microsoft.VisualStudio.Text.UI" Version="$(NuGetVersionVSEditor)" PrivateAssets="all" ExcludeAssets="runtime" /> + <PackageReference Include="Microsoft.VisualStudio.Language" Version="$(NuGetVersionVSEditor)" PrivateAssets="all" ExcludeAssets="runtime" /> + <PackageReference Include="Microsoft.VisualStudio.Language.Intellisense" Version="$(NuGetVersionVSEditor)" PrivateAssets="all" ExcludeAssets="runtime" /> <ProjectReference Include="..\MonoDevelop.TextEditor\MonoDevelop.TextEditor.csproj" Private="False" /> <ProjectReference Include="..\..\..\..\external\xwt\Xwt\Xwt.csproj" Private="False" /> + <ProjectReference Include="..\..\..\..\external\vs-editor-core\src\Editor\Text\Impl\Find\Find.csproj" /> <Reference Include="PresentationCore" /> <Reference Include="PresentationFramework" /> <Reference Include="WindowsBase" /> @@ -20,5 +29,17 @@ </ItemGroup> <ItemGroup> <IncludeCopyLocal Include="DiagnosticMargin.dll" /> + <IncludeCopyLocal Include="Microsoft.VisualStudio.Text.Find.Implementation.dll" /> + </ItemGroup> + <ItemGroup> + <Page Include="**\*.xaml"> + <SubType>Designer</SubType> + <Generator>MSBuild:Compile</Generator> + </Page> + </ItemGroup> + <ItemGroup> + <Compile Update="Find\FindUI.xaml.cs"> + <DependentUpon>FindUI.xaml</DependentUpon> + </Compile> </ItemGroup> </Project>
\ No newline at end of file diff --git a/main/src/addins/MonoDevelop.TextEditor/MonoDevelop.TextEditor.Wpf/Properties/MonoDevelop.TextEditor.Wpf.addin.xml b/main/src/addins/MonoDevelop.TextEditor/MonoDevelop.TextEditor.Wpf/Properties/MonoDevelop.TextEditor.Wpf.addin.xml index bdbfbbd0f1..c3710fea70 100644 --- a/main/src/addins/MonoDevelop.TextEditor/MonoDevelop.TextEditor.Wpf/Properties/MonoDevelop.TextEditor.Wpf.addin.xml +++ b/main/src/addins/MonoDevelop.TextEditor/MonoDevelop.TextEditor.Wpf/Properties/MonoDevelop.TextEditor.Wpf.addin.xml @@ -1,5 +1,6 @@ <ExtensionModel> <Runtime> + <Import assembly="MonoDevelop.TextEditor.Wpf.dll"/> <Import assembly="../../../bin/Microsoft.VisualStudio.Language.NavigateTo.Interfaces.dll" /> </Runtime> <Extension path="/MonoDevelop/Ide/Composition"> @@ -7,6 +8,7 @@ <Assembly file="../../../bin/Microsoft.VisualStudio.Platform.VSEditor.dll"/> <Assembly file="../../../bin/Microsoft.VisualStudio.Text.UI.Wpf.dll"/> <Assembly file="MonoDevelop.TextEditor.Wpf.dll"/> + <Assembly file="Microsoft.VisualStudio.Text.Find.Implementation.dll"/> <Assembly file="DiagnosticMargin.dll"/> </Extension> <Extension path = "/MonoDevelop/Ide/DisplayBindings"> diff --git a/main/src/addins/MonoDevelop.TextEditor/MonoDevelop.TextEditor.Wpf/WpfTextViewDisplayBinding.cs b/main/src/addins/MonoDevelop.TextEditor/MonoDevelop.TextEditor.Wpf/WpfTextViewDisplayBinding.cs index 954564635f..9a38354172 100644 --- a/main/src/addins/MonoDevelop.TextEditor/MonoDevelop.TextEditor.Wpf/WpfTextViewDisplayBinding.cs +++ b/main/src/addins/MonoDevelop.TextEditor/MonoDevelop.TextEditor.Wpf/WpfTextViewDisplayBinding.cs @@ -19,6 +19,8 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+using System;
+using System.Reflection;
using System.Windows;
using System.Windows.Media;
@@ -29,9 +31,23 @@ using MonoDevelop.Ide.Gui; using MonoDevelop.Projects; namespace MonoDevelop.TextEditor -{ +{
class WpfTextViewDisplayBinding : TextViewDisplayBinding<WpfTextViewImports> - { + {
+ static WpfTextViewDisplayBinding ()
+ {
+ AppDomain.CurrentDomain.AssemblyResolve += OnAssemblyResolve;
+ }
+
+ private static Assembly OnAssemblyResolve (object sender, ResolveEventArgs args)
+ {
+ if (args.Name == "MonoDevelop.TextEditor.Wpf, Version=2.6.0, Culture=neutral") {
+ return typeof (WpfTextViewDisplayBinding).Assembly;
+ }
+
+ return null;
+ }
+
protected override ViewContent CreateContent (WpfTextViewImports imports, FilePath fileName, string mimeType, Project ownerProject) { return new WpfTextViewContent (imports, fileName, mimeType, ownerProject); |