From 30482196b6cd7b114a12f127a6820f3cfaf372ef Mon Sep 17 00:00:00 2001 From: david-swift Date: Sat, 10 Feb 2024 16:00:56 +0100 Subject: [PATCH] Add support for popovers --- Documentation/Reference/README.md | 2 + Documentation/Reference/extensions/Popover.md | 9 + Documentation/Reference/extensions/View.md | 8 + Documentation/Reference/structs/Popover.md | 172 +++++++++++++ .../Adwaita/View/Generated/ActionRow.swift | 2 +- Sources/Adwaita/View/Generated/Avatar.swift | 2 +- Sources/Adwaita/View/Generated/Banner.swift | 2 +- Sources/Adwaita/View/Generated/Bin.swift | 2 +- Sources/Adwaita/View/Generated/Box.swift | 2 +- Sources/Adwaita/View/Generated/Button.swift | 2 +- .../View/Generated/ButtonContent.swift | 2 +- Sources/Adwaita/View/Generated/Carousel.swift | 2 +- .../Adwaita/View/Generated/CenterBox.swift | 2 +- .../Adwaita/View/Generated/CheckButton.swift | 2 +- Sources/Adwaita/View/Generated/Clamp.swift | 2 +- Sources/Adwaita/View/Generated/ComboRow.swift | 2 +- Sources/Adwaita/View/Generated/EntryRow.swift | 2 +- .../Adwaita/View/Generated/ExpanderRow.swift | 2 +- .../Adwaita/View/Generated/HeaderBar.swift | 2 +- Sources/Adwaita/View/Generated/Label.swift | 2 +- Sources/Adwaita/View/Generated/LevelBar.swift | 2 +- .../Adwaita/View/Generated/LinkButton.swift | 2 +- Sources/Adwaita/View/Generated/ListBox.swift | 2 +- Sources/Adwaita/View/Generated/Menu.swift | 2 +- Sources/Adwaita/View/Generated/Overlay.swift | 2 +- .../View/Generated/OverlaySplitView.swift | 2 +- .../View/Generated/PasswordEntryRow.swift | 2 +- Sources/Adwaita/View/Generated/Popover.swift | 238 ++++++++++++++++++ .../View/Generated/PreferencesGroup.swift | 2 +- .../View/Generated/PreferencesPage.swift | 2 +- .../View/Generated/PreferencesRow.swift | 2 +- .../Adwaita/View/Generated/ProgressBar.swift | 2 +- .../View/Generated/ScrolledWindow.swift | 2 +- Sources/Adwaita/View/Generated/SpinRow.swift | 2 +- Sources/Adwaita/View/Generated/Spinner.swift | 2 +- .../Adwaita/View/Generated/SplitButton.swift | 2 +- .../Adwaita/View/Generated/StatusPage.swift | 2 +- .../Adwaita/View/Generated/SwitchRow.swift | 2 +- .../Adwaita/View/Generated/ToastOverlay.swift | 2 +- .../Adwaita/View/Generated/ToggleButton.swift | 2 +- .../Adwaita/View/Generated/ToolbarView.swift | 2 +- .../Adwaita/View/Generated/WindowTitle.swift | 2 +- Sources/Adwaita/View/Modifiers/Popover+.swift | 53 ++++ .../Generation/GenerationConfiguration.swift | 3 +- Tests/Page.swift | 5 + Tests/PopoverDemo.swift | 31 +++ 46 files changed, 557 insertions(+), 38 deletions(-) create mode 100644 Documentation/Reference/extensions/Popover.md create mode 100644 Documentation/Reference/structs/Popover.md create mode 100644 Sources/Adwaita/View/Generated/Popover.swift create mode 100644 Sources/Adwaita/View/Modifiers/Popover+.swift create mode 100644 Tests/PopoverDemo.swift diff --git a/Documentation/Reference/README.md b/Documentation/Reference/README.md index a791c1e..b7037c9 100644 --- a/Documentation/Reference/README.md +++ b/Documentation/Reference/README.md @@ -51,6 +51,7 @@ - [Overlay](structs/Overlay.md) - [OverlaySplitView](structs/OverlaySplitView.md) - [PasswordEntryRow](structs/PasswordEntryRow.md) +- [Popover](structs/Popover.md) - [PreferencesGroup](structs/PreferencesGroup.md) - [PreferencesPage](structs/PreferencesPage.md) - [PreferencesRow](structs/PreferencesRow.md) @@ -120,6 +121,7 @@ - [OpaquePointer](extensions/OpaquePointer.md) - [OverlaySplitView](extensions/OverlaySplitView.md) - [PasswordEntryRow](extensions/PasswordEntryRow.md) +- [Popover](extensions/Popover.md) - [ProgressBar](extensions/ProgressBar.md) - [ScrollView](extensions/ScrollView.md) - [Set](extensions/Set.md) diff --git a/Documentation/Reference/extensions/Popover.md b/Documentation/Reference/extensions/Popover.md new file mode 100644 index 0000000..4a18e7c --- /dev/null +++ b/Documentation/Reference/extensions/Popover.md @@ -0,0 +1,9 @@ +**EXTENSION** + +# `Popover` + +## Methods +### `init(visible:)` + +Initialize either a horizontal or vertical clamp. +- Parameter vertical: Whether it is a vertical clamp. diff --git a/Documentation/Reference/extensions/View.md b/Documentation/Reference/extensions/View.md index 92e487f..5011d80 100644 --- a/Documentation/Reference/extensions/View.md +++ b/Documentation/Reference/extensions/View.md @@ -158,6 +158,14 @@ Set the view's visibility. Remove all of the content modifiers for the wrapped views. - Returns: A view. +### `popover(visible:content:)` + +Add a popover on top of the view. +- Parameters: + - visible: Whether the popover is displayed. + - content: The popover's content. +- Returns: The view. + ### `toast(_:signal:)` Present a toast when the signal gets activated. diff --git a/Documentation/Reference/structs/Popover.md b/Documentation/Reference/structs/Popover.md new file mode 100644 index 0000000..3e632c5 --- /dev/null +++ b/Documentation/Reference/structs/Popover.md @@ -0,0 +1,172 @@ +**STRUCT** + +# `Popover` + +`GtkPopover` is a bubble-like context popup. + +![An example GtkPopover](popover.png) + +It is primarily meant to provide context-dependent information +or options. Popovers are attached to a parent widget. By default, +they point to the whole widget area, although this behavior can be +changed with [method@Gtk.Popover.set_pointing_to]. + +The position of a popover relative to the widget it is attached to +can also be changed with [method@Gtk.Popover.set_position] + +By default, `GtkPopover` performs a grab, in order to ensure input +events get redirected to it while it is shown, and also so the popover +is dismissed in the expected situations (clicks outside the popover, +or the Escape key being pressed). If no such modal behavior is desired +on a popover, [method@Gtk.Popover.set_autohide] may be called on it to +tweak its behavior. + +## GtkPopover as menu replacement + +`GtkPopover` is often used to replace menus. The best was to do this +is to use the [class@Gtk.PopoverMenu] subclass which supports being +populated from a `GMenuModel` with [ctor@Gtk.PopoverMenu.new_from_model]. + +```xml +
horizontal-buttonsCutapp.cutedit-cut-symbolicCopyapp.copyedit-copy-symbolicPasteapp.pasteedit-paste-symbolic
+``` + +# CSS nodes + +``` +popover.background[.menu] +├── arrow +╰── contents +╰── +``` + +`GtkPopover` has a main node with name `popover`, an arrow with name `arrow`, +and another node for the content named `contents`. The `popover` node always +gets the `.background` style class. It also gets the `.menu` style class +if the popover is menu-like, e.g. is a [class@Gtk.PopoverMenu]. + +Particular uses of `GtkPopover`, such as touch selection popups or +magnifiers in `GtkEntry` or `GtkTextView` get style classes like +`.touch-selection` or `.magnifier` to differentiate from plain popovers. + +When styling a popover directly, the `popover` node should usually +not have any background. The visible part of the popover can have +a shadow. To specify it in CSS, set the box-shadow of the `contents` node. + +Note that, in order to accomplish appropriate arrow visuals, `GtkPopover` +uses custom drawing for the `arrow` node. This makes it possible for the +arrow to change its shape dynamically, but it also limits the possibilities +of styling it using CSS. In particular, the `arrow` gets drawn over the +`content` node's border and shadow, so they look like one shape, which +means that the border width of the `content` node and the `arrow` node should +be the same. The arrow also does not support any border shape other than +solid, no border-radius, only one border width (border-bottom-width is +used) and no box-shadow. + +## Properties +### `updateFunctions` + +Additional update functions for type extensions. + +### `appearFunctions` + +Additional appear functions for type extensions. + +### `autohide` + +Whether to dismiss the popover on outside clicks. + +### `cascadePopdown` + +Whether the popover pops down after a child popover. + +This is used to implement the expected behavior of submenus. + +### `child` + +The child widget. + +### `defaultWidget` + +The default widget inside the popover. + +### `hasArrow` + +Whether to draw an arrow. + +### `mnemonicsVisible` + +Whether mnemonics are currently visible in this popover. + +### `activateDefault` + +Emitted whend the user activates the default widget. + +This is a [keybinding signal](class.SignalAction.html). + +### `closed` + +Emitted when the popover is closed. + +### `app` + +The application. + +### `window` + +The window. + +## Methods +### `init()` + +Initialize `Popover`. + +### `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. + +### `autohide(_:)` + +Whether to dismiss the popover on outside clicks. + +### `cascadePopdown(_:)` + +Whether the popover pops down after a child popover. + +This is used to implement the expected behavior of submenus. + +### `child(_:)` + +The child widget. + +### `defaultWidget(_:)` + +The default widget inside the popover. + +### `hasArrow(_:)` + +Whether to draw an arrow. + +### `mnemonicsVisible(_:)` + +Whether mnemonics are currently visible in this popover. + +### `activateDefault(_:)` + +Emitted whend the user activates the default widget. + +This is a [keybinding signal](class.SignalAction.html). + +### `closed(_:)` + +Emitted when the popover is closed. diff --git a/Sources/Adwaita/View/Generated/ActionRow.swift b/Sources/Adwaita/View/Generated/ActionRow.swift index 419808b..277ce41 100644 --- a/Sources/Adwaita/View/Generated/ActionRow.swift +++ b/Sources/Adwaita/View/Generated/ActionRow.swift @@ -2,7 +2,7 @@ // ActionRow.swift // Adwaita // -// Created by auto-generation on 04.02.24. +// Created by auto-generation on 10.02.24. // import CAdw diff --git a/Sources/Adwaita/View/Generated/Avatar.swift b/Sources/Adwaita/View/Generated/Avatar.swift index 722826d..76d1741 100644 --- a/Sources/Adwaita/View/Generated/Avatar.swift +++ b/Sources/Adwaita/View/Generated/Avatar.swift @@ -2,7 +2,7 @@ // Avatar.swift // Adwaita // -// Created by auto-generation on 04.02.24. +// Created by auto-generation on 10.02.24. // import CAdw diff --git a/Sources/Adwaita/View/Generated/Banner.swift b/Sources/Adwaita/View/Generated/Banner.swift index b09296e..984638c 100644 --- a/Sources/Adwaita/View/Generated/Banner.swift +++ b/Sources/Adwaita/View/Generated/Banner.swift @@ -2,7 +2,7 @@ // Banner.swift // Adwaita // -// Created by auto-generation on 04.02.24. +// Created by auto-generation on 10.02.24. // import CAdw diff --git a/Sources/Adwaita/View/Generated/Bin.swift b/Sources/Adwaita/View/Generated/Bin.swift index 61a6557..9c7b212 100644 --- a/Sources/Adwaita/View/Generated/Bin.swift +++ b/Sources/Adwaita/View/Generated/Bin.swift @@ -2,7 +2,7 @@ // Bin.swift // Adwaita // -// Created by auto-generation on 04.02.24. +// Created by auto-generation on 10.02.24. // import CAdw diff --git a/Sources/Adwaita/View/Generated/Box.swift b/Sources/Adwaita/View/Generated/Box.swift index 8be3664..d16e1b4 100644 --- a/Sources/Adwaita/View/Generated/Box.swift +++ b/Sources/Adwaita/View/Generated/Box.swift @@ -2,7 +2,7 @@ // Box.swift // Adwaita // -// Created by auto-generation on 04.02.24. +// Created by auto-generation on 10.02.24. // import CAdw diff --git a/Sources/Adwaita/View/Generated/Button.swift b/Sources/Adwaita/View/Generated/Button.swift index 21bedcc..099631f 100644 --- a/Sources/Adwaita/View/Generated/Button.swift +++ b/Sources/Adwaita/View/Generated/Button.swift @@ -2,7 +2,7 @@ // Button.swift // Adwaita // -// Created by auto-generation on 04.02.24. +// Created by auto-generation on 10.02.24. // import CAdw diff --git a/Sources/Adwaita/View/Generated/ButtonContent.swift b/Sources/Adwaita/View/Generated/ButtonContent.swift index 3e456bf..a404498 100644 --- a/Sources/Adwaita/View/Generated/ButtonContent.swift +++ b/Sources/Adwaita/View/Generated/ButtonContent.swift @@ -2,7 +2,7 @@ // ButtonContent.swift // Adwaita // -// Created by auto-generation on 04.02.24. +// Created by auto-generation on 10.02.24. // import CAdw diff --git a/Sources/Adwaita/View/Generated/Carousel.swift b/Sources/Adwaita/View/Generated/Carousel.swift index 8152e68..f470eec 100644 --- a/Sources/Adwaita/View/Generated/Carousel.swift +++ b/Sources/Adwaita/View/Generated/Carousel.swift @@ -2,7 +2,7 @@ // Carousel.swift // Adwaita // -// Created by auto-generation on 04.02.24. +// Created by auto-generation on 10.02.24. // import CAdw diff --git a/Sources/Adwaita/View/Generated/CenterBox.swift b/Sources/Adwaita/View/Generated/CenterBox.swift index 1c2818c..f4245f3 100644 --- a/Sources/Adwaita/View/Generated/CenterBox.swift +++ b/Sources/Adwaita/View/Generated/CenterBox.swift @@ -2,7 +2,7 @@ // CenterBox.swift // Adwaita // -// Created by auto-generation on 04.02.24. +// Created by auto-generation on 10.02.24. // import CAdw diff --git a/Sources/Adwaita/View/Generated/CheckButton.swift b/Sources/Adwaita/View/Generated/CheckButton.swift index 722eafe..4dc1fbf 100644 --- a/Sources/Adwaita/View/Generated/CheckButton.swift +++ b/Sources/Adwaita/View/Generated/CheckButton.swift @@ -2,7 +2,7 @@ // CheckButton.swift // Adwaita // -// Created by auto-generation on 04.02.24. +// Created by auto-generation on 10.02.24. // import CAdw diff --git a/Sources/Adwaita/View/Generated/Clamp.swift b/Sources/Adwaita/View/Generated/Clamp.swift index d7d540a..4b6f3b1 100644 --- a/Sources/Adwaita/View/Generated/Clamp.swift +++ b/Sources/Adwaita/View/Generated/Clamp.swift @@ -2,7 +2,7 @@ // Clamp.swift // Adwaita // -// Created by auto-generation on 04.02.24. +// Created by auto-generation on 10.02.24. // import CAdw diff --git a/Sources/Adwaita/View/Generated/ComboRow.swift b/Sources/Adwaita/View/Generated/ComboRow.swift index 23559f4..6ab28a6 100644 --- a/Sources/Adwaita/View/Generated/ComboRow.swift +++ b/Sources/Adwaita/View/Generated/ComboRow.swift @@ -2,7 +2,7 @@ // ComboRow.swift // Adwaita // -// Created by auto-generation on 04.02.24. +// Created by auto-generation on 10.02.24. // import CAdw diff --git a/Sources/Adwaita/View/Generated/EntryRow.swift b/Sources/Adwaita/View/Generated/EntryRow.swift index 97bb2d8..a47589b 100644 --- a/Sources/Adwaita/View/Generated/EntryRow.swift +++ b/Sources/Adwaita/View/Generated/EntryRow.swift @@ -2,7 +2,7 @@ // EntryRow.swift // Adwaita // -// Created by auto-generation on 04.02.24. +// Created by auto-generation on 10.02.24. // import CAdw diff --git a/Sources/Adwaita/View/Generated/ExpanderRow.swift b/Sources/Adwaita/View/Generated/ExpanderRow.swift index db9b5a4..68c18fc 100644 --- a/Sources/Adwaita/View/Generated/ExpanderRow.swift +++ b/Sources/Adwaita/View/Generated/ExpanderRow.swift @@ -2,7 +2,7 @@ // ExpanderRow.swift // Adwaita // -// Created by auto-generation on 04.02.24. +// Created by auto-generation on 10.02.24. // import CAdw diff --git a/Sources/Adwaita/View/Generated/HeaderBar.swift b/Sources/Adwaita/View/Generated/HeaderBar.swift index 0d27c38..397dc49 100644 --- a/Sources/Adwaita/View/Generated/HeaderBar.swift +++ b/Sources/Adwaita/View/Generated/HeaderBar.swift @@ -2,7 +2,7 @@ // HeaderBar.swift // Adwaita // -// Created by auto-generation on 04.02.24. +// Created by auto-generation on 10.02.24. // import CAdw diff --git a/Sources/Adwaita/View/Generated/Label.swift b/Sources/Adwaita/View/Generated/Label.swift index 8d94803..fe8d5bc 100644 --- a/Sources/Adwaita/View/Generated/Label.swift +++ b/Sources/Adwaita/View/Generated/Label.swift @@ -2,7 +2,7 @@ // Label.swift // Adwaita // -// Created by auto-generation on 04.02.24. +// Created by auto-generation on 10.02.24. // import CAdw diff --git a/Sources/Adwaita/View/Generated/LevelBar.swift b/Sources/Adwaita/View/Generated/LevelBar.swift index f52db0a..e3f0241 100644 --- a/Sources/Adwaita/View/Generated/LevelBar.swift +++ b/Sources/Adwaita/View/Generated/LevelBar.swift @@ -2,7 +2,7 @@ // LevelBar.swift // Adwaita // -// Created by auto-generation on 04.02.24. +// Created by auto-generation on 10.02.24. // import CAdw diff --git a/Sources/Adwaita/View/Generated/LinkButton.swift b/Sources/Adwaita/View/Generated/LinkButton.swift index 734b501..5a85e1b 100644 --- a/Sources/Adwaita/View/Generated/LinkButton.swift +++ b/Sources/Adwaita/View/Generated/LinkButton.swift @@ -2,7 +2,7 @@ // LinkButton.swift // Adwaita // -// Created by auto-generation on 04.02.24. +// Created by auto-generation on 10.02.24. // import CAdw diff --git a/Sources/Adwaita/View/Generated/ListBox.swift b/Sources/Adwaita/View/Generated/ListBox.swift index 44acb80..9a47497 100644 --- a/Sources/Adwaita/View/Generated/ListBox.swift +++ b/Sources/Adwaita/View/Generated/ListBox.swift @@ -2,7 +2,7 @@ // ListBox.swift // Adwaita // -// Created by auto-generation on 04.02.24. +// Created by auto-generation on 10.02.24. // import CAdw diff --git a/Sources/Adwaita/View/Generated/Menu.swift b/Sources/Adwaita/View/Generated/Menu.swift index d742c45..fb38702 100644 --- a/Sources/Adwaita/View/Generated/Menu.swift +++ b/Sources/Adwaita/View/Generated/Menu.swift @@ -2,7 +2,7 @@ // Menu.swift // Adwaita // -// Created by auto-generation on 04.02.24. +// Created by auto-generation on 10.02.24. // import CAdw diff --git a/Sources/Adwaita/View/Generated/Overlay.swift b/Sources/Adwaita/View/Generated/Overlay.swift index d741f1b..2376d68 100644 --- a/Sources/Adwaita/View/Generated/Overlay.swift +++ b/Sources/Adwaita/View/Generated/Overlay.swift @@ -2,7 +2,7 @@ // Overlay.swift // Adwaita // -// Created by auto-generation on 04.02.24. +// Created by auto-generation on 10.02.24. // import CAdw diff --git a/Sources/Adwaita/View/Generated/OverlaySplitView.swift b/Sources/Adwaita/View/Generated/OverlaySplitView.swift index 86e7999..2dd0dc7 100644 --- a/Sources/Adwaita/View/Generated/OverlaySplitView.swift +++ b/Sources/Adwaita/View/Generated/OverlaySplitView.swift @@ -2,7 +2,7 @@ // OverlaySplitView.swift // Adwaita // -// Created by auto-generation on 04.02.24. +// Created by auto-generation on 10.02.24. // import CAdw diff --git a/Sources/Adwaita/View/Generated/PasswordEntryRow.swift b/Sources/Adwaita/View/Generated/PasswordEntryRow.swift index 3de14b1..3709b18 100644 --- a/Sources/Adwaita/View/Generated/PasswordEntryRow.swift +++ b/Sources/Adwaita/View/Generated/PasswordEntryRow.swift @@ -2,7 +2,7 @@ // PasswordEntryRow.swift // Adwaita // -// Created by auto-generation on 04.02.24. +// Created by auto-generation on 10.02.24. // import CAdw diff --git a/Sources/Adwaita/View/Generated/Popover.swift b/Sources/Adwaita/View/Generated/Popover.swift new file mode 100644 index 0000000..d8a8320 --- /dev/null +++ b/Sources/Adwaita/View/Generated/Popover.swift @@ -0,0 +1,238 @@ +// +// Popover.swift +// Adwaita +// +// Created by auto-generation on 10.02.24. +// + +import CAdw +import LevenshteinTransformations + +/// `GtkPopover` is a bubble-like context popup. +/// +/// ![An example GtkPopover](popover.png) +/// +/// It is primarily meant to provide context-dependent information +/// or options. Popovers are attached to a parent widget. By default, +/// they point to the whole widget area, although this behavior can be +/// changed with [method@Gtk.Popover.set_pointing_to]. +/// +/// The position of a popover relative to the widget it is attached to +/// can also be changed with [method@Gtk.Popover.set_position] +/// +/// By default, `GtkPopover` performs a grab, in order to ensure input +/// events get redirected to it while it is shown, and also so the popover +/// is dismissed in the expected situations (clicks outside the popover, +/// or the Escape key being pressed). If no such modal behavior is desired +/// on a popover, [method@Gtk.Popover.set_autohide] may be called on it to +/// tweak its behavior. +/// +/// ## GtkPopover as menu replacement +/// +/// `GtkPopover` is often used to replace menus. The best was to do this +/// is to use the [class@Gtk.PopoverMenu] subclass which supports being +/// populated from a `GMenuModel` with [ctor@Gtk.PopoverMenu.new_from_model]. +/// +/// ```xml +///
horizontal-buttonsCutapp.cutedit-cut-symbolicCopyapp.copyedit-copy-symbolicPasteapp.pasteedit-paste-symbolic
+/// ``` +/// +/// # CSS nodes +/// +/// ``` +/// popover.background[.menu] +/// ├── arrow +/// ╰── contents +/// ╰── +/// ``` +/// +/// `GtkPopover` has a main node with name `popover`, an arrow with name `arrow`, +/// and another node for the content named `contents`. The `popover` node always +/// gets the `.background` style class. It also gets the `.menu` style class +/// if the popover is menu-like, e.g. is a [class@Gtk.PopoverMenu]. +/// +/// Particular uses of `GtkPopover`, such as touch selection popups or +/// magnifiers in `GtkEntry` or `GtkTextView` get style classes like +/// `.touch-selection` or `.magnifier` to differentiate from plain popovers. +/// +/// When styling a popover directly, the `popover` node should usually +/// not have any background. The visible part of the popover can have +/// a shadow. To specify it in CSS, set the box-shadow of the `contents` node. +/// +/// Note that, in order to accomplish appropriate arrow visuals, `GtkPopover` +/// uses custom drawing for the `arrow` node. This makes it possible for the +/// arrow to change its shape dynamically, but it also limits the possibilities +/// of styling it using CSS. In particular, the `arrow` gets drawn over the +/// `content` node's border and shadow, so they look like one shape, which +/// means that the border width of the `content` node and the `arrow` node should +/// be the same. The arrow also does not support any border shape other than +/// solid, no border-radius, only one border width (border-bottom-width is +/// used) and no box-shadow. +public struct Popover: Widget { + + /// Additional update functions for type extensions. + var updateFunctions: [(ViewStorage) -> Void] = [] + /// Additional appear functions for type extensions. + var appearFunctions: [(ViewStorage) -> Void] = [] + + /// Whether to dismiss the popover on outside clicks. + var autohide: Bool? + /// Whether the popover pops down after a child popover. + /// + /// This is used to implement the expected behavior of submenus. + var cascadePopdown: Bool? + /// The child widget. + var child: (() -> Body)? + /// The default widget inside the popover. + var defaultWidget: (() -> Body)? + /// Whether to draw an arrow. + var hasArrow: Bool? + /// Whether mnemonics are currently visible in this popover. + var mnemonicsVisible: Bool? + /// Emitted whend the user activates the default widget. + /// + /// This is a [keybinding signal](class.SignalAction.html). + var activateDefault: (() -> Void)? + /// Emitted when the popover is closed. + var closed: (() -> Void)? + /// The application. + var app: GTUIApp? + /// The window. + var window: GTUIApplicationWindow? + + /// Initialize `Popover`. + 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(gtk_popover_new()?.opaque()) + update(storage, modifiers: modifiers, updateProperties: true) + if let childStorage = child?().widget(modifiers: modifiers).storage(modifiers: modifiers) { + storage.content["child"] = [childStorage] + gtk_popover_set_child(storage.pointer?.cast(), childStorage.pointer?.cast()) + } + if let defaultWidgetStorage = defaultWidget?().widget(modifiers: modifiers).storage(modifiers: modifiers) { + storage.content["defaultWidget"] = [defaultWidgetStorage] + gtk_popover_set_default_widget(storage.pointer?.cast(), defaultWidgetStorage.pointer?.cast()) + } + + + 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 activateDefault { + storage.connectSignal(name: "activate-default", argCount: 0) { + activateDefault() + } + } + if let closed { + storage.connectSignal(name: "closed", argCount: 0) { + closed() + } + } + storage.modify { widget in + if let autohide, updateProperties { + gtk_popover_set_autohide(widget?.cast(), autohide.cBool) + } + if let cascadePopdown, updateProperties { + gtk_popover_set_cascade_popdown(widget?.cast(), cascadePopdown.cBool) + } + if let widget = storage.content["child"]?.first { + child?().widget(modifiers: modifiers).update(widget, modifiers: modifiers, updateProperties: updateProperties) + } + if let widget = storage.content["defaultWidget"]?.first { + defaultWidget?().widget(modifiers: modifiers).update(widget, modifiers: modifiers, updateProperties: updateProperties) + } + if let hasArrow, updateProperties { + gtk_popover_set_has_arrow(widget?.cast(), hasArrow.cBool) + } + if let mnemonicsVisible, updateProperties { + gtk_popover_set_mnemonics_visible(widget?.cast(), mnemonicsVisible.cBool) + } + + + } + for function in updateFunctions { + function(storage) + } + } + + /// Whether to dismiss the popover on outside clicks. + public func autohide(_ autohide: Bool? = true) -> Self { + var newSelf = self + newSelf.autohide = autohide + + return newSelf + } + + /// Whether the popover pops down after a child popover. + /// + /// This is used to implement the expected behavior of submenus. + public func cascadePopdown(_ cascadePopdown: Bool? = true) -> Self { + var newSelf = self + newSelf.cascadePopdown = cascadePopdown + + return newSelf + } + + /// The child widget. + public func child(@ViewBuilder _ child: @escaping (() -> Body)) -> Self { + var newSelf = self + newSelf.child = child + + return newSelf + } + + /// The default widget inside the popover. + public func defaultWidget(@ViewBuilder _ defaultWidget: @escaping (() -> Body)) -> Self { + var newSelf = self + newSelf.defaultWidget = defaultWidget + + return newSelf + } + + /// Whether to draw an arrow. + public func hasArrow(_ hasArrow: Bool? = true) -> Self { + var newSelf = self + newSelf.hasArrow = hasArrow + + return newSelf + } + + /// Whether mnemonics are currently visible in this popover. + public func mnemonicsVisible(_ mnemonicsVisible: Bool? = true) -> Self { + var newSelf = self + newSelf.mnemonicsVisible = mnemonicsVisible + + return newSelf + } + + /// Emitted whend the user activates the default widget. + /// + /// This is a [keybinding signal](class.SignalAction.html). + public func activateDefault(_ activateDefault: @escaping () -> Void) -> Self { + var newSelf = self + newSelf.activateDefault = activateDefault + return newSelf + } + + /// Emitted when the popover is closed. + public func closed(_ closed: @escaping () -> Void) -> Self { + var newSelf = self + newSelf.closed = closed + return newSelf + } + +} diff --git a/Sources/Adwaita/View/Generated/PreferencesGroup.swift b/Sources/Adwaita/View/Generated/PreferencesGroup.swift index 030904b..410ff11 100644 --- a/Sources/Adwaita/View/Generated/PreferencesGroup.swift +++ b/Sources/Adwaita/View/Generated/PreferencesGroup.swift @@ -2,7 +2,7 @@ // PreferencesGroup.swift // Adwaita // -// Created by auto-generation on 04.02.24. +// Created by auto-generation on 10.02.24. // import CAdw diff --git a/Sources/Adwaita/View/Generated/PreferencesPage.swift b/Sources/Adwaita/View/Generated/PreferencesPage.swift index 8139cab..2fd48e6 100644 --- a/Sources/Adwaita/View/Generated/PreferencesPage.swift +++ b/Sources/Adwaita/View/Generated/PreferencesPage.swift @@ -2,7 +2,7 @@ // PreferencesPage.swift // Adwaita // -// Created by auto-generation on 04.02.24. +// Created by auto-generation on 10.02.24. // import CAdw diff --git a/Sources/Adwaita/View/Generated/PreferencesRow.swift b/Sources/Adwaita/View/Generated/PreferencesRow.swift index 2a141e4..39adc53 100644 --- a/Sources/Adwaita/View/Generated/PreferencesRow.swift +++ b/Sources/Adwaita/View/Generated/PreferencesRow.swift @@ -2,7 +2,7 @@ // PreferencesRow.swift // Adwaita // -// Created by auto-generation on 04.02.24. +// Created by auto-generation on 10.02.24. // import CAdw diff --git a/Sources/Adwaita/View/Generated/ProgressBar.swift b/Sources/Adwaita/View/Generated/ProgressBar.swift index b433ef8..e83852f 100644 --- a/Sources/Adwaita/View/Generated/ProgressBar.swift +++ b/Sources/Adwaita/View/Generated/ProgressBar.swift @@ -2,7 +2,7 @@ // ProgressBar.swift // Adwaita // -// Created by auto-generation on 04.02.24. +// Created by auto-generation on 10.02.24. // import CAdw diff --git a/Sources/Adwaita/View/Generated/ScrolledWindow.swift b/Sources/Adwaita/View/Generated/ScrolledWindow.swift index 1c28538..6c8b43a 100644 --- a/Sources/Adwaita/View/Generated/ScrolledWindow.swift +++ b/Sources/Adwaita/View/Generated/ScrolledWindow.swift @@ -2,7 +2,7 @@ // ScrolledWindow.swift // Adwaita // -// Created by auto-generation on 04.02.24. +// Created by auto-generation on 10.02.24. // import CAdw diff --git a/Sources/Adwaita/View/Generated/SpinRow.swift b/Sources/Adwaita/View/Generated/SpinRow.swift index 7192a01..585d121 100644 --- a/Sources/Adwaita/View/Generated/SpinRow.swift +++ b/Sources/Adwaita/View/Generated/SpinRow.swift @@ -2,7 +2,7 @@ // SpinRow.swift // Adwaita // -// Created by auto-generation on 04.02.24. +// Created by auto-generation on 10.02.24. // import CAdw diff --git a/Sources/Adwaita/View/Generated/Spinner.swift b/Sources/Adwaita/View/Generated/Spinner.swift index 6c7ce56..6fadfdc 100644 --- a/Sources/Adwaita/View/Generated/Spinner.swift +++ b/Sources/Adwaita/View/Generated/Spinner.swift @@ -2,7 +2,7 @@ // Spinner.swift // Adwaita // -// Created by auto-generation on 04.02.24. +// Created by auto-generation on 10.02.24. // import CAdw diff --git a/Sources/Adwaita/View/Generated/SplitButton.swift b/Sources/Adwaita/View/Generated/SplitButton.swift index 18f2770..b7de3ef 100644 --- a/Sources/Adwaita/View/Generated/SplitButton.swift +++ b/Sources/Adwaita/View/Generated/SplitButton.swift @@ -2,7 +2,7 @@ // SplitButton.swift // Adwaita // -// Created by auto-generation on 04.02.24. +// Created by auto-generation on 10.02.24. // import CAdw diff --git a/Sources/Adwaita/View/Generated/StatusPage.swift b/Sources/Adwaita/View/Generated/StatusPage.swift index 08c06be..d2b7f82 100644 --- a/Sources/Adwaita/View/Generated/StatusPage.swift +++ b/Sources/Adwaita/View/Generated/StatusPage.swift @@ -2,7 +2,7 @@ // StatusPage.swift // Adwaita // -// Created by auto-generation on 04.02.24. +// Created by auto-generation on 10.02.24. // import CAdw diff --git a/Sources/Adwaita/View/Generated/SwitchRow.swift b/Sources/Adwaita/View/Generated/SwitchRow.swift index 3ae7d5d..d5d5183 100644 --- a/Sources/Adwaita/View/Generated/SwitchRow.swift +++ b/Sources/Adwaita/View/Generated/SwitchRow.swift @@ -2,7 +2,7 @@ // SwitchRow.swift // Adwaita // -// Created by auto-generation on 04.02.24. +// Created by auto-generation on 10.02.24. // import CAdw diff --git a/Sources/Adwaita/View/Generated/ToastOverlay.swift b/Sources/Adwaita/View/Generated/ToastOverlay.swift index dcbb75a..a289d6f 100644 --- a/Sources/Adwaita/View/Generated/ToastOverlay.swift +++ b/Sources/Adwaita/View/Generated/ToastOverlay.swift @@ -2,7 +2,7 @@ // ToastOverlay.swift // Adwaita // -// Created by auto-generation on 04.02.24. +// Created by auto-generation on 10.02.24. // import CAdw diff --git a/Sources/Adwaita/View/Generated/ToggleButton.swift b/Sources/Adwaita/View/Generated/ToggleButton.swift index 8291e6c..030854a 100644 --- a/Sources/Adwaita/View/Generated/ToggleButton.swift +++ b/Sources/Adwaita/View/Generated/ToggleButton.swift @@ -2,7 +2,7 @@ // ToggleButton.swift // Adwaita // -// Created by auto-generation on 04.02.24. +// Created by auto-generation on 10.02.24. // import CAdw diff --git a/Sources/Adwaita/View/Generated/ToolbarView.swift b/Sources/Adwaita/View/Generated/ToolbarView.swift index 27e39ef..6f24eeb 100644 --- a/Sources/Adwaita/View/Generated/ToolbarView.swift +++ b/Sources/Adwaita/View/Generated/ToolbarView.swift @@ -2,7 +2,7 @@ // ToolbarView.swift // Adwaita // -// Created by auto-generation on 04.02.24. +// Created by auto-generation on 10.02.24. // import CAdw diff --git a/Sources/Adwaita/View/Generated/WindowTitle.swift b/Sources/Adwaita/View/Generated/WindowTitle.swift index 03ae2b5..d2d3fe6 100644 --- a/Sources/Adwaita/View/Generated/WindowTitle.swift +++ b/Sources/Adwaita/View/Generated/WindowTitle.swift @@ -2,7 +2,7 @@ // WindowTitle.swift // Adwaita // -// Created by auto-generation on 04.02.24. +// Created by auto-generation on 10.02.24. // import CAdw diff --git a/Sources/Adwaita/View/Modifiers/Popover+.swift b/Sources/Adwaita/View/Modifiers/Popover+.swift new file mode 100644 index 0000000..aca1194 --- /dev/null +++ b/Sources/Adwaita/View/Modifiers/Popover+.swift @@ -0,0 +1,53 @@ +// +// Popover+.swift +// Adwaita +// +// Created by david-swift on 10.02.24. +// + +import CAdw + +extension Popover { + + /// Initialize either a horizontal or vertical clamp. + /// - Parameter vertical: Whether it is a vertical clamp. + init(visible: Binding) { + self.init() + appearFunctions.append { storage in + storage.fields["visible"] = visible + storage.connectSignal(name: "closed", id: "visible") { + if let binding = storage.fields["visible"] as? Binding { + if binding.wrappedValue { + binding.wrappedValue = false + } + } + } + } + updateFunctions.append { storage in + if let binding = storage.fields["visible"] as? Binding { + if binding.wrappedValue { + gtk_popover_popup(storage.pointer?.cast()) + } else { + gtk_popover_popdown(storage.pointer?.cast()) + } + } + } + } + +} + +extension View { + + /// Add a popover on top of the view. + /// - Parameters: + /// - visible: Whether the popover is displayed. + /// - content: The popover's content. + /// - Returns: The view. + public func popover(visible: Binding, @ViewBuilder content: @escaping () -> Body) -> View { + overlay { + Popover(visible: visible) + .child(content) + } + } + +} diff --git a/Sources/Generation/GenerationConfiguration.swift b/Sources/Generation/GenerationConfiguration.swift index c4c1818..4c1375f 100644 --- a/Sources/Generation/GenerationConfiguration.swift +++ b/Sources/Generation/GenerationConfiguration.swift @@ -219,7 +219,8 @@ struct GenerationConfiguration { "window-placement" ] ), - .init(class: "Overlay", staticWidgets: [.init(name: "overlay", add: "gtk_overlay_add_overlay")]) + .init(class: "Overlay", staticWidgets: [.init(name: "overlay", add: "gtk_overlay_add_overlay")]), + .init(class: "Popover", excludeProperties: ["pointing-to", "position"], cast: true) ] /// The unshortening map. diff --git a/Tests/Page.swift b/Tests/Page.swift index d6bf9de..5aec70f 100644 --- a/Tests/Page.swift +++ b/Tests/Page.swift @@ -23,6 +23,7 @@ enum Page: String, Identifiable, CaseIterable, Codable { case carousel case viewSwitcher case form + case popover var id: Self { self @@ -74,6 +75,8 @@ enum Page: String, Identifiable, CaseIterable, Codable { return "Switch the window's view." case .form: return "Group controls used for data entry." + case .popover: + return "Present content in a bubble-like context popup." } } @@ -105,6 +108,8 @@ enum Page: String, Identifiable, CaseIterable, Codable { ViewSwitcherDemo(app: app) case .form: FormDemo(app: app) + case .popover: + PopoverDemo() } } // swiftlint:enable cyclomatic_complexity diff --git a/Tests/PopoverDemo.swift b/Tests/PopoverDemo.swift new file mode 100644 index 0000000..8de65ac --- /dev/null +++ b/Tests/PopoverDemo.swift @@ -0,0 +1,31 @@ +// +// PopoverDemo.swift +// Adwaita +// +// Created by david-swift on 10.02.24. +// + +// swiftlint:disable missing_docs + +import Adwaita + +struct PopoverDemo: View { + + @State private var visible = false + + var view: Body { + VStack { + Button("Present Popover") { + visible = true + } + .style("suggested-action") + .frame(maxSize: 100) + } + .popover(visible: $visible) { + CounterDemo() + } + } + +} + +// swiftlint:enable missing_docs