diff --git a/docs/assets/examples/action_bar.png b/docs/assets/examples/action_bar.png new file mode 100644 index 00000000..601dce17 Binary files /dev/null and b/docs/assets/examples/action_bar.png differ diff --git a/docs/widgets.md b/docs/widgets.md index 37e6b7fa..a9e9f31d 100644 --- a/docs/widgets.md +++ b/docs/widgets.md @@ -143,6 +143,7 @@ renderable CenterBox of BaseWidget - `endWidget: Widget` - `baselinePosition: BaselinePosition = BaselineCenter` - `shrinkCenterLast: bool = false` Requires GTK 4.12 or higher to work. Compile with `-d:gtkminor=12` to enable it +- `orient: Orient = OrientX` ###### Adders @@ -1625,6 +1626,30 @@ A progress bar widget to show progress being made on a long-lasting task - `text: string = ""` +## ActionBar + +```nim +renderable ActionBar of BaseWidget +``` + +A Bar for actions to execute in a given context. Can be hidden with intro- and outro-animations. + +###### Fields + +- All fields from [BaseWidget](#BaseWidget) +- `centerWidget: Widget` +- `packStart: seq[Widget]` Widgets shown on the start of the ActionBar +- `packEnd: seq[Widget]` Widgets shown on the end of the ActionBar +- `revealed: bool` + +###### Adders + +- All adders from [BaseWidget](#BaseWidget) +- `add` +- `addStart` +- `addEnd` + + ## ListView ```nim diff --git a/examples/README.md b/examples/README.md index 5e93dfbc..441a27c6 100644 --- a/examples/README.md +++ b/examples/README.md @@ -123,6 +123,10 @@ The `widgets` directory contains examples for how to use different widgets. Name Image + + Action Bar + Action Bar + Calendar Calendar diff --git a/examples/widgets/action_bar.nim b/examples/widgets/action_bar.nim new file mode 100644 index 00000000..6d18ba65 --- /dev/null +++ b/examples/widgets/action_bar.nim @@ -0,0 +1,72 @@ +# MIT License +# +# Copyright (c) 2022 Can Joshua Lehmann +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import std/[sequtils] +import owlkettle, owlkettle/[dataentries, playground, adw] + +viewable App: + revealed: bool = false + sensitive: bool = true + tooltip: string = "" + sizeRequest: tuple[x, y: int] = (-1, -1) + + dummyText: string = "Some Data" + +method view(app: AppState): Widget = + result = gui: + Window(): + title = "ActionBar Example" + defaultSize = (400, 200) + HeaderBar() {.addTitlebar.}: + insert(app.toAutoFormMenu(ignoreFields = @["dummyText"], sizeRequest = (400, 300))) {.addRight.} + + Button(text = "Reset") {.addRight.}: + style = [ButtonFlat] + proc clicked() = + app.dummyText = "Some Data" + + Box(orient = OrientY): + Button(text = app.dummyText): + style = [ButtonFlat] + proc clicked() = app.revealed = not app.revealed + + Separator() {.expand: false.} + ActionBar {.expand: false.}: + revealed = app.revealed + sensitive = app.sensitive + tooltip = app.tooltip + sizeRequest = app.sizeRequest + + Label(text = "Delete Dataset?") + Button(icon = "process-stop-symbolic") {.addEnd.}: + proc clicked() = + echo "Keep Dataset" + app.revealed = false + + Button(icon = "user-trash-symbolic", style = [ButtonDestructive]) {.addEnd.}: + style = [ButtonDestructive] + proc clicked() = + echo "Delete Dataset" + app.dummyText = "" + app.revealed = false + +adw.brew(gui(App())) diff --git a/examples/widgets/center_box.nim b/examples/widgets/center_box.nim index 2948c637..24046b68 100644 --- a/examples/widgets/center_box.nim +++ b/examples/widgets/center_box.nim @@ -26,11 +26,13 @@ import owlkettle, owlkettle/[dataentries, playground, adw] viewable App: baselinePosition: BaselinePosition = BaselineCenter shrinkCenterLast: bool = false - addStartWidget: bool = true - addEndWidget: bool = true + orient: Orient = OrientX sensitive: bool = true tooltip: string = "" sizeRequest: tuple[x, y: int] = (-1, -1) + + addStartWidget: bool = true + addEndWidget: bool = true method view(app: AppState): Widget = result = gui: @@ -46,7 +48,7 @@ method view(app: AppState): Widget = sensitive = app.sensitive tooltip = app.tooltip sizeRequest = app.sizeRequest - + orient = app.orient if app.addStartWidget: Label(text = "Start of CenterBox") {.addStart.} diff --git a/owlkettle/gtk.nim b/owlkettle/gtk.nim index ff4307ea..980b1a03 100644 --- a/owlkettle/gtk.nim +++ b/owlkettle/gtk.nim @@ -667,6 +667,15 @@ proc gtk_window_close*(window: GtkWidget) proc gtk_window_destroy*(window: GtkWidget) proc gtk_window_set_icon_name*(window: GtkWidget, name: cstring) +# Gtk.ActionBar +proc gtk_action_bar_new*(): GtkWidget +proc gtk_action_bar_get_revealed*(widget: GtkWidget): cbool +proc gtk_action_bar_pack_end*(widget: GtkWidget, child: GtkWidget) +proc gtk_action_bar_pack_start*(widget: GtkWidget, child: GtkWidget) +proc gtk_action_bar_remove*(widget: GtkWidget, child: GtkWidget) +proc gtk_action_bar_set_center_widget*(widget: GtkWidget, center_widget: GtkWidget) +proc gtk_action_bar_set_revealed*(widget: GtkWidget, revealed: cbool) + # Gtk.Button proc gtk_button_new*(): GtkWidget proc gtk_button_new_with_label*(label: cstring): GtkWidget diff --git a/owlkettle/widgets.nim b/owlkettle/widgets.nim index 3340e017..b7822855 100644 --- a/owlkettle/widgets.nim +++ b/owlkettle/widgets.nim @@ -331,6 +331,7 @@ renderable CenterBox of BaseWidget: endWidget: Widget baselinePosition: BaselinePosition = BaselineCenter shrinkCenterLast: bool = false ## Requires GTK 4.12 or higher to work. Compile with `-d:gtkminor=12` to enable it + orient: Orient = OrientX hooks: beforeBuild: @@ -357,6 +358,10 @@ renderable CenterBox of BaseWidget: when GtkMinor >= 12: gtk_center_box_set_shrink_center_last(state.internalWidget, state.shrinkCenterLast.cbool) + hooks orient: + property: + gtk_orientable_set_orientation(state.internalWidget, state.orient.toGtk()) + adder addStart: if widget.hasStartWidget: raise newException(ValueError, "Unable to add multiple children to the start of CenterBox.") @@ -3985,6 +3990,46 @@ renderable ProgressBar of BaseWidget: property: gtk_progress_bar_set_text(state.internalWidget, state.text.cstring) +renderable ActionBar of BaseWidget: + ## A Bar for actions to execute in a given context. Can be hidden with intro- and outro-animations. + centerWidget: Widget + packStart: seq[Widget] ## Widgets shown on the start of the ActionBar + packEnd: seq[Widget] ## Widgets shown on the end of the ActionBar + revealed: bool + + hooks: + beforeBuild: + state.internalWidget = gtk_action_bar_new() + + hooks centerWidget: + (build, update): + state.updateChild(state.centerWidget, widget.valCenterWidget, gtk_action_bar_set_center_widget) + + hooks packStart: + (build, update): + state.updateChildren(state.packStart, widget.valPackStart, gtk_action_bar_pack_start, gtk_action_bar_remove) + + hooks packEnd: + (build, update): + state.updateChildren(state.packEnd, widget.valPackEnd, gtk_action_bar_pack_end, gtk_action_bar_remove) + + hooks revealed: + property: + gtk_action_bar_set_revealed(state.internalWidget, state.revealed.cbool) + + adder add: + if widget.hasCenterWidget: + raise newException(ValueError, "Unable to add multiple children as center widget of ActionBar. Add them to the start or end via {.addStart.} or {.addEnd.}.") + widget.hasCenterWidget = true + widget.valCenterWidget = child + + adder addStart: + widget.hasPackStart = true + widget.valPackStart.add(child) + + adder addEnd: + widget.hasPackEnd = true + widget.valPackEnd.add(child) const ListViewRichList* = StyleClass("rich-list") ListViewNavigationSidebar* = StyleClass("navigation-sidebar") @@ -4166,3 +4211,4 @@ export EmojiChooser export PasswordEntry export CenterBox export ListView +export ActionBar \ No newline at end of file