Add modifiers for modifying child views of a view

This commit is contained in:
david-swift 2023-11-11 16:03:31 +01:00
parent 88eaad2c12
commit a478acbdcd
54 changed files with 511 additions and 180 deletions

View File

@ -16,6 +16,7 @@
- [Binding](structs/Binding.md)
- [Button](structs/Button.md)
- [Clamp](structs/Clamp.md)
- [ContentModifier](structs/ContentModifier.md)
- [EitherView](structs/EitherView.md)
- [HStack](structs/HStack.md)
- [HeaderBar](structs/HeaderBar.md)
@ -24,6 +25,7 @@
- [Menu](structs/Menu.md)
- [MenuButton](structs/MenuButton.md)
- [MenuSection](structs/MenuSection.md)
- [ModifierStopper](structs/ModifierStopper.md)
- [NavigationSplitView](structs/NavigationSplitView.md)
- [ScrollView](structs/ScrollView.md)
- [State](structs/State.md)

View File

@ -40,3 +40,7 @@ Focus the window with a certain id. Create the window if it doesn't already exis
Add a new window with the content of the window with a certain id.
- Parameters:
- id: The window's id.
### `setParentWindows()`
Set the parents of every window having a parent window.

View File

@ -9,6 +9,10 @@ A storage for an app's window.
The window's identifier.
### `parentID`
The identifier of the window's parent window.
### `destroy`
Whether the reference to the window should disappear in the next update.

View File

@ -8,16 +8,18 @@
The array's view body is the array itself.
## Methods
### `widget()`
### `widget(modifiers:)`
Get a widget from a collection of views.
- Parameter modifiers: Modify views before being updated.
- Returns: A widget.
### `update(_:)`
### `update(_:modifiers:)`
Update a collection of views with a collection of view storages.
- Parameters:
- storage: The collection of view storages.
- modifiers: Modify views before being updated.
### `windows()`

View File

@ -3,14 +3,17 @@
# `NativeWidgetPeer`
## Methods
### `update(_:)`
### `update(_:modifiers:)`
A `GTUI.NativeWidgetPeer` is static.
- Parameter storage: The view storage.
- Parameters:
- storage: The view storage.
- modifiers: Modify views before being updated.
### `container()`
### `container(modifiers:)`
A `GTUI.NativeWidgetPeer`'s container is itself.
- Parameter modifiers: Modify views before being updated.
- Returns: The view storage.
### `modifier(code:)`

View File

@ -3,27 +3,41 @@
# `View`
## Methods
### `widget()`
### `widget(modifiers:)`
Wrap the view into a widget.
- Parameter modifiers: Modify views before being updated.
- Returns: The widget.
### `updateStorage(_:)`
### `updateStorage(_:modifiers:)`
Update a storage to a view.
- Parameter storage: The storage.
- Parameters:
- storage: The storage.
- modifiers: Modify views before being updated.
### `storage()`
### `storage(modifiers:)`
Get a storage.
- Parameter modifiers: Modify views before being updated.
- Returns: The storage.
### `getModified(modifiers:)`
### `frame(maxSize:)`
Set the view's maximal size.
- Parameter maxSize: The maximal size.
- Returns: A view.
### `modifyContent(_:modify:)`
Replace every occurrence of a certain view type in the content.
- Parameters:
- type: The view type.
- modify: Modify the view.
- Returns: A view.
### `inspect(_:)`
Modify a GTUI widget before being displayed and when being updated.
@ -94,6 +108,11 @@ Run a function when the view appears for the first time.
- Parameter closure: The function.
- Returns: A view.
### `stopModifiers()`
Remove all of the content modifiers for the wrapped views.
- Returns: A view.
### `topToolbar(visible:_:)`
Add a top toolbar to the view.

View File

@ -5,11 +5,14 @@
A widget is a view that know about its GTUI widget.
## Methods
### `container()`
### `container(modifiers:)`
The view storage.
- Parameter modifiers: Modify views before being updated.
### `update(_:)`
### `update(_:modifiers:)`
Update the stored content.
- Parameter storage: The storage to update.
- Parameters:
- storage: The storage to update.
- modifiers: Modify views before being updated

View File

@ -9,6 +9,10 @@ A structure representing the content for a certain window type.
The window type's identifier.
### `parentID`
The identifier of the window's parent window.
### `open`
The number of instances of the window at the startup.

View File

@ -33,14 +33,17 @@ Initialize a button.
- label: The buttons label.
- handler: The button's action handler.
### `update(_:)`
### `update(_:modifiers:)`
Update a button's view storage.
- Parameter storage: The view storage.
- Parameters:
- storage: The view storage.
- modifiers: Modify views before being updated.
### `container()`
### `container(modifiers:)`
Get a button's view storage.
- Parameter modifiers: Modify views before being updated.
- Returns: The button's view storage.
### `keyboardShortcut(_:window:)`

View File

