forked from aparoksha/adwaita-swift
Add onClose to windows
This commit is contained in:
parent
1bc36e0759
commit
e430031bbc
@ -11,7 +11,7 @@ import CAdw
|
||||
public class SignalData {
|
||||
|
||||
/// The closure.
|
||||
public var closure: ([Any?]) -> Void
|
||||
public var closure: ([Any?]) -> Any?
|
||||
/// Destroy the class.
|
||||
public var selfDestruction: (() -> Void)?
|
||||
|
||||
@ -62,11 +62,19 @@ public class SignalData {
|
||||
}
|
||||
}
|
||||
|
||||
/// The closure as a C handler with a return value.
|
||||
var boolHandler: @convention(c) (UnsafeMutableRawPointer, UnsafeMutableRawPointer) -> Bool {
|
||||
{ _, data in
|
||||
let data = unsafeBitCast(data, to: SignalData.self)
|
||||
return data.closure([]) as? Bool ?? false
|
||||
}
|
||||
}
|
||||
|
||||
/// Initialize the signal data.
|
||||
/// - Parameters:
|
||||
/// - closure: The signal's closure.
|
||||
/// - destroy: The self destruction.
|
||||
public convenience init(closure: @escaping () -> Void, destroy: (() -> Void)? = nil) {
|
||||
public convenience init(closure: @escaping () -> Any?, destroy: (() -> Void)? = nil) {
|
||||
self.init(closure: { _ in closure() }, destroy: destroy)
|
||||
}
|
||||
|
||||
@ -74,19 +82,46 @@ public class SignalData {
|
||||
/// - Parameters:
|
||||
/// - closure: The signal's closure.
|
||||
/// - destroy: The self destruction.
|
||||
public init(closure: @escaping ([Any]) -> Void, destroy: (() -> Void)? = nil) {
|
||||
public convenience init(closure: @escaping () -> Void, destroy: (() -> Void)? = nil) {
|
||||
self.init(closure: { _ in closure(); return nil }, destroy: destroy)
|
||||
}
|
||||
|
||||
/// Initialize the signal data.
|
||||
/// - Parameters:
|
||||
/// - closure: The signal's closure.
|
||||
/// - destroy: The self destruction.
|
||||
public init(closure: @escaping ([Any]) -> Any?, destroy: (() -> Void)? = nil) {
|
||||
self.closure = closure
|
||||
self.selfDestruction = destroy
|
||||
}
|
||||
|
||||
/// The return type.
|
||||
public enum ReturnType {
|
||||
|
||||
/// Returns a boolean.
|
||||
case bool
|
||||
|
||||
}
|
||||
|
||||
/// Connect the signal data to a signal.
|
||||
/// - Parameters:
|
||||
/// - pointer: The pointer to the object which holds the signal.
|
||||
/// - signal: The signal's name.
|
||||
/// - argCount: The number of arguments.
|
||||
public func connect(pointer: UnsafeMutableRawPointer?, signal: String, argCount: Int = 0) {
|
||||
/// - return: The return type.
|
||||
public func connect(
|
||||
pointer: UnsafeMutableRawPointer?,
|
||||
signal: String,
|
||||
argCount: Int = 0,
|
||||
return: ReturnType? = nil
|
||||
) {
|
||||
let callback: GCallback
|
||||
if argCount >= 3 {
|
||||
if let `return` {
|
||||
switch `return` {
|
||||
case .bool:
|
||||
callback = unsafeBitCast(boolHandler, to: GCallback.self)
|
||||
}
|
||||
} else if argCount >= 3 {
|
||||
callback = unsafeBitCast(fiveParamsHandler, to: GCallback.self)
|
||||
} else if argCount == 2 {
|
||||
callback = unsafeBitCast(fourParamsHandler, to: GCallback.self)
|
||||
|
||||
@ -48,7 +48,30 @@ extension Storage {
|
||||
pointer: OpaquePointer? = nil,
|
||||
handler: @escaping () -> Void
|
||||
) {
|
||||
connectSignal(name: name, id: id, argCount: argCount, pointer: pointer) { _ in
|
||||
connectSignal(name: name, id: id, argCount: argCount, pointer: pointer) {
|
||||
handler()
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
/// Connect a handler to a signal.
|
||||
/// - Parameters:
|
||||
/// - name: The signal's name.
|
||||
/// - id: The handlers id to separate form others connecting to the signal.
|
||||
/// - connectFlags: The GConnectFlags.
|
||||
/// - argCount: The number of additional arguments (without the first and the last one).
|
||||
/// - return: The return type.
|
||||
/// - pointer: A custom pointer instead of the stored one.
|
||||
/// - handler: The signal's handler.
|
||||
public func connectSignal(
|
||||
name: String,
|
||||
id: String = "",
|
||||
argCount: Int = 0,
|
||||
return: SignalData.ReturnType? = nil,
|
||||
pointer: OpaquePointer? = nil,
|
||||
handler: @escaping () -> Any?
|
||||
) {
|
||||
connectSignal(name: name, id: id, argCount: argCount, return: `return`, pointer: pointer) { _ in
|
||||
handler()
|
||||
}
|
||||
}
|
||||
@ -66,13 +89,42 @@ extension Storage {
|
||||
argCount: Int = 0,
|
||||
pointer: OpaquePointer? = nil,
|
||||
handler: @escaping ([Any]) -> Void
|
||||
) {
|
||||
connectSignal(name: name, id: id, argCount: argCount, pointer: pointer) { args in
|
||||
handler(args)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
/// Connect a handler to a signal.
|
||||
/// - Parameters:
|
||||
/// - name: The signal's name.
|
||||
/// - id: The handlers id to separate form others connecting to the signal.
|
||||
/// - argCount: The number of additional arguments (without the first and the last one).
|
||||
/// - return: The return type.
|
||||
/// - pointer: A custom pointer instead of the stored one.
|
||||
/// - handler: The signal's handler.
|
||||
public func connectSignal(
|
||||
name: String,
|
||||
id: String = "",
|
||||
argCount: Int = 0,
|
||||
return: SignalData.ReturnType? = nil,
|
||||
pointer: OpaquePointer? = nil,
|
||||
handler: @escaping ([Any]) -> Any?
|
||||
) {
|
||||
if let data = fields[name + id] as? SignalData {
|
||||
data.closure = handler
|
||||
} else {
|
||||
let data = SignalData(closure: handler) { [self] in fields[name + id] = nil }
|
||||
fields[name + id] = data
|
||||
data.connect(pointer: (pointer ?? opaquePointer)?.cast(), signal: name, argCount: argCount)
|
||||
data.connect(
|
||||
pointer: (
|
||||
pointer ?? opaquePointer ?? ((self as? SceneStorage)?.pointer as? AdwaitaWindow)?.pointer?.opaque()
|
||||
)?.cast(),
|
||||
signal: name,
|
||||
argCount: argCount,
|
||||
return: `return`
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -47,6 +47,9 @@ public struct Window: AdwaitaSceneElement {
|
||||
var maximized: Binding<Bool>?
|
||||
/// Whether the window uses the development style.
|
||||
var devel: Bool?
|
||||
/// Run this function when the window should close.
|
||||
/// Return true to stop the closing process.
|
||||
var onClose: (() -> Bool)?
|
||||
|
||||
/// Create a window type with a certain identifier and user interface.
|
||||
/// - Parameters:
|
||||
@ -136,6 +139,9 @@ public struct Window: AdwaitaSceneElement {
|
||||
if minWidth != nil || minHeight != nil {
|
||||
gtk_widget_set_size_request(window.pointer?.cast(), .init(minWidth ?? -1), .init(minHeight ?? -1))
|
||||
}
|
||||
storage.connectSignal(name: "close-request", id: "on-close", return: .bool) {
|
||||
(storage.fields["on-close"] as? (() -> Bool))?() ?? false
|
||||
}
|
||||
update(storage, app: app, updateProperties: true)
|
||||
return storage
|
||||
}
|
||||
@ -246,6 +252,9 @@ public struct Window: AdwaitaSceneElement {
|
||||
gtk_window_unmaximize(window.pointer?.cast())
|
||||
}
|
||||
}
|
||||
if let onClose {
|
||||
storage.fields["on-close"] = onClose
|
||||
}
|
||||
storage.previousState = self
|
||||
}
|
||||
|
||||
@ -373,9 +382,19 @@ public struct Window: AdwaitaSceneElement {
|
||||
return newSelf
|
||||
}
|
||||
|
||||
/// Run this closure when the window should be closed.
|
||||
/// - Parameter onClose: The closure. Return true to cancel the closing process.
|
||||
/// - Returns: The window.
|
||||
///
|
||||
/// This does not get executed if the user quits the whole application.
|
||||
public func onClose(onClose: @escaping () -> Bool) -> Self {
|
||||
var newSelf = self
|
||||
newSelf.onClose = onClose
|
||||
return newSelf
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// swiftlint:enable discouraged_optional_collection
|
||||
|
||||
/// An AdwApplicationWindow.
|
||||
public typealias AdwaitaWindow = Window.AdwaitaWindow
|
||||
|
||||
@ -91,6 +91,8 @@ struct Demo: App {
|
||||
@State private var about = false
|
||||
@State private var preferences = false
|
||||
@State private var title: WindowName = .demo
|
||||
@State private var closeAlert = false
|
||||
@State private var destroy = false
|
||||
var window: AdwaitaWindow
|
||||
var app: AdwaitaApp!
|
||||
var pictureURL: URL?
|
||||
@ -172,6 +174,16 @@ struct Demo: App {
|
||||
.title("Extra Action")
|
||||
}
|
||||
}
|
||||
.alertDialog(
|
||||
visible: $closeAlert,
|
||||
heading: "Close this Window?",
|
||||
body: "Nothing will be lost. This is a demo."
|
||||
)
|
||||
.response("Cancel", role: .close) { }
|
||||
.response("Close", appearance: .suggested, role: .default) {
|
||||
destroy = true
|
||||
window.close()
|
||||
}
|
||||
}
|
||||
|
||||
var menu: AnyView {
|
||||
@ -200,6 +212,7 @@ struct Demo: App {
|
||||
window
|
||||
.size(width: $width, height: $height)
|
||||
.maximized($maximized)
|
||||
.onClose { closeAlert = !destroy; return !destroy }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"app-id": "io.github.AparokshaUI.Demo",
|
||||
"runtime": "org.gnome.Platform",
|
||||
"runtime-version": "48",
|
||||
"runtime-version": "49",
|
||||
"sdk": "org.gnome.Sdk",
|
||||
"sdk-extensions": [
|
||||
"org.freedesktop.Sdk.Extension.swift6"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user