Add support for flow boxes

This commit is contained in:
david-swift 2024-02-12 11:27:12 +01:00
parent 30482196b6
commit 5cf2be2f54
47 changed files with 880 additions and 42 deletions

View File

@ -34,6 +34,7 @@
- [EntryRow](structs/EntryRow.md)
- [ExpanderRow](structs/ExpanderRow.md)
- [FileDialog](structs/FileDialog.md)
- [FlowBox](structs/FlowBox.md)
- [ForEach](structs/ForEach.md)
- [Form](structs/Form.md)
- [HStack](structs/HStack.md)
@ -111,6 +112,7 @@
- [Clamp](extensions/Clamp.md)
- [ComboRow](extensions/ComboRow.md)
- [EntryRow](extensions/EntryRow.md)
- [FlowBox](extensions/FlowBox.md)
- [FormSection](extensions/FormSection.md)
- [HeaderBar](extensions/HeaderBar.md)
- [Int](extensions/Int.md)

View File

@ -0,0 +1,21 @@
**EXTENSION**
# `FlowBox`
## Properties
### `selectionField`
The ID for the field storing the selection value.
### `elementsField`
The ID for the field storing the elements.
## Methods
### `init(_:selection:content:)`
Initialize `FlowBox`.
- Parameters:
- elements: The elements.
- selection: The identifier of the selected element. Selection disabled if `nil`.
- content: The view for an element.

View File

