//
// ToolbarView.swift
// Adwaita
//
// Created by auto-generation on 15.08.24.
//
import CAdw
import LevenshteinTransformations
/// A widget containing a page, as well as top and/or bottom bars.
///
///
///
/// `AdwToolbarView` has a single content widget and one or multiple top and
/// bottom bars, shown at the top and bottom sides respectively.
///
/// Example of an `AdwToolbarView` UI definition:
/// ```xml
///
/// ```
///
/// The following kinds of top and bottom bars are supported:
///
/// - [class@HeaderBar]
/// - [class@TabBar]
/// - [class@ViewSwitcherBar]
/// - [class@Gtk.ActionBar]
/// - [class@Gtk.HeaderBar]
/// - [class@Gtk.PopoverMenuBar]
/// - [class@Gtk.SearchBar]
/// - Any [class@Gtk.Box] or a similar widget with the
/// [`.toolbar`](style-classes.html#toolbars) style class
///
/// By default, top and bottom bars are flat and scrolling content has a subtle
/// undershoot shadow, same as when using the
/// [`.undershoot-top`](style-classes.html#undershoot-indicators) and
/// [`.undershoot-bottom`](style-classes.html#undershoot-indicators) style
/// classes. This works well in most cases, e.g. with [class@StatusPage] or
/// [class@PreferencesPage], where the background at the top and bottom parts of
/// the page is uniform. Additionally, windows with sidebars should always use
/// this style.
///
/// [property@ToolbarView:top-bar-style] and
/// [property@ToolbarView:bottom-bar-style] properties can be used add an opaque
/// background and a persistent shadow to top and bottom bars, this can be useful
/// for content such as [utility panes](https://developer.gnome.org/hig/patterns/containers/utility-panes.html),
/// where some elements are adjacent to the top/bottom bars, or [class@TabView],
/// where each page can have a different background.
///
///
///
/// `AdwToolbarView` ensures the top and bottom bars have consistent backdrop
/// styles and vertical spacing. For comparison:
///
///
///
/// Any top and bottom bars can also be dragged to move the window, equivalent
/// to putting them into a [class@Gtk.WindowHandle].
///
/// Content is typically place between top and bottom bars, but can also extend
/// behind them. This is controlled with the
/// [property@ToolbarView:extend-content-to-top-edge] and
/// [property@ToolbarView:extend-content-to-bottom-edge] properties.
///
/// Top and bottom bars can be hidden and revealed with an animation using the
/// [property@ToolbarView:reveal-top-bars] and
/// [property@ToolbarView:reveal-bottom-bars] properties.
///
/// ## `AdwToolbarView` as `GtkBuildable`
///
/// The `AdwToolbarView` implementation of the [iface@Gtk.Buildable] interface
/// supports adding a top bar by specifying “top” as the “type” attribute of a
/// `` element, or adding a bottom bar by specifying “bottom”.
///
/// ## Accessibility
///
/// `AdwToolbarView` uses the `GTK_ACCESSIBLE_ROLE_GROUP` role.
public struct ToolbarView: AdwaitaWidget {
/// Additional update functions for type extensions.
var updateFunctions: [(ViewStorage, WidgetData, Bool) -> Void] = []
/// Additional appear functions for type extensions.
var appearFunctions: [(ViewStorage, WidgetData) -> Void] = []
/// The current bottom bar height.
///
/// Bottom bar height does change depending on
/// [property@ToolbarView:reveal-bottom-bars], including during the transition.
///
/// See [property@ToolbarView:top-bar-height].
var bottomBarHeight: Int?
/// The content widget.
var content: (() -> Body)?
/// Whether the content widget can extend behind bottom bars.
///
/// This can be used in combination with
/// [property@ToolbarView:reveal-bottom-bars] to show and hide toolbars in
/// fullscreen.
///
/// See [property@ToolbarView:extend-content-to-top-edge].
var extendContentToBottomEdge: Bool?
/// Whether the content widget can extend behind top bars.
///
/// This can be used in combination with [property@ToolbarView:reveal-top-bars]
/// to show and hide toolbars in fullscreen.
///
/// See [property@ToolbarView:extend-content-to-bottom-edge].
var extendContentToTopEdge: Bool?
/// Whether bottom bars are visible.
///
/// The transition will be animated.
///
/// This can be used in combination with
/// [property@ToolbarView:extend-content-to-bottom-edge] to show and hide
/// toolbars in fullscreen.
///
/// See [property@ToolbarView:reveal-top-bars].
var revealBottomBars: Bool?
/// Whether top bars are revealed.
///
/// The transition will be animated.
///
/// This can be used in combination with
/// [property@ToolbarView:extend-content-to-top-edge] to show and hide toolbars
/// in fullscreen.
///
/// See [property@ToolbarView:reveal-bottom-bars].
var revealTopBars: Bool?
/// The current top bar height.
///
/// Top bar height does change depending [property@ToolbarView:reveal-top-bars],
/// including during the transition.
///
/// See [property@ToolbarView:bottom-bar-height].
var topBarHeight: Int?
/// The body for the widget "bottom".
var bottom: () -> Body = { [] }
/// The body for the widget "top".
var top: () -> Body = { [] }
/// Initialize `ToolbarView`.
public init() {
}
/// The view storage.
/// - Parameters:
/// - modifiers: Modify views before being updated.
/// - type: The type of the app storage.
/// - Returns: The view storage.
public func container(data: WidgetData, type: Data.Type) -> ViewStorage where Data: ViewRenderData {
let storage = ViewStorage(adw_toolbar_view_new()?.opaque())
for function in appearFunctions {
function(storage, data)
}
update(storage, data: data, updateProperties: true, type: type)
if let contentStorage = content?().storage(data: data, type: type) {
storage.content["content"] = [contentStorage]
adw_toolbar_view_set_content(storage.opaquePointer, contentStorage.opaquePointer?.cast())
}
var bottomStorage: [ViewStorage] = []
for view in bottom() {
bottomStorage.append(view.storage(data: data, type: type))
adw_toolbar_view_add_bottom_bar(storage.opaquePointer, bottomStorage.last?.opaquePointer?.cast())
}
storage.content["bottom"] = bottomStorage
var topStorage: [ViewStorage] = []
for view in top() {
topStorage.append(view.storage(data: data, type: type))
adw_toolbar_view_add_top_bar(storage.opaquePointer, topStorage.last?.opaquePointer?.cast())
}
storage.content["top"] = topStorage
return storage
}
/// Update the stored content.
/// - Parameters:
/// - storage: The storage to update.
/// - modifiers: Modify views before being updated
/// - updateProperties: Whether to update the view's properties.
/// - type: The type of the app storage.
public func update(_ storage: ViewStorage, data: WidgetData, updateProperties: Bool, type: Data.Type) where Data: ViewRenderData {
storage.modify { widget in
if let widget = storage.content["content"]?.first {
content?().updateStorage(widget, data: data, updateProperties: updateProperties, type: type)
}
if let extendContentToBottomEdge, updateProperties, (storage.previousState as? Self)?.extendContentToBottomEdge != extendContentToBottomEdge {
adw_toolbar_view_set_extend_content_to_bottom_edge(widget, extendContentToBottomEdge.cBool)
}
if let extendContentToTopEdge, updateProperties, (storage.previousState as? Self)?.extendContentToTopEdge != extendContentToTopEdge {
adw_toolbar_view_set_extend_content_to_top_edge(widget, extendContentToTopEdge.cBool)
}
if let revealBottomBars, updateProperties, (storage.previousState as? Self)?.revealBottomBars != revealBottomBars {
adw_toolbar_view_set_reveal_bottom_bars(widget, revealBottomBars.cBool)
}
if let revealTopBars, updateProperties, (storage.previousState as? Self)?.revealTopBars != revealTopBars {
adw_toolbar_view_set_reveal_top_bars(widget, revealTopBars.cBool)
}
if let bottomStorage = storage.content["bottom"] {
for (index, view) in bottom().enumerated() {
if let storage = bottomStorage[safe: index] {
view.updateStorage(
storage,
data: data,
updateProperties: updateProperties,
type: type
)
}
}
}
if let topStorage = storage.content["top"] {
for (index, view) in top().enumerated() {
if let storage = topStorage[safe: index] {
view.updateStorage(
storage,
data: data,
updateProperties: updateProperties,
type: type
)
}
}
}
}
for function in updateFunctions {
function(storage, data, updateProperties)
}
if updateProperties {
storage.previousState = self
}
}
/// The current bottom bar height.
///
/// Bottom bar height does change depending on
/// [property@ToolbarView:reveal-bottom-bars], including during the transition.
///
/// See [property@ToolbarView:top-bar-height].
public func bottomBarHeight(_ bottomBarHeight: Int?) -> Self {
var newSelf = self
newSelf.bottomBarHeight = bottomBarHeight
return newSelf
}
/// The content widget.
public func content(@ViewBuilder _ content: @escaping (() -> Body)) -> Self {
var newSelf = self
newSelf.content = content
return newSelf
}
/// Whether the content widget can extend behind bottom bars.
///
/// This can be used in combination with
/// [property@ToolbarView:reveal-bottom-bars] to show and hide toolbars in
/// fullscreen.
///
/// See [property@ToolbarView:extend-content-to-top-edge].
public func extendContentToBottomEdge(_ extendContentToBottomEdge: Bool? = true) -> Self {
var newSelf = self
newSelf.extendContentToBottomEdge = extendContentToBottomEdge
return newSelf
}
/// Whether the content widget can extend behind top bars.
///
/// This can be used in combination with [property@ToolbarView:reveal-top-bars]
/// to show and hide toolbars in fullscreen.
///
/// See [property@ToolbarView:extend-content-to-bottom-edge].
public func extendContentToTopEdge(_ extendContentToTopEdge: Bool? = true) -> Self {
var newSelf = self
newSelf.extendContentToTopEdge = extendContentToTopEdge
return newSelf
}
/// Whether bottom bars are visible.
///
/// The transition will be animated.
///
/// This can be used in combination with
/// [property@ToolbarView:extend-content-to-bottom-edge] to show and hide
/// toolbars in fullscreen.
///
/// See [property@ToolbarView:reveal-top-bars].
public func revealBottomBars(_ revealBottomBars: Bool? = true) -> Self {
var newSelf = self
newSelf.revealBottomBars = revealBottomBars
return newSelf
}
/// Whether top bars are revealed.
///
/// The transition will be animated.
///
/// This can be used in combination with
/// [property@ToolbarView:extend-content-to-top-edge] to show and hide toolbars
/// in fullscreen.
///
/// See [property@ToolbarView:reveal-bottom-bars].
public func revealTopBars(_ revealTopBars: Bool? = true) -> Self {
var newSelf = self
newSelf.revealTopBars = revealTopBars
return newSelf
}
/// The current top bar height.
///
/// Top bar height does change depending [property@ToolbarView:reveal-top-bars],
/// including during the transition.
///
/// See [property@ToolbarView:bottom-bar-height].
public func topBarHeight(_ topBarHeight: Int?) -> Self {
var newSelf = self
newSelf.topBarHeight = topBarHeight
return newSelf
}
/// Set the body for "bottom".
/// - Parameter body: The body.
/// - Returns: The widget.
public func bottom(@ViewBuilder _ body: @escaping () -> Body) -> Self {
var newSelf = self
newSelf.bottom = body
return newSelf
}
/// Set the body for "top".
/// - Parameter body: The body.
/// - Returns: The widget.
public func top(@ViewBuilder _ body: @escaping () -> Body) -> Self {
var newSelf = self
newSelf.top = body
return newSelf
}
}