From badc0c12f647ad23a09dcfa6211c9c678d020fbb Mon Sep 17 00:00:00 2001 From: david-swift Date: Mon, 9 Dec 2024 21:15:52 +0100 Subject: [PATCH] Add support for pickers --- Sources/Core/View/Picker.swift | 59 +++++++++++++++++++++++++++++ Sources/Core/View/ToolbarView.swift | 53 +++++++++++++++++++++++--- Sources/Demo/Demo.swift | 9 +++++ Sources/MacBackend/AnyView.swift | 18 ++++++++- 4 files changed, 131 insertions(+), 8 deletions(-) create mode 100644 Sources/Core/View/Picker.swift diff --git a/Sources/Core/View/Picker.swift b/Sources/Core/View/Picker.swift new file mode 100644 index 0000000..ee0e031 --- /dev/null +++ b/Sources/Core/View/Picker.swift @@ -0,0 +1,59 @@ +// +// Picker.swift +// MacBackend +// +// Created by david-swift on 08.12.2024. +// + +import SwiftUI + +/// A picker view. +public struct Picker: SwiftUIWidget where Item: Hashable, Item: CustomStringConvertible { + + /// The selected item. + @Meta.Binding var selection: Item + /// The picker's label. + var label: String + /// The picker's items. + var items: [Item] + /// Whether to use the segmented picker stlye. + var segmented = false + + /// Initialize the picker. + /// - Parameters: + /// - label: The picker's label. + /// - items: The picker's items. + /// - selection: The selected item. + public init(_ label: String, items: [Item], selection: Meta.Binding) { + self._selection = selection + self.label = label + self.items = items + } + + /// Get the SwiftUI view. + /// - Parameter properties: The widget data. + /// - Returns: The SwiftUI view. + public static func view(properties: Picker) -> some SwiftUI.View { + let picker = SwiftUI.Picker(properties.label, selection: properties._selection.swiftUI) { + ForEach(properties.items, id: \.hashValue) { item in + SwiftUI.Text(item.description) + .tag(item.description) + } + } + if properties.segmented { + picker + .pickerStyle(.segmented) + } else { + picker + .pickerStyle(.automatic) + } + } + + /// Make the picker segmented. + /// - Parameter segmented: Whether the picker is segmented. + /// - Returns: The picker. + public func segmented(_ segmented: Bool = true) -> Self { + modify { $0.segmented = segmented } + } + +} diff --git a/Sources/Core/View/ToolbarView.swift b/Sources/Core/View/ToolbarView.swift index cc7d5fa..00fec95 100644 --- a/Sources/Core/View/ToolbarView.swift +++ b/Sources/Core/View/ToolbarView.swift @@ -14,6 +14,8 @@ public struct ToolbarView: SwiftUIWidget { var child: Meta.AnyView /// The toolbar views. var toolbarViews: Body + /// The toolbar type. + var toolbarType: ToolbarType = .end /// The wrapped views. public var wrappedViews: [String: Meta.AnyView] { @@ -25,22 +27,61 @@ public struct ToolbarView: SwiftUIWidget { /// Initialize the padding view. /// - Parameters: /// - child: The wrapped view. + /// - type: The position. /// - toolbarViews: The views in the toolbar. - public init(child: Meta.AnyView, @Meta.ViewBuilder toolbarViews: () -> Body) { + public init(child: Meta.AnyView, type: ToolbarType, @Meta.ViewBuilder toolbarViews: () -> Body) { self.child = child self.toolbarViews = toolbarViews() + self.toolbarType = type + } + + /// The type of toolbar. + public enum ToolbarType { + + /// A leading toolbar. + case start + /// A trailing toolbar. + case end + /// A centered toolbar. + case center + } /// Get the SwiftUI view. /// - Parameter properties: The widget data. /// - Returns: The SwiftUI view. public static func view(properties: Self) -> some SwiftUI.View { - MacBackendView(.mainContent) - .toolbar { - ForEach(properties.toolbarViews.indices, id: \.self) { index in - MacBackendView("\(index)") + switch properties.toolbarType { + case .end: + MacBackendView(.mainContent) + .toolbar { + ForEach(properties.toolbarViews.indices, id: \.self) { index in + MacBackendView("\(index)") + } } - } + case .start: + MacBackendView(.mainContent) + .toolbar { + ToolbarItem(placement: .navigation) { + SwiftUI.HStack { + ForEach(properties.toolbarViews.indices, id: \.self) { index in + MacBackendView("\(index)") + } + } + } + } + case .center: + MacBackendView(.mainContent) + .toolbar { + ToolbarItem(placement: .principal) { + SwiftUI.HStack { + ForEach(properties.toolbarViews.indices, id: \.self) { index in + MacBackendView("\(index)") + } + } + } + } + } } } diff --git a/Sources/Demo/Demo.swift b/Sources/Demo/Demo.swift index 7b0c07f..87b068a 100644 --- a/Sources/Demo/Demo.swift +++ b/Sources/Demo/Demo.swift @@ -25,8 +25,17 @@ struct Demo: App { @State private var selectedElement: String? @State private var alert = false @State private var menuPresented = false + @State private var selection = "Hello" var scene: Scene { + Window(id: "secondary") { _ in + Text(selection) + .centeredToolbar { + Picker("Test", items: ["Hello", "World"], selection: $selection) + .segmented() + } + } + .frame(width: .constant(800), height: .constant(600)) Window("Main", id: "main") { _ in NavigationSplitView { List(elements, selection: $selectedElement) { element in diff --git a/Sources/MacBackend/AnyView.swift b/Sources/MacBackend/AnyView.swift index addf3a3..6d7df23 100644 --- a/Sources/MacBackend/AnyView.swift +++ b/Sources/MacBackend/AnyView.swift @@ -39,11 +39,25 @@ extension AnyView { MenuWrapper(content: { self }, isPresented: isPresented, menu: menu) } - /// Set the toolbar. + /// Add toolbar items to the end. /// - Parameter content: The toolbar's content. /// - Returns: The view. public func toolbar(@ViewBuilder content: () -> Body) -> AnyView { - ToolbarView(child: self, toolbarViews: content) + ToolbarView(child: self, type: .end, toolbarViews: content) + } + + /// Add toolbar items to the start. + /// - Parameter content: The toolbar's content. + /// - Returns: The view. + public func leadingToolbar(@ViewBuilder content: () -> Body) -> AnyView { + ToolbarView(child: self, type: .start, toolbarViews: content) + } + + /// Add centered toolbar items. + /// - Parameter content: The toolbar's content. + /// - Returns: The view. + public func centeredToolbar(@ViewBuilder content: () -> Body) -> AnyView { + ToolbarView(child: self, type: .center, toolbarViews: content) } }