Skip to content

Commit

Permalink
Add Expander widget
Browse files Browse the repository at this point in the history
* debug attempt

* #83 Add first attempt at scale widget

* #83 Fix types on bindings

double in C translates to cdouble in nim, not cfloat.

* #83 improve examples and implementation

* stuff

* #83 Add support for initial widget value

* #83 Add support for inverting widget

* #83 fix some bugs

* #83 add update of ScaleState to change proc

* #83 let pageSize just default to double the pageSize

* #83 add support for showing or hiding fill level and precision

* #83 Fix bug causing infinite window growth

* #83 refactor state-variables to use property hooks

* #83 implement suggestion for value 2way bindings

* #83 Fix example

* #83 Add support for configuring value position

* #83 Make orientation configurable

* #83 Fix example datatype (this was int but needs to be float64)

* #83 Fix semantics on marks

* #83 Ensure order of hooks is the same as order of properties

* #83 Add build hook to make initial value assignment work again

* #83 slightly beautify example

* #83 Adjust proc-calling to code conventions

* #83 Add widgets example

* ##83 add doc comments to Scale widget

* #83 Update widgets.md

* Add notice that there's a nimble task to generate docs as well

* #83 Remove nonsense workflow change

* #83 Add scale to example README and mild improvements

* Remove nonsense workflow change from myself

* #83 Mild doc comment improvements

* #83 Fix error introduced by last commit in doc comments

* #83 Remove build hook

* #83 Move float64 to float

* #83 Minor doc update

* #83 Improve Scale example to make it more configurable

* #93 Add AutoForm function

Generates a Box widget with editable
dataentry widgets for each field on the state.
You can exclude certain fields as desired.

* #93 Minor Fix to Scale Widget example

* #93 add support for DateTime with Calendar widget

* #93 Add ability to deal with tuples generally

* #93 add basewidget fields

* Improve example

* Fix Text View example image width

* Update gitignore

* #93 Update Autoform for scale

* debug attempt

* Remove nonsense workflow change from myself

* #93 Add BaseWidget attributes back to example

* #93 Add an auto mini form generator

* #93 Add nicer form fields specifically for sizeRequest tuple

* #93 Fully move over to the non-form-generating approach

* #85 Add Expander Widget including example

* #85 Add BaseWidget fields

* #85 Add example to README.md

* #85 add Activation callback and doc comments

* #85 Update and expand docs

* #85 Fix expander callback delivering outdated values

* #85 Move expander example over to autoform

* #85 Update docs and example screenshot

* #85 Refine example and remove autoform

* #85 Update widgets.md

The introduction of gtkminor in an earlier PR changed this doc comment.
That caused a change in widgets.md

* Update owlkettle/widgets.nim

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

* #85 Move Expander to make sure list is sorted alphabetically

* #85 Update docs

---------

Co-authored-by: Can Lehmann <can.l@posteo.de>
Co-authored-by: Can Lehmann <85876381+can-lehmann@users.noreply.github.com>
  • Loading branch information
3 people authored Oct 8, 2023
1 parent 6b0c75e commit c3aacd3
Show file tree
Hide file tree
Showing 6 changed files with 205 additions and 3 deletions.
Binary file added docs/assets/examples/expander.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
32 changes: 31 additions & 1 deletion docs/widgets.md
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ renderable Picture of BaseWidget

