Reimplement stacks with grid
Some checks failed
Deploy Docs / publish (push) Waiting to run
SwiftLint / SwiftLint (push) Failing after 6s

This commit is contained in:
david-swift 2024-11-20 08:05:52 +01:00
parent b5ee07485b
commit 645c8ec5a7
6 changed files with 140 additions and 57 deletions

View File

@ -15,6 +15,8 @@ public struct Grid: WinUIWidget {
var content: Body
/// The grid's columns.
var columns: [Column]?
/// The grid's rows.
var rows: [Row]?
// swiftlint:disable large_tuple
/// The padding.
var padding: (Double, Double, Double, Double)?
@ -24,17 +26,58 @@ public struct Grid: WinUIWidget {
/// Initialize a grid.
/// - Parameters:
/// - row: The available rows.
/// - columns: The available columns.
/// - content: The content.
public init(columns: [Column]? = nil, @ViewBuilder content: () -> Body) {
public init(rows: [Row]? = nil, columns: [Column]? = nil, @ViewBuilder content: () -> Body) {
self.content = content()
self.columns = columns
}
/// A grid row.
public struct Row: Equatable {
/// The row's relative height.
public var height: Double?
/// The row's minimum height.
public var minHeight: Double?
/// The row's maximum height.
public var maxHeight: Double?
/// Initialize a row.
/// - Parameters:
/// - height: The row's relative height.
/// - minHeight: The row's minimum height.
/// - maxHeight: The row's maximum height.
public init(height: Double? = nil, minHeight: Double? = nil, maxHeight: Double? = nil) {
self.height = height
self.minHeight = minHeight
self.maxHeight = maxHeight
}
/// The WinUI row definition.
var winRow: RowDefinition {
let row = RowDefinition()
if let height {
row.height = .init(value: height, gridUnitType: .star)
} else {
row.height = .init(value: 0, gridUnitType: .auto)
}
if let minHeight {
row.minHeight = minHeight
}
if let maxHeight {
row.maxHeight = maxHeight
}
return row
}
}
/// A grid column.
public struct Column: Equatable {
/// The column's width.
/// The column's relative width.
public var width: Double?
/// The column's minimum width.
public var minWidth: Double?
@ -56,7 +99,7 @@ public struct Grid: WinUIWidget {
var winColumn: ColumnDefinition {
let column = ColumnDefinition()
if let width {
column.width = .init(value: width, gridUnitType: .pixel)
column.width = .init(value: width, gridUnitType: .star)
} else {
column.width = .init(value: 0, gridUnitType: .auto)
}
@ -122,6 +165,15 @@ public struct Grid: WinUIWidget {
grid.columnDefinitions.insertAt(.init(index), column.winColumn)
})
}
if let rows {
(previousState?.rows ?? []).transform(to: rows, functions: .init { index, row in
grid.rowDefinitions[index] = row.winRow
} delete: { index in
_ = grid.rowDefinitions.remove(at: index)
} insert: { index, row in
grid.rowDefinitions.insertAt(.init(index), row.winRow)
})
}
if let padding, previousState?.padding ?? (0, 0, 0, 0) != padding {
grid.padding = .init(left: padding.0, top: padding.1, right: padding.2, bottom: padding.3)
}

View File

@ -8,57 +8,45 @@
import WinUI
/// A container arranging its children vertically.
public struct HStack: WinUIWidget {
public struct HStack: SimpleView {
/// The content.
var content: Body
/// The view.
public var view: Body {
Grid {
{
var body: Body = []
for (index, element) in content.enumerated() {
body.append(
ModifierWrapper(
view: element,
gridColumn: index
)
)
}
return body
}()
}
.inspectOnAppear { storage in
let columns: [Grid.Column]? = storage.content[.mainContent]?.map { storage in
if storage.fields["h-stretch"] as? Bool == true {
.init(width: 1)
} else {
.init()
}
}
for column in columns ?? [] {
(storage.pointer as? WinUI.Grid)?.columnDefinitions.append(column.winColumn)
}
}
}
/// Initialize the wrapper.
/// - Parameter content: The view content.
public init(@ViewBuilder content: () -> Body) {
self.content = content()
}
/// The view storage.
/// - Parameters:
/// - data: The widget data.
/// - type: The view render data type.
/// - Returns: The view storage.
public func container<Data>(
data: WidgetData,
type: Data.Type
) -> ViewStorage where Data: ViewRenderData {
if content.count == 1, let view = content.first {
return view.storage(data: data, type: type)
}
let stack = StackPanel()
stack.orientation = .horizontal
let storages = content.storages(data: data, type: type)
for storage in storages {
stack.children.append(storage.pointer as? UIElement)
}
return .init(stack, content: [.mainContent: storages])
}
/// 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 {
if content.count == 1, let view = content.first {
view.updateStorage(storage, data: data, updateProperties: updateProperties, type: type)
return
}
if let storages = storage.content[.mainContent] {
content.update(storages, data: data, updateProperties: updateProperties, type: type)
}
}
}

View File

@ -26,6 +26,8 @@ public struct ModifierWrapper: WinUIWidget, CommandBarWidget {
var verticalAlignment: VerticalAlignment?
/// The grid column.
var gridColumn: Int?
/// The grid row.
var gridRow: Int?
/// Whether the element is displayed.
var visible: Bool?
/// The view's opacity.
@ -40,6 +42,7 @@ public struct ModifierWrapper: WinUIWidget, CommandBarWidget {
/// - margin: The view's margin.
/// - horizontalAlignment: The horizontal alignment.
/// - verticalAlignment: The vertical alignment.
/// - gridRow: The grid row.
/// - gridColumn: The grid column.
/// - visible: Whether the view is visible.
/// - opacity: The view's opacity.
@ -50,6 +53,7 @@ public struct ModifierWrapper: WinUIWidget, CommandBarWidget {
margin: (Double, Double, Double, Double)? = nil,
horizontalAlignment: HorizontalAlignment? = nil,
verticalAlignment: VerticalAlignment? = nil,
gridRow: Int? = nil,
gridColumn: Int? = nil,
visible: Bool? = nil,
opacity: Double? = nil
@ -60,6 +64,7 @@ public struct ModifierWrapper: WinUIWidget, CommandBarWidget {
self.margin = margin
self.horizontalAlignment = horizontalAlignment
self.verticalAlignment = verticalAlignment
self.gridRow = gridRow
self.gridColumn = gridColumn
self.visible = visible
self.opacity = opacity
@ -74,6 +79,8 @@ public struct ModifierWrapper: WinUIWidget, CommandBarWidget {
public func container<Data>(data: WidgetData, type: Data.Type) -> ViewStorage where Data: ViewRenderData {
let content = view.storage(data: data, type: type)
let storage = ViewStorage(content.pointer)
storage.fields["v-stretch"] = content.fields["v-stretch"]
storage.fields["h-stretch"] = content.fields["h-stretch"]
storage.content[.mainContent] = [content]
update(storage, data: data, updateProperties: true, type: type)
return storage
@ -109,9 +116,14 @@ public struct ModifierWrapper: WinUIWidget, CommandBarWidget {
}
if let horizontalAlignment, previousState?.horizontalAlignment != horizontalAlignment {
view.horizontalAlignment = horizontalAlignment.winAlignment
storage.fields["h-stretch"] = horizontalAlignment == .stretch
}
if let verticalAlignment, previousState?.verticalAlignment != verticalAlignment {
view.verticalAlignment = verticalAlignment.winAlignment
storage.fields["v-stretch"] = verticalAlignment == .stretch
}
if let gridRow, previousState?.gridRow != gridRow {
WinUI.Grid.setRow(view, .init(gridRow))
}
if let gridColumn, previousState?.gridColumn != gridColumn {
WinUI.Grid.setColumn(view, .init(gridColumn))

View File

@ -22,7 +22,7 @@ public struct SettingsControl: SimpleView {
ModifierWrapper(
view: Card {
ModifierWrapper(
view: Grid {
view: HStack {
ModifierWrapper(
view: HStack {
ModifierWrapper(

View File

@ -13,6 +13,36 @@ public struct VStack: WinUIWidget, Wrapper {
/// The content.
var content: Body
/// The grid view.
var view: AnyView {
Grid {
{
var body: Body = []
for (index, element) in content.enumerated() {
body.append(
ModifierWrapper(
view: element,
gridRow: index
)
)
}
return body
}()
}
.inspectOnAppear { storage in
let rows: [Grid.Row]? = storage.content[.mainContent]?.map { storage in
return if storage.fields["v-stretch"] as? Bool == true {
.init(height: 1)
} else {
.init()
}
}
for row in rows ?? [] {
(storage.pointer as? WinUI.Grid)?.rowDefinitions.append(row.winRow)
}
}
}
/// Initialize the wrapper.
/// - Parameter content: The view content.
public init(@ViewBuilder content: () -> Body) {
@ -30,13 +60,9 @@ public struct VStack: WinUIWidget, Wrapper {
) -> ViewStorage where Data: ViewRenderData {
if content.count == 1, let view = content.first {
return view.storage(data: data, type: type)
} else {
return view.storage(data: data, type: type)
}
let stack = StackPanel()
let storages = content.storages(data: data, type: type)
for storage in storages {
stack.children.append(storage.pointer as? UIElement)
}
return .init(stack, content: [.mainContent: storages])
}
/// Update the stored content.
@ -53,10 +79,8 @@ public struct VStack: WinUIWidget, Wrapper {
) where Data: ViewRenderData {
if content.count == 1, let view = content.first {
view.updateStorage(storage, data: data, updateProperties: updateProperties, type: type)
return
}
if let storages = storage.content[.mainContent] {
content.update(storages, data: data, updateProperties: updateProperties, type: type)
} else {
view.updateStorage(storage, data: data, updateProperties: updateProperties, type: type)
}
}

View File

@ -53,6 +53,13 @@ extension AnyView {
ModifierWrapper(view: self, gridColumn: column)
}
/// Set the view's grid row.
/// - Parameter row: The row.
/// - Returns: The view.
public func gridRow(_ row: Int) -> AnyView {
ModifierWrapper(view: self, gridRow: row)
}
/// Whether the view is visible.
/// - Parameter visible: Whether the view is visible.
/// - Returns: The view.