Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a "Form-Generating"-feature to Owlkettle #93

Closed
PhilippMDoerner opened this issue Sep 30, 2023 · 4 comments
Closed

Add a "Form-Generating"-feature to Owlkettle #93

PhilippMDoerner opened this issue Sep 30, 2023 · 4 comments

Comments

@PhilippMDoerner
Copy link
Contributor

PhilippMDoerner commented Sep 30, 2023

The usecase

For all the example widgets I would like to have a generic proc or template or so that I can just hand any kind of <WidgetName>State and that generates me a Form where I have DataEntry fields for every field on said state (except for app and viewed as those are owlkettle internal I think?).

This would be useful to let the user see what happens under various circumstances if they manipulate the state of a widget as they please.

It could also be useful if users want to generate a form to manipulate data on the fly without having to write it by hand.

The concept of a solution

Conceptually, I'd have assumed any approach would simply need to iterate over the fields of <WidgetName>State type, transform the values of the fields into an enum-type and then use fieldName and the enum-type to associate the field on <WidgetName>State with a DataEntry widget. Which DataEntry widget is chosen is determined by the enum-type.

This normally wouldn't be toooooo hard without but the combination of any State type having app and viewed fields that somehow cause compiler crashes when accessed by the loop as well as the guidsl tolerating neither when statements (which would allow me to avoid those) nor macros that enable unrolling a static: seq[string] for-loop in the gui section makes all my typical non-macro approaches impossible.

Prior approach (Placeholder for like 3 other similar ones I all attempted)

Removed, it is irrelevant as I found a solution

@PhilippMDoerner
Copy link
Contributor Author

I've got it to work! Mostly with the approach you had in mind I think:

import owlkettle
import owlkettle/[dataentries, adw, widgetutils]
import std/[options, json, macros, strutils]

type A = object
  name: string

viewable App:
  value: float64 = 100.0
  orient: Orient = OrientX
  inverted: bool = false
  bla: A = A(name: "lala")
  text: string = "Something"

macro getField*(someType: untyped, fieldName: static string): untyped =
  nnkDotExpr.newTree(someType, ident(fieldName))

proc toFormField(state: auto, fieldName: static string, typ: typedesc[SomeFloat]): Widget =
  return gui:
    NumberEntry(value = state.getField(fieldName)):
      proc changed(value: float) =
        state.getField(fieldName) = value

proc toFormField(state: auto, fieldName: static string, typ: typedesc[SomeInteger]): Widget =
  return gui:
    NumberEntry(value = state.getField(fieldName).float):
      proc changed(value: float) =
        state.getField(fieldName) = value.int
        

proc toFormField(state: auto, fieldName: static string, typ: typedesc[string]): Widget =
  return gui:
    Entry(text = state.getField(fieldName)):
      proc changed(text: string) =
        state.getField(fieldName) = text

proc toFormField(state: auto, fieldName: static string, typ: typedesc[bool]): Widget =
    return gui:
      Switch(state = state.getField(fieldName)):
        proc changed(newVal: bool) =
          state.getField(fieldName) = newVal

proc toFormField(state: auto, fieldName: static string, typ: typedesc[object]): Widget =
    return gui:
      Entry(text = $ %*state.getField(fieldName)):
        proc changed(text: string) =
          try:
            state.getField(fieldName) = text.parseJson().to(typ)
          except Exception: discard

proc toFormField(state: auto, fieldName: static string, typ: typedesc[enum]): Widget =
  return gui:
    Entry(text = $state.getField(fieldName)):
      proc changed(text: string) =
        try:
          state.getField(fieldName) = parseEnum[typ](text)
        except Exception: discard

