diff --git a/.spi.yml b/.spi.yml index 8ab4d49..82fa3bd 100644 --- a/.spi.yml +++ b/.spi.yml @@ -1,3 +1,4 @@ version: 1 -external_links: - documentation: "https://david-swift.gitbook.io/adwaita" \ No newline at end of file +builder: + configs: + - documentation_targets: [Adwaita] diff --git a/.swiftlint.yml b/.swiftlint.yml index 062b47f..4a37d11 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -162,4 +162,5 @@ type_contents_order: - other_method excluded: - - Sources/Adwaita/View/Generated/ \ No newline at end of file + - Sources/Adwaita/View/Generated/ + - Sources/Adwaita/Adwaita.docc/ diff --git a/Icons/Screenshot 2024-03-29 at 21.17.17.png b/Icons/Screenshot 2024-03-29 at 21.17.17.png new file mode 100644 index 0000000..2570d8f Binary files /dev/null and b/Icons/Screenshot 2024-03-29 at 21.17.17.png differ diff --git a/Sources/Adwaita/Adwaita.docc/Adwaita.md b/Sources/Adwaita/Adwaita.docc/Adwaita.md new file mode 100644 index 0000000..7be0585 --- /dev/null +++ b/Sources/Adwaita/Adwaita.docc/Adwaita.md @@ -0,0 +1,83 @@ +# ``Adwaita`` + +_Adwaita for Swift_ is a framework for creating user interfaces for GNOME with an API similar to SwiftUI. + +## Overview + +Write user interfaces in a declarative way. + +As an example, the following code defines a _view_ (more information: ``View``). + +```swift +struct Counter: View { + + @State private var count = 0 + + var view: Body { + HStack { + Button(icon: .default(icon: .goPrevious)) { + count -= 1 + } + Text("\(count)") + .style("title-1") + .frame(minWidth: 100) + Button(icon: .default(icon: .goNext)) { + count += 1 + } + } + } + +} +``` + +A view can be implemented in different ways, the following screenshot showing an example. + +![Screenshot of the counter app](Counter.png) + +## Goals + +_Adwaita for Swift_'s main goal is to provide an easy-to-use interface for creating apps for the GNOME ecosystem. +An article about the project's motivation is available on the [website of the Swift programming language](https://www.swift.org/blog/adwaita-swift/). + +## Installation + +### Dependencies + +#### Flatpak + +It is recommended to develop apps inside of a Flatpak. +That way, you don't have to install Swift or any of the dependencies on your system, and you always have access to the latest versions. +Take a look at the [template repository](https://github.com/AparokshaUI/AdwaitaTemplate). +This works on Linux only. + +#### Directly on system + +You can also run your apps directly on the system. + +If you are using a Linux distribution, install `libadwaita-devel` or `libadwaita` (or something similar, based on the package manager) as well as `gtk4-devel`, `gtk4` or similar. + +On macOS, follow these steps: +1. Install [Homebrew](https://brew.sh). +2. Install Libadwaita (and thereby GTK 4): +``` +brew install libadwaita +``` + +### Swift package +1. Open your Swift package in GNOME Builder, Xcode, or any other IDE. +2. Open the `Package.swift` file. +3. Into the `Package` initializer, under `dependencies`, paste: +```swift +.package(url: "https://github.com/AparokshaUI/Adwaita", from: "0.1.0") +``` + +## Template repository + +It is recommended to develop apps on Linux inside a Flatpak. +Find more information in the [template repository](https://github.com/AparokshaUI/AdwaitaTemplate). + +## Topics + +### Tutorials + +- diff --git a/Sources/Adwaita/Adwaita.docc/CreatingViews.md b/Sources/Adwaita/Adwaita.docc/CreatingViews.md new file mode 100644 index 0000000..99feae8 --- /dev/null +++ b/Sources/Adwaita/Adwaita.docc/CreatingViews.md @@ -0,0 +1,156 @@ +# Creating views + +Views are the building blocks of your application. +A view can be as simple as the ``Text`` widget, or as complex as the whole content of a single window. + +## Add views to a window +You can add views to a 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 + // These are the views: + HeaderBar.empty() + Text("Hello, world!") + .padding() + } + } + +} +``` + +In this example, the widgets ``HeaderBar`` and ``Text`` are used. +`padding` is a view modifier, a function that modifies a view, which adds some padding around the text. + +## Create custom views +While directly adding widgets into the `Window`'s body might work for very simple apps, +it can get messy very quickly. +Create custom views by declaring types that conform to the ``View`` protocol: +```swift +// A custom view named "ContentView": +struct ContentView: View { + + var view: Body { + HeaderBar.empty() + Text("Hello, world!") + .padding() + } + +} +``` + +## Properties +As every structure in Swift, custom views can have properties: +```swift +struct HelloView: View { + + // The property "text": + var text: String + var view: Body { + Text("Hello, \(text)!") + .padding() + } + +} +``` +This view can be called via `HelloView(text: "world")` in another view. + +## State +Whenever you want to modify a property that is stored in the view's structure from within your view, +wrap the property with the ``State`` property wrapper: +```swift +struct MyView: View { + + // This property can be modified form within the view: + @State private var text = "world" + var view: Body { + Text("Hello, \(text)!") + .padding() + Button("Change Text") { + text = Bool.random() ? "world" : "John" + } + .padding(10, .horizontal.add(.bottom)) + } + +} +``` +In this example, the text property is set whenever you press the "Change Text" button. + +## Change the state in child views +You can access state properties in child views in the same way as you would access any other property +if the child view cannot modify the state (`HelloView` is defined above): +```swift +struct MyView: View { + + @State private var text = "world" + var view: Body { + // "HelloView" can read the "text" property: + HelloView(text: text) + Button("Change Text") { + text = Bool.random() ? "world" : "John" + } + .padding(10, .horizontal.add(.bottom)) + } + +} +``` + +If the child view should be able to modify the state, use the ``Binding`` property wrapper in the child view +and pass the property with a dollar sign (`$`) to that view. +```swift +struct MyView: View { + + @State private var text = "world" + var view: Body { + HelloView(text: text) + // Pass the editable text property to the child view: + ChangeTextView(text: $text) + } + +} + +struct ChangeTextView: View { + + // Accept the editable text property: + @Binding var text: String + var view: Body { + Button("Change Text") { + // Binding properties can be used the same way as state properties: + text = Bool.random() ? "world" : "John" + } + .padding(10, .horizontal.add(.bottom)) + } + +} +``` + +If you have a more complex type and want to pass a property of the type as a binding, +you can simply access the property on the binding. + +```swift +HelloView(text: $complexType.text) +``` + +Whenever you modify a state property (directly or indirectly through bindings), +the user interface gets automatically updated to reflect that change. + +## Save state values between app launches +It's possible to automatically save a value that conforms to `Codable` whenever it changes to a file. +The value in the file is read when the view containing the state value appears for the first time (e.g. when the user launches the app). + +Use the following syntax, where `"text"` is a unique identifier. +```swift +@State("text") private var text = "world" +``` + +You can organize your content by specifying a custom folder path which will be appended to the XDG data home directory. +```swift +@State("text", folder: "io.github.david_swift.HelloWorld/my-view") private var text = "world" +``` diff --git a/Sources/Adwaita/Adwaita.docc/HelloWorld.tutorial b/Sources/Adwaita/Adwaita.docc/HelloWorld.tutorial new file mode 100644 index 0000000..c2ef268 --- /dev/null +++ b/Sources/Adwaita/Adwaita.docc/HelloWorld.tutorial @@ -0,0 +1,82 @@ +@Tutorial { + + @Intro(title: "The template") { + This is a beginner tutorial. It shows how to create a simple "Hello, world!" app using ``Adwaita``. + While there are instructions for building on macOS, _Adwaita for Swift_ works best on Linux. + } + + @Section(title: "Installation") { + @ContentAndMedia { + Learn how to set up your Linux system or your Mac. + } + @Steps { + @Step { + **If you are on Linux,** install the [GNOME Builder IDE](https://flathub.org/apps/org.gnome.Builder). + @Image(source: "Builder.png", alt: "GNOME Builder in the GNOME Software app store.") + } + @Step { + **If you are on macOS,** install [Xcode](https://developer.apple.com/xcode/). + Open your terminal client and follow the [installation instructions for Homebrew](https://brew.sh). + Then, run `brew install libadwaita`. + @Image(source: "InstallLibadwaita.png", alt: "The macOS Terminal application.") + } + } + } + + @Section(title: "Clone the template repository") { + @ContentAndMedia { + The template repository provides a simple, working app that can be used as a starting point for your own app. + In this section, you'll create a simple "Hello, world!" app and run the app. + } + @Steps { + @Step { + Open your terminal client and navigate to a directory you want to create the package in (e.g. `~/Documents/`). + @Image(source: "ChangeDirectory.png", alt: "The GNOME Console app.") + } + @Step { + Clone the template repository into the `HelloWorld` directory using `git clone https://github.com/AparokshaUI/AdwaitaTemplate HelloWorld`. + + This creates a directory `HelloWorld` containing the content of the [Adwaita Template](https://github.com/AparokshaUI/AdwaitaTemplate). + @Image(source: "GitClone.png", alt: "The GNOME Console app.") + } + @Step { + **If you are on Linux,** use the `Select a Folder...` button in the welcome window of GNOME Builder to open the `HelloWorld` directory. + + It will start to install the dependencies automatically. + @Image(source: "OpenFolder.png", alt: "GNOME Builder's welcome view.") + } + @Step { + **If you are on macOS,** use the `Open Existing Project...` button in the welcome window of Xcode to open the `HelloWorld` directory. + @Image(source: "OpenXcode.png", alt: "Xcode's welcome view.") + } + @Step { + Select the `Package.swift` file in the sidebar. + + This file defines that this Swift _package_ contains an executable, and lists the dependencies required by the executable. + One can see that the Swift files that are part of the executable are located in the `Sources` folder. + @Code(name: "Package.swift", file: "Package.swift") + } + @Step { + Open the `io.github.AparokshaUI.AdwaitaTemplate.json` file. + + This file is relevant for Linux only. + It informs the GNOME Builder about the required dependencies of your app, and how to build and install your app. + It is called a [Flatpak manifest](https://docs.flatpak.org/en/latest/manifests.html). + @Code(name: "io.github.AparokshaUI.AdwaitaTemplate.json", file: "io.github.AparokshaUI.AdwaitaTemplate.json") + } + @Step { + The `Sources` folder contains the actual Swift code of your app. + Open the `AdwaitaTemplate.swift` file to see the definition of an app and its user interface. + @Code(name: "AdwaitaTemplate.swift", file: "AdwaitaTemplate.swift") + } + @Step { + Run the app using the play button in Xcode or GNOME Builder. + A window should open. + + On macOS, the window will look slightly different from the one in the screenshot. Note that libadwaita is built for Linux and therefore works best on Linux. + @Image(source: "AdwaitaTemplate.png", alt: "The result.") + } + } + } + +} diff --git a/Sources/Adwaita/Adwaita.docc/KeyboardShortcuts.md b/Sources/Adwaita/Adwaita.docc/KeyboardShortcuts.md new file mode 100644 index 0000000..3fdb11b --- /dev/null +++ b/Sources/Adwaita/Adwaita.docc/KeyboardShortcuts.md @@ -0,0 +1,115 @@ +# 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 menu +The most elegant way for adding keyboard shortcuts is in many cases adding them via menus. +Here is an example using a menu button: +```swift +struct TestView: View { + + var app: GTUIApp + + var view: Body { + Menu(icon: .default(icon: .openMenu), app: app) { + MenuButton("New Window", window: false) { + app.addWindow("main") + } + // Add a keyboard shortcut to the app. + .keyboardShortcut("n".ctrl()) + } + } + +} +``` +Add the keyboard shortcut to a single window by specifying the `window` parameter in the initializer of `Menu`, +and removing `window: false` in the initializer of `MenuButton`. + +## 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) + } + +} +``` + diff --git a/Sources/Adwaita/Adwaita.docc/Resources/AdwaitaIcon.png b/Sources/Adwaita/Adwaita.docc/Resources/AdwaitaIcon.png new file mode 100644 index 0000000..66edf05 Binary files /dev/null and b/Sources/Adwaita/Adwaita.docc/Resources/AdwaitaIcon.png differ diff --git a/Sources/Adwaita/Adwaita.docc/Resources/AdwaitaTemplate.swift b/Sources/Adwaita/Adwaita.docc/Resources/AdwaitaTemplate.swift new file mode 100644 index 0000000..823eff7 --- /dev/null +++ b/Sources/Adwaita/Adwaita.docc/Resources/AdwaitaTemplate.swift @@ -0,0 +1,23 @@ +// The Swift Programming Language +// https://docs.swift.org/swift-book + +import Adwaita + +@main +struct AdwaitaTemplate: App { + + let id = "io.github.AparokshaUI.AdwaitaTemplate" + var app: GTUIApp! + + var scene: Scene { + Window(id: "main") { window in + Text(Loc.helloWorld) + .padding() + .topToolbar { + ToolbarView(app: app, window: window) + } + } + .defaultSize(width: 450, height: 300) + } + +} diff --git a/Sources/Adwaita/Adwaita.docc/Resources/Counter.png b/Sources/Adwaita/Adwaita.docc/Resources/Counter.png new file mode 100644 index 0000000..06247b8 Binary files /dev/null and b/Sources/Adwaita/Adwaita.docc/Resources/Counter.png differ diff --git a/Sources/Adwaita/Adwaita.docc/Resources/HelloWorld/AdwaitaTemplate.png b/Sources/Adwaita/Adwaita.docc/Resources/HelloWorld/AdwaitaTemplate.png new file mode 100644 index 0000000..f1b19a2 Binary files /dev/null and b/Sources/Adwaita/Adwaita.docc/Resources/HelloWorld/AdwaitaTemplate.png differ diff --git a/Sources/Adwaita/Adwaita.docc/Resources/HelloWorld/Builder.png b/Sources/Adwaita/Adwaita.docc/Resources/HelloWorld/Builder.png new file mode 100644 index 0000000..b8d0442 Binary files /dev/null and b/Sources/Adwaita/Adwaita.docc/Resources/HelloWorld/Builder.png differ diff --git a/Sources/Adwaita/Adwaita.docc/Resources/HelloWorld/ChangeDirectory.png b/Sources/Adwaita/Adwaita.docc/Resources/HelloWorld/ChangeDirectory.png new file mode 100644 index 0000000..952a56f Binary files /dev/null and b/Sources/Adwaita/Adwaita.docc/Resources/HelloWorld/ChangeDirectory.png differ diff --git a/Sources/Adwaita/Adwaita.docc/Resources/HelloWorld/GitClone.png b/Sources/Adwaita/Adwaita.docc/Resources/HelloWorld/GitClone.png new file mode 100644 index 0000000..a05d977 Binary files /dev/null and b/Sources/Adwaita/Adwaita.docc/Resources/HelloWorld/GitClone.png differ diff --git a/Sources/Adwaita/Adwaita.docc/Resources/HelloWorld/InstallLibadwaita.png b/Sources/Adwaita/Adwaita.docc/Resources/HelloWorld/InstallLibadwaita.png new file mode 100644 index 0000000..313f3f6 Binary files /dev/null and b/Sources/Adwaita/Adwaita.docc/Resources/HelloWorld/InstallLibadwaita.png differ diff --git a/Sources/Adwaita/Adwaita.docc/Resources/HelloWorld/OpenFolder.png b/Sources/Adwaita/Adwaita.docc/Resources/HelloWorld/OpenFolder.png new file mode 100644 index 0000000..2de90db Binary files /dev/null and b/Sources/Adwaita/Adwaita.docc/Resources/HelloWorld/OpenFolder.png differ diff --git a/Sources/Adwaita/Adwaita.docc/Resources/HelloWorld/OpenXcode.png b/Sources/Adwaita/Adwaita.docc/Resources/HelloWorld/OpenXcode.png new file mode 100644 index 0000000..df02ffe Binary files /dev/null and b/Sources/Adwaita/Adwaita.docc/Resources/HelloWorld/OpenXcode.png differ diff --git a/Sources/Adwaita/Adwaita.docc/Resources/HelloWorld/Package.swift b/Sources/Adwaita/Adwaita.docc/Resources/HelloWorld/Package.swift new file mode 100644 index 0000000..5b0f9d9 --- /dev/null +++ b/Sources/Adwaita/Adwaita.docc/Resources/HelloWorld/Package.swift @@ -0,0 +1,31 @@ +// swift-tools-version: 5.8 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +import PackageDescription + +let package = Package( + name: "Adwaita Template", + platforms: [ + .macOS(.v13) + ], + dependencies: [ + .package(url: "https://github.com/AparokshaUI/Adwaita", from: "0.2.0"), + .package(url: "https://github.com/AparokshaUI/Localized", from: "0.2.0") + ], + targets: [ + .executableTarget( + name: "AdwaitaTemplate", + dependencies: [ + .product(name: "Adwaita", package: "Adwaita"), + .product(name: "Localized", package: "Localized") + ], + path: "Sources", + resources: [ + .process("Localized.yml") + ], + plugins: [ + .plugin(name: "GenerateLocalized", package: "Localized") + ] + ) + ] +) diff --git a/Sources/Adwaita/Adwaita.docc/Resources/HelloWorld/io.github.AparokshaUI.AdwaitaTemplate.json b/Sources/Adwaita/Adwaita.docc/Resources/HelloWorld/io.github.AparokshaUI.AdwaitaTemplate.json new file mode 100644 index 0000000..6ee9059 --- /dev/null +++ b/Sources/Adwaita/Adwaita.docc/Resources/HelloWorld/io.github.AparokshaUI.AdwaitaTemplate.json @@ -0,0 +1,52 @@ +{ + "app-id": "io.github.AparokshaUI.AdwaitaTemplate", + "runtime": "org.gnome.Platform", + "runtime-version": "46", + "sdk": "org.gnome.Sdk", + "sdk-extensions": [ + "org.freedesktop.Sdk.Extension.swift5" + ], + "command": "AdwaitaTemplate", + "finish-args": [ + "--share=ipc", + "--socket=fallback-x11", + "--device=dri", + "--socket=wayland" + ], + "build-options": { + "append-path": "/usr/lib/sdk/swift5/bin", + "prepend-ld-library-path": "/usr/lib/sdk/swift5/lib" + }, + "cleanup": [ + "/include", + "/lib/pkgconfig", + "/man", + "/share/doc", + "/share/gtk-doc", + "/share/man", + "/share/pkgconfig", + "*.la", + "*.a" + ], + "modules": [ + { + "name": "AdwaitaTemplate", + "builddir": true, + "buildsystem": "simple", + "sources": [ + { + "type": "dir", + "path": "." + } + ], + "build-commands": [ + "swift build -c release --static-swift-stdlib", + "install -Dm755 .build/release/AdwaitaTemplate /app/bin/AdwaitaTemplate", + "install -Dm644 data/io.github.AparokshaUI.AdwaitaTemplate.metainfo.xml $DESTDIR/app/share/metainfo/io.github.AparokshaUI.AdwaitaTemplate.metainfo.xml", + "install -Dm644 data/io.github.AparokshaUI.AdwaitaTemplate.desktop $DESTDIR/app/share/applications/io.github.AparokshaUI.AdwaitaTemplate.desktop", + "install -Dm644 data/icons/io.github.AparokshaUI.AdwaitaTemplate.svg $DESTDIR/app/share/icons/hicolor/scalable/apps/io.github.AparokshaUI.AdwaitaTemplate.svg", + "install -Dm644 data/icons/io.github.AparokshaUI.AdwaitaTemplate-symbolic.svg $DESTDIR/app/share/icons/hicolor/symbolic/apps/io.github.AparokshaUI.AdwaitaTemplate-symbolic.svg" + ] + } + ] +} diff --git a/Sources/Adwaita/Adwaita.docc/Table of Contents.tutorial b/Sources/Adwaita/Adwaita.docc/Table of Contents.tutorial new file mode 100644 index 0000000..a645450 --- /dev/null +++ b/Sources/Adwaita/Adwaita.docc/Table of Contents.tutorial @@ -0,0 +1,13 @@ +@Tutorials(name: "Develop Apps for GNOME") { + + @Intro(title: "Develop Apps for GNOME") { + Learn the basics of _Adwaita for Swift_ to create beautiful apps for the GNOME desktop. + } + + @Chapter(name: "Adwaita for Swift essentials") { + Get to know the most important principles of the _Adwaita for Swift_ framework. + @TutorialReference(tutorial: "doc:HelloWorld") + @Image(source: "AdwaitaIcon.png", alt: "The Adwaita for Swift icon.") + } + +} diff --git a/Sources/Adwaita/Adwaita.docc/Windows.md b/Sources/Adwaita/Adwaita.docc/Windows.md new file mode 100644 index 0000000..186fdb1 --- /dev/null +++ b/Sources/Adwaita/Adwaita.docc/Windows.md @@ -0,0 +1,137 @@ +# Windows + +Windows in _Adwaita_ are not actually single windows in the user interface, +but rather instructions on how to create one type of window. + +## The simplest case +A single window app is an app having exactly one window, and when this window is closed, the app terminates. +We can add multiple windows to an app as well. +Whenever the last one disappears, the app terminates. +```swift +@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 a second window: + Window(id: "window-2") { _ in + HeaderBar.empty() + Text("Window 2") + .padding() + } + } + +} +``` + +## Showing windows +Every app contains the property `app`. +You can use this property for running functions that affect the whole app, e.g. quitting the app. +Another use case is showing a window: +```swift +@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() + } + Window(id: "control") { _ in + HeaderBar.empty() + Button("Show Window") { + // Show the window with the identifier "content": + app.showWindow("content") + } + .padding() + } + } + +} +``` +"Showing" a window means creating an instance of the window type if there isn't one, +or focusing the window that already exists of that type otherwise. +It should be used for opening windows that cannot be presented more than once +and for moving a window that is already open into the foreground. + +## Adding windows +You can call the `addWindow(_:parent:)` function instead of `showWindow(_:)` +if you want to add and focus another instance of a window type: +```swift +@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() + } + Window(id: "control") { _ in + HeaderBar.empty() + Button("Add Window") { + // Add a new instance of the "content" window type + app.addWindow("content") + } + .padding() + } + } + +} +``` +It can be used to add an overlay window to a certain instance of a window type +by specifying the `parent` parameter, e.g. in the example above: +```swift +Window(id: "control") { window in + HeaderBar.empty() + Button("Add Child Window") { + // Add the new instance as a child window of this window + app.addWindow("content", parent: window) + } + .padding() +} +``` + +## Customizing the initial number of windows +By default, every window type of the app's scene appears once when the app starts. +It's possible to customize how many windows are being presented at the app's startup: +```swift +@main +struct HelloWorld: App { + + let id = "io.github.david_swift.HelloWorld" + var app: GTUIApp! + + var scene: Scene { + // Open no window of the "content" type + Window(id: "content", open: 0) { _ in + HeaderBar.empty() + Text("Hello, world!") + .padding() + } + // Open two windows of the "control" type + Window(id: "control", open: 2) { _ in + HeaderBar.empty() + Button("Show Window") { + app.addWindow("content") + } + .padding() + } + } + +} +```