adwaita-swift/Sources/Adwaita/View/ToggleGroup+.swift
david-swift 90e8c78163
Some checks are pending
Deploy Docs / publish (push) Waiting to run
SwiftLint / SwiftLint (push) Waiting to run
Add support for toggle groups
2025-11-03 22:28:28 +01:00

106 lines
3.5 KiB
Swift
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// ToggleGroup+.swift
// Adwaita
//
// Created by david-swift on 03.11.25.
//
import CAdw
import LevenshteinTransformations
extension ToggleGroup {
/// The identifier for the values.
static var values: String { "values" }
/// The identifier for the toggles.
static var toggle: String { "Toggle::" }
/// Initialize a toggle group.
/// - Parameters:
/// - selection: The selected value.
/// - values: The available values.
public init<Element>(
selection: Binding<Element.ID>,
values: [Element]
) where Element: ToggleGroupItem {
self.init()
appearFunctions.append { storage, _ in
storage.notify(name: "active-name", id: "init") {
if let name = adw_toggle_group_get_active_name(storage.opaquePointer),
let values = storage.fields[Self.values] as? [Element],
let value = values.first(where: { $0.id.description == String(cString: name) }) {
selection.wrappedValue = value.id
}
}
Self.updateContent(
storage: storage,
selection: selection.wrappedValue,
values: values,
updateProperties: true
)
}
updateFunctions.append { storage, _, updateProperties in
Self.updateContent(
storage: storage,
selection: selection.wrappedValue,
values: values,
updateProperties: updateProperties
)
}
}
/// Update the combo row's content.
/// - Parameters:
/// - storage: The view storage.
/// - values: The elements.
/// - updateProperties: Whether to update the properties.
static func updateContent<Element>(
storage: ViewStorage,
selection: Element.ID,
values: [Element],
updateProperties: Bool
) where Element: ToggleGroupItem {
guard updateProperties else {
return
}
let old = storage.fields[Self.values] as? [Element] ?? []
old.identifiableTransform(
to: values,
functions: .init { index in
if let id = old[safe: index]?.id.description,
let toggle = storage.fields[Self.toggle + id] as? OpaquePointer {
adw_toggle_group_remove(storage.opaquePointer, toggle)
}
} insert: { _, element in
let toggle = adw_toggle_new()
adw_toggle_set_name(toggle, element.id.description)
if element.showLabel {
adw_toggle_set_label(toggle, element.id.description)
} else {
adw_toggle_set_tooltip(toggle, element.id.description)
}
if let icon = element.icon {
adw_toggle_set_icon_name(toggle, icon.string)
}
storage.fields[Self.toggle + element.id.description] = toggle
adw_toggle_group_add(storage.opaquePointer, toggle)
}
)
storage.fields[Self.values] = values
adw_toggle_group_set_active_name(storage.opaquePointer, selection.description)
}
}
/// An item of a toggle group.
public protocol ToggleGroupItem: Identifiable where Self.ID: CustomStringConvertible {
/// The item's icon.
var icon: Icon? { get }
/// Whether to show the label in the UI (the identifier's string conversion).
///
/// Otherwise, it will be used as the tooltip.
var showLabel: Bool { get }
}