@ -0,0 +1,290 @@
**STRUCT**
# `FlowBox`
A `GtkFlowBox` puts child widgets in reflowing grid.
For instance, with the horizontal orientation, the widgets will be
arranged from left to right, starting a new row under the previous
row when necessary. Reducing the width in this case will require more
rows, so a larger height will be requested.
Likewise, with the vertical orientation, the widgets will be arranged
from top to bottom, starting a new column to the right when necessary.
Reducing the height will require more columns, so a larger width will
be requested.
The size request of a `GtkFlowBox` alone may not be what you expect;
if you need to be able to shrink it along both axes and dynamically
reflow its children, you may have to wrap it in a `GtkScrolledWindow`
to enable that.
The children of a `GtkFlowBox` can be dynamically sorted and filtered.
Although a `GtkFlowBox` must have only `GtkFlowBoxChild` children, you
can add any kind of widget to it via [method@Gtk.FlowBox.insert], and a
`GtkFlowBoxChild` widget will automatically be inserted between the box
and the widget.
Also see [class@Gtk.ListBox].
# CSS nodes
```
flowbox
├── flowboxchild
│ ╰── <child>├── flowboxchild
│ ╰── <child>
╰── [rubberband]
```
`GtkFlowBox` uses a single CSS node with name flowbox. `GtkFlowBoxChild`
uses a single CSS node with name flowboxchild. For rubberband selection,
a subnode with name rubberband is used.
# Accessibility
`GtkFlowBox` uses the %GTK_ACCESSIBLE_ROLE_GRID role, and `GtkFlowBoxChild`
uses the %GTK_ACCESSIBLE_ROLE_GRID_CELL role.
## Properties
### `updateFunctions`
Additional update functions for type extensions.
### `appearFunctions`
Additional appear functions for type extensions.
### `acceptUnpairedRelease`
accept-unpaired-release
### `activateOnSingleClick`
Determines whether children can be activated with a single
click, or require a double-click.
### `columnSpacing`
The amount of horizontal space between two children.
### `homogeneous`
Determines whether all children should be allocated the
same size.
### `maxChildrenPerLine`
The maximum amount of children to request space for consecutively
in the given orientation.
### `minChildrenPerLine`
The minimum number of children to allocate consecutively
in the given orientation.
Setting the minimum children per line ensures
that a reasonably small height will be requested
for the overall minimum width of the box.
### `rowSpacing`
The amount of vertical space between two children.
### `activateCursorChild`
Emitted when the user activates the @box.
This is a [keybinding signal](class.SignalAction.html).
### `childActivated`
Emitted when a child has been activated by the user.
### `moveCursor`
Emitted when the user initiates a cursor movement.
This is a [keybinding signal](class.SignalAction.html).
Applications should not connect to it, but may emit it with
g_signal_emit_by_name() if they need to control the cursor
programmatically.
The default bindings for this signal come in two variants,
the variant with the Shift modifier extends the selection,
the variant without the Shift modifier does not.
There are too many key combinations to list them all here.
- <kbd></kbd>, <kbd></kbd>, <kbd></kbd>, <kbd></kbd>
move by individual children
- <kbd>Home</kbd>, <kbd>End</kbd> move to the ends of the box
- <kbd>PgUp</kbd>, <kbd>PgDn</kbd> move vertically by pages
### `selectAll`
Emitted to select all children of the box,
if the selection mode permits it.
This is a [keybinding signal](class.SignalAction.html).
The default bindings for this signal is <kbd>Ctrl</kbd>-<kbd>a</kbd>.
### `selectedChildrenChanged`
Emitted when the set of selected children changes.
Use [method@Gtk.FlowBox.selected_foreach] or
[method@Gtk.FlowBox.get_selected_children] to obtain the
selected children.
### `toggleCursorChild`
Emitted to toggle the selection of the child that has the focus.
This is a [keybinding signal](class.SignalAction.html).
The default binding for this signal is <kbd>Ctrl</kbd>-<kbd>Space</kbd>.
### `unselectAll`
Emitted to unselect all children of the box,
if the selection mode permits it.
This is a [keybinding signal](class.SignalAction.html).
The default bindings for this signal is <kbd>Ctrl</kbd>-<kbd>Shift</kbd>-<kbd>a</kbd>.
### `elements`
The dynamic widget elements.
### `content`
The dynamic widget content.
### `app`
The application.
### `window`
The window.
## Methods
### `init(_:content:)`
Initialize `FlowBox`.
### `container(modifiers:)`
Get the widget's view storage.
- Parameter modifiers: The view modifiers.
- Returns: The view storage.
### `update(_:modifiers:updateProperties:)`
Update the widget's view storage.
- Parameters:
- storage: The view storage.
- modifiers: The view modifiers.
- updateProperties: Whether to update the view's properties.
### `acceptUnpairedRelease(_:)`
accept-unpaired-release
### `activateOnSingleClick(_:)`
Determines whether children can be activated with a single
click, or require a double-click.
### `columnSpacing(_:)`
The amount of horizontal space between two children.
### `homogeneous(_:)`
Determines whether all children should be allocated the
same size.
### `maxChildrenPerLine(_:)`
The maximum amount of children to request space for consecutively
in the given orientation.
### `minChildrenPerLine(_:)`
The minimum number of children to allocate consecutively
in the given orientation.
Setting the minimum children per line ensures
that a reasonably small height will be requested
for the overall minimum width of the box.
### `rowSpacing(_:)`
The amount of vertical space between two children.
### `activateCursorChild(_:)`
Emitted when the user activates the @box.
This is a [keybinding signal](class.SignalAction.html).
### `childActivated(_:)`
Emitted when a child has been activated by the user.
### `moveCursor(_:)`
Emitted when the user initiates a cursor movement.
This is a [keybinding signal](class.SignalAction.html).
Applications should not connect to it, but may emit it with
g_signal_emit_by_name() if they need to control the cursor
programmatically.
The default bindings for this signal come in two variants,
the variant with the Shift modifier extends the selection,
the variant without the Shift modifier does not.
There are too many key combinations to list them all here.
- <kbd></kbd>, <kbd></kbd>, <kbd></kbd>, <kbd></kbd>
move by individual children
- <kbd>Home</kbd>, <kbd>End</kbd> move to the ends of the box
- <kbd>PgUp</kbd>, <kbd>PgDn</kbd> move vertically by pages
### `selectAll(_:)`
Emitted to select all children of the box,
if the selection mode permits it.
This is a [keybinding signal](class.SignalAction.html).
The default bindings for this signal is <kbd>Ctrl</kbd>-<kbd>a</kbd>.
### `selectedChildrenChanged(_:)`
Emitted when the set of selected children changes.
Use [method@Gtk.FlowBox.selected_foreach] or
[method@Gtk.FlowBox.get_selected_children] to obtain the
selected children.
### `toggleCursorChild(_:)`
Emitted to toggle the selection of the child that has the focus.
This is a [keybinding signal](class.SignalAction.html).
The default binding for this signal is <kbd>Ctrl</kbd>-<kbd>Space</kbd>.
### `unselectAll(_:)`
Emitted to unselect all children of the box,
if the selection mode permits it.
This is a [keybinding signal](class.SignalAction.html).
The default bindings for this signal is <kbd>Ctrl</kbd>-<kbd>Shift</kbd>-<kbd>a</kbd>.

View File

