Skip to content

Commit

Permalink
Add OverlaySplitView (#119)
Browse files Browse the repository at this point in the history
* Move gtk.nim into bindings dir

* Refactor adwaita bindings into a binding module

* Re export bound enums

* Add SearchEntry widget

* Add Search Entry Widget

* Add text field to searchEntry widget

* Add missing text hook

* Improve search entry example

* Further improve example

* Refine which fields you shouldn't have access to

* Add activity to when you stop a search

* Add activity to when you stop a search

* Fix search entry displaying weird spacing

* Unify GtkMinor into a single constant

* Debug change

Attempt to cat out the gtk.nim file to see how the hell it is
getting the impression that GtkMinor is defined twice.

* Move GtkMInor before the passL flag is passed?

Maybe this fixes the problem with the pipeline sudenly thinking
that value was defined twice.

* Unto test-pipeline debug change

* Comment out unsupported search thingy

* Minor tweaks

- Removed searchstring parameter from callbacks
- made sure only changed callback can modify search value
- Updated example
- Moved example to far nicer looking ListBox

* Remove unnecessary Box

* Update examples/widgets/search_entry.nim

Co-authored-by: Can Lehmann <85876381+can-lehmann@users.noreply.github.com>

---------

Co-authored-by: Can Lehmann <85876381+can-lehmann@users.noreply.github.com>

* Add PasswordEntry widget

* Add core of password entry widget

* Add bindings for menu model

I do not plan to act on them yet but I'd like to
at least already add them so I don't have to
make the effort later

* Update password entry docs

* Improve gitignore

* Use unsafeAddr for nim version 1.0

* Fix GValue being let instead of var

* Add text field to password entry

* Ensure activateEventCallback also updates state

* Add missing text hook

* Add way to demonstrate 2 way binding

* Remove unnecessary pragma ping pong

* Removed password from activate callback parameters

* Add ActionBar widget

* Make Centerbox orientable

* Add Action Bar Widget and docs

* Minor refinement to the action bar example

It now actually "deletes" the contents of the label.
There's also a button to reset its value.

* Improve example button styling

* Add examples to .gitignore

* Update docs

* Add overlay split view widget

* Add EditableLabel

* Add core editable label widget

* Enable listening to editing changes

* Update docs for editable label

* Add redraw to editedCallback

* Add more editable functionality to label

Note that maxWidthChars, widthChars and cursorPosition
were not wrapped.

That is because apparently on this Widget they don't do anything.

* Improve example with 2 way binding

Also improve type of alignment because nim
has a great type system.

* Remove unnecessary wrapped enum

* Update owlkettle/widgets.nim

Co-authored-by: Can Lehmann <85876381+can-lehmann@users.noreply.github.com>

* Update owlkettle/widgets.nim

Co-authored-by: Can Lehmann <85876381+can-lehmann@users.noreply.github.com>

* Update docs

---------

Co-authored-by: Can Lehmann <85876381+can-lehmann@users.noreply.github.com>

* Refactor bindings into a bindings directory and move adw.nim bindings into their own module

* Move gtk.nim into bindings dir

* Refactor adwaita bindings into a binding module

* Re export bound enums

* Add SearchEntry widget

* Add Search Entry Widget

* Add text field to searchEntry widget

* Add missing text hook

* Improve search entry example

* Further improve example

* Refine which fields you shouldn't have access to

* Add activity to when you stop a search

* Add activity to when you stop a search

* Fix search entry displaying weird spacing

* Unify GtkMinor into a single constant

* Debug change

Attempt to cat out the gtk.nim file to see how the hell it is
getting the impression that GtkMinor is defined twice.

* Move GtkMInor before the passL flag is passed?

Maybe this fixes the problem with the pipeline sudenly thinking
that value was defined twice.

* Unto test-pipeline debug change

* Comment out unsupported search thingy

* Minor tweaks

- Removed searchstring parameter from callbacks
- made sure only changed callback can modify search value
- Updated example
- Moved example to far nicer looking ListBox

* Remove unnecessary Box

* Update examples/widgets/search_entry.nim

Co-authored-by: Can Lehmann <85876381+can-lehmann@users.noreply.github.com>

---------

Co-authored-by: Can Lehmann <85876381+can-lehmann@users.noreply.github.com>

* Add PasswordEntry widget

* Add core of password entry widget

* Add bindings for menu model

I do not plan to act on them yet but I'd like to
at least already add them so I don't have to
make the effort later

* Update password entry docs

* Improve gitignore

* Use unsafeAddr for nim version 1.0

* Fix GValue being let instead of var

* Add text field to password entry

* Ensure activateEventCallback also updates state

* Add missing text hook

* Add way to demonstrate 2 way binding

* Remove unnecessary pragma ping pong

* Removed password from activate callback parameters

* Add ActionBar widget

* Make Centerbox orientable

* Add Action Bar Widget and docs

* Minor refinement to the action bar example

It now actually "deletes" the contents of the label.
There's also a button to reset its value.

* Improve example button styling

* Add examples to .gitignore

* Update docs

* Add license to adw.nim bindings

---------

Co-authored-by: Can Lehmann <can.l@posteo.de>

* Remove overlay splitview from github CI examples

* Beautify example

* Update image

* Beautify example even more

* Cleanup example

* Add toggle callback

---------

Co-authored-by: Can Lehmann <can.l@posteo.de>
  • Loading branch information
PhilippMDoerner and can-lehmann authored Mar 5, 2024
1 parent a678f9b commit b157585
Show file tree
Hide file tree
Showing 9 changed files with 288 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ examples/widgets/adw/header_bar
examples/widgets/adw/button_content
examples/widgets/adw/banner
examples/widgets/adw/about_window
examples/widgets/adw/overlay_split_view
examples/dialogs/file_dialog
examples/dialogs/message_dialog
examples/dialogs/about_dialog
Expand Down
Binary file added docs/assets/examples/overlay_split_view.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
33 changes: 33 additions & 0 deletions docs/widgets_adwaita.md
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,39 @@ Flap:
```


## OverlaySplitView

```nim
renderable OverlaySplitView of BaseWidget
```

###### Fields

- All fields from [BaseWidget](#BaseWidget)
- `content: Widget`
- `sidebar: Widget`
- `collapsed: bool = false`
- `enableHideGesture: bool = true`
- `enableShowGesture: bool = true`
- `maxSidebarWidth: float = 280.0`
- `minSidebarWidth: float = 180.0`
- `pinSidebar: bool = false`
- `showSidebar: bool = true`
- `sidebarPosition: PackType = PackStart`
- `widthFraction: float = 0.25`
- `widthUnit: LengthUnit = LengthScaleIndependent`

###### Events

- toggle: `proc (shown: bool)`

###### Adders

- All adders from [BaseWidget](#BaseWidget)
- `add`
- `addSidebar`


## AdwHeaderBar

```nim
Expand Down
4 changes: 4 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,10 @@ The `widgets` directory contains examples for how to use different widgets.
<td><a href="https://github.com/can-lehmann/owlkettle/blob/main/examples/widgets/adw/flap.nim">Flap</a></td>
<td><img alt="Flap" src="../docs/assets/examples/flap.png" width="622px"></td>
</tr>
<tr>
<td><a href="https://github.com/can-lehmann/owlkettle/blob/main/examples/widgets/adw/overlay_split_view.nim">Overlay Split View</a></td>
<td><img alt="Overlay Split View" src="../docs/assets/examples/overlay_split_view.png" width="722px"></td>
</tr>
<tr>
<td><a href="https://github.com/can-lehmann/owlkettle/blob/main/examples/widgets/adw/preferences_group.nim">Preferences Group</a></td>
<td><img alt="Preferences Group" src="../docs/assets/examples/preferences_group.png" width="721px"></td>
Expand Down
97 changes: 97 additions & 0 deletions examples/widgets/adw/overlay_split_view.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# 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 owlkettle, owlkettle/[playground, adw]

viewable App:
collapsed: bool = false
enableHideGesture: bool = true
enableShowGesture: bool = true
maxSidebarWidth: float = 300.0
minSidebarWidth: float = 250.0
pinSidebar: bool = false
showSidebar: bool = true
sidebarPosition: PackType = PackStart
widthFraction: float = 0.25
widthUnit: LengthUnit = LengthScaleIndependent
sensitive: bool = true
tooltip: string = ""
sizeRequest: tuple[x, y: int] = (-1, -1)

method view(app: AppState): Widget =
result = gui:
AdwWindow:
defaultSize = (600, 400)

OverlaySplitView:
collapsed = app.collapsed
enableHideGesture = app.enableHideGesture
enableShowGesture = app.enableShowGesture
maxSidebarWidth = app.maxSidebarWidth
minSidebarWidth = app.minSidebarWidth
pinSidebar = app.pinSidebar
showSidebar = app.showSidebar
sidebarPosition = app.sidebarPosition
widthFraction = app.widthFraction
widthUnit = app.widthUnit
tooltip = app.tooltip
sensitive = app.sensitive
sizeRequest = app.sizeRequest

proc toggle(shown: bool) =
echo shown
app.showSidebar = shown

Box:
orient = OrientY

AdwHeaderBar {.expand: false.}:
style = HeaderBarFlat

insert(app.toAutoFormMenu(sizeRequest = (400, 500))){.addRight.}

Button {.addLeft.}:
icon = "sidebar-show-symbolic"
style = ButtonFlat

proc clicked() =
app.showSidebar = not app.showSidebar

Label:
text = "Content"
style = LabelTitle2

Box {.addSidebar.}:
orient = OrientY
spacing = 4

AdwHeaderBar {.expand: false.}:
style = HeaderBarFlat

WindowTitle {.addTitle.}:
title = "Overlay Split View Example"

Label:
text = "Sidebar"
style = LabelTitle2

adw.brew(gui(App()))
1 change: 1 addition & 0 deletions owlkettle.nimble
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ task examples, "Build examples":
"widgets/adw/banner.nim",
"widgets/adw/entry_row.nim",
"widgets/adw/switch_row.nim",
"widgets/adw/overlay_split_view.nim",
"widgets/adw/button_content.nim",
"widgets/adw/about_window.nim"
]
Expand Down
122 changes: 122 additions & 0 deletions owlkettle/adw.nim
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export adw.ColorScheme
export adw.FlapFoldPolicy
export adw.FoldThresholdPolicy
export adw.FlapTransitionType
export adw.LengthUnit
export adw.CenteringPolicy
export adw.AdwVersion

