Reimplement stacks with grid
This commit is contained in:
parent
b5ee07485b
commit
645c8ec5a7
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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))
|
||||
|
@ -22,7 +22,7 @@ public struct SettingsControl: SimpleView {
|
||||
ModifierWrapper(
|
||||
view: Card {
|
||||
ModifierWrapper(
|
||||
view: Grid {
|
||||
view: HStack {
|
||||
ModifierWrapper(
|
||||
view: HStack {
|
||||
ModifierWrapper(
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user