@ -0,0 +1,59 @@
//
// FlowBox+.swift
// Adwaita
//
// Created by david-swift on 12.02.24.
//
import CAdw
extension FlowBox {
/// The ID for the field storing the selection value.
static var selectionField: String { "selection" }
/// The ID for the field storing the elements.
static var elementsField: String { "element" }
/// Initialize `FlowBox`.
/// - Parameters:
/// - elements: The elements.
/// - selection: The identifier of the selected element. Selection disabled if `nil`.
/// - content: The view for an element.
public init(
_ elements: [Element],
selection: Binding<Element.ID>?,
@ViewBuilder content: @escaping (Element) -> Body
) {
self.init(elements, content: content)
let id: (ViewStorage, [Element]) -> Element.ID? = { storage, elements in
if let child = g_list_nth_data(gtk_flow_box_get_selected_children(storage.pointer), 0) {
let element = gtk_flow_box_child_get_child(child.cast())
return elements[safe: storage.content[.mainContent]?.firstIndex { $0.pointer?.cast() == element }]?.id
}
return nil
}
if let selection {
appearFunctions.append { storage in
storage.fields[Self.selectionField] = selection
storage.connectSignal(name: "selected_children_changed", id: Self.selectionField) {
if let binding = storage.fields[Self.selectionField] as? Binding<Element.ID>,
let elements = storage.fields[Self.elementsField] as? [Element],
let id = id(storage, elements) {
binding.wrappedValue = id
}
}
}
updateFunctions.append { storage in
if selection.wrappedValue != id(storage, elements),
let index = elements.firstIndex(where: { $0.id == selection.wrappedValue })?.cInt {
gtk_flow_box_select_child(storage.pointer, gtk_flow_box_get_child_at_index(storage.pointer, index))
}
}
} else {
appearFunctions.append { storage in
gtk_flow_box_set_selection_mode(storage.pointer, GTK_SELECTION_NONE)
}
}
}
}

View File

@ -2,7 +2,7 @@
// ActionRow.swift
// Adwaita
//
// Created by auto-generation on 10.02.24.
// Created by auto-generation on 12.02.24.
//
import CAdw

View File

@ -2,7 +2,7 @@
// Avatar.swift
// Adwaita
//
// Created by auto-generation on 10.02.24.
// Created by auto-generation on 12.02.24.
//
import CAdw

View File

@ -2,7 +2,7 @@
// Banner.swift
// Adwaita
//
// Created by auto-generation on 10.02.24.
// Created by auto-generation on 12.02.24.
//
import CAdw

View File

@ -2,7 +2,7 @@
// Bin.swift
// Adwaita
//
// Created by auto-generation on 10.02.24.
// Created by auto-generation on 12.02.24.
//
import CAdw

View File

@ -2,7 +2,7 @@
// Box.swift
// Adwaita
//
// Created by auto-generation on 10.02.24.
// Created by auto-generation on 12.02.24.
//
import CAdw

View File

@ -2,7 +2,7 @@
// Button.swift
// Adwaita
//
// Created by auto-generation on 10.02.24.
// Created by auto-generation on 12.02.24.
//
import CAdw

View File

@ -2,7 +2,7 @@
// ButtonContent.swift
// Adwaita
//
// Created by auto-generation on 10.02.24.
// Created by auto-generation on 12.02.24.
//
import CAdw

View File

@ -2,7 +2,7 @@
// Carousel.swift
// Adwaita
//
// Created by auto-generation on 10.02.24.
// Created by auto-generation on 12.02.24.
//
import CAdw

View File

@ -2,7 +2,7 @@
// CenterBox.swift
// Adwaita
//
// Created by auto-generation on 10.02.24.
// Created by auto-generation on 12.02.24.
//
import CAdw

View File

@ -2,7 +2,7 @@
// CheckButton.swift
// Adwaita
//
// Created by auto-generation on 10.02.24.
// Created by auto-generation on 12.02.24.
//
import CAdw

View File

@ -2,7 +2,7 @@
// Clamp.swift
// Adwaita
//
// Created by auto-generation on 10.02.24.
// Created by auto-generation on 12.02.24.
//
import CAdw

View File

@ -2,7 +2,7 @@
// ComboRow.swift
// Adwaita
//
// Created by auto-generation on 10.02.24.
// Created by auto-generation on 12.02.24.
//
import CAdw

View File

@ -2,7 +2,7 @@
// EntryRow.swift
// Adwaita
//
// Created by auto-generation on 10.02.24.
// Created by auto-generation on 12.02.24.
//
import CAdw