Expand Down Expand Up @@ -614,6 +615,127 @@ proc `valSwipe=`*(flap: Flap, swipe: bool) =
flap.valSwipeToOpen = swipe
flap.valSwipeToClose = swipe

when AdwVersion >= (1, 4) or defined(owlkettleDocs):
renderable OverlaySplitView of BaseWidget:
content: Widget
sidebar: Widget
collapsed: bool = false
enableHideGesture: bool = true
enableShowGesture: bool = true
maxSidebarWidth: float = 280.0
minSidebarWidth: float = 180.0
pinSidebar: bool = false
showSidebar: bool = true
sidebarPosition: PackType = PackStart
widthFraction: float = 0.25
widthUnit: LengthUnit = LengthScaleIndependent

proc toggle(shown: bool)

hooks:
beforeBuild:
when AdwVersion >= (1, 4):
state.internalWidget = adw_overlay_split_view_new()
connectEvents:
when AdwVersion >= (1, 4):
proc toggleCallback(widget: GtkWidget,
spec: pointer,
data: ptr EventObj[proc (show: bool)]) {.cdecl.} =
let
showSidebar = adw_overlay_split_view_get_show_sidebar(widget) != 0
state = OverlaySplitViewState(data[].widget)
if showSidebar != state.showSidebar:
state.showSidebar = showSidebar
data[].callback(showSidebar)
data[].redraw()