method view(app: AppState): Widget =
  var fieldWidgets: seq[tuple[name: string, field: AlignedChild[Widget]]] = @[]
  for name, value in app[].fieldPairs:
    when name notin ["app", "viewed"]:
      let fieldWidget = app.toFormField(name, value.type)
      if fieldWidget != nil:
        let alignedWidget = AlignedChild[Widget](widget: fieldWidget)
        fieldWidgets.add((name, alignedWidget))

  result = gui:
    Window:
      Box(orient = OrientY, spacing = 6, margin = 12):
        for field in fieldWidgets:
          ActionRow {.expand: false.}:
            margin = 6
            title = field.name
            suffixes = @[field.field]
            
owlkettle.brew(gui(App()))

Sadly couldn't figure out how to get past the need for the third field as "discriminator" between the various toFormField procs.

PhilippMDoerner added a commit to PhilippMDoerner/owlkettle that referenced this issue Oct 1, 2023
PhilippMDoerner added a commit to PhilippMDoerner/owlkettle that referenced this issue Oct 1, 2023
Generates a Box widget with editable
dataentry widgets for each field on the state.
You can exclude certain fields as desired.
@PhilippMDoerner
Copy link
Contributor Author

PhilippMDoerner commented Oct 1, 2023

I decided to create a BoxWidget via a generic proc and use insert to insert it into the example gui-tree.

The main reason for me not making a viewable instead was honestly that I've never seen a generic viewable before and felt that would be too much hassle to troubleshoot for something that is mostly anyway a QoL addition.
Particularly since a generic viewable likely would also require a generic viewable method and IIRC generic methods are fundamentally broken, making it doubly not worth the effort to try and go in that direction.

Also given that I have no clue where to put it, I put it into its own file for now.
I'll open a PR for this once the Scale PR is merged as I directly depend on that example for this ticket and for my testing.

PhilippMDoerner added a commit to PhilippMDoerner/owlkettle that referenced this issue Oct 1, 2023
PhilippMDoerner added a commit to PhilippMDoerner/owlkettle that referenced this issue Oct 2, 2023
PhilippMDoerner added a commit to PhilippMDoerner/owlkettle that referenced this issue Oct 2, 2023
PhilippMDoerner added a commit to PhilippMDoerner/owlkettle that referenced this issue Oct 2, 2023
PhilippMDoerner added a commit to PhilippMDoerner/owlkettle that referenced this issue Oct 2, 2023
This was referenced Oct 2, 2023
@PhilippMDoerner
Copy link
Contributor Author

PhilippMDoerner commented Oct 2, 2023

Sidenote, this issue will encompass 2 PRs that I'll open one after another (because 1) depends on the Scale PR and 2) depends on 1)):

  1. Add the feature of autoform in general (this branch)
  2. Add Autoform to all examples under examples/widgets (this branch)

That is in order to keep the individual PRs smaller, as I thought you might find that preferable over one larger PR.

Also I opened them as Draft PRs already since I have time right now and this way I can basically do everything I can right now, as particularly writing PR descriptions takes me some time typically that I might not have later.

PhilippMDoerner added a commit to PhilippMDoerner/owlkettle that referenced this issue Oct 2, 2023
PhilippMDoerner added a commit to PhilippMDoerner/owlkettle that referenced this issue Oct 2, 2023
PhilippMDoerner added a commit to PhilippMDoerner/owlkettle that referenced this issue Oct 2, 2023
PhilippMDoerner added a commit to PhilippMDoerner/owlkettle that referenced this issue Oct 2, 2023
PhilippMDoerner added a commit to PhilippMDoerner/owlkettle that referenced this issue Oct 2, 2023
PhilippMDoerner added a commit to PhilippMDoerner/owlkettle that referenced this issue Oct 2, 2023
PhilippMDoerner added a commit to PhilippMDoerner/owlkettle that referenced this issue Oct 3, 2023
PhilippMDoerner added a commit to PhilippMDoerner/owlkettle that referenced this issue Oct 3, 2023
PhilippMDoerner added a commit to PhilippMDoerner/owlkettle that referenced this issue Oct 3, 2023
PhilippMDoerner added a commit to PhilippMDoerner/owlkettle that referenced this issue Oct 3, 2023
PhilippMDoerner added a commit to PhilippMDoerner/owlkettle that referenced this issue Oct 3, 2023
PhilippMDoerner added a commit to PhilippMDoerner/owlkettle that referenced this issue Oct 4, 2023
A fully generic approach using T and SomeNumber does the job better
and covers more ground.
PhilippMDoerner added a commit to PhilippMDoerner/owlkettle that referenced this issue Oct 4, 2023
It now no longer is one that represents tuples etc.
as JSON and parses that back.