View File

@ -2,7 +2,7 @@
// ExpanderRow.swift
// Adwaita
//
// Created by auto-generation on 10.02.24.
// Created by auto-generation on 12.02.24.
//
import CAdw

View File

@ -0,0 +1,401 @@
//
// FlowBox.swift
// Adwaita
//
// Created by auto-generation on 12.02.24.
//
import CAdw
import LevenshteinTransformations
/// A `GtkFlowBox` puts child widgets in reflowing grid.
///
/// For instance, with the horizontal orientation, the widgets will be
/// arranged from left to right, starting a new row under the previous
/// row when necessary. Reducing the width in this case will require more
/// rows, so a larger height will be requested.
///
/// Likewise, with the vertical orientation, the widgets will be arranged
/// from top to bottom, starting a new column to the right when necessary.
/// Reducing the height will require more columns, so a larger width will
/// be requested.
///
/// The size request of a `GtkFlowBox` alone may not be what you expect;
/// if you need to be able to shrink it along both axes and dynamically
/// reflow its children, you may have to wrap it in a `GtkScrolledWindow`
/// to enable that.
///
/// The children of a `GtkFlowBox` can be dynamically sorted and filtered.
///
/// Although a `GtkFlowBox` must have only `GtkFlowBoxChild` children, you
/// can add any kind of widget to it via [method@Gtk.FlowBox.insert], and a
/// `GtkFlowBoxChild` widget will automatically be inserted between the box
/// and the widget.
///
/// Also see [class@Gtk.ListBox].
///
/// # CSS nodes
///
/// ```
/// flowbox
/// flowboxchild
/// <child> flowboxchild
/// <child>
/// [rubberband]
/// ```
///
/// `GtkFlowBox` uses a single CSS node with name flowbox. `GtkFlowBoxChild`
/// uses a single CSS node with name flowboxchild. For rubberband selection,
/// a subnode with name rubberband is used.
///
/// # Accessibility
///
/// `GtkFlowBox` uses the %GTK_ACCESSIBLE_ROLE_GRID role, and `GtkFlowBoxChild`
/// uses the %GTK_ACCESSIBLE_ROLE_GRID_CELL role.
public struct FlowBox<Element>: Widget where Element: Identifiable {
/// Additional update functions for type extensions.
var updateFunctions: [(ViewStorage) -> Void] = []
/// Additional appear functions for type extensions.
var appearFunctions: [(ViewStorage) -> Void] = []
/// accept-unpaired-release
var acceptUnpairedRelease: Bool?
/// Determines whether children can be activated with a single
/// click, or require a double-click.
var activateOnSingleClick: Bool?
/// The amount of horizontal space between two children.
var columnSpacing: UInt?
/// Determines whether all children should be allocated the
/// same size.
var homogeneous: Bool?
/// The maximum amount of children to request space for consecutively
/// in the given orientation.
var maxChildrenPerLine: UInt?
/// The minimum number of children to allocate consecutively
/// in the given orientation.
///
/// Setting the minimum children per line ensures
/// that a reasonably small height will be requested
/// for the overall minimum width of the box.
var minChildrenPerLine: UInt?
/// The amount of vertical space between two children.
var rowSpacing: UInt?
/// Emitted when the user activates the @box.
///
/// This is a [keybinding signal](class.SignalAction.html).
var activateCursorChild: (() -> Void)?
/// Emitted when a child has been activated by the user.
var childActivated: (() -> Void)?
/// Emitted when the user initiates a cursor movement.
///
/// This is a [keybinding signal](class.SignalAction.html).
/// Applications should not connect to it, but may emit it with
/// g_signal_emit_by_name() if they need to control the cursor
/// programmatically.
///
/// The default bindings for this signal come in two variants,
/// the variant with the Shift modifier extends the selection,
/// the variant without the Shift modifier does not.
/// There are too many key combinations to list them all here.
///
/// - <kbd></kbd>, <kbd></kbd>, <kbd></kbd>, <kbd></kbd>
/// move by individual children
/// - <kbd>Home</kbd>, <kbd>End</kbd> move to the ends of the box
/// - <kbd>PgUp</kbd>, <kbd>PgDn</kbd> move vertically by pages
var moveCursor: (() -> Void)?
/// Emitted to select all children of the box,
/// if the selection mode permits it.
///
/// This is a [keybinding signal](class.SignalAction.html).
///
/// The default bindings for this signal is <kbd>Ctrl</kbd>-<kbd>a</kbd>.
var selectAll: (() -> Void)?
/// Emitted when the set of selected children changes.
///
/// Use [method@Gtk.FlowBox.selected_foreach] or
/// [method@Gtk.FlowBox.get_selected_children] to obtain the
/// selected children.
var selectedChildrenChanged: (() -> Void)?
/// Emitted to toggle the selection of the child that has the focus.
///
/// This is a [keybinding signal](class.SignalAction.html).
///
/// The default binding for this signal is <kbd>Ctrl</kbd>-<kbd>Space</kbd>.
var toggleCursorChild: (() -> Void)?
/// Emitted to unselect all children of the box,
/// if the selection mode permits it.
///
/// This is a [keybinding signal](class.SignalAction.html).
///
/// The default bindings for this signal is <kbd>Ctrl</kbd>-<kbd>Shift</kbd>-<kbd>a</kbd>.
var unselectAll: (() -> Void)?
/// The dynamic widget elements.
var elements: [Element]
/// The dynamic widget content.
var content: (Element) -> Body
/// The application.
var app: GTUIApp?
/// The window.
var window: GTUIApplicationWindow?
/// Initialize `FlowBox`.
public init(_ elements: [Element], @ViewBuilder content: @escaping (Element) -> Body) {
self.elements = elements
self.content = content
}
/// Get the widget's view storage.
/// - Parameter modifiers: The view modifiers.
/// - Returns: The view storage.
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let storage = ViewStorage(gtk_flow_box_new()?.opaque())
update(storage, modifiers: modifiers, updateProperties: true)
for function in appearFunctions {
function(storage)
}
return storage
}
/// Update the widget's view storage.
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: The view modifiers.
/// - updateProperties: Whether to update the view's properties.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View], updateProperties: Bool) {
if let activateCursorChild {
storage.connectSignal(name: "activate-cursor-child", argCount: 0) {
activateCursorChild()
}
}
if let childActivated {
storage.connectSignal(name: "child-activated", argCount: 1) {
childActivated()
}
}
if let moveCursor {
storage.connectSignal(name: "move-cursor", argCount: 4) {
moveCursor()
}
}
if let selectAll {
storage.connectSignal(name: "select-all", argCount: 0) {
selectAll()
}
}
if let selectedChildrenChanged {
storage.connectSignal(name: "selected-children-changed", argCount: 0) {
selectedChildrenChanged()
}
}
if let toggleCursorChild {
storage.connectSignal(name: "toggle-cursor-child", argCount: 0) {
toggleCursorChild()
}
}
if let unselectAll {
storage.connectSignal(name: "unselect-all", argCount: 0) {
unselectAll()
}
}
storage.modify { widget in
if let activateOnSingleClick, updateProperties {
gtk_flow_box_set_activate_on_single_click(widget, activateOnSingleClick.cBool)
}
if let columnSpacing, updateProperties {
gtk_flow_box_set_column_spacing(widget, columnSpacing.cInt)
}
if let homogeneous, updateProperties {
gtk_flow_box_set_homogeneous(widget, homogeneous.cBool)
}
if let maxChildrenPerLine, updateProperties {
gtk_flow_box_set_max_children_per_line(widget, maxChildrenPerLine.cInt)
}
if let minChildrenPerLine, updateProperties {
gtk_flow_box_set_min_children_per_line(widget, minChildrenPerLine.cInt)
}
if let rowSpacing, updateProperties {
gtk_flow_box_set_row_spacing(widget, rowSpacing.cInt)
}
var contentStorage: [ViewStorage] = storage.content[.mainContent] ?? []
let old = storage.fields["element"] as? [Element] ?? []
old.identifiableTransform(
to: elements,
functions: .init { index, element in
let child = content(element).widget(modifiers: modifiers).container(modifiers: modifiers)
gtk_flow_box_remove(widget, gtk_flow_box_get_child_at_index(widget, index.cInt)?.cast())
gtk_flow_box_insert(widget, child.pointer?.cast(), index.cInt)
contentStorage.remove(at: index)
contentStorage.insert(child, at: index)
} delete: { index in
gtk_flow_box_remove(widget, gtk_flow_box_get_child_at_index(widget, index.cInt)?.cast())
contentStorage.remove(at: index)
} insert: { index, element in
let child = content(element).widget(modifiers: modifiers).container(modifiers: modifiers)
gtk_flow_box_insert(widget, child.pointer?.cast(), index.cInt)
contentStorage.insert(child, at: index)
}
)
storage.fields["element"] = elements
storage.content[.mainContent] = contentStorage
for (index, element) in elements.enumerated() {
content(element).widget(modifiers: modifiers).update(contentStorage[index], modifiers: modifiers, updateProperties: updateProperties)
}
}
for function in updateFunctions {
function(storage)
}
}
/// accept-unpaired-release
public func acceptUnpairedRelease(_ acceptUnpairedRelease: Bool? = true) -> Self {
var newSelf = self
newSelf.acceptUnpairedRelease = acceptUnpairedRelease
return newSelf
}
/// Determines whether children can be activated with a single
/// click, or require a double-click.
public func activateOnSingleClick(_ activateOnSingleClick: Bool? = true) -> Self {
var newSelf = self
newSelf.activateOnSingleClick = activateOnSingleClick
return newSelf
}
/// The amount of horizontal space between two children.
public func columnSpacing(_ columnSpacing: UInt?) -> Self {
var newSelf = self
newSelf.columnSpacing = columnSpacing
return newSelf
}
/// Determines whether all children should be allocated the
/// same size.
public func homogeneous(_ homogeneous: Bool? = true) -> Self {
var newSelf = self
newSelf.homogeneous = homogeneous
return newSelf
}
/// The maximum amount of children to request space for consecutively
/// in the given orientation.
public func maxChildrenPerLine(_ maxChildrenPerLine: UInt?) -> Self {
var newSelf = self
newSelf.maxChildrenPerLine = maxChildrenPerLine
return newSelf
}
/// The minimum number of children to allocate consecutively
/// in the given orientation.
///
/// Setting the minimum children per line ensures
/// that a reasonably small height will be requested
/// for the overall minimum width of the box.
public func minChildrenPerLine(_ minChildrenPerLine: UInt?) -> Self {
var newSelf = self
newSelf.minChildrenPerLine = minChildrenPerLine
return newSelf
}
/// The amount of vertical space between two children.
public func rowSpacing(_ rowSpacing: UInt?) -> Self {
var newSelf = self
newSelf.rowSpacing = rowSpacing
return newSelf
}
/// Emitted when the user activates the @box.
///
/// This is a [keybinding signal](class.SignalAction.html).
public func activateCursorChild(_ activateCursorChild: @escaping () -> Void) -> Self {
var newSelf = self
newSelf.activateCursorChild = activateCursorChild
return newSelf
}
/// Emitted when a child has been activated by the user.
public func childActivated(_ childActivated: @escaping () -> Void) -> Self {
var newSelf = self
newSelf.childActivated = childActivated
return newSelf
}
/// Emitted when the user initiates a cursor movement.
///
/// This is a [keybinding signal](class.SignalAction.html).
/// Applications should not connect to it, but may emit it with
/// g_signal_emit_by_name() if they need to control the cursor
/// programmatically.
///
/// The default bindings for this signal come in two variants,
/// the variant with the Shift modifier extends the selection,
/// the variant without the Shift modifier does not.
/// There are too many key combinations to list them all here.
///
/// - <kbd></kbd>, <kbd></kbd>, <kbd></kbd>, <kbd></kbd>
/// move by individual children
/// - <kbd>Home</kbd>, <kbd>End</kbd> move to the ends of the box
/// - <kbd>PgUp</kbd>, <kbd>PgDn</kbd> move vertically by pages
public func moveCursor(_ moveCursor: @escaping () -> Void) -> Self {
var newSelf = self
newSelf.moveCursor = moveCursor
return newSelf
}
/// Emitted to select all children of the box,
/// if the selection mode permits it.
///
/// This is a [keybinding signal](class.SignalAction.html).
///
/// The default bindings for this signal is <kbd>Ctrl</kbd>-<kbd>a</kbd>.
public func selectAll(_ selectAll: @escaping () -> Void) -> Self {
var newSelf = self
newSelf.selectAll = selectAll
return newSelf
}
/// Emitted when the set of selected children changes.
///
/// Use [method@Gtk.FlowBox.selected_foreach] or
/// [method@Gtk.FlowBox.get_selected_children] to obtain the
/// selected children.
public func selectedChildrenChanged(_ selectedChildrenChanged: @escaping () -> Void) -> Self {
var newSelf = self
newSelf.selectedChildrenChanged = selectedChildrenChanged
return newSelf
}
/// Emitted to toggle the selection of the child that has the focus.
///
/// This is a [keybinding signal](class.SignalAction.html).
///
/// The default binding for this signal is <kbd>Ctrl</kbd>-<kbd>Space</kbd>.
public func toggleCursorChild(_ toggleCursorChild: @escaping () -> Void) -> Self {
var newSelf = self
newSelf.toggleCursorChild = toggleCursorChild
return newSelf
}
/// Emitted to unselect all children of the box,
/// if the selection mode permits it.
///
/// This is a [keybinding signal](class.SignalAction.html).
///
/// The default bindings for this signal is <kbd>Ctrl</kbd>-<kbd>Shift</kbd>-<kbd>a</kbd>.
public func unselectAll(_ unselectAll: @escaping () -> Void) -> Self {
var newSelf = self
newSelf.unselectAll = unselectAll
return newSelf
}
}

View File

@ -2,7 +2,7 @@
// HeaderBar.swift
// Adwaita
//
// Created by auto-generation on 10.02.24.
// Created by auto-generation on 12.02.24.
//
import CAdw

View File

@ -2,7 +2,7 @@
// Label.swift
// Adwaita
//
// Created by auto-generation on 10.02.24.
// Created by auto-generation on 12.02.24.
//
import CAdw

View File

@ -2,7 +2,7 @@
// LevelBar.swift
// Adwaita
//
// Created by auto-generation on 10.02.24.
// Created by auto-generation on 12.02.24.
//
import CAdw

View File

@ -2,7 +2,7 @@
// LinkButton.swift
// Adwaita
//
// Created by auto-generation on 10.02.24.
// Created by auto-generation on 12.02.24.
//
import CAdw

View File

@ -2,7 +2,7 @@
// ListBox.swift
// Adwaita
//
// Created by auto-generation on 10.02.24.
// Created by auto-generation on 12.02.24.
//
import CAdw

View File

@ -2,7 +2,7 @@
// Menu.swift
// Adwaita
//
// Created by auto-generation on 10.02.24.
// Created by auto-generation on 12.02.24.
//
import CAdw

View File

@ -2,7 +2,7 @@
// Overlay.swift
// Adwaita
//
// Created by auto-generation on 10.02.24.
// Created by auto-generation on 12.02.24.
//
import CAdw