@ -14,12 +14,15 @@ The content.
The maximum size.
## Methods
### `update(_:)`
### `update(_:modifiers:)`
Update a view storage.
- Parameter storage: The view storage.
- Parameters:
- storage: The view storage.
- modifiers: Modify views before being updated.
### `container()`
### `container(modifiers:)`
Get a view storage.
- Parameter modifiers: Modify views before being updated.
- Returns: The view storage.

View File

@ -0,0 +1,33 @@
**STRUCT**
# `ContentModifier`
A widget which replaces views of a specific type in its content.
## Properties
### `content`
The wrapped view.
### `modify`
The closure for the modification.
## Methods
### `container(modifiers:)`
Get the content's container.
- Parameter modifiers: Modify views before being updated.
- Returns: The content's container.
### `update(_:modifiers:)`
Update the content.
- Parameters:
- storage: The content's storage.
- modifiers: Modify views before being updated.
### `modifyView(_:)`
Apply the modifier to a view.
- Parameter view: The view.

View File

@ -34,18 +34,21 @@ Initialize an `EitherView`.
- trueView: The view that is presented if `isTrue` is true.
- falseView: The view that is presented if `isTrue` is false.
### `update(_:)`
### `update(_:modifiers:)`
Update an `EitherView`'s storage.
- Parameter storage: The view storage.
- Parameters:
- storage: The view storage.
- modifiers: Modify views before being updated.
### `updateContent(_:state:stack:)`
### `updateContent(_:state:stack:modifiers:)`
Update the content of a view in the view storage.
- Parameters:
- storage: The view storage.
- state: Whether it is the true or false view.
- stack: The stack.
- modifiers: Modify views before being updated.
### `setVisible(_:view:)`
@ -54,7 +57,8 @@ Set the visible content page.
- stack: The stack.
- view: The visible view.
### `container()`
### `container(modifiers:)`
Get a GtkStack view storage.
- Parameter modifiers: Modify views before being updated.
- Returns: The view storage.

View File

@ -15,12 +15,15 @@ The content.
Initialize a `HStack`.
- Parameter content: The view content.
### `update(_:)`
### `update(_:modifiers:)`
Update a view storage.
- Parameter storage: The view storage.
- Parameters:
- storage: The view storage.
- modifiers: Modify views before being updated.
### `container()`
### `container(modifiers:)`
Get a view storage.
- Parameter modifiers: Modify views before being updated.
- Returns: The view storage.

View File

@ -59,14 +59,17 @@ Initialize a header bar with only views at the end.
- Parameter start: The views.
- Returns: The header bar.
### `update(_:)`
### `update(_:modifiers:)`
Update a header bar's view storage.
- Parameter storage: The view storage.
- Parameters:
- storage: The view storage.
- modifiers: Modify views before being updated.
### `container()`
### `container(modifiers:)`
Get the container for a header bar.
- Parameter modifiers: Modify views before being updated.
- Returns: The view storage.
### `headerBarTitle(view:)`

View File

@ -14,12 +14,15 @@ The custom code to edit the widget.
The wrapped view.
## Methods
### `container()`
### `container(modifiers:)`
Get the content's container.
- Parameter modifiers: Modify views before being updated.
- Returns: The content's container.
### `update(_:)`
### `update(_:modifiers:)`
Update the content.
- Parameter storage: The content's storage.
- Parameters:
- storage: The content's storage.
- modifiers: Modify views before being updated.

View File

@ -26,14 +26,17 @@ Initialize `List`.
- selection: The identifier of the selected element.
- content: The view for an element.
### `update(_:)`
### `update(_:modifiers:)`
Update a view storage.
- Parameter storage: The view storage.
- Parameters:
- storage: The view storage.
- modifiers: Modify views before being updated.
### `container()`
### `container(modifiers:)`
Get a view storage.
- Parameter modifiers: Modify views before being updated.
- Returns: The view storage.
### `updateSelection(box:)`

View File

@ -45,12 +45,15 @@ Initialize a menu button.
- window: The application window.
- content: The menu's content.
### `update(_:)`
### `update(_:modifiers:)`
Update a button's view storage.
- Parameter storage: The view storage.
- Parameters:
- storage: The view storage.
- modifiers: Modify views before being updated.
### `container()`
### `container(modifiers:)`
Get a button's view storage.
- Parameter modifiers: Modify views before being updated.
- Returns: The button's view storage.

View File

@ -0,0 +1,24 @@
**STRUCT**
# `ModifierStopper`
Remove all of the content modifiers for the wrapped views.
## Properties
### `content`
The wrapped view.
## Methods
### `container(modifiers:)`
Get the content's container.
- Parameter modifiers: Modify views before being updated.
- Returns: The content's container.
### `update(_:modifiers:)`
Update the content.
- Parameters:
- storage: The content's storage.
- modifiers: Modify views before being updated.

View File