Instead, it now provides a dummy widget
that will explain to the user that they must implement a
`toFormField` proc with a more elaborate tooltip.
PhilippMDoerner added a commit to PhilippMDoerner/owlkettle that referenced this issue Oct 4, 2023
PhilippMDoerner added a commit to PhilippMDoerner/owlkettle that referenced this issue Oct 4, 2023
Values for this widget must be fetched via
gtk_editable_get_text and then parsed.

This provides a default parseInput proc that users can override.

However this state still doesn't update the value displayed by the
widget.
It does however update the value within the state of the example so... yay?
PhilippMDoerner added a commit to PhilippMDoerner/owlkettle that referenced this issue Oct 4, 2023
PhilippMDoerner added a commit to PhilippMDoerner/owlkettle that referenced this issue Oct 5, 2023
PhilippMDoerner added a commit to PhilippMDoerner/owlkettle that referenced this issue Oct 5, 2023
They now provide the form as a menu button popover
PhilippMDoerner added a commit to PhilippMDoerner/owlkettle that referenced this issue Oct 5, 2023
The new implementation enables
generating an entire form based on either
`toFormField` for individual entries with custom datatypes
or `toListFormField` for seq[T] of custom datatypes.
PhilippMDoerner added a commit to PhilippMDoerner/owlkettle that referenced this issue Oct 5, 2023
PhilippMDoerner added a commit to PhilippMDoerner/owlkettle that referenced this issue Oct 5, 2023
can-lehmann added a commit that referenced this issue Oct 8, 2023
* 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

* Add Autoform to calendar

* Add Autoform to drop_down

* #93 Add ability to deal with tuples generally

* #93 add basewidget fields

* Add Basewidget fields to dropdown

* Add autoform to picture.nim with Basewidget fields

* Add autoform to popover_menu.nim

Note:
It appears while `hasArrow` and `tooltip`
are available for PopoverMenu, they don't really do much

* Add Autoform to radio group

Orientation of radio group appears to
not change when you change the orientation.
It appears to solely rely on Box.
Is that a bug or just gtk behaviour?

* Fix radiogroup not allow runtime orient updates

Radiogroup was missing a property hook for
orient.
This commit adds said missing property hook.
This enables runtime-changing of the orientation of RadioGroup

* Add autoform to text_view

* Fix popover_menu example

* Fixed wrong fix for popover_menu

* Beautify Scale

* 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

* Update calendar example

* Update Dropdown example

* Update picture example

* Update Popover example

* Update radiogroup

* Update text_view example

* Update calendar image

* #93 Add nicer form fields specifically for sizeRequest tuple

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

* Update calendar image

* Update popover_menu example screenshot

* Update images of remaining examples

* #93 Minor fixes

* #93 update callback useable for calendar

* Remove pointless AlignedChild export

* Update Autoform to use FormulaEntry

* Move Calendar into a dialog

* #93 remove completely pointless overload for ints

A fully generic approach using T and SomeNumber does the job better
and covers more ground.

* #93 Change Default widget for objects and Co

It now no longer is one that represents tuples etc.
as JSON and parses that back.

Instead, it now provides a dummy widget
that will explain to the user that they must implement a
`toFormField` proc with a more elaborate tooltip.

* Minimize example to menubutton instead of sidebar

* #93 Move all toFormFields into autoform

* #93 Update widget examples

They now provide the form as a menu button popover

* Undo changes to example images

* #93 Overhaul autoform

The new implementation enables
generating an entire form based on either
`toFormField` for individual entries with custom datatypes
or `toListFormField` for seq[T] of custom datatypes.