View File

@ -2,7 +2,7 @@
// OverlaySplitView.swift
// Adwaita
//
// Created by auto-generation on 10.02.24.
// Created by auto-generation on 12.02.24.
//
import CAdw

View File

@ -2,7 +2,7 @@
// PasswordEntryRow.swift
// Adwaita
//
// Created by auto-generation on 10.02.24.
// Created by auto-generation on 12.02.24.
//
import CAdw

View File

@ -2,7 +2,7 @@
// Popover.swift
// Adwaita
//
// Created by auto-generation on 10.02.24.
// Created by auto-generation on 12.02.24.
//
import CAdw

View File

@ -2,7 +2,7 @@
// PreferencesGroup.swift
// Adwaita
//
// Created by auto-generation on 10.02.24.
// Created by auto-generation on 12.02.24.
//
import CAdw

View File

@ -2,7 +2,7 @@
// PreferencesPage.swift
// Adwaita
//
// Created by auto-generation on 10.02.24.
// Created by auto-generation on 12.02.24.
//
import CAdw

View File

@ -2,7 +2,7 @@
// PreferencesRow.swift
// Adwaita
//
// Created by auto-generation on 10.02.24.
// Created by auto-generation on 12.02.24.
//
import CAdw

View File

@ -2,7 +2,7 @@
// ProgressBar.swift
// Adwaita
//
// Created by auto-generation on 10.02.24.
// Created by auto-generation on 12.02.24.
//
import CAdw

