Skip to content

Commit

Permalink
Add FileDialog convenience methods.
Browse files Browse the repository at this point in the history
  • Loading branch information
rhx committed Jan 24, 2024
1 parent 48bb7c6 commit afd49e3
Show file tree
Hide file tree
Showing 3 changed files with 147 additions and 3 deletions.
3 changes: 2 additions & 1 deletion Sources/Gtk/FileChooser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@
// SwiftGtk
//
// Created by Rene Hexel on 4/8/19.
// Copyright © 2019, 2020 Rene Hexel. All rights reserved.
// Copyright © 2019, 2020, 2024 Rene Hexel. All rights reserved.
//
import CGtk
import GtkCHelpers
import GLib
import GLibObject
import GIO

@available(*, deprecated, renamed: "FileDialog")
public extension FileChooserDialog {
/// Convenience constructor to create a file chooser dialog with two buttons.
/// - Parameter title: Title of the dialog
Expand Down
7 changes: 5 additions & 2 deletions Sources/Gtk/FileChooserNative.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,22 @@
// Gtk
//
// Created by Rene Hexel on 18/8/19.
// Copyright © 2019, 2020 Rene Hexel. All rights reserved.
// Copyright © 2019, 2020, 2024 Rene Hexel. All rights reserved.
//
import CGtk
import GtkCHelpers
import GLib
import GLibObject
import GIO

@available(*, deprecated, renamed: "FileDialog")
public extension FileChooserNative {
/// Convenence initialiser to create a new, native file chooser
/// - Parameter title: Title of the native file chooser (optional)
/// - Parameter action: File chooser kind, e.g. `.open` or `.save`
/// - Parameter acceptLabel: Text of the accept button or `nil` for the default
/// - Parameter cancelLabel: Text of the cancel button or `nil` for the default
/// - Parameter cancelLabel: Text of the cancel button or `nil` for the defaults
/// - Note: ``FileChooserNative`` has been deprecated in gtk-4.10. Use ``FileDialog`` instead.
@inlinable convenience init(title: UnsafePointer<gchar>! = nil, action: FileChooserAction = .open, acceptLabel: UnsafePointer<gchar>? = nil, cancelLabel: UnsafePointer<gchar>? = nil) {
self.init(gtk_file_chooser_native_new(title, nil, action, acceptLabel, cancelLabel))
}
Expand All @@ -27,6 +29,7 @@ public extension FileChooserNative {
/// - Parameter action: File chooser kind, e.g. `.open` or `.save`
/// - Parameter acceptLabel: Text of the accept button or `nil` for the default
/// - Parameter cancelLabel: Text of the cancel button or `nil` for the default
/// - Note: ``FileChooserNative`` has been deprecated in gtk-4.10. Use ``FileDialog`` instead.
@inlinable convenience init<W: WindowProtocol>(title: UnsafePointer<gchar>! = nil, parent: W, action: FileChooserAction = .open, acceptLabel: UnsafePointer<gchar>? = nil, cancelLabel: UnsafePointer<gchar>? = nil) {
self.init(gtk_file_chooser_native_new(title, parent.window_ptr, action, acceptLabel, cancelLabel))
}
Expand Down
140 changes: 140 additions & 0 deletions Sources/Gtk/FileDialog.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
//
// FileDialog.swift
//
// Created by Rene Hexel on 24/1/2024.
// Copyright © 2024 Rene Hexel. All rights reserved.
//
import CGtk
import GtkCHelpers
import GLib
import GLibObject
import GIO

public extension FileDialogProtocol {
/// Open the file dialog.
///
/// This method initiates an asynchronous file selection operation,
/// showing the dialog to the user. The callback provided will be
/// called when the user has selected a file name, or has cancelled
/// the operation.
///
/// - Parameters:
/// - parentWindow: The parent ``Window`` to attach the dialog to.
/// - cancellable: The ``Cancellable`` to cancel the operation.
/// - callback: The function or closure to call when interaction has completed.
@inlinable
public func open<W: WindowProtocol, C: CancellableProtocol>(parentWindow: W, cancellable: C, callback: @escaping (FileDialogRef, Result<FileRef, any Error>) -> Void) {
open(parentWindowRef: WindowRef(parentWindow), cancellableRef: GIO.CancellableRef(cancellable), callback: callback)
}

/// Open the file dialog.
///
/// This method initiates an asynchronous file selection operation,
/// showing the dialog to the user. The callback provided will be
/// called when the user has selected a file name, or has cancelled
/// the operation.
///
/// - Parameters:
/// - parentWindow: The parent ``Window`` to attach the dialog to.
/// - callback: The function or closure to call when interaction has completed.
@inlinable
public func open<W: WindowProtocol>(parentWindow: W, callback: @escaping (FileDialogRef, Result<FileRef, any Error>) -> Void) {
open(parentWindowRef: WindowRef(parentWindow), cancellableRef: nil, callback: callback)
}

/// Open the file dialog.
///
/// This method initiates an asynchronous file selection operation,
/// showing the dialog to the user. The callback provided will be
/// called when the user has selected a file name, or has cancelled
/// the operation.
///
/// - Parameters:
/// - callback: The function or closure to call when interaction has completed.
@inlinable
public func open(callback: @escaping (FileDialogRef, Result<FileRef, any Error>) -> Void) {
open(parentWindowRef: nil, cancellableRef: nil, callback: callback)
}

/// Open the file dialog.
///
/// This method initiates an asynchronous file selection operation,
/// showing the dialog to the user. The callback provided will be
/// called when the user has selected a file name, or has cancelled
/// the operation.
/// - Parameters:
/// - parentWindowRef: A reference to the parent ``Window``.
/// - cancellableRef: A reference to a ``Cancellable`` to cancel the operation.
/// - callback: The closure to call when interaction has completed.
@inlinable
public func open(parentWindowRef: WindowRef?, cancellableRef: GIO.CancellableRef?, callback: @escaping (FileDialogRef, Result<FileRef, any Error>) -> Void) {
let callbackHolder = ClosureHolder<(FileDialogRef, Result<FileRef, any Error>), Void> { callback($0.0, $0.1) }
let asyncReadyCallbackHolder = unsafeBitCast(Unmanaged.passRetained(callbackHolder).toOpaque(), to: gpointer.self)
open(parent: parentWindowRef, cancellable: cancellableRef, callback: {
(dialogPtr, result, userData) in
let callbackHolder = Unmanaged<ClosureHolder<(FileDialogRef, Result<FileRef, any Error>), Void>>.fromOpaque(userData!).takeRetainedValue()
let dialogRef = FileDialogRef(gpointer: dialogPtr)!
let dialogResult = Result {
try dialogRef.openFinish(result: GIO.AsyncResultRef(result))!
}
callbackHolder.call((dialogRef, dialogResult))
}, userData: asyncReadyCallbackHolder)
}
}

// MARK: - async methods

public extension FileDialogProtocol {
/// Asynchronously opens the file dialog.
///
/// This method initiates an asynchronous file selection operation,
/// showing the dialog to the user. The returned result will contain
/// the file the user has selected, or an errof if the operation was cancelled.
/// - Returns: The result of the file dialog interaction.
@available(macOS 10.15, *)
@inlinable
func open() async -> Result<FileRef, any Error> {
await withCheckedContinuation { continuation in
open {
continuation.resume(returning: $1)
}
}
}

/// Asynchronously opens the file dialog.
///
/// This method initiates an asynchronous file selection operation,
/// showing the dialog to the user. The returned result will contain
/// the file the user has selected, or an errof if the operation was cancelled.
/// - Parameter parentWindow: The parent ``Window`` to attach the dialog to.
/// - Returns: The result of the file dialog interaction.
@available(macOS 10.15, *)
@inlinable
func open<W: WindowProtocol>(parentWindow: W) async -> Result<FileRef, any Error> {
await withCheckedContinuation { continuation in
open(parentWindow: parentWindow) {
continuation.resume(returning: $1)
}
}
}

/// Asynchronously opens the file dialog.
///
/// This method initiates an asynchronous file selection operation,
/// showing the dialog to the user. The returned result will contain
/// the file the user has selected, or an errof if the operation was cancelled.
/// - Returns: The result of the file operation
/// - Parameters:
/// - parentWindow: The parent ``Window`` to attach the dialog to.
/// - cancellable: The ``Cancellable`` to cancel the operation.
@available(macOS 10.15, *)
@inlinable
func open<W: WindowProtocol, C: CancellableProtocol>(parentWindow: W, cancellable: C) async -> Result<FileRef, any Error> {
await withCheckedContinuation { continuation in
open(parentWindow: parentWindow, cancellable: cancellable) {
continuation.resume(returning: $1)
}
}
}

}

0 comments on commit afd49e3

Please sign in to comment.