@ -29,12 +29,15 @@ Initialize a navigation split view.
- sidebar: The sidebar content.
- content: The main content.
### `container()`
### `container(modifiers:)`
Get the container of the navigation split view widget.
- Parameter modifiers: Modify views before being updated.
- Returns: The view storage.
### `update(_:)`
### `update(_:modifiers:)`
Update the view storage of the navigation split view widget.
- Parameter storage: The view storage.
- Parameters:
- storage: The view storage.
- modifiers: Modify views before being updated.

View File

@ -15,12 +15,15 @@ The content.
Initialize a `ScrollView`.
- Parameter content: The view content.
### `update(_:)`
### `update(_:modifiers:)`
Update a view storage.
- Parameter storage: The view storage.
- Parameters:
- storage: The view storage.
- modifiers: Modify views before being updated.
### `container()`
### `container(modifiers:)`
Get a view storage.
- Parameter modifiers: Modify views before being updated.
- Returns: The view storage.

View File

@ -26,12 +26,15 @@ Initialize a `StateWrapper`.
- content: The view content.
- state: The state information.
### `update(_:)`
### `update(_:modifiers:)`
Update a view storage.
- Parameter storage: The view storage.
- Parameters:
- storage: The view storage.
- modifiers: Modify views before being updated.
### `container()`
### `container(modifiers:)`
Get a view storage.
- Parameter modifiers: Modify views before being updated.
- Returns: The view storage.

View File

@ -31,12 +31,15 @@ Initialize a status page widget.
- description: Additional details.
- content: Additional content.
### `update(_:)`
### `update(_:modifiers:)`
Update the view storage of the text widget.
- Parameter storage: The view storage.
- Parameters:
- storage: The view storage.
- modifiers: Modify views before being updated.
### `container()`
### `container(modifiers:)`
Get the container of the text widget.
- Parameter modifiers: Modify views before being updated.
- Returns: The view storage.

View File

@ -15,12 +15,14 @@ The content.
Initialize a text widget.
- Parameter text: The content.
### `update(_:)`
### `update(_:modifiers:)`
Update the view storage of the text widget.
- Parameter storage: The view storage.
- Parameters:
- storage: The view storage.
- modifiers: Modify views before being updated.
### `container()`
### `container(modifiers:)`
Get the container of the text widget.
- Returns: The view storage.

View File

@ -26,12 +26,15 @@ Whether the toolbar is visible.
The identifier of the toolbar content.
## Methods
### `container()`
### `container(modifiers:)`
Get the container of the toolbar view widget.
- Parameter modifiers: Modify views before being updated.
- Returns: The view storage.
### `update(_:)`
### `update(_:modifiers:)`
Update the view storage of the toolbar view widget.
- Parameter storage: The view storage.
- Parameters:
- storage: The view storage.
- modifiers: Modify views before being updated.

View File

@ -14,12 +14,15 @@ The function.
The content.
## Methods
### `container()`
### `container(modifiers:)`
Get the content's container.
- Parameter modifiers: Modify views before being updated.
- Returns: The content's container.
### `update(_:)`
### `update(_:modifiers:)`
Update the content.
- Parameter storage: The content's storage.
- Parameters:
- storage: The content's storage.
- modifiers: Modify views before being updated.

View File

@ -15,12 +15,15 @@ The content.
Initialize a `VStack`.
- Parameter content: The view content.
### `update(_:)`
### `update(_:modifiers:)`
Update a view storage.
- Parameter storage: The view storage.
- Parameters:
- storage: The view storage.
- modifiers: Modify views before being updated.
### `container()`
### `container(modifiers:)`
Get a view storage.
- Parameter modifiers: Modify views before being updated.
- Returns: The view storage.

View File

@ -19,6 +19,10 @@ The window's content.
Whether an instance of the window type should be opened when the app is starting up.
### `parentID`
The identifier of the window's parent.
### `shortcuts`
The keyboard shortcuts.
@ -59,6 +63,12 @@ Get the storage of the content view.
Update a window storage's content.
- Parameter storage: The storage to update.
### `overlay(windows:)`
Add windows that overlay the last instance of this window if presented.
- Parameter windows: The windows.
- Returns: The new windows and this window.
### `keyboardShortcut(_:action:)`
Add a keyboard shortcut.

View File

@ -103,6 +103,8 @@ If you want to use _Adwaita_ in a project, but there are widgets missing, open a
| `onAppear(_:)` | Run when the view is rendered for the first time. |
| `topToolbar(visible:_:)` | Add a native toolbar to the view. Normally, it contains a HeaderBar. |
| `bottomToolbar(visible:_:)` | Add a native bottom toolbar to the view. |
| `modifyContent(_:modify:)` | Replace all occurrences of a certain view type with another view. |
| `stopModifiers()` | Ignore all the `modifyContent(_:modify:)` modifiers from higher above in the view tree. |
### `Button` Modifiers
| Syntax | Description |