View File

@ -2,7 +2,7 @@
// ScrolledWindow.swift
// Adwaita
//
// Created by auto-generation on 10.02.24.
// Created by auto-generation on 12.02.24.
//
import CAdw

View File

@ -2,7 +2,7 @@
// SpinRow.swift
// Adwaita
//
// Created by auto-generation on 10.02.24.
// Created by auto-generation on 12.02.24.
//
import CAdw

View File

@ -2,7 +2,7 @@
// Spinner.swift
// Adwaita
//
// Created by auto-generation on 10.02.24.
// Created by auto-generation on 12.02.24.
//
import CAdw

View File

@ -2,7 +2,7 @@
// SplitButton.swift
// Adwaita
//
// Created by auto-generation on 10.02.24.
// Created by auto-generation on 12.02.24.
//
import CAdw

View File

@ -2,7 +2,7 @@
// StatusPage.swift
// Adwaita
//
// Created by auto-generation on 10.02.24.
// Created by auto-generation on 12.02.24.
//
import CAdw

View File

@ -2,7 +2,7 @@
// SwitchRow.swift
// Adwaita
//
// Created by auto-generation on 10.02.24.
// Created by auto-generation on 12.02.24.
//
import CAdw

View File

@ -2,7 +2,7 @@
// ToastOverlay.swift
// Adwaita
//
// Created by auto-generation on 10.02.24.
// Created by auto-generation on 12.02.24.
//
import CAdw

