forked from aparoksha/adwaita-swift
Support modifying a window's instance inside views
Also add support for observing a window's size
This commit is contained in:
parent
24fc372849
commit
461e9f4d50
@ -12,6 +12,7 @@
|
|||||||
- [WindowScene](protocols/WindowScene.md)
|
- [WindowScene](protocols/WindowScene.md)
|
||||||
- [WindowSceneGroup](protocols/WindowSceneGroup.md)
|
- [WindowSceneGroup](protocols/WindowSceneGroup.md)
|
||||||
- [WindowType](protocols/WindowType.md)
|
- [WindowType](protocols/WindowType.md)
|
||||||
|
- [WindowView](protocols/WindowView.md)
|
||||||
|
|
||||||
## Structs
|
## Structs
|
||||||
|
|
||||||
|
|||||||
@ -171,6 +171,12 @@ Bind a signal that focuses the view.
|
|||||||
- Parameter focus: Whether the view is focused.
|
- Parameter focus: Whether the view is focused.
|
||||||
- Returns: A view.
|
- Returns: A view.
|
||||||
|
|
||||||
|
### `tooltip(_:)`
|
||||||
|
|
||||||
|
Add a tooltip to the widget.
|
||||||
|
- Parameter tooltip: The tooltip text.
|
||||||
|
- Returns: A view.
|
||||||
|
|
||||||
### `stopModifiers()`
|
### `stopModifiers()`
|
||||||
|
|
||||||
Remove all of the content modifiers for the wrapped views.
|
Remove all of the content modifiers for the wrapped views.
|
||||||
|
|||||||
13
Documentation/Reference/protocols/WindowView.md
Normal file
13
Documentation/Reference/protocols/WindowView.md
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
**PROTOCOL**
|
||||||
|
|
||||||
|
# `WindowView`
|
||||||
|
|
||||||
|
A special view that can access the window of the current instance
|
||||||
|
if located as the first view directly inside a window.
|
||||||
|
|
||||||
|
## Methods
|
||||||
|
### `window(_:)`
|
||||||
|
|
||||||
|
Modify the window.
|
||||||
|
- Parameter window: The window.
|
||||||
|
- Returns: The window.
|
||||||
@ -31,10 +31,6 @@ The keyboard shortcuts.
|
|||||||
|
|
||||||
The keyboard shortcuts on the app level.
|
The keyboard shortcuts on the app level.
|
||||||
|
|
||||||
### `defaultSize`
|
|
||||||
|
|
||||||
The default window size.
|
|
||||||
|
|
||||||
### `title`
|
### `title`
|
||||||
|
|
||||||
The window's title.
|
The window's title.
|
||||||
@ -51,6 +47,18 @@ Whether the window is deletable.
|
|||||||
|
|
||||||
The signals for the importers and exporters.
|
The signals for the importers and exporters.
|
||||||
|
|
||||||
|
### `width`
|
||||||
|
|
||||||
|
The binding for the window's width.
|
||||||
|
|
||||||
|
### `height`
|
||||||
|
|
||||||
|
The binding for the window's height.
|
||||||
|
|
||||||
|
### `setDefaultSize`
|
||||||
|
|
||||||
|
Whether to update the default size.
|
||||||
|
|
||||||
## Methods
|
## Methods
|
||||||
### `init(id:open:content:)`
|
### `init(id:open:content:)`
|
||||||
|
|
||||||
@ -86,10 +94,25 @@ Update a window storage's content.
|
|||||||
- app: The GTUI app.
|
- app: The GTUI app.
|
||||||
- force: Whether to force update all the views.
|
- force: Whether to force update all the views.
|
||||||
|
|
||||||
### `setProperties(window:)`
|
### `getTemplate(content:)`
|
||||||
|
|
||||||
|
Get the actual window template.
|
||||||
|
- Parameter content: The content view.s
|
||||||
|
- Returns: The window.
|
||||||
|
|
||||||
|
### `setProperties(window:template:)`
|
||||||
|
|
||||||
Set some general propreties of the window.
|
Set some general propreties of the window.
|
||||||
- Parameter window: The window.
|
- Parameters:
|
||||||
|
- window: The window.
|
||||||
|
- template: The window template.
|
||||||
|
|
||||||
|
### `updateSize(window:template:)`
|
||||||
|
|
||||||
|
Update the window's size.
|
||||||
|
- Parameters:
|
||||||
|
- window: The window.
|
||||||
|
- template: The window template.
|
||||||
|
|
||||||
### `overlay(windows:)`
|
### `overlay(windows:)`
|
||||||
|
|
||||||
@ -126,10 +149,10 @@ Add a keyboard shortcut.
|
|||||||
- action: The closure to execute when the keyboard shortcut is pressed.
|
- action: The closure to execute when the keyboard shortcut is pressed.
|
||||||
- Returns: The window.
|
- Returns: The window.
|
||||||
|
|
||||||
### `updateShortcuts(window:)`
|
### `updateShortcuts(window:template:)`
|
||||||
|
|
||||||
Update the keyboard shortcuts.
|
Update the keyboard shortcuts.
|
||||||
- Parameter window: The application window.
|
- Parameters: window: The application window.
|
||||||
|
|
||||||
### `closeShortcut()`
|
### `closeShortcut()`
|
||||||
|
|
||||||
@ -161,3 +184,11 @@ Set whether the window is resizable.
|
|||||||
Set whether the window is deletable.
|
Set whether the window is deletable.
|
||||||
- Parameter resizable: The deletability.
|
- Parameter resizable: The deletability.
|
||||||
- Returns: The window.
|
- Returns: The window.
|
||||||
|
|
||||||
|
### `size(width:height:)`
|
||||||
|
|
||||||
|
Add a tooltip to the widget.
|
||||||
|
- Parameters:
|
||||||
|
- width: The window's actual width.
|
||||||
|
- height: The window's actual height.
|
||||||
|
- Returns: The window.
|
||||||
|
|||||||
17
Sources/Adwaita/Model/User Interface/View/WindowView.swift
Normal file
17
Sources/Adwaita/Model/User Interface/View/WindowView.swift
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
//
|
||||||
|
// WindowView.swift
|
||||||
|
// Adwaita
|
||||||
|
//
|
||||||
|
// Created by david-swift on 26.02.24.
|
||||||
|
//
|
||||||
|
|
||||||
|
/// A special view that can access the window of the current instance
|
||||||
|
/// if located as the first view directly inside a window.
|
||||||
|
public protocol WindowView: View {
|
||||||
|
|
||||||
|
/// Modify the window.
|
||||||
|
/// - Parameter window: The window.
|
||||||
|
/// - Returns: The window.
|
||||||
|
func window(_ window: Window) -> Window
|
||||||
|
|
||||||
|
}
|
||||||
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
// swiftlint:disable discouraged_optional_collection
|
// swiftlint:disable discouraged_optional_collection
|
||||||
|
|
||||||
|
import CAdw
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
/// A structure representing an application window type.
|
/// A structure representing an application window type.
|
||||||
@ -26,8 +27,6 @@ public struct Window: WindowScene {
|
|||||||
var shortcuts: [String: (GTUIApplicationWindow) -> Void] = [:]
|
var shortcuts: [String: (GTUIApplicationWindow) -> Void] = [:]
|
||||||
/// The keyboard shortcuts on the app level.
|
/// The keyboard shortcuts on the app level.
|
||||||
public var appShortcuts: [String: (GTUIApp) -> Void] = [:]
|
public var appShortcuts: [String: (GTUIApp) -> Void] = [:]
|
||||||
/// The default window size.
|
|
||||||
var defaultSize: (Int, Int)?
|
|
||||||
/// The window's title.
|
/// The window's title.
|
||||||
var title: String?
|
var title: String?
|
||||||
/// Whether the window is resizable.
|
/// Whether the window is resizable.
|
||||||
@ -36,6 +35,12 @@ public struct Window: WindowScene {
|
|||||||
var deletable = true
|
var deletable = true
|
||||||
/// The signals for the importers and exporters.
|
/// The signals for the importers and exporters.
|
||||||
var signals: [Signal] = []
|
var signals: [Signal] = []
|
||||||
|
/// The binding for the window's width.
|
||||||
|
var width: Binding<Int>?
|
||||||
|
/// The binding for the window's height.
|
||||||
|
var height: Binding<Int>?
|
||||||
|
/// Whether to update the default size.
|
||||||
|
var setDefaultSize = false
|
||||||
|
|
||||||
/// Create a window type with a certain identifier and user interface.
|
/// Create a window type with a certain identifier and user interface.
|
||||||
/// - Parameters:
|
/// - Parameters:
|
||||||
@ -77,11 +82,12 @@ public struct Window: WindowScene {
|
|||||||
/// - Returns: The storage of the content of the window.
|
/// - Returns: The storage of the content of the window.
|
||||||
func getViewStorage(window: GTUIApplicationWindow) -> ViewStorage {
|
func getViewStorage(window: GTUIApplicationWindow) -> ViewStorage {
|
||||||
let content = content(window)
|
let content = content(window)
|
||||||
|
let template = getTemplate(content: content)
|
||||||
let storage = content.widget(modifiers: []).container(modifiers: [])
|
let storage = content.widget(modifiers: []).container(modifiers: [])
|
||||||
window.setChild(storage.pointer)
|
window.setChild(storage.pointer)
|
||||||
window.setDefaultSize(width: defaultSize?.0, height: defaultSize?.1)
|
setProperties(window: window, template: template)
|
||||||
setProperties(window: window)
|
updateShortcuts(window: window, template: template)
|
||||||
updateShortcuts(window: window)
|
window.setDefaultSize(width: template.width?.wrappedValue, height: template.height?.wrappedValue)
|
||||||
return storage
|
return storage
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,11 +99,12 @@ public struct Window: WindowScene {
|
|||||||
public func update(_ storage: WindowStorage, app: GTUIApp, force: Bool) {
|
public func update(_ storage: WindowStorage, app: GTUIApp, force: Bool) {
|
||||||
if let window = storage.window as? GTUIApplicationWindow {
|
if let window = storage.window as? GTUIApplicationWindow {
|
||||||
let content = content(window)
|
let content = content(window)
|
||||||
|
let template = getTemplate(content: content)
|
||||||
if let view = storage.view {
|
if let view = storage.view {
|
||||||
content.widget(modifiers: []).updateStorage(view, modifiers: [], updateProperties: force)
|
content.widget(modifiers: []).updateStorage(view, modifiers: [], updateProperties: force)
|
||||||
}
|
}
|
||||||
setProperties(window: window)
|
setProperties(window: window, template: template)
|
||||||
updateShortcuts(window: window)
|
updateShortcuts(window: window, template: template)
|
||||||
updateAppShortcuts(app: app)
|
updateAppShortcuts(app: app)
|
||||||
}
|
}
|
||||||
for signal in signals where signal.update {
|
for signal in signals where signal.update {
|
||||||
@ -107,14 +114,61 @@ public struct Window: WindowScene {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the actual window template.
|
||||||
|
/// - Parameter content: The content view.s
|
||||||
|
/// - Returns: The window.
|
||||||
|
func getTemplate(content: Body) -> Self {
|
||||||
|
var windowTemplate = self
|
||||||
|
if let view = content.first as? WindowView {
|
||||||
|
windowTemplate = view.window(windowTemplate)
|
||||||
|
}
|
||||||
|
return windowTemplate
|
||||||
|
}
|
||||||
|
|
||||||
/// Set some general propreties of the window.
|
/// Set some general propreties of the window.
|
||||||
/// - Parameter window: The window.
|
/// - Parameters:
|
||||||
func setProperties(window: GTUIApplicationWindow) {
|
/// - window: The window.
|
||||||
if let title {
|
/// - template: The window template.
|
||||||
|
func setProperties(window: GTUIApplicationWindow, template: Self) {
|
||||||
|
if let title = template.title {
|
||||||
window.setTitle(title)
|
window.setTitle(title)
|
||||||
}
|
}
|
||||||
window.setResizability(resizable)
|
window.setResizability(template.resizable)
|
||||||
window.setDeletability(deletable)
|
window.setDeletability(template.deletable)
|
||||||
|
var storage = window.fields["storage"] as? ViewStorage
|
||||||
|
if storage == nil {
|
||||||
|
storage = .init(window.pointer?.opaque())
|
||||||
|
window.fields["storage"] = storage
|
||||||
|
}
|
||||||
|
if template.setDefaultSize {
|
||||||
|
window.setDefaultSize(width: template.width?.wrappedValue, height: template.height?.wrappedValue)
|
||||||
|
}
|
||||||
|
if template.width != nil {
|
||||||
|
storage?.notify(name: "default-width") {
|
||||||
|
updateSize(window: window, template: template)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if template.height != nil {
|
||||||
|
storage?.notify(name: "default-height") {
|
||||||
|
updateSize(window: window, template: template)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Update the window's size.
|
||||||
|
/// - Parameters:
|
||||||
|
/// - window: The window.
|
||||||
|
/// - template: The window template.
|
||||||
|
func updateSize(window: GTUIApplicationWindow, template: Self) {
|
||||||
|
var width: Int32 = 0
|
||||||
|
var height: Int32 = 0
|
||||||
|
gtk_window_get_default_size(window.pointer, &width, &height)
|
||||||
|
if width != template.width?.wrappedValue ?? 0 {
|
||||||
|
template.width?.wrappedValue = .init(width)
|
||||||
|
}
|
||||||
|
if height != template.height?.wrappedValue ?? 0 {
|
||||||
|
template.height?.wrappedValue = .init(height)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add windows that overlay the last instance of this window if presented.
|
/// Add windows that overlay the last instance of this window if presented.
|
||||||
@ -197,9 +251,9 @@ public struct Window: WindowScene {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Update the keyboard shortcuts.
|
/// Update the keyboard shortcuts.
|
||||||
/// - Parameter window: The application window.
|
/// - Parameters: window: The application window.
|
||||||
func updateShortcuts(window: GTUIApplicationWindow) {
|
func updateShortcuts(window: GTUIApplicationWindow, template: Self) {
|
||||||
for shortcut in shortcuts {
|
for shortcut in template.shortcuts {
|
||||||
window.addKeyboardShortcut(shortcut.key, id: shortcut.key) { shortcut.value(window) }
|
window.addKeyboardShortcut(shortcut.key, id: shortcut.key) { shortcut.value(window) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -217,7 +271,9 @@ public struct Window: WindowScene {
|
|||||||
/// - Returns: The window.
|
/// - Returns: The window.
|
||||||
public func defaultSize(width: Int, height: Int) -> Self {
|
public func defaultSize(width: Int, height: Int) -> Self {
|
||||||
var newSelf = self
|
var newSelf = self
|
||||||
newSelf.defaultSize = (width, height)
|
newSelf.width = .constant(width)
|
||||||
|
newSelf.height = .constant(height)
|
||||||
|
newSelf.setDefaultSize = true
|
||||||
return newSelf
|
return newSelf
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -248,6 +304,18 @@ public struct Window: WindowScene {
|
|||||||
return newSelf
|
return newSelf
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Add a tooltip to the widget.
|
||||||
|
/// - Parameters:
|
||||||
|
/// - width: The window's actual width.
|
||||||
|
/// - height: The window's actual height.
|
||||||
|
/// - Returns: The window.
|
||||||
|
public func size(width: Binding<Int>? = nil, height: Binding<Int>? = nil) -> Self {
|
||||||
|
var newSelf = self
|
||||||
|
newSelf.width = width
|
||||||
|
newSelf.height = height
|
||||||
|
return newSelf
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// swiftlint:enable discouraged_optional_collection
|
// swiftlint:enable discouraged_optional_collection
|
||||||
|
|||||||
@ -19,7 +19,6 @@ struct Demo: App {
|
|||||||
Window(id: "main") { window in
|
Window(id: "main") { window in
|
||||||
DemoContent(window: window, app: app)
|
DemoContent(window: window, app: app)
|
||||||
}
|
}
|
||||||
.defaultSize(width: 650, height: 450)
|
|
||||||
.overlay {
|
.overlay {
|
||||||
AboutWindow(id: "about", appName: "Demo", developer: "david-swift", version: "Test")
|
AboutWindow(id: "about", appName: "Demo", developer: "david-swift", version: "Test")
|
||||||
.icon(.default(icon: .applicationXExecutable))
|
.icon(.default(icon: .applicationXExecutable))
|
||||||
@ -71,13 +70,17 @@ struct Demo: App {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct DemoContent: View {
|
struct DemoContent: WindowView {
|
||||||
|
|
||||||
@State("selection")
|
@State("selection")
|
||||||
private var selection: Page = .welcome
|
private var selection: Page = .welcome
|
||||||
@State private var toast: Signal = .init()
|
@State private var toast: Signal = .init()
|
||||||
@State("sidebar-visible")
|
@State("sidebar-visible")
|
||||||
private var sidebarVisible = true
|
private var sidebarVisible = true
|
||||||
|
@State("width")
|
||||||
|
private var width = 650
|
||||||
|
@State("height")
|
||||||
|
private var height = 450
|
||||||
var window: GTUIApplicationWindow
|
var window: GTUIApplicationWindow
|
||||||
var app: GTUIApp!
|
var app: GTUIApp!
|
||||||
|
|
||||||
@ -152,6 +155,11 @@ struct Demo: App {
|
|||||||
.tooltip("Main Menu")
|
.tooltip("Main Menu")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func window(_ window: Window) -> Window {
|
||||||
|
window
|
||||||
|
.size(width: $width, height: $height)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user