- All fields from [BaseWidget](#BaseWidget)
- `pixbuf: Pixbuf`
- `contentFit: ContentFit = ContentContain` Requires GTK 4.8 to fully work, compile with `-d:gtk48` to enable
- `contentFit: ContentFit = ContentContain` Requires GTK 4.8 or higher to fully work, compile with `-d:gtkminor=8` to enable


## Button
Expand Down Expand Up @@ -1476,3 +1476,33 @@ Scale:
```


## Expander

```nim
renderable Expander of BaseWidget
```

Container that shows or hides its child depending on whether it is expanded/collapsed

###### Fields

- All fields from [BaseWidget](#BaseWidget)
- `label: string` Sets the clickable header of the Expander. Overwritten by `labelWidget` if it is provided via adder.
- `labelWidget: Widget` Sets the clickable header of the Expander. Overwrites `label` if provided.
- `expanded: bool = false` Determines whether the Expander body is shown (expanded = true) or not (expanded = false)
- `child: Widget` Determines the body of the Expander.
- `resizeToplevel: bool = false`
- `useMarkup: bool = false`
- `useUnderline: bool = false`

###### Events

- activate: `proc (activated: bool)` Triggered whenever Expander is expanded or collapsed

###### Adders

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


4 changes: 4 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,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/drop_down.nim">Drop Down</a></td>
<td><img alt="Drop Down" src="../docs/assets/examples/drop_down.png" width="378px"></td>
</tr>
<tr>
<td><a href="https://github.com/can-lehmann/owlkettle/blob/main/examples/widgets/expander.nim">Expander</a></td>
<td><img alt="Expander" src="../docs/assets/examples/expander.png" width="922px"></td>
</tr>
<tr>
<td><a href="https://github.com/can-lehmann/owlkettle/blob/main/examples/widgets/fixed.nim">Fixed</a></td>
<td><img alt="Fixed" src="../docs/assets/examples/fixed.png" width="461px"></td>
Expand Down
82 changes: 82 additions & 0 deletions examples/widgets/expander.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# MIT License
#
# Copyright (c) 2023 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/[adw, playground]

viewable App:
label: string = "A String Label"
expanded: bool = false
resizeToplevel: bool = false
useMarkup: bool = false
useUnderline: bool = false
sensitive: bool = true
sizeRequest: tuple[x, y: int] = (-1, -1)
tooltip: string = ""


method view(app: AppState): Widget =
result = gui:
Window():
defaultSize = (800, 600)
title = "Expander Example"
HeaderBar {.addTitlebar.}:
insert(app.toAutoFormMenu(sizeRequest = (400, 520))) {.addRight.}

Box(orient = OrientY, spacing = 6, margin = 12):
Label():
useMarkup = true
text = """<span size="x-large" weight="bold"> Expander with String Label </span>"""

Expander():
label = app.label
expanded = app.expanded
resizeTopLevel = app.resizeTopLevel
useMarkup = app.useMarkup
useUnderline = app.useUnderline
sensitive = app.sensitive
sizeRequest = app.sizeRequest
tooltip = app.tooltip

proc activate(activated: bool) =
app.expanded = activated

Label(text = "I am a child widget inserted into the Expander")

Separator() {.expand: false.}

Label():
useMarkup = true
text = """<span size="x-large" weight="bold"> Expander with Widget Label </span>"""

Expander():
expanded = app.expanded
resizeTopLevel = app.resizeTopLevel
useMarkup = app.useMarkup
useUnderline = app.useUnderline

proc activate(activated: bool) =
app.expanded = activated

Label(text = "A Widget Label") {.addLabel.}
Label(text = "I am a child widget inserted into the Expander")

adw.brew(gui(App()))
12 changes: 12 additions & 0 deletions owlkettle/gtk.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1050,6 +1050,18 @@ proc gtk_level_bar_set_mode*(widget: GtkWidget, mode: GtkLevelBarMode)
proc gtk_level_bar_set_value*(widget: GtkWidget, value: cdouble)
proc gtk_level_bar_set_min_value*(widget: GtkWidget, value: cdouble)
proc gtk_level_bar_set_max_value*(widget: GtkWidget, value: cdouble)

# Gtk.Expander
proc gtk_expander_new*(label: cstring): GtkWidget
proc gtk_expander_set_child*(widget: GtkWidget, child: GtkWidget)
proc gtk_expander_set_expanded*(widget: GtkWidget, expanded: cbool)
proc gtk_expander_set_label*(widget: GtkWidget, label: cstring)
proc gtk_expander_set_label_widget*(widget: GtkWidget, label_widget: GtkWidget)
proc gtk_expander_set_resize_toplevel*(widget: GtkWidget, resize_toplevel: cbool)
proc gtk_expander_set_use_markup*(widget: GtkWidget, use_markup: cbool)
proc gtk_expander_set_use_underline*(widget: GtkWidget, use_underline: cbool)
proc gtk_expander_get_expanded*(widget: GtkWidget): cbool

{.pop.}

{.push hint[Name]: off.}
Expand Down
78 changes: 76 additions & 2 deletions owlkettle/widgets.nim
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,7 @@ renderable Overlay of BaseWidget:

adder add:
if widget.hasChild:
raise newException(ValueError, "Unable to add multiple children to a Overlay. You can add overlays using the addOverlay adder.")
raise newException(ValueError, "Unable to add multiple children to an Overlay. You can add overlays using the addOverlay adder.")
widget.hasChild = true
widget.valChild = child

Expand Down Expand Up @@ -3525,6 +3525,79 @@ renderable Scale of BaseWidget:
echo "New value is ", newValue
app.value = newValue

renderable Expander of BaseWidget:
## Container that shows or hides its child depending on whether it is expanded/collapsed
label: string ## Sets the clickable header of the Expander. Overwritten by `labelWidget` if it is provided via adder.
labelWidget: Widget ## Sets the clickable header of the Expander. Overwrites `label` if provided.
expanded: bool = false ## Determines whether the Expander body is shown (expanded = true) or not (expanded = false)
child: Widget ## Determines the body of the Expander.
resizeToplevel: bool = false
useMarkup: bool = false
useUnderline: bool = false

proc activate(activated: bool) ## Triggered whenever Expander is expanded or collapsed

hooks:
beforeBuild:
state.internalWidget = gtk_expander_new(widget.valLabel.cstring)

connectEvents:
proc activateEventCallback(
widget: GtkWidget,
data: ptr EventObj[proc(activated: bool)]
) {.cdecl.} =
let expanded: bool = not gtk_expander_get_expanded(widget).bool # Necessary as widget hasn't updated itself yet, thus this returns the old value
ExpanderState(data[].widget).expanded = expanded
data[].callback(expanded)
data[].redraw()

state.connect(state.activate, "activate", activateEventCallback)

disconnectEvents:
disconnect(state.internalWidget, state.activate)

hooks label:
property:
gtk_expander_set_label(state.internalWidget, state.label.cstring)

hooks expanded:
property:
gtk_expander_set_expanded(state.internalWidget, state.expanded.cbool)

hooks resizeToplevel:
property:
gtk_expander_set_resize_toplevel(state.internalWidget, state.resizeToplevel.cbool)

hooks useMarkup:
property:
gtk_expander_set_use_markup(state.internalWidget, state.useMarkup.cbool)

hooks useUnderline:
property:
gtk_expander_set_use_underline(state.internalWidget, state.useUnderline.cbool)

hooks child:
(build, update):
state.updateChild(state.child, widget.valChild, gtk_expander_set_child)

hooks labelWidget:
(build, update):
state.updateChild(state.labelWidget, widget.valLabelWidget, gtk_expander_set_label_widget)

adder add:
if widget.hasChild:
raise newException(ValueError, "Unable to add multiple children to the body of an Expander.")

widget.hasChild = true
widget.valChild = child

adder addLabel:
if widget.hasLabelWidget:
raise newException(ValueError, "Unable to add multiple Labels as the header of an Expander")

widget.hasLabelWidget = true
widget.valLabelWidget = child

export BaseWidget, BaseWidgetState, BaseWindow, BaseWindowState
export Window, Box, Overlay, Label, Icon, Picture, Button, HeaderBar, ScrolledWindow, Entry, Spinner
export SpinButton, Paned, ColorButton, Switch, LinkButton, ToggleButton, CheckButton, RadioGroup
Expand All @@ -3538,4 +3611,5 @@ export ColorChooserDialog, ColorChooserDialogState
export MessageDialog, MessageDialogState
export AboutDialog, AboutDialogState
export buildState, updateState, assignAppEvents
export Scale
export Scale
export Expander

0 comments on commit c3aacd3

Please sign in to comment.