From d0d7d2b6d382776494358664d5f3a0933a71c67c Mon Sep 17 00:00:00 2001 From: david-swift Date: Tue, 3 Feb 2026 00:07:26 +0100 Subject: [PATCH] Use the new wrapModifier for simple modifiers --- Sources/Adwaita/View/AnyView+.swift | 85 +------- .../Adwaita/View/AnyView+wrapModifier.swift | 123 ++++++++++++ Sources/Adwaita/View/Forms/Form.swift | 7 +- Sources/Adwaita/View/HStack.swift | 6 +- .../View/Modifiers/ModifierWrapper.swift | 190 ------------------ Sources/Demo/FlowBoxDemo.swift | 2 +- Sources/Demo/ListDemo.swift | 2 +- 7 files changed, 129 insertions(+), 286 deletions(-) create mode 100644 Sources/Adwaita/View/AnyView+wrapModifier.swift delete mode 100644 Sources/Adwaita/View/Modifiers/ModifierWrapper.swift diff --git a/Sources/Adwaita/View/AnyView+.swift b/Sources/Adwaita/View/AnyView+.swift index 2cca766..90bc6be 100644 --- a/Sources/Adwaita/View/AnyView+.swift +++ b/Sources/Adwaita/View/AnyView+.swift @@ -5,6 +5,7 @@ // Created by david-swift on 16.10.24. // +import CAdw import Foundation extension AnyView { @@ -243,90 +244,6 @@ extension AnyView { .maximumSize(maxHeight ?? -1) } - /// Add padding around a view. - /// - Parameters: - /// - padding: The size of the padding. - /// - edges: The edges which are affected by the padding. - /// - Returns: A view. - public func padding(_ padding: Int = 10, _ edges: Set = .all) -> AnyView { - ModifierWrapper(content: self, padding: padding, edges: edges) - } - - /// Add a padding of 10 around a view. - /// - Parameters: - /// - edges: The edges which are affected by the padding. - /// - Returns: A view. - public func padding(_ edges: Set = .all) -> AnyView { - padding(10, edges) - } - - /// Enable or disable the horizontal expansion. - /// - Parameter enabled: Whether it is enabled or disabled. - /// - Returns: A view. - public func hexpand(_ enabled: Bool = true) -> AnyView { - ModifierWrapper(content: self, hexpand: enabled) - } - - /// Enable or disable the vertical expansion. - /// - Parameter enabled: Whether it is enabled or disabled. - /// - Returns: A view. - public func vexpand(_ enabled: Bool = true) -> AnyView { - ModifierWrapper(content: self, vexpand: enabled) - } - - /// Set the horizontal alignment. - /// - Parameter align: The alignment. - /// - Returns: A view. - public func halign(_ align: Alignment) -> AnyView { - ModifierWrapper(content: self, halign: align) - } - - /// Set the vertical alignment. - /// - Parameter align: The alignment. - /// - Returns: A view. - public func valign(_ align: Alignment) -> AnyView { - ModifierWrapper(content: self, valign: align) - } - - /// Set the view's minimal width or height. - /// - Parameters: - /// - minWidth: The minimal width. - /// - minHeight: The minimal height. - /// - Returns: A view. - public func frame(minWidth: Int? = nil, minHeight: Int? = nil) -> AnyView { - ModifierWrapper(content: self, minWidth: minWidth, minHeight: minHeight) - } - - /// Add a style class to the view. - /// - Parameters: - /// - style: The style class. - /// - active: Whether the style is currently applied. - /// - Returns: A view. - public func style(_ style: String, active: Bool = true) -> AnyView { - ModifierWrapper(content: self, style: style, styleActive: active) - } - - /// Make the view insensitive (useful e.g. in overlays). - /// - Parameter insensitive: Whether the view is insensitive. - /// - Returns: A view. - public func insensitive(_ insensitive: Bool = true) -> AnyView { - ModifierWrapper(content: self, insensitive: insensitive) - } - - /// Set the view's visibility. - /// - Parameter visible: Whether the view is visible. - /// - Returns: A view. - public func visible(_ visible: Bool = true) -> AnyView { - ModifierWrapper(content: self, visible: visible) - } - - /// Add a tooltip to the widget. - /// - Parameter tooltip: The tooltip text. - /// - Returns: A view. - public func tooltip(_ tooltip: String) -> AnyView { - ModifierWrapper(content: self, tooltip: tooltip) - } - /// Present a toast when the signal gets activated. /// - Parameters: /// - title: The title of the toast. diff --git a/Sources/Adwaita/View/AnyView+wrapModifier.swift b/Sources/Adwaita/View/AnyView+wrapModifier.swift new file mode 100644 index 0000000..193f08b --- /dev/null +++ b/Sources/Adwaita/View/AnyView+wrapModifier.swift @@ -0,0 +1,123 @@ +// +// AnyView+wrapModifier.swift +// Adwaita +// +// Created by david-swift on 02.02.26. +// + +import CAdw + +extension AnyView { + + /// Add padding around a view. + /// - Parameters: + /// - padding: The size of the padding. + /// - edges: The edges which are affected by the padding. + /// - Returns: A view. + public func padding(_ padding: Int = 10, _ edges: Set = .all) -> AnyView { + wrapModifier(properties: [padding, edges]) { storage in + if edges.contains(.leading) { gtk_widget_set_margin_start(storage.opaquePointer?.cast(), padding.cInt) } + if edges.contains(.trailing) { gtk_widget_set_margin_end(storage.opaquePointer?.cast(), padding.cInt) } + if edges.contains(.top) { gtk_widget_set_margin_top(storage.opaquePointer?.cast(), padding.cInt) } + if edges.contains(.bottom) { gtk_widget_set_margin_bottom(storage.opaquePointer?.cast(), padding.cInt) } + } + } + + /// Add a padding of 10 around a view. + /// - Parameters: + /// - edges: The edges which are affected by the padding. + /// - Returns: A view. + public func padding(_ edges: Set = .all) -> AnyView { + padding(10, edges) + } + + /// Enable or disable the horizontal expansion. + /// - Parameter enabled: Whether it is enabled or disabled. + /// - Returns: A view. + public func hexpand(_ enabled: Bool = true) -> AnyView { + wrapModifier(properties: [enabled]) { storage in + gtk_widget_set_hexpand(storage.opaquePointer?.cast(), enabled.cBool) + } + } + + /// Enable or disable the vertical expansion. + /// - Parameter enabled: Whether it is enabled or disabled. + /// - Returns: A view. + public func vexpand(_ enabled: Bool = true) -> AnyView { + wrapModifier(properties: [enabled]) { storage in + gtk_widget_set_vexpand(storage.opaquePointer?.cast(), enabled.cBool) + } + } + + /// Set the horizontal alignment. + /// - Parameter align: The alignment. + /// - Returns: A view. + public func halign(_ align: Alignment) -> AnyView { + wrapModifier(properties: [align]) { storage in + gtk_widget_set_halign(storage.opaquePointer?.cast(), align.cAlign) + } + } + + /// Set the vertical alignment. + /// - Parameter align: The alignment. + /// - Returns: A view. + public func valign(_ align: Alignment) -> AnyView { + wrapModifier(properties: [align]) { storage in + gtk_widget_set_valign(storage.opaquePointer?.cast(), align.cAlign) + } + } + + /// Set the view's minimal width or height. + /// - Parameters: + /// - minWidth: The minimal width. + /// - minHeight: The minimal height. + /// - Returns: A view. + public func frame(minWidth: Int? = nil, minHeight: Int? = nil) -> AnyView { + wrapModifier(properties: [minWidth, minHeight]) { storage in + gtk_widget_set_size_request(storage.opaquePointer?.cast(), minWidth?.cInt ?? 1, minHeight?.cInt ?? -1) + } + } + + /// Add a style class to the view. + /// - Parameters: + /// - style: The style class. + /// - active: Whether the style is currently applied. + /// - Returns: A view. + public func style(_ style: String, active: Bool = true) -> AnyView { + wrapModifier(properties: [style, active]) { storage in + if active { + gtk_widget_add_css_class(storage.opaquePointer?.cast(), style) + } else { + gtk_widget_remove_css_class(storage.opaquePointer?.cast(), style) + } + } + } + + /// Make the view insensitive (useful e.g. in overlays). + /// - Parameter insensitive: Whether the view is insensitive. + /// - Returns: A view. + public func insensitive(_ insensitive: Bool = true) -> AnyView { + wrapModifier(properties: [insensitive]) { storage in + gtk_widget_set_sensitive(storage.opaquePointer?.cast(), insensitive ? 0 : 1) + } + } + + /// Set the view's visibility. + /// - Parameter visible: Whether the view is visible. + /// - Returns: A view. + public func visible(_ visible: Bool = true) -> AnyView { + wrapModifier(properties: [visible]) { storage in + gtk_widget_set_visible(storage.opaquePointer?.cast(), visible.cBool) + } + } + + /// Add a tooltip to the widget. + /// - Parameter tooltip: The tooltip text. + /// - Returns: A view. + public func tooltip(_ tooltip: String) -> AnyView { + wrapModifier(properties: [tooltip]) { storage in + gtk_widget_set_tooltip_markup(storage.opaquePointer?.cast(), tooltip) + } + } + +} diff --git a/Sources/Adwaita/View/Forms/Form.swift b/Sources/Adwaita/View/Forms/Form.swift index 4eb8f12..eccc5e3 100644 --- a/Sources/Adwaita/View/Forms/Form.swift +++ b/Sources/Adwaita/View/Forms/Form.swift @@ -15,11 +15,8 @@ public struct Form: SimpleView { /// The view's body. public var view: Body { - ModifierWrapper( - content: List([Int](content.indices), selection: nil) { index in content[index] }, - style: "boxed-list", - styleActive: true - ) + List([Int](content.indices), selection: nil) { index in content[index] } + .style("boxed-list") } /// Initialize a `Form`. diff --git a/Sources/Adwaita/View/HStack.swift b/Sources/Adwaita/View/HStack.swift index df34219..9c2eead 100644 --- a/Sources/Adwaita/View/HStack.swift +++ b/Sources/Adwaita/View/HStack.swift @@ -17,11 +17,7 @@ public struct HStack: SimpleView { /// The view's body. public var view: Body { - ModifierWrapper( - content: VStack(horizontal: true, spacing: spacing, content: content), - style: "linked", - styleActive: linked - ) + VStack(horizontal: true, spacing: spacing, content: content) } /// Initialize a `HStack`. diff --git a/Sources/Adwaita/View/Modifiers/ModifierWrapper.swift b/Sources/Adwaita/View/Modifiers/ModifierWrapper.swift deleted file mode 100644 index 6ccec1c..0000000 --- a/Sources/Adwaita/View/Modifiers/ModifierWrapper.swift +++ /dev/null @@ -1,190 +0,0 @@ -// -// ModifierWrapper.swift -// Adwaita -// -// Created by david-swift on 04.09.24. -// - -import CAdw - -/// A wrapper for view modifiers for any view. -struct ModifierWrapper: AdwaitaWidget { - - /// The view. - var content: AnyView - /// The padding. - var padding: Int? - /// The padding edges. - var edges: Set? - /// Whether to expand horizontally. - var hexpand: Bool? - /// Whether to expand vertically. - var vexpand: Bool? - /// The horizontal alignment. - var halign: Alignment? - /// The vertical alignment. - var valign: Alignment? - /// The minimum width. - var minWidth: Int? - /// The minimum height. - var minHeight: Int? - /// The style class. - var style: String? - /// Whether the style is active. - var styleActive: Bool? - /// Whether the view is insensitive. - var insensitive: Bool? - /// Whether the view is visible. - var visible: Bool? - /// The tooltip. - var tooltip: String? - - /// Initialize a modifier wrapper. - /// - Parameters: - /// - content: The view. - /// - padding: The padding. - /// - edges: The padding edges. - /// - hexpand: Whether to expand horizontally. - /// - vexpand: Whether to expand vertically. - /// - halign: The horizontal alignment. - /// - valign: The vertical alignment. - /// - minWidth: The minimum width. - /// - minHeight: The minimum height. - /// - style: The style class. - /// - styleActive: Whether the style is active. - /// - insensitive: Whether the view is insensitive. - /// - visible: Whether the view is visible. - /// - tooltip: The tooltip. - init( - content: AnyView, - padding: Int? = nil, - edges: Set? = nil, - hexpand: Bool? = nil, - vexpand: Bool? = nil, - halign: Alignment? = nil, - valign: Alignment? = nil, - minWidth: Int? = nil, - minHeight: Int? = nil, - style: String? = nil, - styleActive: Bool? = nil, - insensitive: Bool? = nil, - visible: Bool? = nil, - tooltip: String? = nil - ) { - self.content = content - self.padding = padding - self.edges = edges - self.hexpand = hexpand - self.vexpand = vexpand - self.halign = halign - self.valign = valign - self.minWidth = minWidth - self.minHeight = minHeight - self.style = style - self.styleActive = styleActive - self.insensitive = insensitive - self.visible = visible - self.tooltip = tooltip - } - - /// The view storage. - /// - Parameters: - /// - modifiers: Modify views before being updated. - /// - type: The view render data type. - /// - Returns: The view storage. - func container(data: WidgetData, type: Data.Type) -> ViewStorage where Data: ViewRenderData { - let content = content.storage(data: data, type: type) - return .init(content.pointer, content: [.mainContent: [content]]) - } - - /// Update the stored content. - /// - Parameters: - /// - storage: The storage to update. - /// - modifiers: Modify views before being updated - /// - updateProperties: Whether to update the view's properties. - /// - type: The view render data type. - func update( - _ storage: ViewStorage, - data: WidgetData, - updateProperties: Bool, - type: Data.Type - ) where Data: ViewRenderData { - if let storage = storage.content[.mainContent]?.first { - content.updateStorage(storage, data: data, updateProperties: updateProperties, type: type) - } - guard updateProperties else { - return - } - update1(storage, data: data, updateProperties: updateProperties, type: type) - update2(storage, data: data, updateProperties: updateProperties, type: type) - storage.previousState = self - } - - /// Update part 1 of the properties. - /// - Parameters: - /// - storage: The storage to update. - /// - modifiers: Modify views before being updated - /// - updateProperties: Whether to update the view's properties. - /// - type: The view render data type. - func update1( - _ storage: ViewStorage, - data: WidgetData, - updateProperties: Bool, - type: Data.Type - ) where Data: ViewRenderData { - let previousState = storage.previousState as? Self - if let padding, let edges, previousState?.padding != padding || previousState?.edges != edges { - if edges.contains(.leading) { gtk_widget_set_margin_start(storage.opaquePointer?.cast(), padding.cInt) } - if edges.contains(.trailing) { gtk_widget_set_margin_end(storage.opaquePointer?.cast(), padding.cInt) } - if edges.contains(.top) { gtk_widget_set_margin_top(storage.opaquePointer?.cast(), padding.cInt) } - if edges.contains(.bottom) { gtk_widget_set_margin_bottom(storage.opaquePointer?.cast(), padding.cInt) } - } - if let hexpand, previousState?.hexpand != hexpand { - gtk_widget_set_hexpand(storage.opaquePointer?.cast(), hexpand.cBool) - } - if let vexpand, previousState?.vexpand != vexpand { - gtk_widget_set_vexpand(storage.opaquePointer?.cast(), vexpand.cBool) - } - if let halign, previousState?.halign != halign { - gtk_widget_set_halign(storage.opaquePointer?.cast(), halign.cAlign) - } - if let valign, previousState?.valign != valign { - gtk_widget_set_valign(storage.opaquePointer?.cast(), valign.cAlign) - } - } - - /// Update part 2 of the properties. - /// - Parameters: - /// - storage: The storage to update. - /// - modifiers: Modify views before being updated - /// - updateProperties: Whether to update the view's properties. - /// - type: The view render data type. - func update2( - _ storage: ViewStorage, - data: WidgetData, - updateProperties: Bool, - type: Data.Type - ) where Data: ViewRenderData { - let previousState = storage.previousState as? Self - if minWidth != previousState?.minWidth || minHeight != previousState?.minHeight { - gtk_widget_set_size_request(storage.opaquePointer?.cast(), minWidth?.cInt ?? 1, minHeight?.cInt ?? -1) - } - if let style, let styleActive, previousState?.styleActive != styleActive { - if styleActive { - gtk_widget_add_css_class(storage.opaquePointer?.cast(), style) - } else { - gtk_widget_remove_css_class(storage.opaquePointer?.cast(), style) - } - } - if let insensitive, previousState?.insensitive != insensitive { - gtk_widget_set_sensitive(storage.opaquePointer?.cast(), insensitive ? 0 : 1) - } - if let visible, previousState?.visible != visible { - gtk_widget_set_visible(storage.opaquePointer?.cast(), visible.cBool) - } - if let tooltip, previousState?.tooltip != tooltip { - gtk_widget_set_tooltip_markup(storage.opaquePointer?.cast(), tooltip) - } - } - -} diff --git a/Sources/Demo/FlowBoxDemo.swift b/Sources/Demo/FlowBoxDemo.swift index d802586..cce2a08 100644 --- a/Sources/Demo/FlowBoxDemo.swift +++ b/Sources/Demo/FlowBoxDemo.swift @@ -28,7 +28,7 @@ struct FlowBoxDemo: View { selectedItem = items[safe: index]?.id ?? items[safe: index ?? 0 - 1]?.id ?? items.first?.id ?? "" } } - .linked() + .modifyContent(VStack.self) { $0.linked() } .padding() .halign(.center) if !items.isEmpty { diff --git a/Sources/Demo/ListDemo.swift b/Sources/Demo/ListDemo.swift index b245463..df092ee 100644 --- a/Sources/Demo/ListDemo.swift +++ b/Sources/Demo/ListDemo.swift @@ -28,7 +28,7 @@ struct ListDemo: View { selectedItem = items[safe: index]?.id ?? items[safe: index ?? 0 - 1]?.id ?? items.first?.id ?? "" } } - .linked() + .modifyContent(VStack.self) { $0.linked() } .padding() .halign(.center) if !items.isEmpty {