state.connect(state.toggle, "notify::show-sidebar", toggleCallback)
disconnectEvents:
when AdwVersion >= (1, 4):
state.internalWidget.disconnect(state.toggle)

hooks content:
(build, update):
when AdwVersion >= (1, 4):
state.updateChild(
state.content,
widget.valContent,
adw_overlay_split_view_set_content
)

hooks sidebar:
(build, update):
when AdwVersion >= (1, 4):
state.updateChild(
state.sidebar,
widget.valSidebar,
adw_overlay_split_view_set_sidebar
)

hooks collapsed:
property:
when AdwVersion >= (1, 4):
adw_overlay_split_view_set_collapsed(state.internalWidget, state.collapsed.cbool)

hooks enableHideGesture:
property:
when AdwVersion >= (1, 4):
adw_overlay_split_view_set_enable_hide_gesture(state.internalWidget, state.enableHideGesture.cbool)

hooks enableShowGesture:
property:
when AdwVersion >= (1, 4):
adw_overlay_split_view_set_enable_show_gesture(state.internalWidget, state.enableShowGesture.cbool)

hooks maxSidebarWidth:
property:
when AdwVersion >= (1, 4):
adw_overlay_split_view_set_max_sidebar_width(state.internalWidget, state.maxSidebarWidth.cdouble)

