| // 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'; |
| |
| /// Flutter code sample for [MenuBar]. |
| |
| void main() => runApp(const MenuBarApp()); |
| |
| /// A class for consolidating the definition of menu entries. |
| /// |
| /// This sort of class is not required, but illustrates one way that defining |
| /// menus could be done. |
| class MenuEntry { |
| const MenuEntry({required this.label, this.shortcut, this.onPressed, this.menuChildren}) |
| : assert(menuChildren == null || onPressed == null, 'onPressed is ignored if menuChildren are provided'); |
| final String label; |
| |
| final MenuSerializableShortcut? shortcut; |
| final VoidCallback? onPressed; |
| final List<MenuEntry>? menuChildren; |
| |
| static List<Widget> build(List<MenuEntry> selections) { |
| Widget buildSelection(MenuEntry selection) { |
| if (selection.menuChildren != null) { |
| return SubmenuButton( |
| menuChildren: MenuEntry.build(selection.menuChildren!), |
| child: Text(selection.label), |
| ); |
| } |
| return MenuItemButton( |
| shortcut: selection.shortcut, |
| onPressed: selection.onPressed, |
| child: Text(selection.label), |
| ); |
| } |
| |
| return selections.map<Widget>(buildSelection).toList(); |
| } |
| |
| static Map<MenuSerializableShortcut, Intent> shortcuts(List<MenuEntry> selections) { |
| final Map<MenuSerializableShortcut, Intent> result = <MenuSerializableShortcut, Intent>{}; |
| for (final MenuEntry selection in selections) { |
| if (selection.menuChildren != null) { |
| result.addAll(MenuEntry.shortcuts(selection.menuChildren!)); |
| } else { |
| if (selection.shortcut != null && selection.onPressed != null) { |
| result[selection.shortcut!] = VoidCallbackIntent(selection.onPressed!); |
| } |
| } |
| } |
| return result; |
| } |
| } |
| |
| class MyMenuBar extends StatefulWidget { |
| const MyMenuBar({ |
| super.key, |
| required this.message, |
| }); |
| |
| final String message; |
| |
| @override |
| State<MyMenuBar> createState() => _MyMenuBarState(); |
| } |
| |
| class _MyMenuBarState extends State<MyMenuBar> { |
| ShortcutRegistryEntry? _shortcutsEntry; |
| String? _lastSelection; |
| |
| Color get backgroundColor => _backgroundColor; |
| Color _backgroundColor = Colors.red; |
| set backgroundColor(Color value) { |
| if (_backgroundColor != value) { |
| setState(() { |
| _backgroundColor = value; |
| }); |
| } |
| } |
| |
| bool get showingMessage => _showMessage; |
| bool _showMessage = false; |
| set showingMessage(bool value) { |
| if (_showMessage != value) { |
| setState(() { |
| _showMessage = value; |
| }); |
| } |
| } |
| |
| @override |
| void dispose() { |
| _shortcutsEntry?.dispose(); |
| super.dispose(); |
| } |
| |
| @override |
| Widget build(BuildContext context) { |
| return Column( |
| children: <Widget>[ |
| Row( |
| mainAxisSize: MainAxisSize.min, |
| children: <Widget>[ |
| Expanded( |
| child: MenuBar( |
| children: MenuEntry.build(_getMenus()), |
| ), |
| ), |
| ], |
| ), |
| Expanded( |
| child: Container( |
| alignment: Alignment.center, |
| color: backgroundColor, |
| child: Column( |
| mainAxisAlignment: MainAxisAlignment.center, |
| children: <Widget>[ |
| Padding( |
| padding: const EdgeInsets.all(12.0), |
| child: Text( |
| showingMessage ? widget.message : '', |
| style: Theme.of(context).textTheme.headlineSmall, |
| ), |
| ), |
| Text(_lastSelection != null ? 'Last Selected: $_lastSelection' : ''), |
| ], |
| ), |
| ), |
| ), |
| ], |
| ); |
| } |
| |
| List<MenuEntry> _getMenus() { |
| final List<MenuEntry> result = <MenuEntry>[ |
| MenuEntry( |
| label: 'Menu Demo', |
| menuChildren: <MenuEntry>[ |
| MenuEntry( |
| label: 'About', |
| onPressed: () { |
| showAboutDialog( |
| context: context, |
| applicationName: 'MenuBar Sample', |
| applicationVersion: '1.0.0', |
| ); |
| setState(() { |
| _lastSelection = 'About'; |
| }); |
| }, |
| ), |
| MenuEntry( |
| label: showingMessage ? 'Hide Message' : 'Show Message', |
| onPressed: () { |
| setState(() { |
| _lastSelection = showingMessage ? 'Hide Message' : 'Show Message'; |
| showingMessage = !showingMessage; |
| }); |
| }, |
| shortcut: const SingleActivator(LogicalKeyboardKey.keyS, control: true), |
| ), |
| // Hides the message, but is only enabled if the message isn't |
| // already hidden. |
| MenuEntry( |
| label: 'Reset Message', |
| onPressed: showingMessage |
| ? () { |
| setState(() { |
| _lastSelection = 'Reset Message'; |
| showingMessage = false; |
| }); |
| } |
| : null, |
| shortcut: const SingleActivator(LogicalKeyboardKey.escape), |
| ), |
| MenuEntry( |
| label: 'Background Color', |
| menuChildren: <MenuEntry>[ |
| MenuEntry( |
| label: 'Red Background', |
| onPressed: () { |
| setState(() { |
| _lastSelection = 'Red Background'; |
| backgroundColor = Colors.red; |
| }); |
| }, |
| shortcut: const SingleActivator(LogicalKeyboardKey.keyR, control: true), |
| ), |
| MenuEntry( |
| label: 'Green Background', |
| onPressed: () { |
| setState(() { |
| _lastSelection = 'Green Background'; |
| backgroundColor = Colors.green; |
| }); |
| }, |
| shortcut: const SingleActivator(LogicalKeyboardKey.keyG, control: true), |
| ), |
| MenuEntry( |
| label: 'Blue Background', |
| onPressed: () { |
| setState(() { |
| _lastSelection = 'Blue Background'; |
| backgroundColor = Colors.blue; |
| }); |
| }, |
| shortcut: const SingleActivator(LogicalKeyboardKey.keyB, control: true), |
| ), |
| ], |
| ), |
| ], |
| ), |
| ]; |
| // (Re-)register the shortcuts with the ShortcutRegistry so that they are |
| // available to the entire application, and update them if they've changed. |
| _shortcutsEntry?.dispose(); |
| _shortcutsEntry = ShortcutRegistry.of(context).addAll(MenuEntry.shortcuts(result)); |
| return result; |
| } |
| } |
| |
| class MenuBarApp extends StatelessWidget { |
| const MenuBarApp({super.key}); |
| |
| static const String kMessage = '"Talk less. Smile more." - A. Burr'; |
| |
| @override |
| Widget build(BuildContext context) { |
| return const MaterialApp( |
| home: Scaffold(body: SafeArea(child: MyMenuBar(message: kMessage))), |
| ); |
| } |
| } |