View File

@ -13,22 +13,30 @@ extension Array: View where Element == View {
public var view: Body { self }
/// Get a widget from a collection of views.
/// - Parameter modifiers: Modify views before being updated.
/// - Returns: A widget.
public func widget() -> Widget {
if count == 1, let widget = self[safe: 0]?.widget() {
public func widget(modifiers: [(View) -> View]) -> Widget {
if count == 1, let widget = self[safe: 0]?.widget(modifiers: modifiers) {
return widget
} else {
return VStack { self }
var modified = self
for (index, view) in modified.enumerated() {
for modifier in modifiers {
modified[index] = modifier(view)
}
}
return VStack { modified }
}
}
/// Update a collection of views with a collection of view storages.
/// - Parameters:
/// - storage: The collection of view storages.
public func update(_ storage: [ViewStorage]) {
/// - modifiers: Modify views before being updated.
public func update(_ storage: [ViewStorage], modifiers: [(View) -> View]) {
for (index, element) in enumerated() {
if let storage = storage[safe: index] {
element.widget().updateStorage(storage)
element.widget(modifiers: modifiers).updateStorage(storage, modifiers: modifiers)
}
}
}

View File

@ -10,12 +10,15 @@ import GTUI
extension NativeWidgetPeer: Widget {
/// A `GTUI.NativeWidgetPeer` is static.
/// - Parameter storage: The view storage.
public func update(_ storage: ViewStorage) { }
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: Modify views before being updated.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) { }
/// A `GTUI.NativeWidgetPeer`'s container is itself.
/// - Parameter modifiers: Modify views before being updated.
/// - Returns: The view storage.
public func container() -> ViewStorage {
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let bold = "\(modifier(code: 1))"
let yellow = 33
let warning = "\(modifier(code: yellow))\(bold)"

View File

@ -61,7 +61,7 @@ public class GTUIApp: Application {
/// Set the parents of every window having a parent window.
func setParentWindows() {
for window in sceneStorage {
if let parent = sceneStorage.first { $0.id == window.parentID } {
if let parent = sceneStorage.first(where: { $0.id == window.parentID }) {
window.window.setParent(parent.window)
}
}

View File

@ -30,9 +30,11 @@ public protocol View {
extension View {
/// Wrap the view into a widget.
/// - Parameter modifiers: Modify views before being updated.
/// - Returns: The widget.
public func widget() -> Widget {
if let peer = self as? Widget {
public func widget(modifiers: [(View) -> View]) -> Widget {
let modified = getModified(modifiers: modifiers)
if let peer = modified as? Widget {
return peer
} else {
var state: [String: StateProtocol] = [:]
@ -46,19 +48,31 @@ extension View {
}
/// Update a storage to a view.
/// - Parameter storage: The storage.
func updateStorage(_ storage: ViewStorage) {
if let widget = self as? Widget {
widget.update(storage)
/// - Parameters:
/// - storage: The storage.
/// - modifiers: Modify views before being updated.
func updateStorage(_ storage: ViewStorage, modifiers: [(View) -> View]) {
let modified = getModified(modifiers: modifiers)
if let widget = modified as? Widget {
widget.update(storage, modifiers: modifiers)
} else {
StateWrapper { self }.update(storage)
StateWrapper { self }.update(storage, modifiers: modifiers)
}
}
/// Get a storage.
/// - Parameter modifiers: Modify views before being updated.
/// - Returns: The storage.
func storage() -> ViewStorage {
widget().container()
func storage(modifiers: [(View) -> View]) -> ViewStorage {
widget(modifiers: modifiers).container(modifiers: modifiers)
}
func getModified(modifiers: [(View) -> View]) -> View {
var modified: View = self
for modifier in modifiers {
modified = modifier(modified)
}
return modified
}
}

View File

@ -11,10 +11,13 @@ import GTUI
public protocol Widget: View {
/// The view storage.
func container() -> ViewStorage
/// - Parameter modifiers: Modify views before being updated.
func container(modifiers: [(View) -> View]) -> ViewStorage
/// Update the stored content.
/// - Parameter storage: The storage to update.
func update(_ storage: ViewStorage)
/// - Parameters:
/// - storage: The storage to update.
/// - modifiers: Modify views before being updated
func update(_ storage: ViewStorage, modifiers: [(View) -> View])
}

View File

@ -40,8 +40,10 @@ public struct Button: Widget {
}
/// Update a button's view storage.
/// - Parameter storage: The view storage.
public func update(_ storage: ViewStorage) {
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: Modify views before being updated.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
if let button = storage.view as? GTUI.Button {
let content = button.getContent()
if let label {
@ -58,8 +60,9 @@ public struct Button: Widget {
}
/// Get a button's view storage.
/// - Parameter modifiers: Modify views before being updated.
/// - Returns: The button's view storage.
public func container() -> ViewStorage {
public func container(modifiers: [(View) -> View]) -> ViewStorage {
if let icon {
return .init(GTUI.Button(label, icon: icon).handler(handler))
} else {

View File

@ -42,11 +42,13 @@ public struct EitherView: Widget {
}
/// Update an `EitherView`'s storage.
/// - Parameter storage: The view storage.
public func update(_ storage: ViewStorage) {
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: Modify views before being updated.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
let stack = storage.view as? Stack
updateContent(storage, state: true, stack: stack)
updateContent(storage, state: false, stack: stack)
updateContent(storage, state: true, stack: stack, modifiers: modifiers)
updateContent(storage, state: false, stack: stack, modifiers: modifiers)
if isTrue, let trueView = storage.content["\(true)"]?.last?.view {
setVisible(stack, view: trueView)
} else if !isTrue, let falseView = storage.content["\(false)"]?.last?.view {
@ -59,11 +61,12 @@ public struct EitherView: Widget {
/// - storage: The view storage.
/// - state: Whether it is the true or false view.
/// - stack: The stack.
private func updateContent(_ storage: ViewStorage, state: Bool, stack: Stack?) {
let activeView = (state ? trueView : falseView)?.widget()
/// - modifiers: Modify views before being updated.
private func updateContent(_ storage: ViewStorage, state: Bool, stack: Stack?, modifiers: [(View) -> View]) {
let activeView = (state ? trueView : falseView)?.widget(modifiers: modifiers)
if let view = storage.content["\(state)"]?[safe: 0] {
activeView?.updateStorage(view)
} else if let view = activeView?.storage() {
activeView?.updateStorage(view, modifiers: modifiers)
} else if let view = activeView?.storage(modifiers: modifiers) {
_ = stack?.append(view.view)
storage.content["\(state)"] = [view]
}
@ -78,17 +81,18 @@ public struct EitherView: Widget {
}
/// Get a GtkStack view storage.
/// - Parameter modifiers: Modify views before being updated.
/// - Returns: The view storage.
public func container() -> ViewStorage {
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let stack = Stack()
var content: [String: [ViewStorage]] = [:]
if let trueView {
let view = trueView.widget().storage()
let view = trueView.widget(modifiers: modifiers).storage(modifiers: modifiers)
_ = stack.append(view.view)
content["\(true)"] = [view]
}
if let falseView {
let view = falseView.widget().storage()
let view = falseView.widget(modifiers: modifiers).storage(modifiers: modifiers)
_ = stack.append(view.view)
content["\(false)"] = [view]
}

View File

@ -20,18 +20,21 @@ public struct HStack: Widget {
}
/// Update a view storage.
/// - Parameter storage: The view storage.
public func update(_ storage: ViewStorage) {
content().update(storage.content[.mainContent] ?? [])
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: Modify views before being updated.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
content().update(storage.content[.mainContent] ?? [], modifiers: modifiers)
}
/// Get a view storage.
/// - Parameter modifiers: Modify views before being updated.
/// - Returns: The view storage.
public func container() -> ViewStorage {
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let box: Box = .init(horizontal: true)
var content: [ViewStorage] = []
for element in self.content() {
let widget = element.storage()
let widget = element.storage(modifiers: modifiers)
_ = box.append(widget.view)
content.append(widget)
}

View File

@ -58,35 +58,38 @@ public struct HeaderBar: Widget {
}
/// Update a header bar's view storage.
/// - Parameter storage: The view storage.
public func update(_ storage: ViewStorage) {
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: Modify views before being updated.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
if let bar = storage.view as? GTUI.HeaderBar {
_ = bar.showTitleButtons(titleButtons)
}
start.update(storage.content[startID] ?? [])
end.update(storage.content[endID] ?? [])
start.update(storage.content[startID] ?? [], modifiers: modifiers)
end.update(storage.content[endID] ?? [], modifiers: modifiers)
if let first = storage.content[titleID]?.first {
headerBarTitle?.widget().update(first)
headerBarTitle?.widget(modifiers: modifiers).update(first, modifiers: modifiers)
}
}
/// Get the container for a header bar.
/// - Parameter modifiers: Modify views before being updated.
/// - Returns: The view storage.
public func container() -> ViewStorage {
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let bar: GTUI.HeaderBar = .init()
var startContent: [ViewStorage] = []
var endContent: [ViewStorage] = []
for element in start {
let element = element.storage()
let element = element.storage(modifiers: modifiers)
_ = bar.packStart(element.view)
startContent.append(element)
}
for element in end {
let element = element.storage()
let element = element.storage(modifiers: modifiers)
_ = bar.packEnd(element.view)
endContent.append(element)
}
let title = headerBarTitle?.widget().container()
let title = headerBarTitle?.widget(modifiers: modifiers).container(modifiers: modifiers)
let titleStorage: [ViewStorage]
if let title {
_ = bar.titleWidget(title.view)

View File

@ -33,20 +33,23 @@ public struct List<Element>: Widget where Element: Identifiable {
}
/// Update a view storage.
/// - Parameter storage: The view storage.
public func update(_ storage: ViewStorage) {
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: Modify views before being updated.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
if let box = storage.view as? ListBox {
updateSelection(box: box)
}
}
/// Get a view storage.
/// - Parameter modifiers: Modify views before being updated.
/// - Returns: The view storage.
public func container() -> ViewStorage {
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let box: ListBox = .init()
var content: [ViewStorage] = []
for element in elements {
let widget = self.content(element).widget().container()
let widget = self.content(element).widget(modifiers: modifiers).container(modifiers: modifiers)
_ = box.append(widget.view)
content.append(widget)
}

View File

@ -63,8 +63,10 @@ public struct Menu: Widget {
}
/// Update a button's view storage.
/// - Parameter storage: The view storage.
public func update(_ storage: ViewStorage) {
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: Modify views before being updated.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
if let button = storage.view as? GTUI.MenuButton {
let content = button.getContent()
if let label {
@ -81,8 +83,9 @@ public struct Menu: Widget {
}
/// Get a button's view storage.
/// - Parameter modifiers: Modify views before being updated.
/// - Returns: The button's view storage.
public func container() -> ViewStorage {
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let button: GTUI.MenuButton
if let icon {
button = .init(label, icon: icon)

View File

@ -16,20 +16,23 @@ struct Clamp: Widget {
var maxSize: Int
/// Update a view storage.
/// - Parameter storage: The view storage.
func update(_ storage: ViewStorage) {
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: Modify views before being updated.
func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
if let clamp = storage.view as? GTUI.Clamp {
_ = clamp.maximumSize(maxSize)
}
if let storage = storage.content[.mainContent]?[safe: 0] {
content.widget().update(storage)
content.widget(modifiers: modifiers).update(storage, modifiers: modifiers)
}
}
/// Get a view storage.
/// - Parameter modifiers: Modify views before being updated.
/// - Returns: The view storage.
func container() -> ViewStorage {
let container = content.storage()
func container(modifiers: [(View) -> View]) -> ViewStorage {
let container = content.storage(modifiers: modifiers)
let clamp: GTUI.Clamp = .init(container.view)
_ = clamp.maximumSize(maxSize)
return .init(clamp, content: [.mainContent: [container]])

View File

@ -0,0 +1,60 @@
//
// ContentModifier.swift
// Adwaita
//
// Created by david-swift on 11.11.23.
//
import GTUI
/// A widget which replaces views of a specific type in its content.
struct ContentModifier<Content>: Widget where Content: View {
/// The wrapped view.
var content: View
/// The closure for the modification.
var modify: (Content) -> View
/// Get the content's container.
/// - Parameter modifiers: Modify views before being updated.
/// - Returns: The content's container.
func container(modifiers: [(View) -> View]) -> ViewStorage {
let storage = content.storage(modifiers: modifiers + [modifyView])
return storage
}
/// Update the content.
/// - Parameters:
/// - storage: The content's storage.
/// - modifiers: Modify views before being updated.
func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
content.updateStorage(storage, modifiers: modifiers + [modifyView])
}
/// Apply the modifier to a view.
/// - Parameter view: The view.
func modifyView(_ view: View) -> View {
if let view = view as? Content {
return modify(view).stopModifiers()
} else {
return view
}
}
}
extension View {
/// Replace every occurrence of a certain view type in the content.
/// - Parameters:
/// - type: The view type.
/// - modify: Modify the view.
/// - Returns: A view.
public func modifyContent<Content>(
_ type: Content.Type,
modify: @escaping (Content) -> View
) -> View where Content: View {
ContentModifier(content: self, modify: modify)
}
}

View File

@ -16,17 +16,20 @@ struct InspectorWrapper: Widget {
var content: View
/// Get the content's container.
/// - Parameter modifiers: Modify views before being updated.
/// - Returns: The content's container.
func container() -> ViewStorage {
let storage = content.storage()
func container(modifiers: [(View) -> View]) -> ViewStorage {
let storage = content.storage(modifiers: modifiers)
modify(storage.view)
return storage
}
/// Update the content.
/// - Parameter storage: The content's storage.
func update(_ storage: ViewStorage) {
content.updateStorage(storage)
/// - Parameters:
/// - storage: The content's storage.
/// - modifiers: Modify views before being updated.
func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
content.updateStorage(storage, modifiers: modifiers)
modify(storage.view)
}

View File

@ -0,0 +1,42 @@
//
// ModifierStopper.swift
// Adwaita
//
// Created by david-swift on 11.11.23.
//
import GTUI
/// Remove all of the content modifiers for the wrapped views.
struct ModifierStopper: Widget {
/// The wrapped view.
var content: View
/// Get the content's container.
/// - Parameter modifiers: Modify views before being updated.
/// - Returns: The content's container.
func container(modifiers: [(View) -> View]) -> ViewStorage {
let storage = content.storage(modifiers: [])
return storage
}
/// Update the content.
/// - Parameters:
/// - storage: The content's storage.
/// - modifiers: Modify views before being updated.
func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
content.updateStorage(storage, modifiers: [])
}
}
extension View {
/// Remove all of the content modifiers for the wrapped views.
/// - Returns: A view.
public func stopModifiers() -> View {
ModifierStopper(content: self)
}
}

View File

@ -23,13 +23,14 @@ struct ToolbarView: Widget {
let toolbarID = "toolbar"
/// Get the container of the toolbar view widget.
/// - Parameter modifiers: Modify views before being updated.
/// - Returns: The view storage.
func container() -> ViewStorage {
let content = content.storage()
func container(modifiers: [(View) -> View]) -> ViewStorage {
let content = content.storage(modifiers: modifiers)
let view = GTUI.ToolbarView(content.view)
var toolbarContent: [ViewStorage] = []
for item in toolbar() {
let storage = item.storage()
let storage = item.storage(modifiers: modifiers)
toolbarContent.append(storage)
if bottom {
_ = view.addBottomBar(storage.view)
@ -46,14 +47,16 @@ struct ToolbarView: Widget {
}
/// Update the view storage of the toolbar view widget.
/// - Parameter storage: The view storage.
func update(_ storage: ViewStorage) {
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: Modify views before being updated.
func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
if let mainContent = storage.content[.mainContent]?.first {
content.widget().update(mainContent)
content.widget(modifiers: modifiers).update(mainContent, modifiers: modifiers)
}
if let toolbar = storage.content[toolbarID] {
for (index, content) in toolbar.enumerated() {
self.toolbar()[safe: index]?.updateStorage(content)
self.toolbar()[safe: index]?.updateStorage(content, modifiers: modifiers)
}
}
if let view = storage.view as? GTUI.ToolbarView {

View File

@ -16,17 +16,20 @@ struct UpdateObserver: Widget {
var content: View
/// Get the content's container.
/// - Parameter modifiers: Modify views before being updated.
/// - Returns: The content's container.
func container() -> ViewStorage {
func container(modifiers: [(View) -> View]) -> ViewStorage {
onUpdate()
return content.storage()
return content.storage(modifiers: modifiers)
}
/// Update the content.
/// - Parameter storage: The content's storage.
func update(_ storage: ViewStorage) {
/// - Parameters:
/// - storage: The content's storage.
/// - modifiers: Modify views before being updated.
func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
onUpdate()
content.updateStorage(storage)
content.updateStorage(storage, modifiers: modifiers)
}
}

View File

@ -30,17 +30,18 @@ public struct NavigationSplitView: Widget {
}
/// Get the container of the navigation split view widget.
/// - Parameter modifiers: Modify views before being updated.
/// - Returns: The view storage.
public func container() -> ViewStorage {
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let splitView: GTUI.NavigationSplitView = .init()
var content: [String: [ViewStorage]] = [:]
let sidebar = sidebar().widget().container()
let sidebar = sidebar().widget(modifiers: modifiers).container(modifiers: modifiers)
let label = sidebar.view.fields[.navigationLabel] as? String ?? ""
_ = splitView.sidebar(sidebar.view, title: label)
content[sidebarID] = [sidebar]
let mainContent = self.content().widget().container()
let mainContent = self.content().widget(modifiers: modifiers).container(modifiers: modifiers)
let mainLabel = mainContent.view.fields[.navigationLabel] as? String ?? ""
_ = splitView.content(mainContent.view, title: mainLabel)
content[contentID] = [mainContent]
@ -49,13 +50,15 @@ public struct NavigationSplitView: Widget {
}
/// Update the view storage of the navigation split view widget.
/// - Parameter storage: The view storage.
public func update(_ storage: ViewStorage) {
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: Modify views before being updated.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
if let storage = storage.content[contentID]?[safe: 0] {
content().widget().update(storage)
content().widget(modifiers: modifiers).update(storage, modifiers: modifiers)
}
if let storage = storage.content[sidebarID]?[safe: 0] {
sidebar().widget().update(storage)
sidebar().widget(modifiers: modifiers).update(storage, modifiers: modifiers)
}
}

View File

@ -20,17 +20,20 @@ public struct ScrollView: Widget {
}
/// Update a view storage.
/// - Parameter storage: The view storage.
public func update(_ storage: ViewStorage) {
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: Modify views before being updated.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
if let first = storage.content[.mainContent]?.first {
content().widget().update(first)
content().widget(modifiers: modifiers).update(first, modifiers: modifiers)
}
}
/// Get a view storage.
/// - Parameter modifiers: Modify views before being updated.
/// - Returns: The view storage.
public func container() -> ViewStorage {
let container = content().widget().container()
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let container = content().widget(modifiers: modifiers).container(modifiers: modifiers)
return .init(Scrolled().setChild(container.view), content: [.mainContent: [container]])
}

View File

@ -31,22 +31,25 @@ public struct StateWrapper: Widget {
}
/// Update a view storage.
/// - Parameter storage: The view storage.
public func update(_ storage: ViewStorage) {
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: Modify views before being updated.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
for property in state {
if let value = storage.state[property.key]?.value {
property.value.value = value
}
}
if let storage = storage.content[.mainContent]?.first {
content().widget().update(storage)
content().widget(modifiers: modifiers).update(storage, modifiers: modifiers)
}
}
/// Get a view storage.
/// - Parameter modifiers: Modify views before being updated.
/// - Returns: The view storage.
public func container() -> ViewStorage {
let content = content().widget().container()
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let content = content().widget(modifiers: modifiers).container(modifiers: modifiers)
return .init(content.view, content: [.mainContent: [content]], state: state)
}

View File

@ -38,20 +38,23 @@ public struct StatusPage: Widget {
}
/// Update the view storage of the text widget.
/// - Parameter storage: The view storage.
public func update(_ storage: ViewStorage) {
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: Modify views before being updated.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
if let statusPage = storage.view as? GTUI.StatusPage {
_ = statusPage.title(title).description(description).icon(icon)
}
if let storage = storage.content[.mainContent]?.first {
content.widget().update(storage)
content.widget(modifiers: modifiers).update(storage, modifiers: modifiers)
}
}
/// Get the container of the text widget.
/// - Parameter modifiers: Modify views before being updated.
/// - Returns: The view storage.
public func container() -> ViewStorage {
let child = content.widget().container()
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let child = content.widget(modifiers: []).container(modifiers: modifiers)
return .init(
GTUI.StatusPage().title(title).description(description).icon(icon).child(child.view),
content: [.mainContent: [child]]

View File

@ -20,8 +20,10 @@ public struct Text: Widget {
}
/// Update the view storage of the text widget.
/// - Parameter storage: The view storage.
public func update(_ storage: ViewStorage) {
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: Modify views before being updated.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
if let label = storage.view as? MarkupLabel {
label.setText(text)
}
@ -29,7 +31,7 @@ public struct Text: Widget {
/// Get the container of the text widget.
/// - Returns: The view storage.
public func container() -> ViewStorage {
public func container(modifiers: [(View) -> View]) -> ViewStorage {
.init(MarkupLabel(self.text))
}

View File

@ -20,18 +20,21 @@ public struct VStack: Widget {
}
/// Update a view storage.
/// - Parameter storage: The view storage.
public func update(_ storage: ViewStorage) {
content().update(storage.content[.mainContent] ?? [])
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: Modify views before being updated.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
content().update(storage.content[.mainContent] ?? [], modifiers: modifiers)
}
/// Get a view storage.
/// - Parameter modifiers: Modify views before being updated.
/// - Returns: The view storage.
public func container() -> ViewStorage {
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let box: Box = .init(horizontal: false)
var content: [ViewStorage] = []
for element in self.content() {
let widget = element.storage()
let widget = element.storage(modifiers: modifiers)
_ = box.append(widget.view)
content.append(widget)
}

View File

@ -66,7 +66,7 @@ public struct Window: WindowScene {
/// - Returns: The storage of the content of the window.
func getViewStorage(window: GTUIApplicationWindow) -> ViewStorage {
let content = content(window)
let storage = content.widget().container()
let storage = content.widget(modifiers: []).container(modifiers: [])
window.setChild(storage.view)
updateShortcuts(window: window)
return storage
@ -77,7 +77,7 @@ public struct Window: WindowScene {
public func update(_ storage: WindowStorage, app: GTUIApp) {
if let window = storage.window as? GTUIApplicationWindow {
let content = content(window)
content.widget().updateStorage(storage.view)
content.widget(modifiers: []).updateStorage(storage.view, modifiers: [])
updateShortcuts(window: window)
updateAppShortcuts(app: app)
}

View File

@ -46,7 +46,7 @@ struct Demo: App {
struct DemoContent: View {
@State private var selection: Page = .welcome
@State private var selection: Page = .transition
var window: GTUIApplicationWindow
var app: GTUIApp!

View File

@ -16,15 +16,16 @@ struct TransitionDemo: View {
var view: Body {
VStack {
if firstView {
content("First View")
Text("First View")
.transition(.slideDown)
.style("accent")
} else {
content("Second View")
Text("Second View")
.transition(.slideUp)
.style("success")
}
}
.modifyContent(Text.self) { $0.style("title-2").padding() }
.style("card")
.frame(maxSize: 200)
.padding()
@ -36,12 +37,6 @@ struct TransitionDemo: View {
.frame(maxSize: 100)
}
private func content(_ text: String) -> View {
Text(text)
.style("title-2")
.padding()
}
}
// swiftlint:enable missing_docs no_magic_numbers