| // Copyright 2014 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import 'package:flutter/material.dart'; |
| import 'package:flutter/services.dart'; |
| |
| void main() { |
| runApp( |
| const MaterialApp( |
| title: 'Menu Tester', |
| home: Material( |
| child: Home(), |
| ), |
| ), |
| ); |
| } |
| |
| class Home extends StatefulWidget { |
| const Home({super.key}); |
| |
| @override |
| State<Home> createState() => _HomeState(); |
| } |
| |
| class _HomeState extends State<Home> { |
| final MenuController _controller = MenuController(); |
| VisualDensity _density = VisualDensity.standard; |
| TextDirection _textDirection = TextDirection.ltr; |
| double _extraPadding = 0; |
| bool _addItem = false; |
| bool _accelerators = true; |
| bool _transparent = false; |
| bool _funkyTheme = false; |
| |
| @override |
| Widget build(BuildContext context) { |
| final ThemeData theme = Theme.of(context); |
| MenuThemeData menuTheme = MenuTheme.of(context); |
| MenuBarThemeData menuBarTheme = MenuBarTheme.of(context); |
| MenuButtonThemeData menuButtonTheme = MenuButtonTheme.of(context); |
| if (_funkyTheme) { |
| menuTheme = const MenuThemeData( |
| style: MenuStyle( |
| shape: MaterialStatePropertyAll<OutlinedBorder>( |
| RoundedRectangleBorder( |
| borderRadius: BorderRadius.all( |
| Radius.circular(10), |
| ), |
| ), |
| ), |
| backgroundColor: MaterialStatePropertyAll<Color?>(Colors.blue), |
| elevation: MaterialStatePropertyAll<double?>(10), |
| padding: MaterialStatePropertyAll<EdgeInsetsDirectional>( |
| EdgeInsetsDirectional.all(20), |
| ), |
| ), |
| ); |
| menuButtonTheme = const MenuButtonThemeData( |
| style: ButtonStyle( |
| shape: MaterialStatePropertyAll<OutlinedBorder>(StadiumBorder()), |
| backgroundColor: MaterialStatePropertyAll<Color?>(Colors.green), |
| foregroundColor: MaterialStatePropertyAll<Color?>(Colors.white), |
| ), |
| ); |
| menuBarTheme = const MenuBarThemeData( |
| style: MenuStyle( |
| shape: MaterialStatePropertyAll<OutlinedBorder>(RoundedRectangleBorder()), |
| backgroundColor: MaterialStatePropertyAll<Color?>(Colors.blue), |
| elevation: MaterialStatePropertyAll<double?>(10), |
| padding: MaterialStatePropertyAll<EdgeInsetsDirectional>( |
| EdgeInsetsDirectional.all(20), |
| ), |
| ), |
| ); |
| } |
| return SafeArea( |
| child: Padding( |
| padding: EdgeInsets.all(_extraPadding), |
| child: Directionality( |
| textDirection: _textDirection, |
| child: Theme( |
| data: theme.copyWith( |
| visualDensity: _density, |
| menuTheme: _transparent |
| ? MenuThemeData( |
| style: MenuStyle( |
| backgroundColor: MaterialStatePropertyAll<Color>( |
| Colors.blue.withOpacity(0.12), |
| ), |
| elevation: const MaterialStatePropertyAll<double>(0), |
| ), |
| ) |
| : menuTheme, |
| menuBarTheme: menuBarTheme, |
| menuButtonTheme: menuButtonTheme, |
| ), |
| child: Column( |
| crossAxisAlignment: CrossAxisAlignment.start, |
| children: <Widget>[ |
| _TestMenus( |
| menuController: _controller, |
| accelerators: _accelerators, |
| addItem: _addItem, |
| ), |
| Expanded( |
| child: SingleChildScrollView( |
| child: _Controls( |
| menuController: _controller, |
| density: _density, |
| addItem: _addItem, |
| accelerators: _accelerators, |
| transparent: _transparent, |
| funkyTheme: _funkyTheme, |
| extraPadding: _extraPadding, |
| textDirection: _textDirection, |
| onDensityChanged: (VisualDensity value) { |
| setState(() { |
| _density = value; |
| }); |
| }, |
| onTextDirectionChanged: (TextDirection value) { |
| setState(() { |
| _textDirection = value; |
| }); |
| }, |
| onExtraPaddingChanged: (double value) { |
| setState(() { |
| _extraPadding = value; |
| }); |
| }, |
| onAddItemChanged: (bool value) { |
| setState(() { |
| _addItem = value; |
| }); |
| }, |
| onAcceleratorsChanged: (bool value) { |
| setState(() { |
| _accelerators = value; |
| }); |
| }, |
| onTransparentChanged: (bool value) { |
| setState(() { |
| _transparent = value; |
| }); |
| }, |
| onFunkyThemeChanged: (bool value) { |
| setState(() { |
| _funkyTheme = value; |
| }); |
| }, |
| ), |
| ), |
| ), |
| ], |
| ), |
| ), |
| ), |
| ), |
| ); |
| } |
| } |
| |
| class _Controls extends StatefulWidget { |
| const _Controls({ |
| required this.density, |
| required this.textDirection, |
| required this.extraPadding, |
| this.addItem = false, |
| this.accelerators = true, |
| this.transparent = false, |
| this.funkyTheme = false, |
| required this.onDensityChanged, |
| required this.onTextDirectionChanged, |
| required this.onExtraPaddingChanged, |
| required this.onAddItemChanged, |
| required this.onAcceleratorsChanged, |
| required this.onTransparentChanged, |
| required this.onFunkyThemeChanged, |
| required this.menuController, |
| }); |
| |
| final VisualDensity density; |
| final TextDirection textDirection; |
| final double extraPadding; |
| final bool addItem; |
| final bool accelerators; |
| final bool transparent; |
| final bool funkyTheme; |
| final ValueChanged<VisualDensity> onDensityChanged; |
| final ValueChanged<TextDirection> onTextDirectionChanged; |
| final ValueChanged<double> onExtraPaddingChanged; |
| final ValueChanged<bool> onAddItemChanged; |
| final ValueChanged<bool> onAcceleratorsChanged; |
| final ValueChanged<bool> onTransparentChanged; |
| final ValueChanged<bool> onFunkyThemeChanged; |
| final MenuController menuController; |
| |
| @override |
| State<_Controls> createState() => _ControlsState(); |
| } |
| |
| class _ControlsState extends State<_Controls> { |
| final FocusNode _focusNode = FocusNode(debugLabel: 'Floating'); |
| |
| @override |
| void dispose() { |
| _focusNode.dispose(); |
| super.dispose(); |
| } |
| |
| @override |
| Widget build(BuildContext context) { |
| return Center( |
| child: SingleChildScrollView( |
| child: Column( |
| children: <Widget>[ |
| MenuAnchor( |
| childFocusNode: _focusNode, |
| style: const MenuStyle(alignment: AlignmentDirectional.topEnd), |
| alignmentOffset: const Offset(100, -8), |
| menuChildren: <Widget>[ |
| MenuItemButton( |
| shortcut: TestMenu.standaloneMenu1.shortcut, |
| onPressed: () { |
| _itemSelected(TestMenu.standaloneMenu1); |
| }, |
| child: MenuAcceleratorLabel(TestMenu.standaloneMenu1.label), |
| ), |
| MenuItemButton( |
| leadingIcon: const Icon(Icons.send), |
| trailingIcon: const Icon(Icons.mail), |
| onPressed: () { |
| _itemSelected(TestMenu.standaloneMenu2); |
| }, |
| child: MenuAcceleratorLabel(TestMenu.standaloneMenu2.label), |
| ), |
| ], |
| builder: (BuildContext context, MenuController controller, Widget? child) { |
| return TextButton( |
| focusNode: _focusNode, |
| onPressed: () { |
| if (controller.isOpen) { |
| controller.close(); |
| } else { |
| controller.open(); |
| } |
| }, |
| child: child!, |
| ); |
| }, |
| child: const MenuAcceleratorLabel('Open Menu'), |
| ), |
| ConstrainedBox( |
| constraints: const BoxConstraints(maxWidth: 400), |
| child: Column( |
| crossAxisAlignment: CrossAxisAlignment.stretch, |
| children: <Widget>[ |
| _ControlSlider( |
| label: 'Extra Padding: ${widget.extraPadding.toStringAsFixed(1)}', |
| value: widget.extraPadding, |
| max: 40, |
| divisions: 20, |
| onChanged: (double value) { |
| widget.onExtraPaddingChanged(value); |
| }, |
| ), |
| _ControlSlider( |
| label: 'Horizontal Density: ${widget.density.horizontal.toStringAsFixed(1)}', |
| value: widget.density.horizontal, |
| max: 4, |
| min: -4, |
| divisions: 12, |
| onChanged: (double value) { |
| widget.onDensityChanged( |
| VisualDensity( |
| horizontal: value, |
| vertical: widget.density.vertical, |
| ), |
| ); |
| }, |
| ), |
| _ControlSlider( |
| label: 'Vertical Density: ${widget.density.vertical.toStringAsFixed(1)}', |
| value: widget.density.vertical, |
| max: 4, |
| min: -4, |
| divisions: 12, |
| onChanged: (double value) { |
| widget.onDensityChanged( |
| VisualDensity( |
| horizontal: widget.density.horizontal, |
| vertical: value, |
| ), |
| ); |
| }, |
| ), |
| ], |
| ), |
| ), |
| Column( |
| crossAxisAlignment: CrossAxisAlignment.start, |
| children: <Widget>[ |
| Row( |
| mainAxisSize: MainAxisSize.min, |
| children: <Widget>[ |
| Checkbox( |
| value: widget.textDirection == TextDirection.rtl, |
| onChanged: (bool? value) { |
| if (value ?? false) { |
| widget.onTextDirectionChanged(TextDirection.rtl); |
| } else { |
| widget.onTextDirectionChanged(TextDirection.ltr); |
| } |
| }, |
| ), |
| const Text('RTL Text') |
| ], |
| ), |
| Row( |
| mainAxisSize: MainAxisSize.min, |
| children: <Widget>[ |
| Checkbox( |
| value: widget.addItem, |
| onChanged: (bool? value) { |
| if (value ?? false) { |
| widget.onAddItemChanged(true); |
| } else { |
| widget.onAddItemChanged(false); |
| } |
| }, |
| ), |
| const Text('Add Item') |
| ], |
| ), |
| Row( |
| mainAxisSize: MainAxisSize.min, |
| children: <Widget>[ |
| Checkbox( |
| value: widget.accelerators, |
| onChanged: (bool? value) { |
| if (value ?? false) { |
| widget.onAcceleratorsChanged(true); |
| } else { |
| widget.onAcceleratorsChanged(false); |
| } |
| }, |
| ), |
| const Text('Enable Accelerators') |
| ], |
| ), |
| Row( |
| mainAxisSize: MainAxisSize.min, |
| children: <Widget>[ |
| Checkbox( |
| value: widget.transparent, |
| onChanged: (bool? value) { |
| if (value ?? false) { |
| widget.onTransparentChanged(true); |
| } else { |
| widget.onTransparentChanged(false); |
| } |
| }, |
| ), |
| const Text('Transparent') |
| ], |
| ), |
| Row( |
| mainAxisSize: MainAxisSize.min, |
| children: <Widget>[ |
| Checkbox( |
| value: widget.funkyTheme, |
| onChanged: (bool? value) { |
| if (value ?? false) { |
| widget.onFunkyThemeChanged(true); |
| } else { |
| widget.onFunkyThemeChanged(false); |
| } |
| }, |
| ), |
| const Text('Funky Theme') |
| ], |
| ), |
| ], |
| ), |
| ], |
| ), |
| ), |
| ); |
| } |
| |
| void _itemSelected(TestMenu item) { |
| debugPrint('App: Selected item ${item.label}'); |
| } |
| } |
| |
| class _ControlSlider extends StatelessWidget { |
| const _ControlSlider({ |
| required this.label, |
| required this.value, |
| required this.onChanged, |
| this.min = 0, |
| this.max = 1, |
| this.divisions, |
| }); |
| |
| final String label; |
| final double value; |
| final ValueChanged<double> onChanged; |
| final double min; |
| final double max; |
| final int? divisions; |
| |
| @override |
| Widget build(BuildContext context) { |
| return Row( |
| mainAxisAlignment: MainAxisAlignment.end, |
| children: <Widget>[ |
| Container( |
| alignment: AlignmentDirectional.centerEnd, |
| constraints: const BoxConstraints(minWidth: 150), |
| child: Text(label), |
| ), |
| Expanded( |
| child: Slider( |
| value: value, |
| min: min, |
| max: max, |
| divisions: divisions, |
| onChanged: onChanged, |
| ), |
| ), |
| ], |
| ); |
| } |
| } |
| |
| class _TestMenus extends StatefulWidget { |
| const _TestMenus({ |
| required this.menuController, |
| this.addItem = false, |
| this.accelerators = false, |
| }); |
| |
| final MenuController menuController; |
| final bool addItem; |
| final bool accelerators; |
| |
| @override |
| State<_TestMenus> createState() => _TestMenusState(); |
| } |
| |
| class _TestMenusState extends State<_TestMenus> { |
| final TextEditingController textController = TextEditingController(); |
| bool? checkboxState = false; |
| TestMenu? radioValue; |
| ShortcutRegistryEntry? _shortcutsEntry; |
| |
| void _itemSelected(TestMenu item) { |
| debugPrint('App: Selected item ${item.label}'); |
| } |
| |
| void _openItem(TestMenu item) { |
| debugPrint('App: Opened item ${item.label}'); |
| } |
| |
| void _closeItem(TestMenu item) { |
| debugPrint('App: Closed item ${item.label}'); |
| } |
| |
| void _setRadio(TestMenu? item) { |
| debugPrint('App: Set Radio item ${item?.label}'); |
| setState(() { |
| radioValue = item; |
| }); |
| } |
| |
| void _setCheck(TestMenu item) { |
| debugPrint('App: Set Checkbox item ${item.label}'); |
| setState(() { |
| switch (checkboxState) { |
| case false: |
| checkboxState = true; |
| break; |
| case true: |
| checkboxState = null; |
| break; |
| case null: |
| checkboxState = false; |
| break; |
| } |
| }); |
| } |
| |
| @override |
| void didChangeDependencies() { |
| super.didChangeDependencies(); |
| _shortcutsEntry?.dispose(); |
| final Map<ShortcutActivator, Intent> shortcuts = <ShortcutActivator, Intent>{}; |
| for (final TestMenu item in TestMenu.values) { |
| if (item.shortcut == null) { |
| continue; |
| } |
| switch (item) { |
| case TestMenu.radioMenu1: |
| case TestMenu.radioMenu2: |
| case TestMenu.radioMenu3: |
| shortcuts[item.shortcut!] = VoidCallbackIntent(() => _setRadio(item)); |
| break; |
| case TestMenu.subMenu1: |
| shortcuts[item.shortcut!] = VoidCallbackIntent(() => _setCheck(item)); |
| break; |
| case TestMenu.mainMenu1: |
| case TestMenu.mainMenu2: |
| case TestMenu.mainMenu3: |
| case TestMenu.mainMenu4: |
| case TestMenu.subMenu2: |
| case TestMenu.subMenu3: |
| case TestMenu.subMenu4: |
| case TestMenu.subMenu5: |
| case TestMenu.subMenu6: |
| case TestMenu.subMenu7: |
| case TestMenu.subMenu8: |
| case TestMenu.subSubMenu1: |
| case TestMenu.subSubMenu2: |
| case TestMenu.subSubMenu3: |
| case TestMenu.subSubSubMenu1: |
| case TestMenu.testButton: |
| case TestMenu.standaloneMenu1: |
| case TestMenu.standaloneMenu2: |
| shortcuts[item.shortcut!] = VoidCallbackIntent(() => _itemSelected(item)); |
| break; |
| } |
| } |
| _shortcutsEntry = ShortcutRegistry.of(context).addAll(shortcuts); |
| } |
| |
| @override |
| void dispose() { |
| _shortcutsEntry?.dispose(); |
| super.dispose(); |
| } |
| |
| @override |
| Widget build(BuildContext context) { |
| return Row( |
| children: <Widget>[ |
| Expanded( |
| child: MenuBar( |
| controller: widget.menuController, |
| children: createTestMenus( |
| onPressed: _itemSelected, |
| onOpen: _openItem, |
| onClose: _closeItem, |
| onCheckboxChanged: (TestMenu menu, bool? value) { |
| _setCheck(menu); |
| }, |
| onRadioChanged: _setRadio, |
| checkboxValue: checkboxState, |
| radioValue: radioValue, |
| menuController: widget.menuController, |
| textEditingController: textController, |
| includeExtraGroups: widget.addItem, |
| accelerators: widget.accelerators, |
| ), |
| ), |
| ), |
| ], |
| ); |
| } |
| } |
| |
| List<Widget> createTestMenus({ |
| void Function(TestMenu)? onPressed, |
| void Function(TestMenu, bool?)? onCheckboxChanged, |
| void Function(TestMenu?)? onRadioChanged, |
| void Function(TestMenu)? onOpen, |
| void Function(TestMenu)? onClose, |
| Map<TestMenu, MenuSerializableShortcut> shortcuts = const <TestMenu, MenuSerializableShortcut>{}, |
| bool? checkboxValue, |
| TestMenu? radioValue, |
| MenuController? menuController, |
| TextEditingController? textEditingController, |
| bool includeExtraGroups = false, |
| bool accelerators = false, |
| }) { |
| Widget submenuButton( |
| TestMenu menu, { |
| required List<Widget> menuChildren, |
| }) { |
| return SubmenuButton( |
| onOpen: onOpen != null ? () => onOpen(menu) : null, |
| onClose: onClose != null ? () => onClose(menu) : null, |
| menuChildren: menuChildren, |
| child: accelerators ? MenuAcceleratorLabel(menu.acceleratorLabel) : Text(menu.label), |
| ); |
| } |
| |
| Widget menuItemButton( |
| TestMenu menu, { |
| bool enabled = true, |
| Widget? leadingIcon, |
| Widget? trailingIcon, |
| Key? key, |
| }) { |
| return MenuItemButton( |
| key: key, |
| onPressed: enabled && onPressed != null ? () => onPressed(menu) : null, |
| shortcut: shortcuts[menu], |
| leadingIcon: leadingIcon, |
| trailingIcon: trailingIcon, |
| child: accelerators ? MenuAcceleratorLabel(menu.acceleratorLabel) : Text(menu.label), |
| ); |
| } |
| |
| Widget checkboxMenuButton( |
| TestMenu menu, { |
| bool enabled = true, |
| bool tristate = false, |
| Widget? leadingIcon, |
| Widget? trailingIcon, |
| Key? key, |
| }) { |
| return CheckboxMenuButton( |
| key: key, |
| value: checkboxValue, |
| tristate: tristate, |
| onChanged: enabled && onCheckboxChanged != null ? (bool? value) => onCheckboxChanged(menu, value) : null, |
| shortcut: menu.shortcut, |
| trailingIcon: trailingIcon, |
| child: accelerators ? MenuAcceleratorLabel(menu.acceleratorLabel) : Text(menu.label), |
| ); |
| } |
| |
| Widget radioMenuButton( |
| TestMenu menu, { |
| bool enabled = true, |
| bool toggleable = false, |
| Widget? leadingIcon, |
| Widget? trailingIcon, |
| Key? key, |
| }) { |
| return RadioMenuButton<TestMenu>( |
| key: key, |
| groupValue: radioValue, |
| value: menu, |
| toggleable: toggleable, |
| onChanged: enabled && onRadioChanged != null ? onRadioChanged : null, |
| shortcut: menu.shortcut, |
| trailingIcon: trailingIcon, |
| child: accelerators ? MenuAcceleratorLabel(menu.acceleratorLabel) : Text(menu.label), |
| ); |
| } |
| |
| final List<Widget> result = <Widget>[ |
| submenuButton( |
| TestMenu.mainMenu1, |
| menuChildren: <Widget>[ |
| checkboxMenuButton( |
| TestMenu.subMenu1, |
| tristate: true, |
| trailingIcon: const Icon(Icons.assessment), |
| ), |
| radioMenuButton( |
| TestMenu.radioMenu1, |
| toggleable: true, |
| trailingIcon: const Icon(Icons.assessment), |
| ), |
| radioMenuButton( |
| TestMenu.radioMenu2, |
| toggleable: true, |
| trailingIcon: const Icon(Icons.assessment), |
| ), |
| radioMenuButton( |
| TestMenu.radioMenu3, |
| toggleable: true, |
| trailingIcon: const Icon(Icons.assessment), |
| ), |
| menuItemButton( |
| TestMenu.subMenu2, |
| leadingIcon: const Icon(Icons.send), |
| trailingIcon: const Icon(Icons.mail), |
| ), |
| ], |
| ), |
| submenuButton( |
| TestMenu.mainMenu2, |
| menuChildren: <Widget>[ |
| MenuAcceleratorCallbackBinding( |
| onInvoke: onPressed != null |
| ? () { |
| onPressed.call(TestMenu.testButton); |
| menuController?.close(); |
| } |
| : null, |
| child: TextButton( |
| onPressed: onPressed != null |
| ? () { |
| onPressed.call(TestMenu.testButton); |
| menuController?.close(); |
| } |
| : null, |
| child: accelerators |
| ? MenuAcceleratorLabel(TestMenu.testButton.acceleratorLabel) |
| : Text(TestMenu.testButton.label), |
| ), |
| ), |
| menuItemButton(TestMenu.subMenu3), |
| ], |
| ), |
| submenuButton( |
| TestMenu.mainMenu3, |
| menuChildren: <Widget>[ |
| menuItemButton(TestMenu.subMenu8), |
| ], |
| ), |
| submenuButton( |
| TestMenu.mainMenu4, |
| menuChildren: <Widget>[ |
| MenuItemButton( |
| onPressed: () { |
| debugPrint('Activated text input item with ${textEditingController?.text} as a value.'); |
| }, |
| child: SizedBox( |
| width: 200, |
| child: TextField( |
| controller: textEditingController, |
| onSubmitted: (String value) { |
| debugPrint('String $value submitted.'); |
| }, |
| ), |
| ), |
| ), |
| submenuButton( |
| TestMenu.subMenu5, |
| menuChildren: <Widget>[ |
| menuItemButton(TestMenu.subSubMenu1), |
| menuItemButton(TestMenu.subSubMenu2), |
| if (includeExtraGroups) |
| submenuButton( |
| TestMenu.subSubMenu3, |
| menuChildren: <Widget>[ |
| menuItemButton(TestMenu.subSubSubMenu1), |
| ], |
| ), |
| ], |
| ), |
| menuItemButton(TestMenu.subMenu6, enabled: false), |
| menuItemButton(TestMenu.subMenu7), |
| menuItemButton(TestMenu.subMenu7), |
| menuItemButton(TestMenu.subMenu8), |
| ], |
| ), |
| ]; |
| return result; |
| } |
| |
| enum TestMenu { |
| mainMenu1('Menu 1'), |
| mainMenu2('M&enu &2'), |
| mainMenu3('Me&nu &3'), |
| mainMenu4('Men&u &4'), |
| radioMenu1('Radio Menu One', SingleActivator(LogicalKeyboardKey.digit1, control: true)), |
| radioMenu2('Radio Menu Two', SingleActivator(LogicalKeyboardKey.digit2, control: true)), |
| radioMenu3('Radio Menu Three', SingleActivator(LogicalKeyboardKey.digit3, control: true)), |
| subMenu1('Sub Menu &1', SingleActivator(LogicalKeyboardKey.keyB, control: true)), |
| subMenu2('Sub Menu &2'), |
| subMenu3('Sub Menu &3', SingleActivator(LogicalKeyboardKey.enter, control: true)), |
| subMenu4('Sub Menu &4'), |
| subMenu5('Sub Menu &5'), |
| subMenu6('Sub Menu &6', SingleActivator(LogicalKeyboardKey.tab, control: true)), |
| subMenu7('Sub Menu &7'), |
| subMenu8('Sub Menu &8'), |
| subSubMenu1('Sub Sub Menu &1', SingleActivator(LogicalKeyboardKey.f10, control: true)), |
| subSubMenu2('Sub Sub Menu &2'), |
| subSubMenu3('Sub Sub Menu &3'), |
| subSubSubMenu1('Sub Sub Sub Menu &1', SingleActivator(LogicalKeyboardKey.f11, control: true)), |
| testButton('&TEST && &&& Button &'), |
| standaloneMenu1('Standalone Menu &1', SingleActivator(LogicalKeyboardKey.keyC, control: true)), |
| standaloneMenu2('Standalone Menu &2'); |
| |
| const TestMenu(this.acceleratorLabel, [this.shortcut]); |
| final MenuSerializableShortcut? shortcut; |
| final String acceleratorLabel; |
| // Strip the accelerator markers. |
| String get label => MenuAcceleratorLabel.stripAcceleratorMarkers(acceleratorLabel); |
| int get acceleratorIndex { |
| int index = -1; |
| MenuAcceleratorLabel.stripAcceleratorMarkers(acceleratorLabel, setIndex: (int i) => index = i); |
| return index; |
| } |
| } |