hooks minSidebarWidth:
property:
when AdwVersion >= (1, 4):
adw_overlay_split_view_set_min_sidebar_width(state.internalWidget, state.minSidebarWidth.cdouble)

hooks pinSidebar:
property:
when AdwVersion >= (1, 4):
adw_overlay_split_view_set_pin_sidebar(state.internalWidget, state.pinSidebar.cbool)

hooks showSidebar:
property:
when AdwVersion >= (1, 4):
adw_overlay_split_view_set_show_sidebar(state.internalWidget, state.showSidebar.cbool)

hooks sidebarPosition:
property:
when AdwVersion >= (1, 4):
adw_overlay_split_view_set_sidebar_position(state.internalWidget, state.sidebarPosition.toGtk())

hooks widthFraction:
property:
when AdwVersion >= (1, 4):
adw_overlay_split_view_set_sidebar_width_fraction(state.internalWidget, state.widthFraction.cdouble)

hooks widthUnit:
property:
when AdwVersion >= (1, 4):
adw_overlay_split_view_set_sidebar_width_unit(state.internalWidget, state.widthUnit)

adder add:
if widget.hasContent:
raise newException(ValueError, "Unable to add multiple children to a OverlaySplitView. Use a Box widget to display multiple widgets!")
widget.hasContent = true
widget.valContent = child

adder addSidebar:
if widget.hasSidebar:
raise newException(ValueError, "Unable to add multiple sidebars to a OverlaySplitView. Use a Box widget to display multiple widgets!")
widget.hasSidebar = true
widget.valSidebar = child

export OverlaySplitView

renderable AdwHeaderBar of BaseWidget:
## Adwaita Headerbar that combines GTK Headerbar and WindowControls.
packLeft: seq[Widget]
Expand Down
23 changes: 23 additions & 0 deletions owlkettle/bindings/adw.nim
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@ type
FlapTransitionOver
FlapTransitionUnder
FlapTransitionSlide

LengthUnit* = enum
LengthPixel
LengthPoint
LengthScaleIndependent


{.push importc, cdecl.}
# Adw
Expand Down Expand Up @@ -157,6 +163,23 @@ proc adw_flap_set_swipe_to_close*(flap: GtkWidget, swipe: cbool)
proc adw_flap_get_reveal_flap*(flap: GtkWidget): cbool
proc adw_flap_get_folded*(flap: GtkWidget): cbool

when AdwVersion >= (1, 4):
# Adw.OverlaySplitView
proc adw_overlay_split_view_new*(): GtkWidget
proc adw_overlay_split_view_get_show_sidebar*(self: GtkWidget): cbool
proc adw_overlay_split_view_set_collapsed*(self: GtkWidget, collapsed: cbool)
proc adw_overlay_split_view_set_content*(self, content: GtkWidget)
proc adw_overlay_split_view_set_enable_hide_gesture*(self: GtkWidget, enable_hide_gesture: cbool)
proc adw_overlay_split_view_set_enable_show_gesture*(self: GtkWidget, enable_show_gesture: cbool)
proc adw_overlay_split_view_set_max_sidebar_width*(self: GtkWidget, width: cdouble)
proc adw_overlay_split_view_set_min_sidebar_width*(self: GtkWidget, width: cdouble)
proc adw_overlay_split_view_set_pin_sidebar*(self: GtkWidget, pin_sidebar: cbool)
proc adw_overlay_split_view_set_show_sidebar*(self: GtkWidget, show_sidebar: cbool)
proc adw_overlay_split_view_set_sidebar*(self, sidebar: GtkWidget)
proc adw_overlay_split_view_set_sidebar_position*(self: GtkWidget, position: GtkPackType)
proc adw_overlay_split_view_set_sidebar_width_fraction*(self: GtkWidget, fraction: cdouble)
proc adw_overlay_split_view_set_sidebar_width_unit*(self: GtkWidget, unit: LengthUnit)

# Adw.SplitButton
proc adw_split_button_new*(): GtkWidget
proc adw_split_button_set_child*(button, child: GtkWidget)
Expand Down
7 changes: 7 additions & 0 deletions owlkettle/widgets.nim
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@ customPragmas()
when defined(owlkettleDocs) and isMainModule:
echo "# Widgets"

type PackType* = enum
PackStart
PackEnd

proc toGtk*(packType: PackType): GtkPackType =
result = GtkPackType(ord(packType))

type
Margin* = object
top*, bottom*, left*, right*: int
Expand Down

0 comments on commit b157585

Please sign in to comment.