Make icons own widget
Some checks failed
Deploy Docs / publish (push) Waiting to run
SwiftLint / SwiftLint (push) Failing after 4s

This commit is contained in:
david-swift 2024-11-09 22:17:45 +01:00
parent f1f8c1b0a0
commit 266fb1dc23
5 changed files with 99 additions and 16 deletions

View File

@ -9,12 +9,12 @@ import Foundation
import WinUI
/// An icon.
public enum Icon: Equatable {
public enum Icon: WinUIWidget, Equatable {
/// An SVG icon.
case svg(url: URL)
/// A system icon.
case systemIcon(unicode: Character)
case systemIcon(unicode: Character, fontSize: Double = 20)
/// The WinUI icon.
var winIcon: IconElement {
@ -24,10 +24,54 @@ public enum Icon: Equatable {
let source = SvgImageSource(.init(url.path))
icon.source = source
return icon
case let .systemIcon(character):
case let .systemIcon(character, fontSize):
let icon = FontIcon()
icon.fontSize = fontSize
icon.glyph = String(character)
return icon
}
}
/// Update the stored content.
/// - Parameters:
/// - storage: The storage to update.
/// - data: The widget data.
/// - updateProperties: Whether to update the view's properties.
/// - type: The view render data type.
public func update<Data>(
_ storage: ViewStorage,
data: WidgetData,
updateProperties: Bool,
type: Data.Type
) where Data : ViewRenderData {
guard updateProperties else {
return
}
switch self {
case let .svg(url):
(storage.pointer as? ImageIcon)?.source = SvgImageSource(.init(url.path))
case let .systemIcon(character, fontSize):
(storage.pointer as? FontIcon)?.glyph = String(character)
(storage.pointer as? FontIcon)?.fontSize = fontSize
}
}
/// Initialize the widget.
/// - Returns: The widget.
public func initializeWidget() -> Any {
winIcon
}
/// Set the font size.
/// - Parameter size: The font size.
/// - Returns: The icon.
public func fontSize(_ size: Double) -> Self {
switch self {
case let .systemIcon(character, _):
.systemIcon(unicode: character, fontSize: size)
default:
self
}
}
}

View File

@ -26,6 +26,33 @@ public struct Button: WinUIWidget {
self.label = [Text(label)]
}
/// Initialize a button.
/// - Parameters:
/// - icon: The button's icon.
/// - label: The button's label.
/// - action: The button's action.
public init(icon: Icon, label: String, action: @escaping () -> Void) {
self.action = action
self.label = [
HStack {
ModifierWrapper(
view: icon.fontSize(16),
margin: (0, 0, 8, 0)
)
Text(label)
}
]
}
/// Initialize a button.
/// - Parameters:
/// - icon: The button's icon.
/// - action: The button's action.
public init(icon: Icon, action: @escaping () -> Void) {
self.action = action
self.label = [icon.fontSize(16)]
}
/// Initialize a button.
/// - Parameters:
/// - action: The button's action.

View File

@ -31,7 +31,9 @@ public struct ToggleSwitch: WinUIWidget {
/// Initialize the widget.
/// - Returns: The widget.
public func initializeWidget() -> Any {
WinUI.ToggleSwitch()
let element = WinUI.ToggleSwitch()
element.flowDirection = .rightToLeft
return element
}
}

View File

@ -10,6 +10,8 @@ public struct SettingsControl: SimpleView {
/// The settings item's title.
var title: String
/// The settings item's icon.
var icon: Icon
/// The settings item's description.
var description: String?
/// The control view.
@ -22,14 +24,20 @@ public struct SettingsControl: SimpleView {
ModifierWrapper(
view: Grid {
ModifierWrapper(
view: VStack {
Text(title)
view: HStack {
ModifierWrapper(
view: Text(description ?? "")
.style(.caption),
visible: description != nil,
opacity: 0.8
view: icon,
margin: (0, 0, 18, 0)
)
VStack {
Text(title)
ModifierWrapper(
view: Text(description ?? "")
.style(.caption),
visible: description != nil,
opacity: 0.8
)
}
},
horizontalAlignment: .stretch,
verticalAlignment: .center
@ -51,10 +59,12 @@ public struct SettingsControl: SimpleView {
/// Initialize a settings item.
/// - Parameters:
/// - title: The settings item's title.
/// - icon: The settings item's icon.
/// - description: The settings item's description.
/// - control: The control view.
public init(_ title: String, description: String? = nil, @ViewBuilder control: () -> Body) {
public init(_ title: String, icon: Icon, description: String? = nil, @ViewBuilder control: () -> Body) {
self.title = title
self.icon = icon
self.description = description
self.control = control()
}

View File

@ -57,7 +57,7 @@ struct ContentView: View {
case .settings:
settings
case let .custom(item: item):
Button("\(item)") {
Button(icon: item.icon, label: item.description) {
selectedItem = .custom(item: .shop)
}
.horizontalAlignment(.center)
@ -77,18 +77,18 @@ struct ContentView: View {
ScrollView {
VStack {
SettingsSection("General") {
SettingsControl("Button Control") {
SettingsControl("Button Control", icon: .systemIcon(unicode: "\u{E7C9}")) {
Button("Control") { }
}
SettingsControl("Combo Box", description: "Selected item: \(comboBoxSelection)") {
SettingsControl("Combo Box", icon: .systemIcon(unicode: "\u{E700}"), description: "Selected item: \(comboBoxSelection)") {
ComboBox(NavigationItem.allCases, selection: $comboBoxSelection)
}
SettingsControl("Toggle Switch", description: "Current state: \(switchState ? "on" : "off")") {
SettingsControl("Toggle Switch", icon: .systemIcon(unicode: "\u{F19E}"), description: "Current state: \(switchState ? "on" : "off")") {
ToggleSwitch(isOn: $switchState)
}
}
SettingsSection("About") {
SettingsControl("WinUI for Swift Demo", description: "main") {
SettingsControl("WinUI for Swift Demo", icon: .systemIcon(unicode: "\u{E946}"), description: "main") {
HyperlinkButton("Website", url: "https://aparoksha.dev/")
}
}