diff --git a/Sources/SwiftWebUI/SwiftWebUI.swift b/Sources/SwiftWebUI/SwiftWebUI.swift index b1fe331..de20011 100644 --- a/Sources/SwiftWebUI/SwiftWebUI.swift +++ b/Sources/SwiftWebUI/SwiftWebUI.swift @@ -1,13 +1,35 @@ +import Foundation import webui -public typealias Event = UnsafeMutablePointer? +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?) { + 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 @@ -20,8 +42,10 @@ 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. @@ -29,9 +53,7 @@ public final class Window { /// - 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") } } @@ -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)`") } } @@ -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?, 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()) @@ -105,19 +143,20 @@ public func clean() { /// - event: The event object. /// - idx: The argument position starting from 0. public func getArg(_ 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)`") @@ -128,16 +167,15 @@ public func getArg(_ event: Event, _ idx: Int = 0) throws -> T { /// - event: The event object. /// - value: The response value. public func response(_ 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. }