299 lines
12 KiB
Swift
299 lines
12 KiB
Swift
//
|
|
// NavigationView.swift
|
|
// Adwaita
|
|
//
|
|
// Created by auto-generation on 22.05.24.
|
|
//
|
|
|
|
import CAdw
|
|
import LevenshteinTransformations
|
|
|
|
/// A page-based navigation container.
|
|
///
|
|
/// <picture><source srcset="navigation-view-dark.png" media="(prefers-color-scheme: dark)"><img src="navigation-view.png" alt="navigation-view"></picture>
|
|
///
|
|
/// `AdwNavigationView` presents one child at a time, similar to
|
|
/// [class@Gtk.Stack].
|
|
///
|
|
/// `AdwNavigationView` can only contain [class@NavigationPage] children.
|
|
///
|
|
/// It maintains a navigation stack that can be controlled with
|
|
/// [method@NavigationView.push] and [method@NavigationView.pop]. The whole
|
|
/// navigation stack can also be replaced using [method@NavigationView.replace].
|
|
///
|
|
/// `AdwNavigationView` allows to manage pages statically or dynamically.
|
|
///
|
|
/// Static pages can be added using the [method@NavigationView.add] method. The
|
|
/// `AdwNavigationView` will keep a reference to these pages, but they aren't
|
|
/// accessible to the user until [method@NavigationView.push] is called (except
|
|
/// for the first page, which is pushed automatically). Use the
|
|
/// [method@NavigationView.remove] method to remove them. This is useful for
|
|
/// applications that have a small number of unique pages and just need
|
|
/// navigation between them.
|
|
///
|
|
/// Dynamic pages are automatically destroyed once they are popped off the
|
|
/// navigation stack. To add a page like this, push it using the
|
|
/// [method@NavigationView.push] method without calling
|
|
/// [method@NavigationView.add] first.
|
|
///
|
|
/// ## Tags
|
|
///
|
|
/// Static pages, as well as any pages in the navigation stack, can be accessed
|
|
/// by their [property@NavigationPage:tag]. For example,
|
|
/// [method@NavigationView.push_by_tag] can be used to push a static page that's
|
|
/// not in the navigation stack without having to keep a reference to it manually.
|
|
///
|
|
/// ## Header Bar Integration
|
|
///
|
|
/// When used inside `AdwNavigationView`, [class@HeaderBar] will automatically
|
|
/// display a back button that can be used to go back to the previous page when
|
|
/// possible. The button also has a context menu, allowing to pop multiple pages
|
|
/// at once, potentially across multiple navigation views.
|
|
///
|
|
/// Set [property@HeaderBar:show-back-button] to `FALSE` to disable this behavior
|
|
/// in rare scenarios where it's unwanted.
|
|
///
|
|
/// `AdwHeaderBar` will also display the title of the `AdwNavigationPage` it's
|
|
/// placed into, so most applications shouldn't need to customize it at all.
|
|
///
|
|
/// ## Shortcuts and Gestures
|
|
///
|
|
/// `AdwNavigationView` supports the following shortcuts for going to the
|
|
/// previous page:
|
|
///
|
|
/// - <kbd>Escape</kbd> (unless [property@NavigationView:pop-on-escape] is set to
|
|
/// `FALSE`)
|
|
/// - <kbd>Alt</kbd>+<kbd>←</kbd>
|
|
/// - Back mouse button
|
|
///
|
|
/// Additionally, it supports interactive gestures:
|
|
///
|
|
/// - One-finger swipe towards the right on touchscreens
|
|
/// - Scrolling towards the right on touchpads (usually two-finger swipe)
|
|
///
|
|
/// These gestures have transitions enabled regardless of the
|
|
/// [property@NavigationView:animate-transitions] value.
|
|
///
|
|
/// Applications can also enable shortcuts for pushing another page onto the
|
|
/// navigation stack via connecting to the [signal@NavigationView::get-next-page]
|
|
/// signal, in that case the following shortcuts are supported:
|
|
///
|
|
/// - <kbd>Alt</kbd>+<kbd>→</kbd>
|
|
/// - Forward mouse button
|
|
/// - Swipe/scrolling towards the left
|
|
///
|
|
/// For right-to-left locales, the gestures and shortcuts are reversed.
|
|
///
|
|
/// [property@NavigationPage:can-pop] can be used to disable them, along with the
|
|
/// header bar back buttons.
|
|
///
|
|
/// ## Actions
|
|
///
|
|
/// `AdwNavigationView` defines actions for controlling the navigation stack.
|
|
/// actions for controlling the navigation stack:
|
|
///
|
|
/// - `navigation.push` takes a string parameter specifying the tag of the page to
|
|
/// push, and is equivalent to calling [method@NavigationView.push_by_tag].
|
|
///
|
|
/// - `navigation.pop` doesn't take any parameters and pops the current page from
|
|
/// the navigation stack, equivalent to calling [method@NavigationView.pop].
|
|
///
|
|
/// ## `AdwNavigationView` as `GtkBuildable`
|
|
///
|
|
/// `AdwNavigationView` allows to add pages as children, equivalent to using the
|
|
/// [method@NavigationView.add] method.
|
|
///
|
|
/// Example of an `AdwNavigationView` UI definition:
|
|
///
|
|
/// ```xml
|
|
/// <object class="AdwNavigationView"><child><object class="AdwNavigationPage"><property name="title" translatable="yes">Page 1</property><property name="child"><object class="AdwToolbarView"><child type="top"><object class="AdwHeaderBar"/></child><property name="content"><object class="GtkButton"><property name="label" translatable="yes">Open Page 2</property><property name="halign">center</property><property name="valign">center</property><property name="action-name">navigation.push</property><property name="action-target">'page-2'</property><style><class name="pill"/></style></object></property></object></property></object></child><child><object class="AdwNavigationPage"><property name="title" translatable="yes">Page 2</property><property name="tag">page-2</property><property name="child"><object class="AdwToolbarView"><child type="top"><object class="AdwHeaderBar"/></child><property name="content"><!-- ... --></property></object></property></object></child></object>
|
|
/// ```
|
|
///
|
|
/// <picture><source srcset="navigation-view-example-dark.png" media="(prefers-color-scheme: dark)"><img src="navigation-view-example.png" alt="navigation-view-example"></picture>
|
|
///
|
|
/// ## CSS nodes
|
|
///
|
|
/// `AdwNavigationView` has a single CSS node with the name `navigation-view`.
|
|
///
|
|
/// ## Accessibility
|
|
///
|
|
/// `AdwNavigationView` uses the `GTK_ACCESSIBLE_ROLE_GROUP` role.
|
|
public struct NavigationView: Widget {
|
|
|
|
/// Additional update functions for type extensions.
|
|
var updateFunctions: [(ViewStorage, [(View) -> View], Bool) -> Void] = []
|
|
/// Additional appear functions for type extensions.
|
|
var appearFunctions: [(ViewStorage, [(View) -> View]) -> Void] = []
|
|
|
|
/// Whether to animate page transitions.
|
|
///
|
|
/// Gesture-based transitions are always animated.
|
|
var animateTransitions: Bool?
|
|
/// Whether pressing Escape pops the current page.
|
|
///
|
|
/// Applications using `AdwNavigationView` to implement a browser may want to
|
|
/// disable it.
|
|
var popOnEscape: Bool?
|
|
/// Emitted when a push shortcut or a gesture is triggered.
|
|
///
|
|
/// To support the push shortcuts and gestures, the application is expected to
|
|
/// return the page to push in the handler.
|
|
///
|
|
/// This signal can be emitted multiple times for the gestures, for example
|
|
/// when the gesture is cancelled by the user. As such, the application must
|
|
/// not make any irreversible changes in the handler, such as removing the page
|
|
/// from a forward stack.
|
|
///
|
|
/// Instead, it should be done in the [signal@NavigationView::pushed] handler.
|
|
var getNextPage: (() -> Void)?
|
|
/// Emitted after @page has been popped from the navigation stack.
|
|
///
|
|
/// See [method@NavigationView.pop].
|
|
///
|
|
/// When using [method@NavigationView.pop_to_page] or
|
|
/// [method@NavigationView.pop_to_tag], this signal is emitted for each of the
|
|
/// popped pages.
|
|
var popped: (() -> Void)?
|
|
/// Emitted after a page has been pushed to the navigation stack.
|
|
///
|
|
/// See [method@NavigationView.push].
|
|
var pushed: (() -> Void)?
|
|
/// Emitted after the navigation stack has been replaced.
|
|
///
|
|
/// See [method@NavigationView.replace].
|
|
var replaced: (() -> Void)?
|
|
/// The application.
|
|
var app: GTUIApp?
|
|
/// The window.
|
|
var window: GTUIApplicationWindow?
|
|
|
|
/// Initialize `NavigationView`.
|
|
public init() {
|
|
}
|
|
|
|
/// 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(adw_navigation_view_new()?.opaque())
|
|
for function in appearFunctions {
|
|
function(storage, modifiers)
|
|
}
|
|
update(storage, modifiers: modifiers, updateProperties: true)
|
|
|
|
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 getNextPage {
|
|
storage.connectSignal(name: "get-next-page", argCount: 0) {
|
|
getNextPage()
|
|
}
|
|
}
|
|
if let popped {
|
|
storage.connectSignal(name: "popped", argCount: 1) {
|
|
popped()
|
|
}
|
|
}
|
|
if let pushed {
|
|
storage.connectSignal(name: "pushed", argCount: 0) {
|
|
pushed()
|
|
}
|
|
}
|
|
if let replaced {
|
|
storage.connectSignal(name: "replaced", argCount: 0) {
|
|
replaced()
|
|
}
|
|
}
|
|
storage.modify { widget in
|
|
|
|
if let animateTransitions, updateProperties {
|
|
adw_navigation_view_set_animate_transitions(widget, animateTransitions.cBool)
|
|
}
|
|
if let popOnEscape, updateProperties {
|
|
adw_navigation_view_set_pop_on_escape(widget, popOnEscape.cBool)
|
|
}
|
|
|
|
|
|
}
|
|
for function in updateFunctions {
|
|
function(storage, modifiers, updateProperties)
|
|
}
|
|
}
|
|
|
|
/// Whether to animate page transitions.
|
|
///
|
|
/// Gesture-based transitions are always animated.
|
|
public func animateTransitions(_ animateTransitions: Bool? = true) -> Self {
|
|
var newSelf = self
|
|
newSelf.animateTransitions = animateTransitions
|
|
|
|
return newSelf
|
|
}
|
|
|
|
/// Whether pressing Escape pops the current page.
|
|
///
|
|
/// Applications using `AdwNavigationView` to implement a browser may want to
|
|
/// disable it.
|
|
public func popOnEscape(_ popOnEscape: Bool? = true) -> Self {
|
|
var newSelf = self
|
|
newSelf.popOnEscape = popOnEscape
|
|
|
|
return newSelf
|
|
}
|
|
|
|
/// Emitted when a push shortcut or a gesture is triggered.
|
|
///
|
|
/// To support the push shortcuts and gestures, the application is expected to
|
|
/// return the page to push in the handler.
|
|
///
|
|
/// This signal can be emitted multiple times for the gestures, for example
|
|
/// when the gesture is cancelled by the user. As such, the application must
|
|
/// not make any irreversible changes in the handler, such as removing the page
|
|
/// from a forward stack.
|
|
///
|
|
/// Instead, it should be done in the [signal@NavigationView::pushed] handler.
|
|
public func getNextPage(_ getNextPage: @escaping () -> Void) -> Self {
|
|
var newSelf = self
|
|
newSelf.getNextPage = getNextPage
|
|
return newSelf
|
|
}
|
|
|
|
/// Emitted after @page has been popped from the navigation stack.
|
|
///
|
|
/// See [method@NavigationView.pop].
|
|
///
|
|
/// When using [method@NavigationView.pop_to_page] or
|
|
/// [method@NavigationView.pop_to_tag], this signal is emitted for each of the
|
|
/// popped pages.
|
|
public func popped(_ popped: @escaping () -> Void) -> Self {
|
|
var newSelf = self
|
|
newSelf.popped = popped
|
|
return newSelf
|
|
}
|
|
|
|
/// Emitted after a page has been pushed to the navigation stack.
|
|
///
|
|
/// See [method@NavigationView.push].
|
|
public func pushed(_ pushed: @escaping () -> Void) -> Self {
|
|
var newSelf = self
|
|
newSelf.pushed = pushed
|
|
return newSelf
|
|
}
|
|
|
|
/// Emitted after the navigation stack has been replaced.
|
|
///
|
|
/// See [method@NavigationView.replace].
|
|
public func replaced(_ replaced: @escaping () -> Void) -> Self {
|
|
var newSelf = self
|
|
newSelf.replaced = replaced
|
|
return newSelf
|
|
}
|
|
|
|
}
|