Add support for keypaths where sensible #74
This commit is contained in:
parent
c08a9dc3bd
commit
2072c16040
@ -17,27 +17,40 @@ extension DropDown {
|
|||||||
|
|
||||||
/// Initialize a combo row.
|
/// Initialize a combo row.
|
||||||
/// - Parameters:
|
/// - Parameters:
|
||||||
/// - title: The row's title.
|
|
||||||
/// - selection: The selected value.
|
/// - selection: The selected value.
|
||||||
/// - values: The available values.
|
/// - values: The available values.
|
||||||
public init<Element>(
|
public init<Element>(
|
||||||
selection: Binding<Element.ID>,
|
selection: Binding<Element.ID>,
|
||||||
values: [Element]
|
values: [Element]
|
||||||
) where Element: Identifiable, Element: CustomStringConvertible {
|
) where Element: Identifiable, Element: CustomStringConvertible {
|
||||||
|
self.init(selection: selection, values: values, id: \.id, description: \.description)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initialize a combo row.
|
||||||
|
/// - Parameters:
|
||||||
|
/// - title: The row's title.
|
||||||
|
/// - selection: The selected value.
|
||||||
|
/// - values: The available values.
|
||||||
|
public init<Element, Identifier>(
|
||||||
|
selection: Binding<Identifier>,
|
||||||
|
values: [Element],
|
||||||
|
id: KeyPath<Element, Identifier>,
|
||||||
|
description: KeyPath<Element, String>
|
||||||
|
) where Identifier: Equatable {
|
||||||
self.init()
|
self.init()
|
||||||
self = self.selected(.init {
|
self = self.selected(.init {
|
||||||
.init(values.firstIndex { $0.id == selection.wrappedValue } ?? 0)
|
.init(values.firstIndex { $0[keyPath: id] == selection.wrappedValue } ?? 0)
|
||||||
} set: { index in
|
} set: { index in
|
||||||
if let id = values[safe: .init(index)]?.id {
|
if let id = values[safe: .init(index)]?[keyPath: id] {
|
||||||
selection.wrappedValue = id
|
selection.wrappedValue = id
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
appearFunctions.append { storage, _ in
|
appearFunctions.append { storage, _ in
|
||||||
storage.fields[Self.stringList] = gtk_drop_down_get_model(storage.opaquePointer)
|
storage.fields[Self.stringList] = gtk_drop_down_get_model(storage.opaquePointer)
|
||||||
Self.updateContent(storage: storage, values: values, element: Element.self)
|
Self.updateContent(storage: storage, values: values, id: id, description: description)
|
||||||
}
|
}
|
||||||
updateFunctions.append { storage, _, _ in
|
updateFunctions.append { storage, _, _ in
|
||||||
Self.updateContent(storage: storage, values: values, element: Element.self)
|
Self.updateContent(storage: storage, values: values, id: id, description: description)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,20 +58,23 @@ extension DropDown {
|
|||||||
/// - Parameters:
|
/// - Parameters:
|
||||||
/// - storage: The view storage.
|
/// - storage: The view storage.
|
||||||
/// - values: The elements.
|
/// - values: The elements.
|
||||||
/// - element: The type of the elements.
|
/// - id: The keypath to the id.
|
||||||
static func updateContent<Element>(
|
/// - description: The keypath to the description.
|
||||||
|
static func updateContent<Element, Identifier>(
|
||||||
storage: ViewStorage,
|
storage: ViewStorage,
|
||||||
values: [Element],
|
values: [Element],
|
||||||
element: Element.Type
|
id: KeyPath<Element, Identifier>,
|
||||||
) where Element: Identifiable, Element: CustomStringConvertible {
|
description: KeyPath<Element, String>
|
||||||
|
) where Identifier: Equatable {
|
||||||
if let list = storage.fields[Self.stringList] as? OpaquePointer {
|
if let list = storage.fields[Self.stringList] as? OpaquePointer {
|
||||||
let old = storage.fields[Self.values] as? [Element] ?? []
|
let old = storage.fields[Self.values] as? [Element] ?? []
|
||||||
old.identifiableTransform(
|
old.transform(
|
||||||
to: values,
|
to: values,
|
||||||
|
id: id,
|
||||||
functions: .init { index in
|
functions: .init { index in
|
||||||
gtk_string_list_remove(list, .init(index))
|
gtk_string_list_remove(list, .init(index))
|
||||||
} insert: { _, element in
|
} insert: { _, element in
|
||||||
gtk_string_list_append(list, element.description)
|
gtk_string_list_append(list, element[keyPath: description])
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
storage.fields[Self.values] = values
|
storage.fields[Self.values] = values
|
||||||
|
|||||||
@ -17,19 +17,21 @@ extension FlowBox {
|
|||||||
/// Initialize `FlowBox`.
|
/// Initialize `FlowBox`.
|
||||||
/// - Parameters:
|
/// - Parameters:
|
||||||
/// - elements: The elements.
|
/// - elements: The elements.
|
||||||
|
/// - id: The element identifier keypath.
|
||||||
/// - selection: The identifier of the selected element. Selection disabled if `nil`.
|
/// - selection: The identifier of the selected element. Selection disabled if `nil`.
|
||||||
/// - content: The view for an element.
|
/// - content: The view for an element.
|
||||||
public init(
|
public init(
|
||||||
_ elements: [Element],
|
_ elements: [Element],
|
||||||
selection: Binding<Element.ID>? = nil,
|
id: KeyPath<Element, Identifier>,
|
||||||
|
selection: Binding<Identifier>? = nil,
|
||||||
@ViewBuilder content: @escaping (Element) -> Body
|
@ViewBuilder content: @escaping (Element) -> Body
|
||||||
) {
|
) {
|
||||||
self.init(elements, content: content)
|
self.init(elements, id: id, content: content)
|
||||||
let id: (ViewStorage, [Element]) -> Element.ID? = { storage, elements in
|
let getID: (ViewStorage, [Element]) -> Identifier? = { storage, elements in
|
||||||
if let child = g_list_nth_data(gtk_flow_box_get_selected_children(storage.opaquePointer), 0) {
|
if let child = g_list_nth_data(gtk_flow_box_get_selected_children(storage.opaquePointer), 0) {
|
||||||
let element = gtk_flow_box_child_get_child(child.cast())
|
let element = gtk_flow_box_child_get_child(child.cast())
|
||||||
return elements[safe: storage.content[.mainContent]?
|
return elements[safe: storage.content[.mainContent]?
|
||||||
.firstIndex { $0.opaquePointer?.cast() == element }]?.id
|
.firstIndex { $0.opaquePointer?.cast() == element }]?[keyPath: id]
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -37,12 +39,12 @@ extension FlowBox {
|
|||||||
updateFunctions.append { storage, _, _ in
|
updateFunctions.append { storage, _, _ in
|
||||||
storage.connectSignal(name: "selected_children_changed", id: Self.selectionField) {
|
storage.connectSignal(name: "selected_children_changed", id: Self.selectionField) {
|
||||||
if let elements = storage.fields[Self.elementsField] as? [Element],
|
if let elements = storage.fields[Self.elementsField] as? [Element],
|
||||||
let id = id(storage, elements) {
|
let id = getID(storage, elements) {
|
||||||
selection.wrappedValue = id
|
selection.wrappedValue = id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if selection.wrappedValue != id(storage, elements),
|
if selection.wrappedValue != getID(storage, elements),
|
||||||
let index = elements.firstIndex(where: { $0.id == selection.wrappedValue })?.cInt {
|
let index = elements.firstIndex(where: { $0[keyPath: id] == selection.wrappedValue })?.cInt {
|
||||||
gtk_flow_box_select_child(
|
gtk_flow_box_select_child(
|
||||||
storage.opaquePointer,
|
storage.opaquePointer,
|
||||||
gtk_flow_box_get_child_at_index(storage.opaquePointer, index)
|
gtk_flow_box_get_child_at_index(storage.opaquePointer, index)
|
||||||
@ -57,3 +59,20 @@ extension FlowBox {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension FlowBox where Element: Identifiable, Identifier == Element.ID {
|
||||||
|
|
||||||
|
/// Initialize `FlowBox`.
|
||||||
|
/// - Parameters:
|
||||||
|
/// - elements: The elements.
|
||||||
|
/// - selection: The identifier of the selected element. Selection disabled if `nil`.
|
||||||
|
/// - content: The view for an element.
|
||||||
|
public init(
|
||||||
|
_ elements: [Element],
|
||||||
|
selection: Binding<Element.ID>? = nil,
|
||||||
|
@ViewBuilder content: @escaping (Element) -> Body
|
||||||
|
) {
|
||||||
|
self.init(elements, id: \.id, selection: selection, content: content)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import CAdw
|
|||||||
import LevenshteinTransformations
|
import LevenshteinTransformations
|
||||||
|
|
||||||
/// A dynamic list but without a list design in the user interface.
|
/// A dynamic list but without a list design in the user interface.
|
||||||
public struct ForEach<Element>: AdwaitaWidget where Element: Identifiable {
|
public struct ForEach<Element, Identifier>: AdwaitaWidget where Identifier: Equatable {
|
||||||
|
|
||||||
/// The dynamic widget elements.
|
/// The dynamic widget elements.
|
||||||
var elements: [Element]
|
var elements: [Element]
|
||||||
@ -19,12 +19,20 @@ public struct ForEach<Element>: AdwaitaWidget where Element: Identifiable {
|
|||||||
var horizontal: Bool
|
var horizontal: Bool
|
||||||
/// Whether the children should all be the same size.
|
/// Whether the children should all be the same size.
|
||||||
var homogeneous: Bool?
|
var homogeneous: Bool?
|
||||||
|
/// The path to the identifier.
|
||||||
|
var id: KeyPath<Element, Identifier>
|
||||||
|
|
||||||
/// Initialize `ForEach`.
|
/// Initialize `ForEach`.
|
||||||
public init(_ elements: [Element], horizontal: Bool = false, @ViewBuilder content: @escaping (Element) -> Body) {
|
public init(
|
||||||
|
_ elements: [Element],
|
||||||
|
id: KeyPath<Element, Identifier>,
|
||||||
|
horizontal: Bool = false,
|
||||||
|
@ViewBuilder content: @escaping (Element) -> Body
|
||||||
|
) {
|
||||||
self.elements = elements
|
self.elements = elements
|
||||||
self.content = content
|
self.content = content
|
||||||
self.horizontal = horizontal
|
self.horizontal = horizontal
|
||||||
|
self.id = id
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The view storage.
|
/// The view storage.
|
||||||
@ -56,8 +64,9 @@ public struct ForEach<Element>: AdwaitaWidget where Element: Identifiable {
|
|||||||
var contentStorage: [ViewStorage] = storage.content[.mainContent] ?? []
|
var contentStorage: [ViewStorage] = storage.content[.mainContent] ?? []
|
||||||
let old = storage.fields["element"] as? [Element] ?? []
|
let old = storage.fields["element"] as? [Element] ?? []
|
||||||
let widget: UnsafeMutablePointer<GtkBox>? = storage.opaquePointer?.cast()
|
let widget: UnsafeMutablePointer<GtkBox>? = storage.opaquePointer?.cast()
|
||||||
old.identifiableTransform(
|
old.transform(
|
||||||
to: elements,
|
to: elements,
|
||||||
|
id: id,
|
||||||
functions: .init { index in
|
functions: .init { index in
|
||||||
let child = contentStorage[safe: index]?.opaquePointer
|
let child = contentStorage[safe: index]?.opaquePointer
|
||||||
gtk_box_remove(widget, child?.cast())
|
gtk_box_remove(widget, child?.cast())
|
||||||
@ -105,3 +114,15 @@ public struct ForEach<Element>: AdwaitaWidget where Element: Identifiable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension ForEach where Element: Identifiable, Identifier == Element.ID {
|
||||||
|
|
||||||
|
/// Initialize `ForEach`.
|
||||||
|
public init(_ elements: [Element], horizontal: Bool = false, @ViewBuilder content: @escaping (Element) -> Body) {
|
||||||
|
self.elements = elements
|
||||||
|
self.content = content
|
||||||
|
self.horizontal = horizontal
|
||||||
|
self.id = \.id
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@ -26,11 +26,26 @@ extension ComboRow {
|
|||||||
selection: Binding<Element.ID>,
|
selection: Binding<Element.ID>,
|
||||||
values: [Element]
|
values: [Element]
|
||||||
) where Element: Identifiable, Element: CustomStringConvertible {
|
) where Element: Identifiable, Element: CustomStringConvertible {
|
||||||
|
self.init(title, selection: selection, values: values, id: \.id, description: \.description)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initialize a combo row.
|
||||||
|
/// - Parameters:
|
||||||
|
/// - title: The row's title.
|
||||||
|
/// - selection: The selected value.
|
||||||
|
/// - values: The available values.
|
||||||
|
public init<Element, Identifier>(
|
||||||
|
_ title: String,
|
||||||
|
selection: Binding<Identifier>,
|
||||||
|
values: [Element],
|
||||||
|
id: KeyPath<Element, Identifier>,
|
||||||
|
description: KeyPath<Element, String>
|
||||||
|
) where Identifier: Equatable {
|
||||||
self = self.title(title)
|
self = self.title(title)
|
||||||
self = self.selected(.init {
|
self = self.selected(.init {
|
||||||
.init(values.firstIndex { $0.id == selection.wrappedValue } ?? 0)
|
.init(values.firstIndex { $0[keyPath: id] == selection.wrappedValue } ?? 0)
|
||||||
} set: { index in
|
} set: { index in
|
||||||
if let id = values[safe: .init(index)]?.id {
|
if let id = values[safe: .init(index)]?[keyPath: id] {
|
||||||
selection.wrappedValue = id
|
selection.wrappedValue = id
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -39,34 +54,10 @@ extension ComboRow {
|
|||||||
storage.fields[Self.stringList] = list
|
storage.fields[Self.stringList] = list
|
||||||
adw_combo_row_set_model(storage.opaquePointer?.cast(), list)
|
adw_combo_row_set_model(storage.opaquePointer?.cast(), list)
|
||||||
g_object_unref(list?.cast())
|
g_object_unref(list?.cast())
|
||||||
Self.updateContent(storage: storage, values: values, element: Element.self)
|
DropDown.updateContent(storage: storage, values: values, id: id, description: description)
|
||||||
}
|
}
|
||||||
updateFunctions.append { storage, _, _ in
|
updateFunctions.append { storage, _, _ in
|
||||||
Self.updateContent(storage: storage, values: values, element: Element.self)
|
DropDown.updateContent(storage: storage, values: values, id: id, description: description)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Update the combo row's content.
|
|
||||||
/// - Parameters:
|
|
||||||
/// - storage: The view storage.
|
|
||||||
/// - values: The elements.
|
|
||||||
/// - element: The type of the elements.
|
|
||||||
static func updateContent<Element>(
|
|
||||||
storage: ViewStorage,
|
|
||||||
values: [Element],
|
|
||||||
element: Element.Type
|
|
||||||
) where Element: Identifiable, Element: CustomStringConvertible {
|
|
||||||
if let list = storage.fields[Self.stringList] as? OpaquePointer {
|
|
||||||
let old = storage.fields[Self.values] as? [Element] ?? []
|
|
||||||
old.identifiableTransform(
|
|
||||||
to: values,
|
|
||||||
functions: .init { index in
|
|
||||||
gtk_string_list_remove(list, .init(index))
|
|
||||||
} insert: { _, element in
|
|
||||||
gtk_string_list_append(list, element.description)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
storage.fields[Self.values] = values
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// ActionRow.swift
|
// ActionRow.swift
|
||||||
// Adwaita
|
// Adwaita
|
||||||
//
|
//
|
||||||
// Created by auto-generation on 03.02.26.
|
// Created by auto-generation on 04.02.26.
|
||||||
//
|
//
|
||||||
|
|
||||||
import CAdw
|
import CAdw
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// AspectFrame.swift
|
// AspectFrame.swift
|
||||||
// Adwaita
|
// Adwaita
|
||||||
//
|
//
|
||||||
// Created by auto-generation on 03.02.26.
|
// Created by auto-generation on 04.02.26.
|
||||||
//
|
//
|
||||||
|
|
||||||
import CAdw
|
import CAdw
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// Avatar.swift
|
// Avatar.swift
|
||||||
// Adwaita
|
// Adwaita
|
||||||
//
|
//
|
||||||
// Created by auto-generation on 03.02.26.
|
// Created by auto-generation on 04.02.26.
|
||||||
//
|
//
|
||||||
|
|
||||||
import CAdw
|
import CAdw
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// Banner.swift
|
// Banner.swift
|
||||||
// Adwaita
|
// Adwaita
|
||||||
//
|
//
|
||||||
// Created by auto-generation on 03.02.26.
|
// Created by auto-generation on 04.02.26.
|
||||||
//
|
//
|
||||||
|
|
||||||
import CAdw
|
import CAdw
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// Bin.swift
|
// Bin.swift
|
||||||
// Adwaita
|
// Adwaita
|
||||||
//
|
//
|
||||||
// Created by auto-generation on 03.02.26.
|
// Created by auto-generation on 04.02.26.
|
||||||
//
|
//
|
||||||
|
|
||||||
import CAdw
|
import CAdw
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// Box.swift
|
// Box.swift
|
||||||
// Adwaita
|
// Adwaita
|
||||||
//
|
//
|
||||||
// Created by auto-generation on 03.02.26.
|
// Created by auto-generation on 04.02.26.
|
||||||
//
|
//
|
||||||
|
|
||||||
import CAdw
|
import CAdw
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// Button.swift
|
// Button.swift
|
||||||
// Adwaita
|
// Adwaita
|
||||||
//
|
//
|
||||||
// Created by auto-generation on 03.02.26.
|
// Created by auto-generation on 04.02.26.
|
||||||
//
|
//
|
||||||
|
|
||||||
import CAdw
|
import CAdw
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// ButtonContent.swift
|
// ButtonContent.swift
|
||||||
// Adwaita
|
// Adwaita
|
||||||
//
|
//
|
||||||
// Created by auto-generation on 03.02.26.
|
// Created by auto-generation on 04.02.26.
|
||||||
//
|
//
|
||||||
|
|
||||||
import CAdw
|
import CAdw
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// Carousel.swift
|
// Carousel.swift
|
||||||
// Adwaita
|
// Adwaita
|
||||||
//
|
//
|
||||||
// Created by auto-generation on 03.02.26.
|
// Created by auto-generation on 04.02.26.
|
||||||
//
|
//
|
||||||
|
|
||||||
import CAdw
|
import CAdw
|
||||||
@ -19,7 +19,7 @@ import LevenshteinTransformations
|
|||||||
/// to provide page indicators for `AdwCarousel`.
|
/// to provide page indicators for `AdwCarousel`.
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
public struct Carousel<Element>: AdwaitaWidget where Element: Identifiable {
|
public struct Carousel<Element, Identifier>: AdwaitaWidget where Identifier: Equatable {
|
||||||
|
|
||||||
#if exposeGeneratedAppearUpdateFunctions
|
#if exposeGeneratedAppearUpdateFunctions
|
||||||
/// Additional update functions for type extensions.
|
/// Additional update functions for type extensions.
|
||||||
@ -70,11 +70,14 @@ public struct Carousel<Element>: AdwaitaWidget where Element: Identifiable {
|
|||||||
var elements: [Element]
|
var elements: [Element]
|
||||||
/// The dynamic widget content.
|
/// The dynamic widget content.
|
||||||
var content: (Element) -> Body
|
var content: (Element) -> Body
|
||||||
|
/// The dynamic widget identifier key path.
|
||||||
|
var id: KeyPath<Element, Identifier>
|
||||||
|
|
||||||
/// Initialize `Carousel`.
|
/// Initialize `Carousel`.
|
||||||
public init(_ elements: [Element], @ViewBuilder content: @escaping (Element) -> Body) {
|
public init(_ elements: [Element], id: KeyPath<Element, Identifier>, @ViewBuilder content: @escaping (Element) -> Body) {
|
||||||
self.elements = elements
|
self.elements = elements
|
||||||
self.content = content
|
self.content = content
|
||||||
|
self.id = id
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The view storage.
|
/// The view storage.
|
||||||
@ -126,8 +129,9 @@ public struct Carousel<Element>: AdwaitaWidget where Element: Identifiable {
|
|||||||
|
|
||||||
var contentStorage: [ViewStorage] = storage.content[.mainContent] ?? []
|
var contentStorage: [ViewStorage] = storage.content[.mainContent] ?? []
|
||||||
let old = storage.fields["element"] as? [Element] ?? []
|
let old = storage.fields["element"] as? [Element] ?? []
|
||||||
old.identifiableTransform(
|
old.transform(
|
||||||
to: elements,
|
to: elements,
|
||||||
|
id: id,
|
||||||
functions: .init { index in
|
functions: .init { index in
|
||||||
adw_carousel_remove(widget, adw_carousel_get_nth_page(widget, UInt(index).cInt))
|
adw_carousel_remove(widget, adw_carousel_get_nth_page(widget, UInt(index).cInt))
|
||||||
contentStorage.remove(at: index)
|
contentStorage.remove(at: index)
|
||||||
@ -212,3 +216,14 @@ public struct Carousel<Element>: AdwaitaWidget where Element: Identifiable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension Carousel where Element: Identifiable, Identifier == Element.ID {
|
||||||
|
|
||||||
|
/// Initialize `Carousel`.
|
||||||
|
public init(_ elements: [Element], @ViewBuilder content: @escaping (Element) -> Body) {
|
||||||
|
self.elements = elements
|
||||||
|
self.content = content
|
||||||
|
self.id = \.id
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// CenterBox.swift
|
// CenterBox.swift
|
||||||
// Adwaita
|
// Adwaita
|
||||||
//
|
//
|
||||||
// Created by auto-generation on 03.02.26.
|
// Created by auto-generation on 04.02.26.
|
||||||
//
|
//
|
||||||
|
|
||||||
import CAdw
|
import CAdw
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// CheckButton.swift
|
// CheckButton.swift
|
||||||
// Adwaita
|
// Adwaita
|
||||||
//
|
//
|
||||||
// Created by auto-generation on 03.02.26.
|
// Created by auto-generation on 04.02.26.
|
||||||
//
|
//
|
||||||
|
|
||||||
import CAdw
|
import CAdw
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// Clamp.swift
|
// Clamp.swift
|
||||||
// Adwaita
|
// Adwaita
|
||||||
//
|
//
|
||||||
// Created by auto-generation on 03.02.26.
|
// Created by auto-generation on 04.02.26.
|
||||||
//
|
//
|
||||||
|
|
||||||
import CAdw
|
import CAdw
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// ComboRow.swift
|
// ComboRow.swift
|
||||||
// Adwaita
|
// Adwaita
|
||||||
//
|
//
|
||||||
// Created by auto-generation on 03.02.26.
|
// Created by auto-generation on 04.02.26.
|
||||||
//
|
//
|
||||||
|
|
||||||
import CAdw
|
import CAdw
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// DropDown.swift
|
// DropDown.swift
|
||||||
// Adwaita
|
// Adwaita
|
||||||
//
|
//
|
||||||
// Created by auto-generation on 03.02.26.
|
// Created by auto-generation on 04.02.26.
|
||||||
//
|
//
|
||||||
|
|
||||||
import CAdw
|
import CAdw
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// Entry.swift
|
// Entry.swift
|
||||||
// Adwaita
|
// Adwaita
|
||||||
//
|
//
|
||||||
// Created by auto-generation on 03.02.26.
|
// Created by auto-generation on 04.02.26.
|
||||||
//
|
//
|
||||||
|
|
||||||
import CAdw
|
import CAdw
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// EntryRow.swift
|
// EntryRow.swift
|
||||||
// Adwaita
|
// Adwaita
|
||||||
//
|
//
|
||||||
// Created by auto-generation on 03.02.26.
|
// Created by auto-generation on 04.02.26.
|
||||||
//
|
//
|
||||||
|
|
||||||
import CAdw
|
import CAdw
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// ExpanderRow.swift
|
// ExpanderRow.swift
|
||||||
// Adwaita
|
// Adwaita
|
||||||
//
|
//
|
||||||
// Created by auto-generation on 03.02.26.
|
// Created by auto-generation on 04.02.26.
|
||||||
//
|
//
|
||||||
|
|
||||||
import CAdw
|
import CAdw
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// Fixed.swift
|
// Fixed.swift
|
||||||
// Adwaita
|
// Adwaita
|
||||||
//
|
//
|
||||||
// Created by auto-generation on 03.02.26.
|
// Created by auto-generation on 04.02.26.
|
||||||
//
|
//
|
||||||
|
|
||||||
import CAdw
|
import CAdw
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// FlowBox.swift
|
// FlowBox.swift
|
||||||
// Adwaita
|
// Adwaita
|
||||||
//
|
//
|
||||||
// Created by auto-generation on 03.02.26.
|
// Created by auto-generation on 04.02.26.
|
||||||
//
|
//
|
||||||
|
|
||||||
import CAdw
|
import CAdw
|
||||||
@ -37,7 +37,7 @@ import LevenshteinTransformations
|
|||||||
/// Also see `Gtk.ListBox`.
|
/// Also see `Gtk.ListBox`.
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
public struct FlowBox<Element>: AdwaitaWidget where Element: Identifiable {
|
public struct FlowBox<Element, Identifier>: AdwaitaWidget where Identifier: Equatable {
|
||||||
|
|
||||||
#if exposeGeneratedAppearUpdateFunctions
|
#if exposeGeneratedAppearUpdateFunctions
|
||||||
/// Additional update functions for type extensions.
|
/// Additional update functions for type extensions.
|
||||||
@ -130,11 +130,14 @@ public struct FlowBox<Element>: AdwaitaWidget where Element: Identifiable {
|
|||||||
var elements: [Element]
|
var elements: [Element]
|
||||||
/// The dynamic widget content.
|
/// The dynamic widget content.
|
||||||
var content: (Element) -> Body
|
var content: (Element) -> Body
|
||||||
|
/// The dynamic widget identifier key path.
|
||||||
|
var id: KeyPath<Element, Identifier>
|
||||||
|
|
||||||
/// Initialize `FlowBox`.
|
/// Initialize `FlowBox`.
|
||||||
init(_ elements: [Element], @ViewBuilder content: @escaping (Element) -> Body) {
|
init(_ elements: [Element], id: KeyPath<Element, Identifier>, @ViewBuilder content: @escaping (Element) -> Body) {
|
||||||
self.elements = elements
|
self.elements = elements
|
||||||
self.content = content
|
self.content = content
|
||||||
|
self.id = id
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The view storage.
|
/// The view storage.
|
||||||
@ -216,8 +219,9 @@ public struct FlowBox<Element>: AdwaitaWidget where Element: Identifiable {
|
|||||||
|
|
||||||
var contentStorage: [ViewStorage] = storage.content[.mainContent] ?? []
|
var contentStorage: [ViewStorage] = storage.content[.mainContent] ?? []
|
||||||
let old = storage.fields["element"] as? [Element] ?? []
|
let old = storage.fields["element"] as? [Element] ?? []
|
||||||
old.identifiableTransform(
|
old.transform(
|
||||||
to: elements,
|
to: elements,
|
||||||
|
id: id,
|
||||||
functions: .init { index in
|
functions: .init { index in
|
||||||
gtk_flow_box_remove(widget, gtk_flow_box_get_child_at_index(widget, index.cInt)?.cast())
|
gtk_flow_box_remove(widget, gtk_flow_box_get_child_at_index(widget, index.cInt)?.cast())
|
||||||
contentStorage.remove(at: index)
|
contentStorage.remove(at: index)
|
||||||
@ -377,3 +381,14 @@ public struct FlowBox<Element>: AdwaitaWidget where Element: Identifiable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension FlowBox where Element: Identifiable, Identifier == Element.ID {
|
||||||
|
|
||||||
|
/// Initialize `FlowBox`.
|
||||||
|
public init(_ elements: [Element], @ViewBuilder content: @escaping (Element) -> Body) {
|
||||||
|
self.elements = elements
|
||||||
|
self.content = content
|
||||||
|
self.id = \.id
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// HeaderBar.swift
|
// HeaderBar.swift
|
||||||
// Adwaita
|
// Adwaita
|
||||||
//
|
//
|
||||||
// Created by auto-generation on 03.02.26.
|
// Created by auto-generation on 04.02.26.
|
||||||
//
|
//
|
||||||
|
|
||||||
import CAdw
|
import CAdw
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// Image.swift
|
// Image.swift
|
||||||
// Adwaita
|
// Adwaita
|
||||||
//
|
//
|
||||||
// Created by auto-generation on 03.02.26.
|
// Created by auto-generation on 04.02.26.
|
||||||
//
|
//
|
||||||
|
|
||||||
import CAdw
|
import CAdw
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// Label.swift
|
// Label.swift
|
||||||
// Adwaita
|
// Adwaita
|
||||||
//
|
//
|
||||||
// Created by auto-generation on 03.02.26.
|
// Created by auto-generation on 04.02.26.
|
||||||
//
|
//
|
||||||
|
|
||||||
import CAdw
|
import CAdw
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// LevelBar.swift
|
// LevelBar.swift
|
||||||
// Adwaita
|
// Adwaita
|
||||||
//
|
//
|
||||||
// Created by auto-generation on 03.02.26.
|
// Created by auto-generation on 04.02.26.
|
||||||
//
|
//
|
||||||
|
|
||||||
import CAdw
|
import CAdw
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// LinkButton.swift
|
// LinkButton.swift
|
||||||
// Adwaita
|
// Adwaita
|
||||||
//
|
//
|
||||||
// Created by auto-generation on 03.02.26.
|
// Created by auto-generation on 04.02.26.
|
||||||
//
|
//
|
||||||
|
|
||||||
import CAdw
|
import CAdw
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// ListBox.swift
|
// ListBox.swift
|
||||||
// Adwaita
|
// Adwaita
|
||||||
//
|
//
|
||||||
// Created by auto-generation on 03.02.26.
|
// Created by auto-generation on 04.02.26.
|
||||||
//
|
//
|
||||||
|
|
||||||
import CAdw
|
import CAdw
|
||||||
@ -34,7 +34,7 @@ import LevenshteinTransformations
|
|||||||
/// as selected when the user tries to select it.
|
/// as selected when the user tries to select it.
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
public struct ListBox<Element>: AdwaitaWidget where Element: Identifiable {
|
public struct ListBox<Element, Identifier>: AdwaitaWidget where Identifier: Equatable {
|
||||||
|
|
||||||
#if exposeGeneratedAppearUpdateFunctions
|
#if exposeGeneratedAppearUpdateFunctions
|
||||||
/// Additional update functions for type extensions.
|
/// Additional update functions for type extensions.
|
||||||
@ -107,11 +107,14 @@ public struct ListBox<Element>: AdwaitaWidget where Element: Identifiable {
|
|||||||
var elements: [Element]
|
var elements: [Element]
|
||||||
/// The dynamic widget content.
|
/// The dynamic widget content.
|
||||||
var content: (Element) -> Body
|
var content: (Element) -> Body
|
||||||
|
/// The dynamic widget identifier key path.
|
||||||
|
var id: KeyPath<Element, Identifier>
|
||||||
|
|
||||||
/// Initialize `ListBox`.
|
/// Initialize `ListBox`.
|
||||||
public init(_ elements: [Element], @ViewBuilder content: @escaping (Element) -> Body) {
|
public init(_ elements: [Element], id: KeyPath<Element, Identifier>, @ViewBuilder content: @escaping (Element) -> Body) {
|
||||||
self.elements = elements
|
self.elements = elements
|
||||||
self.content = content
|
self.content = content
|
||||||
|
self.id = id
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The view storage.
|
/// The view storage.
|
||||||
@ -186,8 +189,9 @@ public struct ListBox<Element>: AdwaitaWidget where Element: Identifiable {
|
|||||||
|
|
||||||
var contentStorage: [ViewStorage] = storage.content[.mainContent] ?? []
|
var contentStorage: [ViewStorage] = storage.content[.mainContent] ?? []
|
||||||
let old = storage.fields["element"] as? [Element] ?? []
|
let old = storage.fields["element"] as? [Element] ?? []
|
||||||
old.identifiableTransform(
|
old.transform(
|
||||||
to: elements,
|
to: elements,
|
||||||
|
id: id,
|
||||||
functions: .init { index in
|
functions: .init { index in
|
||||||
gtk_list_box_remove(widget, gtk_list_box_get_row_at_index(widget, index.cInt)?.cast())
|
gtk_list_box_remove(widget, gtk_list_box_get_row_at_index(widget, index.cInt)?.cast())
|
||||||
contentStorage.remove(at: index)
|
contentStorage.remove(at: index)
|
||||||
@ -320,3 +324,14 @@ public struct ListBox<Element>: AdwaitaWidget where Element: Identifiable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension ListBox where Element: Identifiable, Identifier == Element.ID {
|
||||||
|
|
||||||
|
/// Initialize `ListBox`.
|
||||||
|
public init(_ elements: [Element], @ViewBuilder content: @escaping (Element) -> Body) {
|
||||||
|
self.elements = elements
|
||||||
|
self.content = content
|
||||||
|
self.id = \.id
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// Menu.swift
|
// Menu.swift
|
||||||
// Adwaita
|
// Adwaita
|
||||||
//
|
//
|
||||||
// Created by auto-generation on 03.02.26.
|
// Created by auto-generation on 04.02.26.
|
||||||
//
|
//
|
||||||
|
|
||||||
import CAdw
|
import CAdw
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// NavigationView.swift
|
// NavigationView.swift
|
||||||
// Adwaita
|
// Adwaita
|
||||||
//
|
//
|
||||||
// Created by auto-generation on 03.02.26.
|
// Created by auto-generation on 04.02.26.
|
||||||
//
|
//
|
||||||
|
|
||||||
import CAdw
|
import CAdw
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// Overlay.swift
|
// Overlay.swift
|
||||||
// Adwaita
|
// Adwaita
|
||||||
//
|
//
|
||||||
// Created by auto-generation on 03.02.26.
|
// Created by auto-generation on 04.02.26.
|
||||||
//
|
//
|
||||||
|
|
||||||
import CAdw
|
import CAdw
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// OverlaySplitView.swift
|
// OverlaySplitView.swift
|
||||||
// Adwaita
|
// Adwaita
|
||||||
//
|
//
|
||||||
// Created by auto-generation on 03.02.26.
|
// Created by auto-generation on 04.02.26.
|
||||||
//
|
//
|
||||||
|
|
||||||
import CAdw
|
import CAdw
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// PasswordEntryRow.swift
|
// PasswordEntryRow.swift
|
||||||
// Adwaita
|
// Adwaita
|
||||||
//
|
//
|
||||||
// Created by auto-generation on 03.02.26.
|
// Created by auto-generation on 04.02.26.
|
||||||
//
|
//
|
||||||
|
|
||||||
import CAdw
|
import CAdw
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// Picture.swift
|
// Picture.swift
|
||||||
// Adwaita
|
// Adwaita
|
||||||
//
|
//
|
||||||
// Created by auto-generation on 03.02.26.
|
// Created by auto-generation on 04.02.26.
|
||||||
//
|
//
|
||||||
|
|
||||||
import CAdw
|
import CAdw
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// Popover.swift
|
// Popover.swift
|
||||||
// Adwaita
|
// Adwaita
|
||||||
//
|
//
|
||||||
// Created by auto-generation on 03.02.26.
|
// Created by auto-generation on 04.02.26.
|
||||||
//
|
//
|
||||||
|
|
||||||
import CAdw
|
import CAdw
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// PreferencesGroup.swift
|
// PreferencesGroup.swift
|
||||||
// Adwaita
|
// Adwaita
|
||||||
//
|
//
|
||||||
// Created by auto-generation on 03.02.26.
|
// Created by auto-generation on 04.02.26.
|
||||||
//
|
//
|
||||||
|
|
||||||
import CAdw
|
import CAdw
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// PreferencesPage.swift
|
// PreferencesPage.swift
|
||||||
// Adwaita
|
// Adwaita
|
||||||
//
|
//
|
||||||
// Created by auto-generation on 03.02.26.
|
// Created by auto-generation on 04.02.26.
|
||||||
//
|
//
|
||||||
|
|
||||||
import CAdw
|
import CAdw
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// PreferencesRow.swift
|
// PreferencesRow.swift
|
||||||
// Adwaita
|
// Adwaita
|
||||||
//
|
//
|
||||||
// Created by auto-generation on 03.02.26.
|
// Created by auto-generation on 04.02.26.
|
||||||
//
|
//
|
||||||
|
|
||||||
import CAdw
|
import CAdw
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// ProgressBar.swift
|
// ProgressBar.swift
|
||||||
// Adwaita
|
// Adwaita
|
||||||
//
|
//
|
||||||
// Created by auto-generation on 03.02.26.
|
// Created by auto-generation on 04.02.26.
|
||||||
//
|
//
|
||||||
|
|
||||||
import CAdw
|
import CAdw
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// ScrolledWindow.swift
|
// ScrolledWindow.swift
|
||||||
// Adwaita
|
// Adwaita
|
||||||
//
|
//
|
||||||
// Created by auto-generation on 03.02.26.
|
// Created by auto-generation on 04.02.26.
|
||||||
//
|
//
|
||||||
|
|
||||||
import CAdw
|
import CAdw
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// SearchBar.swift
|
// SearchBar.swift
|
||||||
// Adwaita
|
// Adwaita
|
||||||
//
|
//
|
||||||
// Created by auto-generation on 03.02.26.
|
// Created by auto-generation on 04.02.26.
|
||||||
//
|
//
|
||||||
|
|
||||||
import CAdw
|
import CAdw
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// SearchEntry.swift
|
// SearchEntry.swift
|
||||||
// Adwaita
|
// Adwaita
|
||||||
//
|
//
|
||||||
// Created by auto-generation on 03.02.26.
|
// Created by auto-generation on 04.02.26.
|
||||||
//
|
//
|
||||||
|
|
||||||
import CAdw
|
import CAdw
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// Separator.swift
|
// Separator.swift
|
||||||
// Adwaita
|
// Adwaita
|
||||||
//
|
//
|
||||||
// Created by auto-generation on 03.02.26.
|
// Created by auto-generation on 04.02.26.
|
||||||
//
|
//
|
||||||
|
|
||||||
import CAdw
|
import CAdw
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// SpinRow.swift
|
// SpinRow.swift
|
||||||
// Adwaita
|
// Adwaita
|
||||||
//
|
//
|
||||||
// Created by auto-generation on 03.02.26.
|
// Created by auto-generation on 04.02.26.
|
||||||
//
|
//
|
||||||
|
|
||||||
import CAdw
|
import CAdw
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// Spinner.swift
|
// Spinner.swift
|
||||||
// Adwaita
|
// Adwaita
|
||||||
//
|
//
|
||||||
// Created by auto-generation on 03.02.26.
|
// Created by auto-generation on 04.02.26.
|
||||||
//
|
//
|
||||||
|
|
||||||
import CAdw
|
import CAdw
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// SplitButton.swift
|
// SplitButton.swift
|
||||||
// Adwaita
|
// Adwaita
|
||||||
//
|
//
|
||||||
// Created by auto-generation on 03.02.26.
|
// Created by auto-generation on 04.02.26.
|
||||||
//
|
//
|
||||||
|
|
||||||
import CAdw
|
import CAdw
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// StatusPage.swift
|
// StatusPage.swift
|
||||||
// Adwaita
|
// Adwaita
|
||||||
//
|
//
|
||||||
// Created by auto-generation on 03.02.26.
|
// Created by auto-generation on 04.02.26.
|
||||||
//
|
//
|
||||||
|
|
||||||
import CAdw
|
import CAdw
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// SwitchRow.swift
|
// SwitchRow.swift
|
||||||
// Adwaita
|
// Adwaita
|
||||||
//
|
//
|
||||||
// Created by auto-generation on 03.02.26.
|
// Created by auto-generation on 04.02.26.
|
||||||
//
|
//
|
||||||
|
|
||||||
import CAdw
|
import CAdw
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// ToastOverlay.swift
|
// ToastOverlay.swift
|
||||||
// Adwaita
|
// Adwaita
|
||||||
//
|
//
|
||||||
// Created by auto-generation on 03.02.26.
|
// Created by auto-generation on 04.02.26.
|
||||||
//
|
//
|
||||||
|
|
||||||
import CAdw
|
import CAdw
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// ToggleButton.swift
|
// ToggleButton.swift
|
||||||
// Adwaita
|
// Adwaita
|
||||||
//
|
//
|
||||||
// Created by auto-generation on 03.02.26.
|
// Created by auto-generation on 04.02.26.
|
||||||
//
|
//
|
||||||
|
|
||||||
import CAdw
|
import CAdw
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// ToggleGroup.swift
|
// ToggleGroup.swift
|
||||||
// Adwaita
|
// Adwaita
|
||||||
//
|
//
|
||||||
// Created by auto-generation on 03.02.26.
|
// Created by auto-generation on 04.02.26.
|
||||||
//
|
//
|
||||||
|
|
||||||
import CAdw
|
import CAdw
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// ToolbarView.swift
|
// ToolbarView.swift
|
||||||
// Adwaita
|
// Adwaita
|
||||||
//
|
//
|
||||||
// Created by auto-generation on 03.02.26.
|
// Created by auto-generation on 04.02.26.
|
||||||
//
|
//
|
||||||
|
|
||||||
import CAdw
|
import CAdw
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// WindowTitle.swift
|
// WindowTitle.swift
|
||||||
// Adwaita
|
// Adwaita
|
||||||
//
|
//
|
||||||
// Created by auto-generation on 03.02.26.
|
// Created by auto-generation on 04.02.26.
|
||||||
//
|
//
|
||||||
|
|
||||||
import CAdw
|
import CAdw
|
||||||
|
|||||||
@ -1,24 +0,0 @@
|
|||||||
//
|
|
||||||
// List+.swift
|
|
||||||
// Adwaita
|
|
||||||
//
|
|
||||||
// Created by david-swift on 16.10.24.
|
|
||||||
//
|
|
||||||
|
|
||||||
extension List {
|
|
||||||
|
|
||||||
/// Add the "navigation-sidebar" style class.
|
|
||||||
/// - Parameter active: Whether the style is applied.
|
|
||||||
/// - Returns: A view.
|
|
||||||
public func sidebarStyle(_ active: Bool = true) -> AnyView {
|
|
||||||
style("navigation-sidebar", active: active)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Apply the boxed list style class.
|
|
||||||
/// - Parameter active: Whether the style is applied.
|
|
||||||
/// - Returns: A view.
|
|
||||||
public func boxedList(_ active: Bool = true) -> AnyView {
|
|
||||||
style("boxed-list", active: active)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -21,17 +21,19 @@ extension List {
|
|||||||
/// Initialize `List`.
|
/// Initialize `List`.
|
||||||
/// - Parameters:
|
/// - Parameters:
|
||||||
/// - elements: The elements.
|
/// - elements: The elements.
|
||||||
|
/// - id: The key path to the elements' identifiers.
|
||||||
/// - selection: The identifier of the selected element. Selection disabled if `nil`.
|
/// - selection: The identifier of the selected element. Selection disabled if `nil`.
|
||||||
/// - content: The view for an element.
|
/// - content: The view for an element.
|
||||||
public init(
|
public init(
|
||||||
_ elements: [Element],
|
_ elements: [Element],
|
||||||
selection: Binding<Element.ID>?,
|
id: KeyPath<Element, Identifier>,
|
||||||
|
selection: Binding<Identifier>?,
|
||||||
@ViewBuilder content: @escaping (Element) -> Body
|
@ViewBuilder content: @escaping (Element) -> Body
|
||||||
) {
|
) {
|
||||||
self.init(elements, content: content)
|
self.init(elements, id: id, content: content)
|
||||||
let id: (ViewStorage, [Element]) -> Element.ID? = { storage, elements in
|
let getID: (ViewStorage, [Element]) -> Identifier? = { storage, elements in
|
||||||
if let row = gtk_list_box_get_selected_row(storage.opaquePointer) {
|
if let row = gtk_list_box_get_selected_row(storage.opaquePointer) {
|
||||||
return elements[safe: .init(gtk_list_box_row_get_index(row))]?.id
|
return elements[safe: .init(gtk_list_box_row_get_index(row))]?[keyPath: id]
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -39,13 +41,13 @@ extension List {
|
|||||||
updateFunctions.append { storage, _, _ in
|
updateFunctions.append { storage, _, _ in
|
||||||
storage.connectSignal(name: "selected_rows_changed", id: Self.selectionField) {
|
storage.connectSignal(name: "selected_rows_changed", id: Self.selectionField) {
|
||||||
if let elements = storage.fields[Self.elementsField] as? [Element],
|
if let elements = storage.fields[Self.elementsField] as? [Element],
|
||||||
let id = id(storage, elements),
|
let id = getID(storage, elements),
|
||||||
selection.wrappedValue != id {
|
selection.wrappedValue != id {
|
||||||
selection.wrappedValue = id
|
selection.wrappedValue = id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if selection.wrappedValue != id(storage, elements),
|
if selection.wrappedValue != getID(storage, elements),
|
||||||
let index = elements.firstIndex(where: { $0.id == selection.wrappedValue })?.cInt {
|
let index = elements.firstIndex(where: { $0[keyPath: id] == selection.wrappedValue })?.cInt {
|
||||||
gtk_list_box_select_row(
|
gtk_list_box_select_row(
|
||||||
storage.opaquePointer,
|
storage.opaquePointer,
|
||||||
gtk_list_box_get_row_at_index(storage.opaquePointer, index)
|
gtk_list_box_get_row_at_index(storage.opaquePointer, index)
|
||||||
@ -59,4 +61,35 @@ extension List {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Add the "navigation-sidebar" style class.
|
||||||
|
/// - Parameter active: Whether the style is applied.
|
||||||
|
/// - Returns: A view.
|
||||||
|
public func sidebarStyle(_ active: Bool = true) -> AnyView {
|
||||||
|
style("navigation-sidebar", active: active)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Apply the boxed list style class.
|
||||||
|
/// - Parameter active: Whether the style is applied.
|
||||||
|
/// - Returns: A view.
|
||||||
|
public func boxedList(_ active: Bool = true) -> AnyView {
|
||||||
|
style("boxed-list", active: active)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension List where Element: Identifiable, Element.ID == Identifier {
|
||||||
|
|
||||||
|
/// Initialize `List`.
|
||||||
|
/// - Parameters:
|
||||||
|
/// - elements: The elements.
|
||||||
|
/// - selection: The identifier of the selected element. Selection disabled if `nil`.
|
||||||
|
/// - content: The view for an element.
|
||||||
|
public init(
|
||||||
|
_ elements: [Element],
|
||||||
|
selection: Binding<Element.ID>?,
|
||||||
|
@ViewBuilder content: @escaping (Element) -> Body
|
||||||
|
) {
|
||||||
|
self.init(elements, id: \.id, selection: selection, content: content)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,72 +23,103 @@ extension ToggleGroup {
|
|||||||
selection: Binding<Element.ID>,
|
selection: Binding<Element.ID>,
|
||||||
values: [Element]
|
values: [Element]
|
||||||
) where Element: ToggleGroupItem {
|
) where Element: ToggleGroupItem {
|
||||||
|
self.init(
|
||||||
|
selection: selection,
|
||||||
|
values: values,
|
||||||
|
id: \.id,
|
||||||
|
label: \.id.description,
|
||||||
|
icon: \.icon,
|
||||||
|
showLabel: \.showLabel
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initialize a toggle group.
|
||||||
|
/// - Parameters:
|
||||||
|
/// - selection: The selected value.
|
||||||
|
/// - values: The available values.
|
||||||
|
/// - id: The path to the identifier.
|
||||||
|
/// - label: The path to the label.
|
||||||
|
/// - icon: The path to the icon.
|
||||||
|
/// - showLabel: The path to the boolean that defines whether to show an element's label.
|
||||||
|
public init<Element, Identifier>(
|
||||||
|
selection: Binding<Identifier>,
|
||||||
|
values: [Element],
|
||||||
|
id: KeyPath<Element, Identifier>,
|
||||||
|
label: KeyPath<Element, String>,
|
||||||
|
icon: KeyPath<Element, Icon?>? = nil,
|
||||||
|
showLabel: KeyPath<Element, Bool>? = nil
|
||||||
|
) where Identifier: Equatable {
|
||||||
self.init()
|
self.init()
|
||||||
appearFunctions.append { storage, _ in
|
appearFunctions.append { storage, _ in
|
||||||
storage.notify(name: "active-name", id: "init") {
|
storage.notify(name: "active-name", id: "init") {
|
||||||
if let name = adw_toggle_group_get_active_name(storage.opaquePointer),
|
if let name = adw_toggle_group_get_active_name(storage.opaquePointer),
|
||||||
let values = storage.fields[Self.values] as? [Element],
|
let values = storage.fields[Self.values] as? [Element],
|
||||||
let value = values.first(where: { $0.id.description == String(cString: name) }) {
|
let identifier = values
|
||||||
selection.wrappedValue = value.id
|
.map({ $0[keyPath: label] }).first(where: { $0.description == String(cString: name) }),
|
||||||
|
let value = values.first(where: { $0[keyPath: label] == identifier }) {
|
||||||
|
selection.wrappedValue = value[keyPath: id]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Self.updateContent(
|
|
||||||
storage: storage,
|
|
||||||
selection: selection.wrappedValue,
|
|
||||||
values: values,
|
|
||||||
updateProperties: true
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
updateFunctions.append { storage, _, updateProperties in
|
updateFunctions.append { storage, _, updateProperties in
|
||||||
Self.updateContent(
|
Self.updateContent(
|
||||||
storage: storage,
|
storage: storage,
|
||||||
selection: selection.wrappedValue,
|
selection: selection.wrappedValue,
|
||||||
values: values,
|
values: values,
|
||||||
|
id: id,
|
||||||
|
label: label,
|
||||||
|
icon: icon,
|
||||||
|
showLabel: showLabel,
|
||||||
updateProperties: updateProperties
|
updateProperties: updateProperties
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// swiftlint:disable function_parameter_count
|
||||||
/// Update the combo row's content.
|
/// Update the combo row's content.
|
||||||
/// - Parameters:
|
static func updateContent<Element, Identifier>(
|
||||||
/// - storage: The view storage.
|
|
||||||
/// - values: The elements.
|
|
||||||
/// - updateProperties: Whether to update the properties.
|
|
||||||
static func updateContent<Element>(
|
|
||||||
storage: ViewStorage,
|
storage: ViewStorage,
|
||||||
selection: Element.ID,
|
selection: Identifier,
|
||||||
values: [Element],
|
values: [Element],
|
||||||
|
id: KeyPath<Element, Identifier>,
|
||||||
|
label: KeyPath<Element, String>,
|
||||||
|
icon: KeyPath<Element, Icon?>?,
|
||||||
|
showLabel: KeyPath<Element, Bool>?,
|
||||||
updateProperties: Bool
|
updateProperties: Bool
|
||||||
) where Element: ToggleGroupItem {
|
) where Identifier: Equatable {
|
||||||
guard updateProperties else {
|
guard updateProperties else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let old = storage.fields[Self.values] as? [Element] ?? []
|
let old = storage.fields[Self.values] as? [Element] ?? []
|
||||||
old.identifiableTransform(
|
old.transform(
|
||||||
to: values,
|
to: values,
|
||||||
|
id: id,
|
||||||
functions: .init { index in
|
functions: .init { index in
|
||||||
if let id = old[safe: index]?.id.description,
|
if let id = old[safe: index]?[keyPath: label],
|
||||||
let toggle = storage.fields[Self.toggle + id] as? OpaquePointer {
|
let toggle = storage.fields[Self.toggle + id] as? OpaquePointer {
|
||||||
adw_toggle_group_remove(storage.opaquePointer, toggle)
|
adw_toggle_group_remove(storage.opaquePointer, toggle)
|
||||||
}
|
}
|
||||||
} insert: { _, element in
|
} insert: { _, element in
|
||||||
let toggle = adw_toggle_new()
|
let toggle = adw_toggle_new()
|
||||||
adw_toggle_set_name(toggle, element.id.description)
|
adw_toggle_set_name(toggle, element[keyPath: label])
|
||||||
if element.showLabel {
|
if let showLabel, !element[keyPath: showLabel] {
|
||||||
adw_toggle_set_label(toggle, element.id.description)
|
adw_toggle_set_tooltip(toggle, element[keyPath: label])
|
||||||
} else {
|
} else {
|
||||||
adw_toggle_set_tooltip(toggle, element.id.description)
|
adw_toggle_set_label(toggle, element[keyPath: label])
|
||||||
}
|
}
|
||||||
if let icon = element.icon {
|
if let icon, let icon = element[keyPath: icon] {
|
||||||
adw_toggle_set_icon_name(toggle, icon.string)
|
adw_toggle_set_icon_name(toggle, icon.string)
|
||||||
}
|
}
|
||||||
storage.fields[Self.toggle + element.id.description] = toggle
|
storage.fields[Self.toggle + element[keyPath: label]] = toggle
|
||||||
adw_toggle_group_add(storage.opaquePointer, toggle)
|
adw_toggle_group_add(storage.opaquePointer, toggle)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
storage.fields[Self.values] = values
|
storage.fields[Self.values] = values
|
||||||
adw_toggle_group_set_active_name(storage.opaquePointer, selection.description)
|
if let selection = values.first(where: { $0[keyPath: id] == selection }) {
|
||||||
|
adw_toggle_group_set_active_name(storage.opaquePointer, selection[keyPath: label])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
// swiftlint:enable function_parameter_count
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -15,8 +15,13 @@ struct ToggleGroupDemo: View {
|
|||||||
@State private var selection: Subview = .view1
|
@State private var selection: Subview = .view1
|
||||||
|
|
||||||
var view: Body {
|
var view: Body {
|
||||||
ToggleGroup(selection: $selection, values: Subview.allCases)
|
ToggleGroup(
|
||||||
.padding()
|
selection: $selection,
|
||||||
|
values: Subview.allCases,
|
||||||
|
id: \.self,
|
||||||
|
label: \.rawValue
|
||||||
|
)
|
||||||
|
.padding()
|
||||||
VStack {
|
VStack {
|
||||||
Text(selection.rawValue)
|
Text(selection.rawValue)
|
||||||
.padding()
|
.padding()
|
||||||
@ -26,19 +31,11 @@ struct ToggleGroupDemo: View {
|
|||||||
.padding()
|
.padding()
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Subview: String, ToggleGroupItem, CaseIterable, CustomStringConvertible {
|
enum Subview: String, CaseIterable, Equatable {
|
||||||
|
|
||||||
case view1 = "View 1"
|
case view1 = "View 1"
|
||||||
case view2 = "View 2"
|
case view2 = "View 2"
|
||||||
|
|
||||||
var id: Self { self }
|
|
||||||
|
|
||||||
var description: String { rawValue }
|
|
||||||
|
|
||||||
var icon: Icon? { nil }
|
|
||||||
|
|
||||||
var showLabel: Bool { true }
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,7 +24,7 @@ extension Class {
|
|||||||
.filter { config.requiredProperties.contains($0.name) }
|
.filter { config.requiredProperties.contains($0.name) }
|
||||||
var initializer = "\(config.internalInitializer ? "" : "public ")init("
|
var initializer = "\(config.internalInitializer ? "" : "public ")init("
|
||||||
if config.dynamicWidget != nil {
|
if config.dynamicWidget != nil {
|
||||||
initializer.append("_ elements: [Element], ")
|
initializer.append("_ elements: [Element], id: KeyPath<Element, Identifier>, ")
|
||||||
}
|
}
|
||||||
for property in requiredProperties {
|
for property in requiredProperties {
|
||||||
initializer.append("\(property.parameter(config: config, genConfig: genConfig)), ")
|
initializer.append("\(property.parameter(config: config, genConfig: genConfig)), ")
|
||||||
@ -46,6 +46,7 @@ extension Class {
|
|||||||
|
|
||||||
self.elements = elements
|
self.elements = elements
|
||||||
self.content = content
|
self.content = content
|
||||||
|
self.id = id
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -167,6 +168,8 @@ extension Class {
|
|||||||
var elements: [Element]
|
var elements: [Element]
|
||||||
/// The dynamic widget content.
|
/// The dynamic widget content.
|
||||||
var content: (Element) -> Body
|
var content: (Element) -> Body
|
||||||
|
/// The dynamic widget identifier key path.
|
||||||
|
var id: KeyPath<Element, Identifier>
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
content += staticWidgetProperties(namespace: namespace, configs: configs)
|
content += staticWidgetProperties(namespace: namespace, configs: configs)
|
||||||
@ -226,8 +229,9 @@ extension Class {
|
|||||||
return """
|
return """
|
||||||
var contentStorage: [ViewStorage] = storage.content[.mainContent] ?? []
|
var contentStorage: [ViewStorage] = storage.content[.mainContent] ?? []
|
||||||
let old = storage.fields["element"] as? [Element] ?? []
|
let old = storage.fields["element"] as? [Element] ?? []
|
||||||
old.identifiableTransform(
|
old.transform(
|
||||||
to: elements,
|
to: elements,
|
||||||
|
id: id,
|
||||||
functions: .init { index in
|
functions: .init { index in
|
||||||
\(dynamicWidget.remove)(\(widget), \(dynamicWidget.getElement))
|
\(dynamicWidget.remove)(\(widget), \(dynamicWidget.getElement))
|
||||||
contentStorage.remove(at: index)
|
contentStorage.remove(at: index)
|
||||||
|
|||||||
@ -64,10 +64,25 @@ struct Class: ClassLike, Decodable {
|
|||||||
dateFormatter.dateFormat = "dd.MM.yy"
|
dateFormatter.dateFormat = "dd.MM.yy"
|
||||||
let widgetName = config.name ?? config.class
|
let widgetName = config.name ?? config.class
|
||||||
let definition: String
|
let definition: String
|
||||||
|
var extensions = ""
|
||||||
if config.dynamicWidget == nil {
|
if config.dynamicWidget == nil {
|
||||||
definition = "\(widgetName): AdwaitaWidget"
|
definition = "\(widgetName): AdwaitaWidget"
|
||||||
} else {
|
} else {
|
||||||
definition = "\(widgetName)<Element>: AdwaitaWidget where Element: Identifiable"
|
definition = "\(widgetName)<Element, Identifier>: AdwaitaWidget where Identifier: Equatable"
|
||||||
|
extensions += """
|
||||||
|
|
||||||
|
extension \(widgetName) where Element: Identifiable, Identifier == Element.ID {
|
||||||
|
|
||||||
|
/// Initialize `\(widgetName)`.
|
||||||
|
public init(_ elements: [Element], @ViewBuilder content: @escaping (Element) -> Body) {
|
||||||
|
self.elements = elements
|
||||||
|
self.content = content
|
||||||
|
self.id = \\.id
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
"""
|
||||||
}
|
}
|
||||||
return """
|
return """
|
||||||
//
|
//
|
||||||
@ -135,7 +150,7 @@ struct Class: ClassLike, Decodable {
|
|||||||
}
|
}
|
||||||
\(generateModifiers(config: config, genConfig: genConfig, namespace: namespace, configs: configs))
|
\(generateModifiers(config: config, genConfig: genConfig, namespace: namespace, configs: configs))
|
||||||
}
|
}
|
||||||
|
\(extensions)
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
// swiftlint:enable function_body_length line_length
|
// swiftlint:enable function_body_length line_length
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user