@ -16,6 +16,8 @@
@@ -16,6 +16,8 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System ;
using System.ComponentModel ;
using System.Composition ;
using System.Linq ;
using System.Windows ;
@ -23,9 +25,11 @@ using System.Windows.Controls;
@@ -23,9 +25,11 @@ using System.Windows.Controls;
using System.Windows.Controls.Primitives ;
using System.Windows.Data ;
using System.Windows.Input ;
using System.Windows.Media ;
using System.Windows.Threading ;
using ICSharpCode.ILSpy.Themes ;
using ICSharpCode.ILSpyX.TreeView ;
using TomsToolbox.Composition ;
@ -85,7 +89,8 @@ namespace ICSharpCode.ILSpy.Controls
@@ -85,7 +89,8 @@ namespace ICSharpCode.ILSpy.Controls
}
}
static Button CreateToolbarItem ( IExport < ICommand , IToolbarCommandMetadata > commandExport )
static UIElement CreateToolbarItem ( IExport < ICommand , IToolbarCommandMetadata > commandExport )
{
var command = commandExport . Value ;
@ -108,9 +113,106 @@ namespace ICSharpCode.ILSpy.Controls
@@ -108,9 +113,106 @@ namespace ICSharpCode.ILSpy.Controls
parameterBinding . ParameterBinding ) ;
}
if ( command is IProvideParameterList parameterList )
{
toolbarItem . Margin = new Thickness ( 2 , 0 , 0 , 0 ) ;
var dropDownPanel = new StackPanel { Orientation = Orientation . Horizontal } ;
var dropDownToggle = new ToggleButton {
Style = ThemeManager . Current . CreateToolBarToggleButtonStyle ( ) ,
Content = "▾" ,
Padding = new Thickness ( 0 ) ,
MinWidth = 0 ,
Margin = new Thickness ( 0 , 0 , 2 , 0 )
} ;
var contextMenu = new ContextMenu {
PlacementTarget = dropDownPanel ,
Tag = command
} ;
ContextMenuService . SetPlacement ( toolbarItem , PlacementMode . Bottom ) ;
toolbarItem . ContextMenu = contextMenu ;
toolbarItem . ContextMenuOpening + = ( _ , _ ) = >
PrepareParameterList ( contextMenu ) ;
dropDownToggle . Checked + = ( _ , _ ) = > {
PrepareParameterList ( contextMenu ) ;
contextMenu . Placement = PlacementMode . Bottom ;
contextMenu . SetCurrentValue ( ContextMenu . IsOpenProperty , true ) ;
} ;
BindingOperations . SetBinding ( dropDownToggle , ToggleButton . IsCheckedProperty ,
new Binding ( nameof ( contextMenu . IsOpen ) ) { Source = contextMenu } ) ;
BindingOperations . SetBinding ( dropDownToggle , IsEnabledProperty ,
new Binding ( nameof ( IsEnabled ) ) { Source = toolbarItem } ) ;
// When the toggle button is checked, clicking it to uncheck will dismiss the menu first
// which unchecks the toggle button via binding above and the click is used to open it again.
// This is a workaround to ignore the click to uncheck the already unchecked toggle button.
// We have to ensure the dismissing click is on the toggle button, otherwise the flag
// will not get cleared and menu will not open next time.
Mouse . AddPreviewMouseDownOutsideCapturedElementHandler ( contextMenu , ( _ , e ) = > {
var point = e . GetPosition ( dropDownToggle ) ;
dropDownToggle . Tag = dropDownToggle . InputHitTest ( point ) ;
} ) ;
dropDownToggle . PreviewMouseLeftButtonDown + = ( _ , e ) = > {
e . Handled = dropDownToggle . Tag ! = null ;
dropDownToggle . Tag = null ;
} ;
dropDownPanel . Children . Add ( toolbarItem ) ;
dropDownPanel . Children . Add ( dropDownToggle ) ;
return dropDownPanel ;
}
return toolbarItem ;
}
static void PrepareParameterList ( ContextMenu menu )
{
const int maximumParameterListCount = 2 0 ;
var command = ( ICommand ) menu . Tag ;
var parameterList = ( IProvideParameterList ) command ;
menu . Items . Clear ( ) ;
foreach ( var parameter in parameterList . ParameterList )
{
MenuItem parameterItem = new MenuItem ( ) ;
parameterItem . Command = CommandWrapper . Unwrap ( command ) ;
parameterItem . CommandParameter = parameter ;
parameterItem . CommandTarget = menu . PlacementTarget ;
parameterItem . InputGestureText = " " ;
var headerPresenter = new ContentPresenter { RecognizesAccessKey = false } ;
parameterItem . Header = headerPresenter ;
var header = parameterList . GetParameterText ( parameter ) ;
switch ( header )
{
case SharpTreeNode node :
headerPresenter . Content = node . NavigationText ;
if ( node . Icon is ImageSource icon )
parameterItem . Icon = new Image {
Width = 1 6 ,
Height = 1 6 ,
Source = icon
} ;
break ;
default :
headerPresenter . Content = header ;
break ;
}
menu . Items . Add ( parameterItem ) ;
if ( menu . Items . Count > = maximumParameterListCount )
break ;
}
}
void MainWindow_KeyDown ( object sender , KeyEventArgs e )
{
if ( e . Handled | | e . KeyboardDevice . Modifiers ! = ModifierKeys . Alt | | e . Key ! = Key . System )