View File

@ -2,7 +2,7 @@
// ToggleButton.swift
// Adwaita
//
// Created by auto-generation on 10.02.24.
// Created by auto-generation on 12.02.24.
//
import CAdw

View File

@ -2,7 +2,7 @@
// ToolbarView.swift
// Adwaita
//
// Created by auto-generation on 10.02.24.
// Created by auto-generation on 12.02.24.
//
import CAdw

View File

@ -2,7 +2,7 @@
// WindowTitle.swift
// Adwaita
//
// Created by auto-generation on 10.02.24.
// Created by auto-generation on 12.02.24.
//
import CAdw

View File

@ -220,7 +220,16 @@ struct GenerationConfiguration {
]
),
.init(class: "Overlay", staticWidgets: [.init(name: "overlay", add: "gtk_overlay_add_overlay")]),
.init(class: "Popover", excludeProperties: ["pointing-to", "position"], cast: true)
.init(class: "Popover", excludeProperties: ["pointing-to", "position"], cast: true),
.init(
class: "FlowBox",
dynamicWidget: .init(
insert: "gtk_flow_box_insert",
remove: "gtk_flow_box_remove",
getElement: "gtk_flow_box_get_child_at_index(widget, index.cInt)?.cast()"
),
excludeProperties: ["selection-mode"]
)
]
/// The unshortening map.

49
Tests/FlowBoxDemo.swift Normal file
View File

@ -0,0 +1,49 @@
//
// ListDemo.swift
// Adwaita
//
// Created by david-swift on 01.01.24.
//
// swiftlint:disable missing_docs no_magic_numbers
import Adwaita
import Foundation
struct FlowBoxDemo: View {
@State private var items: [ListDemo.Element] = []
@State private var selectedItem = ""
var view: Body {
HStack {
Button("Add Element") {
let element = ListDemo.Element(id: UUID().uuidString)
items.append(element)
selectedItem = element.id
}
Button("Delete Selected Element") {
let index = items.firstIndex { $0.id == selectedItem }
items = items.filter { $0.id != selectedItem }
selectedItem = items[safe: index]?.id ?? items[safe: index ?? 0 - 1]?.id ?? items.first?.id ?? ""
}
}
.padding()
.style("linked")
.halign(.center)
if !items.isEmpty {
FlowBox(items, selection: $selectedItem) { item in
HStack {
Text(.init("\(item.id)".prefix(5)))
.hexpand()
}
.padding()
}
.valign(.center)
.padding()
}
}
}
// swiftlint:enable missing_docs no_magic_numbers

View File

@ -24,6 +24,7 @@ enum Page: String, Identifiable, CaseIterable, Codable {
case viewSwitcher
case form
case popover
case flowBox
var id: Self {
self
@ -35,6 +36,8 @@ enum Page: String, Identifiable, CaseIterable, Codable {
return "Overlay Window"
case .viewSwitcher:
return "View Switcher"
case .flowBox:
return "Flow Box"
default:
return rawValue.capitalized
}
@ -77,6 +80,8 @@ enum Page: String, Identifiable, CaseIterable, Codable {
return "Group controls used for data entry."
case .popover:
return "Present content in a bubble-like context popup."
case .flowBox:
return "Display views in a reflowing grid."
}
}
@ -110,6 +115,8 @@ enum Page: String, Identifiable, CaseIterable, Codable {
FormDemo(app: app)
case .popover:
PopoverDemo()
case .flowBox:
FlowBoxDemo()
}
}
// swiftlint:enable cyclomatic_complexity

View File

@ -20,9 +20,9 @@ struct PopoverDemo: View {
}
.style("suggested-action")
.frame(maxSize: 100)
}
.popover(visible: $visible) {
CounterDemo()
.popover(visible: $visible) {
CounterDemo()
}
}
}