Add support for modal windows

This commit is contained in:
david-swift 2023-11-09 20:09:21 +01:00
parent ac0c775985
commit da08bc435c
7 changed files with 104 additions and 4 deletions

View File

@ -32,8 +32,9 @@ public class GTUIApp: Application {
let body = body() let body = body()
for windowScene in body.scene.windows() { for windowScene in body.scene.windows() {
for _ in 0..<windowScene.open { for _ in 0..<windowScene.open {
sceneStorage.append(windowScene.createWindow(app: self)) addWindow(windowScene.id)
} }
setParentWindows()
} }
} }
@ -48,9 +49,21 @@ public class GTUIApp: Application {
/// - Parameters: /// - Parameters:
/// - id: The window's id. /// - id: The window's id.
public func addWindow(_ id: String) { public func addWindow(_ id: String) {
if let window = body().scene.windows().first(where: { $0.id == id }) { State<Any>.updateViews()
sceneStorage.append(window.createWindow(app: self)) if let window = body().scene.windows().last(where: { $0.id == id }) {
let window = window.createWindow(app: self)
sceneStorage.append(window)
setParentWindows()
showWindow(id) showWindow(id)
} }
} }
/// Set the parents of every window having a parent window.
func setParentWindows() {
for window in sceneStorage {
if let parent = sceneStorage.first { $0.id == window.parentID } {
window.window.setParent(parent.window)
}
}
}
} }

View File

@ -12,6 +12,8 @@ public protocol WindowScene: WindowSceneGroup {
/// The window type's identifier. /// The window type's identifier.
var id: String { get } var id: String { get }
/// The identifier of the window's parent window.
var parentID: String? { get set }
/// The number of instances of the window at the startup. /// The number of instances of the window at the startup.
var `open`: Int { get } var `open`: Int { get }
/// The keyboard shortcuts on the application's level. /// The keyboard shortcuts on the application's level.

View File

@ -12,6 +12,8 @@ public class WindowStorage {
/// The window's identifier. /// The window's identifier.
public var id: String public var id: String
/// The identifier of the window's parent window.
public var parentID: String?
/// Whether the reference to the window should disappear in the next update. /// Whether the reference to the window should disappear in the next update.
public var destroy = false public var destroy = false
/// The GTUI window. /// The GTUI window.

View File

@ -18,6 +18,8 @@ public struct Window: WindowScene {
var content: (GTUIApplicationWindow) -> Body var content: (GTUIApplicationWindow) -> Body
/// Whether an instance of the window type should be opened when the app is starting up. /// Whether an instance of the window type should be opened when the app is starting up.
public var `open`: Int public var `open`: Int
/// The identifier of the window's parent.
public var parentID: String?
/// The keyboard shortcuts. /// The keyboard shortcuts.
var shortcuts: [String: (GTUIApplicationWindow) -> Void] = [:] var shortcuts: [String: (GTUIApplicationWindow) -> Void] = [:]
/// The keyboard shortcuts on the app level. /// The keyboard shortcuts on the app level.
@ -45,6 +47,7 @@ public struct Window: WindowScene {
windowStorage.destroy = true windowStorage.destroy = true
return false return false
} }
windowStorage.parentID = parentID
return windowStorage return windowStorage
} }
@ -80,6 +83,17 @@ public struct Window: WindowScene {
} }
} }
/// Add windows that overlay the last instance of this window if presented.
/// - Parameter windows: The windows.
/// - Returns: The new windows and this window.
public func overlay(@SceneBuilder windows: () -> [WindowSceneGroup]) -> [WindowScene] {
windows().windows().map { window in
var newWindow = window
newWindow.parentID = id
return newWindow
} + [self]
}
/// Add a keyboard shortcut. /// Add a keyboard shortcut.
/// - Parameters: /// - Parameters:
/// - shortcut: The keyboard shortcut. /// - shortcut: The keyboard shortcut.

View File

@ -20,6 +20,12 @@ struct Demo: App {
Window(id: "main") { window in Window(id: "main") { window in
DemoContent(window: window, app: app) DemoContent(window: window, app: app)
} }
.overlay {
Window(id: "overlay", open: 0) { window in
OverlayWindowDemo.WindowContent(window: window)
}
.keyboardShortcut("Escape") { $0.close() }
}
HelperWindows() HelperWindows()
} }

View File

@ -0,0 +1,53 @@
//
// OverlayWindowDemo.swift
// Adwaita
//
// Created by david-swift on 09.11.23.
//
// swiftlint:disable missing_docs implicitly_unwrapped_optional no_magic_numbers
import Adwaita
struct OverlayWindowDemo: View {
var app: GTUIApp!
var view: Body {
VStack {
Button("Show Window") {
app.showWindow("overlay")
}
.style("pill")
.frame(maxSize: 100)
.padding()
}
}
struct WindowContent: View {
var window: GTUIWindow
var view: Body {
VStack {
Button("Close Window") {
window.close()
}
.style("pill")
.padding()
.frame(maxSize: 100)
}
.valign(.center)
.topToolbar {
HeaderBar.empty()
}
.onAppear {
window.setDefaultSize(width: 300, height: 200)
}
}
}
}
// swiftlint:enable missing_docs implicitly_unwrapped_optional no_magic_numbers

View File

@ -18,13 +18,19 @@ enum Page: String, Identifiable, CaseIterable {
case toolbar case toolbar
case transition case transition
case dice case dice
case overlayWindow
var id: Self { var id: Self {
self self
} }
var label: String { var label: String {
rawValue.capitalized switch self {
case .overlayWindow:
return "Overlay Window"
default:
return rawValue.capitalized
}
} }
var icon: GTUI.Icon? { var icon: GTUI.Icon? {
@ -50,6 +56,8 @@ enum Page: String, Identifiable, CaseIterable {
return "A slide transition between two views." return "A slide transition between two views."
case .dice: case .dice:
return "Roll the dice." return "Roll the dice."
case .overlayWindow:
return "A window on top of another window."
} }
} }
@ -68,6 +76,8 @@ enum Page: String, Identifiable, CaseIterable {
TransitionDemo() TransitionDemo()
case .dice: case .dice:
DiceDemo() DiceDemo()
case .overlayWindow:
OverlayWindowDemo(app: app)
} }
} }