Skip to content

Commit

Permalink
feat: add swift event handler to wrap c event for improved accessibility
Browse files Browse the repository at this point in the history
  • Loading branch information
ttytm committed Jun 15, 2024
1 parent 9479d99 commit 74887df
Showing 1 changed file with 59 additions and 21 deletions.
80 changes: 59 additions & 21 deletions Sources/SwiftWebUI/SwiftWebUI.swift
Original file line number Diff line number Diff line change
@@ -1,13 +1,35 @@
import Foundation
import webui

public typealias Event = UnsafeMutablePointer<webui_event_t>?
public typealias BindCallback = (Event) -> Void

public typealias BindCallback = @convention(c) (Event) -> Void
var callbacks: [Int: BindCallback] = [:]

enum WebUIError: Error {
case runtimeError(String)
}

func swiftEventHandler(_ event: UnsafeMutablePointer<webui_event_t>?) {
let e = event?.pointee
guard let window = e?.window,
let eventType = e?.event_type,
let element = e?.element,
let eventNumber = e?.event_number,
let bindId = e?.bind_id
else {
return
}
let swiftEvent = Event(
window: window,
eventType: eventType,
element: element,
eventNumber: eventNumber,
bindId: bindId
)
// Call user callback function.
callbacks[swiftEvent.bindId]?(swiftEvent)
}

public final class Window {
let id: Int

Expand All @@ -20,18 +42,18 @@ public final class Window {
/// - Parameters:
/// - element: The name under which the function will be callable / the HTML elements ID.
/// - callback: The callback function.
public func bind(_ element: String, _ callback: BindCallback) {
webui_bind(id, element, callback)
// public func bind(_ element: String, _ callback: BindCallbackSwift) {
public func bind(_ element: String, _ callback: @escaping BindCallback) {
let id = webui_bind(id, element, swiftEventHandler)
callbacks[id] = callback
}

/// Shows a window using embedded HTML, or a file.
/// If the window is already open, it will be refreshed.
/// - Parameter html: The HTML, URL, or a local file.
/// - Throws: `WebUIError.runtimeError` if showing the window was not successful.
public func show(_ html: String) throws {
if !(html.withCString { html in
webui_show(id, html)
}) {
if !(html.withCString { html in webui_show(id, html) }) {
throw WebUIError.runtimeError("error: failed to show window")
}
}
Expand All @@ -54,9 +76,7 @@ public final class Window {
/// Sets windows root folder.
/// - Parameter path: The local folder full path.
public func setRootFolder(_ path: String) throws {
if !(path.withCString { p in
webui_set_root_folder(id, p)
}) {
if !(path.withCString { p in webui_set_root_folder(id, p) }) {
throw WebUIError.runtimeError("error: failed to set root folder for window `\(id)`")
}
}
Expand All @@ -70,6 +90,24 @@ public final class Window {
}
}

public struct Event {
let cStruct: webui_event_t
let id: Int
public let window: Int
public let eventType: Int
public let element: String
public let bindId: Int

init(window: Int, eventType: Int, element: UnsafeMutablePointer<CChar>?, eventNumber: Int, bindId: Int) {
cStruct = webui_event_t(window: window, event_type: eventType, element: element, event_number: eventNumber, bind_id: bindId)
id = eventNumber
self.window = window
self.eventType = eventType
self.element = String(cString: element!)
self.bindId = bindId
}
}

/// Creates a new window object.
public func newWindow() -> Window {
return Window(webui_new_window())
Expand Down Expand Up @@ -105,19 +143,20 @@ public func clean() {
/// - event: The event object.
/// - idx: The argument position starting from 0.
public func getArg<T>(_ event: Event, _ idx: Int = 0) throws -> T {
let arg_count = webui_get_count(event)
var cEvent = event.cStruct
let arg_count = webui_get_count(&cEvent)
if idx >= arg_count {
throw WebUIError.runtimeError("error: argument index out of range (index: \(idx), argument count: \(arg_count))")
}
if T.self == String.self {
let str = webui_get_string_at(event, idx)!
let str = webui_get_string_at(&cEvent, idx)!
return String(cString: str) as! T
} else if T.self == Int.self {
return Int(webui_get_int_at(event, idx)) as! T
return Int(webui_get_int_at(&cEvent, idx)) as! T
} else if T.self == Bool.self {
return webui_get_bool_at(event, idx) as! T
return webui_get_bool_at(&cEvent, idx) as! T
} else if T.self == Double.self {
return webui_get_float_at(event, idx) as! T
return webui_get_float_at(&cEvent, idx) as! T
}
// TODO: automatically decode other types.
throw WebUIError.runtimeError("error: failed to get argument at index `\(idx)`")
Expand All @@ -128,16 +167,15 @@ public func getArg<T>(_ event: Event, _ idx: Int = 0) throws -> T {
/// - event: The event object.
/// - value: The response value.
public func response<T>(_ event: Event, _ value: T) {
var cEvent = event.cStruct
if value is String {
(value as! String).withCString { str in
webui_return_string(event, str)
}
(value as! String).withCString { str in webui_return_string(&cEvent, str) }
} else if value is Int {
webui_return_int(event, Int64(value as! Int))
webui_return_int(&cEvent, Int64(value as! Int))
} else if value is Bool {
webui_return_bool(event, value as! Bool)
webui_return_bool(&cEvent, value as! Bool)
} else if value is Double {
webui_return_float(event, value as! Double)
webui_return_float(&cEvent, value as! Double)
}
// TODO: automatically encode other types as JSON string.
}
Expand Down

0 comments on commit 74887df

Please sign in to comment.