diff --git a/Documentation/Reference/README.md b/Documentation/Reference/README.md index ed8b37e..3bf0af7 100644 --- a/Documentation/Reference/README.md +++ b/Documentation/Reference/README.md @@ -11,6 +11,7 @@ ## Structs +- [ApplicationWindow](structs/ApplicationWindow.md) - [Binding](structs/Binding.md) - [Button](structs/Button.md) - [Clamp](structs/Clamp.md) @@ -58,6 +59,7 @@ ## Typealiases - [Body](typealiases/Body.md) +- [GTUIApplicationWindow](typealiases/GTUIApplicationWindow.md) - [GTUIWindow](typealiases/GTUIWindow.md) - [Scene](typealiases/Scene.md) - [SceneBuilder](typealiases/SceneBuilder.md) diff --git a/Documentation/Reference/extensions/WindowScene.md b/Documentation/Reference/extensions/WindowScene.md index eb8d999..89264b5 100644 --- a/Documentation/Reference/extensions/WindowScene.md +++ b/Documentation/Reference/extensions/WindowScene.md @@ -6,3 +6,22 @@ ### `scene` The window scene's body is itself. + +## Methods +### `appKeyboardShortcut(_:action:)` + +Add a keyboard shortcut that is available for the whole app. +- Parameters: + - shortcut: The keyboard shortcut. + - The closure to execute. + +### `updateAppShortcuts(app:)` + +Update the app shortcuts. + +Call this function in types of window scene. + +### `quitShortcut()` + +Add the shortcut "q" which terminates the application. +- Returns: The app. diff --git a/Documentation/Reference/extensions/WindowSceneGroup.md b/Documentation/Reference/extensions/WindowSceneGroup.md index 9a13c53..11d2098 100644 --- a/Documentation/Reference/extensions/WindowSceneGroup.md +++ b/Documentation/Reference/extensions/WindowSceneGroup.md @@ -8,7 +8,9 @@ Get the windows described by the group. - Returns: The windows. -### `update(_:)` +### `update(_:app:)` Update the windows described by the group. -- Parameter storage: The window's storage. +- Parameters: + - storage: The window's storage. + - app: The application. diff --git a/Documentation/Reference/protocols/WindowScene.md b/Documentation/Reference/protocols/WindowScene.md index d320f1e..4ecddbc 100644 --- a/Documentation/Reference/protocols/WindowScene.md +++ b/Documentation/Reference/protocols/WindowScene.md @@ -13,6 +13,10 @@ The window type's identifier. The number of instances of the window at the startup. +### `appShortcuts` + +The keyboard shortcuts on the application's level. + ## Methods ### `createWindow(app:)` @@ -20,7 +24,9 @@ Get the storage for the window. - Parameter app: The application. - Returns: The storage. -### `update(_:)` +### `update(_:app:)` Update a window storage's content. -- Parameter storage: The storage to update. +- Parameters: + - storage: The storage to update. + - app: The application. diff --git a/Documentation/Reference/structs/ApplicationWindow.md b/Documentation/Reference/structs/ApplicationWindow.md new file mode 100644 index 0000000..a086a32 --- /dev/null +++ b/Documentation/Reference/structs/ApplicationWindow.md @@ -0,0 +1,78 @@ +**STRUCT** + +# `ApplicationWindow` + +A structure representing an application window type. + +Note that multiple instances of a window can be opened at the same time. + +## Properties +### `id` + +The window's identifier. + +### `content` + +The window's content. + +### `open` + +Whether an instance of the window type should be opened when the app is starting up. + +### `shortcuts` + +The keyboard shortcuts. + +### `appShortcuts` + +The keyboard shortcuts on the app level. + +## Methods +### `init(id:open:content:)` + +Create a window type with a certain identifier and user interface. +- Parameters: + - id: The identifier. + - open: The number of instances of the window type when the app is starting. + - content: The window's content. + +### `createWindow(app:)` + +Get the storage for the window. +- Parameter app: The application. +- Returns: The storage. + +### `createGTUIWindow(app:)` + +Get the window. +- Parameter app: The application. +- Returns: The window. + +### `getViewStorage(window:)` + +Get the storage of the content view. +- Parameter window: The window. +- Returns: The storage of the content of the window. + +### `update(_:app:)` + +Update a window storage's content. +- Parameter storage: The storage to update. + +### `keyboardShortcut(_:action:)` + +Add a keyboard shortcut. +- Parameters: + - shortcut: The keyboard shortcut. + - action: The closure to execute when the keyboard shortcut is pressed. +- Returns: The window. + +### `updateShortcuts(window:)` + +Update the keyboard shortcuts. +- Parameter window: The application window. + +### `closeShortcut()` + +Add the shortcut "w" which closes the window. +- Returns: The window. diff --git a/Documentation/Reference/structs/Button.md b/Documentation/Reference/structs/Button.md index ebe0a23..61dd5c7 100644 --- a/Documentation/Reference/structs/Button.md +++ b/Documentation/Reference/structs/Button.md @@ -42,3 +42,23 @@ Update a button's view storage. Get a button's view storage. - Returns: The button's view storage. + +### `keyboardShortcut(_:window:)` + +Create a keyboard shortcut for an application window from a button. + +Note that the keyboard shortcut is available after the view has been visible for the first time. +- Parameters: + - shortcut: The keyboard shortcut. + - window: The application window. +- Returns: The button. + +### `keyboardShortcut(_:app:)` + +Create a keyboard shortcut for an application from a button. + +Note that the keyboard shortcut is available after the view has been visible for the first time. +- Parameters: + - shortcut: The keyboard shortcut. + - window: The application. +- Returns: The button. diff --git a/Documentation/Reference/structs/Window.md b/Documentation/Reference/structs/Window.md index 0f942b8..8003790 100644 --- a/Documentation/Reference/structs/Window.md +++ b/Documentation/Reference/structs/Window.md @@ -19,6 +19,10 @@ The window's content. Whether an instance of the window type should be opened when the app is starting up. +### `appShortcuts` + +The keyboard shortcuts on the app level. + ## Methods ### `init(id:open:content:)` @@ -46,7 +50,9 @@ Get the storage of the content view. - Parameter window: The window. - Returns: The storage of the content of the window. -### `update(_:)` +### `update(_:app:)` Update a window storage's content. -- Parameter storage: The storage to update. +- Parameters: + - storage: The storage to update. + - app: The application. diff --git a/Documentation/Reference/typealiases/GTUIApplicationWindow.md b/Documentation/Reference/typealiases/GTUIApplicationWindow.md new file mode 100644 index 0000000..19c4f00 --- /dev/null +++ b/Documentation/Reference/typealiases/GTUIApplicationWindow.md @@ -0,0 +1,5 @@ +**TYPEALIAS** + +# `GTUIApplicationWindow` + +A GTUI application window. \ No newline at end of file diff --git a/README.md b/README.md index 3c75fb1..f68b89a 100644 --- a/README.md +++ b/README.md @@ -85,23 +85,56 @@ If you want to use _Adwaita_ in a project, but there are widgets missing, open a ### View Modifiers -| Syntax | Description | -| ---------------------------- | -------------------------------------------------------------------------------------- | +| Syntax | Description | +| ---------------------------- | --------------------------------------------------------------------------------------- | | `inspect(_:)` | Edit the underlying [GTUI][10] widget. | -| `padding(_:_:)` | Add empty space around a view. | -| `hexpand(_:)` | Enable or disable the horizontal expansion of a view. | -| `vexpand(_:)` | Enable or disable the vertical expansion of a view. | -| `halign(_:)` | Set the horizontal alignment of a view. | -| `valign(_:)` | Set the vertical alignment of a view. | -| `frame(minWidth:minHeight:)` | Set the view’s minimal width or height. | -| `frame(maxSize:)` | Set the view’s maximal size. | -| `transition(_:)` | Assign a transition with the view that is used if it is a direct child of an EitherView. | -| `onUpdate(_:)` | Run a function every time a view gets updated. | -| `navigationTitle(_:)` | Add a title that is used if the view is a direct child of a NavigationView. | -| `style(_:)` | Add a style class to the view. | -| `onAppear(_:)` | Run when the view is rendered for the first time. | -| `topToolbar(visible:_:)` | Add a native toolbar to the view. Normally, it contains a HeaderBar. | -| `bottomToolbar(visible:_:)` | Add a native bottom toolbar to the view. | +| `padding(_:_:)` | Add empty space around a view. | +| `hexpand(_:)` | Enable or disable the horizontal expansion of a view. | +| `vexpand(_:)` | Enable or disable the vertical expansion of a view. | +| `halign(_:)` | Set the horizontal alignment of a view. | +| `valign(_:)` | Set the vertical alignment of a view. | +| `frame(minWidth:minHeight:)` | Set the view’s minimal width or height. | +| `frame(maxSize:)` | Set the view’s maximal size. | +| `transition(_:)` | Assign a transition with the view that is used if it is a direct child of an EitherView.| +| `onUpdate(_:)` | Run a function every time a view gets updated. | +| `navigationTitle(_:)` | Add a title that is used if the view is a direct child of a NavigationView. | +| `style(_:)` | Add a style class to the view. | +| `onAppear(_:)` | Run when the view is rendered for the first time. | +| `topToolbar(visible:_:)` | Add a native toolbar to the view. Normally, it contains a HeaderBar. | +| `bottomToolbar(visible:_:)` | Add a native bottom toolbar to the view. | + +### `Button` Modifiers +| Syntax | Description | +| ---------------------------- | --------------------------------------------------------------------------------------- | +| `keyboardShortcut(_:window:)`| Create a keyboard shortcut for the window with the button's action. | +| `keyboardShortcut(_:app:)` | Create a keyboard shortcut for the application with the button's action. | + +### `HeaderBar` Modifiers +| Syntax | Description | +| ---------------------------- | --------------------------------------------------------------------------------------- | +| `headerBarTitle(view:)` | Customize the title view in the header bar. | + +### `List` Modifiers +| Syntax | Description | +| ---------------------------- | --------------------------------------------------------------------------------------- | +| `sidebarStyle()` | Change the style of the list to match a sidebar. | + +### Window Types +| Name | Description | Widget | +| -------------------- | ----------------------------------------------------------------- | ---------------------- | +| Window | A simple application window. | AdwApplicationWindow | + +### Window Modifiers +| Syntax | Description | +| ------------------------------- | --------------------------------------------------------------------------------------- | +| `appKeyboardShortcut(_:action:)`| Create a keyboard shortcut available in the whole the application. | +| `quitShortcut()` | Create a keyboard shortcut for quitting the application with "Ctrl + q". | + +### `Window` Modifiers +| Syntax | Description | +| ------------------------------- | --------------------------------------------------------------------------------------- | +| `keyboardShortcut(_:action:)` | Create a keyboard shortcut available in one window. | +| `closeShortcut()` | Create a keyboard shortcut for closing the window with "Ctrl + w". | ## Installation ### Dependencies @@ -131,21 +164,22 @@ brew install libadwaita * [Hello World][13] * [Creating Views][14] * [Windows][15] +* [Keyboard Shortcuts][16] ### Advanced -* [Creating Widgets][16] +* [Creating Widgets][17] ## Thanks ### Dependencies -- [SwiftGui][17] licensed under the [GPL-3.0 license][18] +- [SwiftGui][18] licensed under the [GPL-3.0 license][19] ### Other Thanks -- The [contributors][19] -- [SwiftLint][20] for checking whether code style conventions are violated -- The programming language [Swift][21] -- [SourceDocs][22] used for generating the [docs][23] +- The [contributors][20] +- [SwiftLint][21] for checking whether code style conventions are violated +- The programming language [Swift][22] +- [SourceDocs][23] used for generating the [docs][24] [1]: Tests/ [2]: #goals @@ -160,16 +194,17 @@ brew install libadwaita [11]: https://brew.sh [12]: user-manual/GettingStarted.md [13]: user-manual/Basics/HelloWorld.md -[14]: user-manual/Basics/CreatingViews.md -[15]: user-manual/Basics/Windows.md -[16]: user-manual/Advanced/CreatingWidgets.md -[17]: https://github.com/JCWasmx86/SwiftGui -[18]: https://github.com/JCWasmx86/SwiftGui/blob/main/COPYING -[19]: Contributors.md -[20]: https://github.com/realm/SwiftLint -[21]: https://github.com/apple/swift -[22]: https://github.com/SourceDocs/SourceDocs -[23]: Documentation/Reference/README.md +[14]: user-manual/Basics/CreatingViews.md +[15]: user-manual/Basics/Windows.md +[16]: user-manual/Basics/KeyboardShortcuts.md +[17]: user-manual/Advanced/CreatingWidgets.md +[18]: https://github.com/JCWasmx86/SwiftGui +[19]: https://github.com/JCWasmx86/SwiftGui/blob/main/COPYING +[20]: Contributors.md +[21]: https://github.com/realm/SwiftLint +[22]: https://github.com/apple/swift +[23]: https://github.com/SourceDocs/SourceDocs +[24]: Documentation/Reference/README.md [image-1]: Icons/Screenshot.png [image-2]: Icons/Demo.png diff --git a/SUMMARY.md b/SUMMARY.md index 60e3751..cfc3d5d 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -8,14 +8,16 @@ * [Hello World][3] * [Creating Views][4] * [Windows][5] +* [Keyboard Shortcuts][6] ## Advanced -* [Creating Widgets][6] +* [Creating Widgets][7] [1]: README.md [2]: user-manual/GettingStarted.md [3]: user-manual/Basics/HelloWorld.md [4]: user-manual/Basics/CreatingViews.md [5]: user-manual/Basics/Windows.md -[6]: user-manual/Advanced/CreatingWidgets.md +[6]: user-manual/Basics/KeyboardShortcuts.md +[7]: user-manual/Advanced/CreatingWidgets.md diff --git a/Sources/Adwaita/Model/User Interface/App.swift b/Sources/Adwaita/Model/User Interface/App.swift index 1bec892..5b38477 100644 --- a/Sources/Adwaita/Model/User Interface/App.swift +++ b/Sources/Adwaita/Model/User Interface/App.swift @@ -51,7 +51,7 @@ extension App { if window.destroy { removeIndices.insert(index, at: 0) } else if let scene = appInstance.scene.windows().first(where: { $0.id == window.id }) { - scene.update(window) + scene.update(window, app: appInstance.app) } } for index in removeIndices { diff --git a/Sources/Adwaita/Model/User Interface/GTUIApplicationWindow.swift b/Sources/Adwaita/Model/User Interface/GTUIApplicationWindow.swift new file mode 100644 index 0000000..a4d3cf4 --- /dev/null +++ b/Sources/Adwaita/Model/User Interface/GTUIApplicationWindow.swift @@ -0,0 +1,11 @@ +// +// GTUIApplicationWindow.swift +// Adwaita +// +// Created by david-swift on 19.10.23. +// + +import GTUI + +/// A GTUI application window. +public typealias GTUIApplicationWindow = GTUI.ApplicationWindow diff --git a/Sources/Adwaita/Model/User Interface/WindowScene.swift b/Sources/Adwaita/Model/User Interface/WindowScene.swift index 0c30236..88f45ce 100644 --- a/Sources/Adwaita/Model/User Interface/WindowScene.swift +++ b/Sources/Adwaita/Model/User Interface/WindowScene.swift @@ -14,13 +14,17 @@ public protocol WindowScene: WindowSceneGroup { var id: String { get } /// The number of instances of the window at the startup. var `open`: Int { get } + /// The keyboard shortcuts on the application's level. + var appShortcuts: [String: (GTUIApp) -> Void] { get set } /// Get the storage for the window. /// - Parameter app: The application. /// - Returns: The storage. func createWindow(app: GTUIApp) -> WindowStorage /// Update a window storage's content. - /// - Parameter storage: The storage to update. - func update(_ storage: WindowStorage) + /// - Parameters: + /// - storage: The storage to update. + /// - app: The application. + func update(_ storage: WindowStorage, app: GTUIApp) } @@ -29,4 +33,29 @@ extension WindowScene { /// The window scene's body is itself. @SceneBuilder public var scene: Scene { self } + /// Add a keyboard shortcut that is available for the whole app. + /// - Parameters: + /// - shortcut: The keyboard shortcut. + /// - The closure to execute. + public func appKeyboardShortcut(_ shortcut: String, action: @escaping (GTUIApp) -> Void) -> Self { + var newSelf = self + newSelf.appShortcuts[shortcut] = action + return newSelf + } + + /// Update the app shortcuts. + /// + /// Call this function in types of window scene. + public func updateAppShortcuts(app: GTUIApp) { + for shortcut in appShortcuts { + app.addKeyboardShortcut(shortcut.key, id: shortcut.key) { shortcut.value(app) } + } + } + + /// Add the shortcut "q" which terminates the application. + /// - Returns: The app. + public func quitShortcut() -> Self { + appKeyboardShortcut("q".ctrl()) { $0.quit() } + } + } diff --git a/Sources/Adwaita/Model/User Interface/WindowSceneGroup.swift b/Sources/Adwaita/Model/User Interface/WindowSceneGroup.swift index 4695c61..19ebae1 100644 --- a/Sources/Adwaita/Model/User Interface/WindowSceneGroup.swift +++ b/Sources/Adwaita/Model/User Interface/WindowSceneGroup.swift @@ -30,11 +30,13 @@ extension WindowSceneGroup { } /// Update the windows described by the group. - /// - Parameter storage: The window's storage. - func update(_ storage: [WindowStorage]) { + /// - Parameters: + /// - storage: The window's storage. + /// - app: The application. + func update(_ storage: [WindowStorage], app: GTUIApp) { for (index, window) in windows().enumerated() { if let storage = storage[safe: index] { - window.update(storage) + window.update(storage, app: app) } } } diff --git a/Sources/Adwaita/View/Button.swift b/Sources/Adwaita/View/Button.swift index e7b8905..747d1d2 100644 --- a/Sources/Adwaita/View/Button.swift +++ b/Sources/Adwaita/View/Button.swift @@ -67,4 +67,28 @@ public struct Button: Widget { } } + /// Create a keyboard shortcut for an application window from a button. + /// + /// Note that the keyboard shortcut is available after the view has been visible for the first time. + /// - Parameters: + /// - shortcut: The keyboard shortcut. + /// - window: The application window. + /// - Returns: The button. + public func keyboardShortcut(_ shortcut: String, window: GTUIApplicationWindow) -> Self { + window.addKeyboardShortcut(shortcut, id: shortcut, handler: handler) + return self + } + + /// Create a keyboard shortcut for an application from a button. + /// + /// Note that the keyboard shortcut is available after the view has been visible for the first time. + /// - Parameters: + /// - shortcut: The keyboard shortcut. + /// - window: The application. + /// - Returns: The button. + public func keyboardShortcut(_ shortcut: String, app: GTUIApp) -> Self { + app.addKeyboardShortcut(shortcut, id: shortcut, handler: handler) + return self + } + } diff --git a/Sources/Adwaita/Window/Window.swift b/Sources/Adwaita/Window/Window.swift index 8918623..3ad235f 100644 --- a/Sources/Adwaita/Window/Window.swift +++ b/Sources/Adwaita/Window/Window.swift @@ -7,7 +7,7 @@ import GTUI -/// A structure representing a simple window type. +/// A structure representing an application window type. /// /// Note that multiple instances of a window can be opened at the same time. public struct Window: WindowScene { @@ -15,16 +15,20 @@ public struct Window: WindowScene { /// The window's identifier. public var id: String /// The window's content. - var content: (GTUIWindow) -> Body + var content: (GTUIApplicationWindow) -> Body /// Whether an instance of the window type should be opened when the app is starting up. public var `open`: Int + /// The keyboard shortcuts. + var shortcuts: [String: (GTUIApplicationWindow) -> Void] = [:] + /// The keyboard shortcuts on the app level. + public var appShortcuts: [String: (GTUIApp) -> Void] = [:] /// Create a window type with a certain identifier and user interface. /// - Parameters: /// - id: The identifier. /// - open: The number of instances of the window type when the app is starting. /// - content: The window's content. - public init(id: String, `open`: Int = 1, @ViewBuilder content: @escaping (GTUIWindow) -> Body) { + public init(id: String, `open`: Int = 1, @ViewBuilder content: @escaping (GTUIApplicationWindow) -> Body) { self.content = content self.id = id self.open = open @@ -47,8 +51,9 @@ public struct Window: WindowScene { /// Get the window. /// - Parameter app: The application. /// - Returns: The window. - func createGTUIWindow(app: GTUIApp) -> GTUIWindow { - let window = GTUIWindow(app: app) + func createGTUIWindow(app: GTUIApp) -> GTUIApplicationWindow { + let window = GTUIApplicationWindow(app: app) + updateAppShortcuts(app: app) window.show() return window } @@ -56,16 +61,48 @@ public struct Window: WindowScene { /// Get the storage of the content view. /// - Parameter window: The window. /// - Returns: The storage of the content of the window. - func getViewStorage(window: GTUIWindow) -> ViewStorage { - let storage = content(window).widget().container() + func getViewStorage(window: GTUIApplicationWindow) -> ViewStorage { + let content = content(window) + let storage = content.widget().container() window.setChild(storage.view) + updateShortcuts(window: window) return storage } /// Update a window storage's content. /// - Parameter storage: The storage to update. - public func update(_ storage: WindowStorage) { - content(storage.window).widget().updateStorage(storage.view) + public func update(_ storage: WindowStorage, app: GTUIApp) { + if let window = storage.window as? GTUIApplicationWindow { + let content = content(window) + content.widget().updateStorage(storage.view) + updateShortcuts(window: window) + updateAppShortcuts(app: app) + } + } + + /// Add a keyboard shortcut. + /// - Parameters: + /// - shortcut: The keyboard shortcut. + /// - action: The closure to execute when the keyboard shortcut is pressed. + /// - Returns: The window. + public func keyboardShortcut(_ shortcut: String, action: @escaping (GTUIApplicationWindow) -> Void) -> Self { + var newSelf = self + newSelf.shortcuts[shortcut] = action + return newSelf + } + + /// Update the keyboard shortcuts. + /// - Parameter window: The application window. + func updateShortcuts(window: GTUIApplicationWindow) { + for shortcut in shortcuts { + window.addKeyboardShortcut(shortcut.key, id: shortcut.key) { shortcut.value(window) } + } + } + + /// Add the shortcut "w" which closes the window. + /// - Returns: The window. + public func closeShortcut() -> Self { + keyboardShortcut("w".ctrl()) { $0.close() } } } diff --git a/Tests/Demo.swift b/Tests/Demo.swift index 3cf2fd8..1847d30 100644 --- a/Tests/Demo.swift +++ b/Tests/Demo.swift @@ -20,6 +20,9 @@ struct Demo: App { Window(id: "main") { window in DemoContent(window: window, app: app) } + .appKeyboardShortcut("n".ctrl()) { $0.addWindow("main") } + .closeShortcut() + .quitShortcut() HelperWindows() } @@ -29,9 +32,11 @@ struct Demo: App { Window(id: "content", open: 0) { window in WindowsDemo.WindowContent(window: window) } + .closeShortcut() Window(id: "toolbar-demo", open: 0) { window in ToolbarDemo.WindowContent(window: window) } + .closeShortcut() } } diff --git a/user-manual/Basics/KeyboardShortcuts.md b/user-manual/Basics/KeyboardShortcuts.md new file mode 100644 index 0000000..99c6069 --- /dev/null +++ b/user-manual/Basics/KeyboardShortcuts.md @@ -0,0 +1,91 @@ +# Keyboard Shortcuts + +Keyboard shortcuts can be attached to individual windows or whole applications. + +## About Keyboard Shortcuts +Keyboard shortcuts are represented as a `String`. +You can add a single character by adding itself to the string, e.g. `"n"`. +The F keys are written as `"F1"`, `"F2"`, etc. +For character keys, write the lowercase name instead of the symbol, such as `"minus"` instead of `"-"`. + +Add modifiers to the shortcut using the following string modifiers: +- `.shift()` +- `.ctrl()` +- `.alt()` +- `.meta()` +- `.super()` +- `.hyper()` + +As an example, the following syntax represents the `Ctrl + N` shortcut: `"n".ctrl()`. + +## Add Shortcuts to a Window +Add a keyboard shortcut to an invividual window. It is only available in that window. +```swift +import Adwaita + +@main +struct HelloWorld: App { + + let id = "io.github.david-swift.HelloWorld" + var app: GTUIApp! + + var scene: Scene { + Window(id: "content") { _ in + HeaderBar.empty() + Text("Hello, world!") + .padding() + } + // Add the shortcut "Ctrl + W" for closing the window + .keyboardShortcut("w".ctrl()) { window in + window.close() + } + } + +} +``` + +## Add Shortcuts to an App +Add a keyboard to an app so that the shortcut is available in every top-level window. +```swift +import Adwaita + +@main +struct HelloWorld: App { + + let id = "io.github.david-swift.HelloWorld" + var app: GTUIApp! + + var scene: Scene { + Window(id: "content") { _ in + HeaderBar.empty() + Text("Hello, world!") + .padding() + } + // Add the shortcut "Ctrl + Q" for terminating the app + .appKeyboardShortcut("q".ctrl()) { app in + app.quit() + } + } + +} +``` + +## Create Shortcuts from a Button +It's possible to easily create a keyboard shortcut from a button. +Use `appKeyboardShortcut` instead of `keyboardShortcut` for shortcuts on an application level. +Note that the shortcut gets activated after presenting the view for the first time. +```swift +struct HelloView: View { + + var window: GTUIWindow + + var view: Body { + Button("New Item") { + print("New Item") + } + // Add a keyboard shortcut to the window "window". + .keyboardShortcut("n".ctrl().shift(), window: window) + } + +} +```