* #93 Remove unused imports

* #93 Move examples back from WindowSurface to Window

* Update doc comments

* Undo examples changes

* Update example headerbars

* Make menubutton for form flat as per adw standards

* Make headerbar buttons into flat buttons

* Rename autoform to playground

* Variousf ixes to popover example

* Lots of example fixes

* Undo unnecessary changes

* Remove unnecessary defaultsize

---------

Co-authored-by: Can Lehmann <can.l@posteo.de>
@can-lehmann
Copy link
Owner

Closed by eba600b

can-lehmann added a commit that referenced this issue Oct 8, 2023
* 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

* #86 Add Status Page widget + example

* #86 Add mention of freedesktop spec

Also update other docs to point to the tooling section.

* #86 Update link to not point to localhost

* #86 Update Status Page docs

* #86 Remove autoform and refine example

* #86 update image

* Update examples/widgets/adw/status_page.nim

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

* #86 Fix incorrect alt attribute on example README

---------

Co-authored-by: Can Lehmann <can.l@posteo.de>
PhilippMDoerner added a commit to PhilippMDoerner/owlkettle that referenced this issue Oct 8, 2023
* debug attempt

* can-lehmann#83 Add first attempt at scale widget

* can-lehmann#83 Fix types on bindings

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

* can-lehmann#83 improve examples and implementation

* stuff

* can-lehmann#83 Add support for initial widget value

* can-lehmann#83 Add support for inverting widget

* can-lehmann#83 fix some bugs

* can-lehmann#83 add update of ScaleState to change proc

* can-lehmann#83 let pageSize just default to double the pageSize

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

* can-lehmann#83 Fix bug causing infinite window growth

* can-lehmann#83 refactor state-variables to use property hooks

* can-lehmann#83 implement suggestion for value 2way bindings

* can-lehmann#83 Fix example

* can-lehmann#83 Add support for configuring value position

* can-lehmann#83 Make orientation configurable

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

* can-lehmann#83 Fix semantics on marks

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

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

* can-lehmann#83 slightly beautify example

* can-lehmann#83 Adjust proc-calling to code conventions

* can-lehmann#83 Add widgets example

* #can-lehmann#83 add doc comments to Scale widget

* can-lehmann#83 Update widgets.md

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

* can-lehmann#83 Remove nonsense workflow change

* can-lehmann#83 Add scale to example README and mild improvements

* Remove nonsense workflow change from myself

* can-lehmann#83 Mild doc comment improvements

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

* can-lehmann#83 Remove build hook

* can-lehmann#83 Move float64 to float

* can-lehmann#83 Minor doc update

* can-lehmann#83 Improve Scale example to make it more configurable

* can-lehmann#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.

* can-lehmann#93 Minor Fix to Scale Widget example

* can-lehmann#93 add support for DateTime with Calendar widget

* can-lehmann#93 Add ability to deal with tuples generally

* can-lehmann#93 add basewidget fields

* Improve example

* Fix Text View example image width

* Update gitignore

* can-lehmann#93 Update Autoform for scale

* debug attempt

* Remove nonsense workflow change from myself

* can-lehmann#93 Add BaseWidget attributes back to example

* can-lehmann#93 Add an auto mini form generator

* can-lehmann#93 Add nicer form fields specifically for sizeRequest tuple

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

* can-lehmann#86 Add Status Page widget + example

* can-lehmann#86 Add mention of freedesktop spec

Also update other docs to point to the tooling section.

* can-lehmann#86 Update link to not point to localhost

* can-lehmann#86 Update Status Page docs

* can-lehmann#86 Remove autoform and refine example

* can-lehmann#86 update image

* Update examples/widgets/adw/status_page.nim

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

* can-lehmann#86 Fix incorrect alt attribute on example README

---------

Co-authored-by: Can Lehmann <can.l@posteo.de>
can-lehmann added a commit that referenced this issue Oct 8, 2023
* 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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants