Skip to content

Commit

Permalink
Merge branch '#93-add-form-generator' into add-autoform-to-all-the-wi…
Browse files Browse the repository at this point in the history
…dgets
  • Loading branch information
PhilippMDoerner committed Oct 4, 2023
2 parents 2c2bd18 + 934c75f commit c5a786e
Showing 1 changed file with 63 additions and 47 deletions.
110 changes: 63 additions & 47 deletions owlkettle/autoform.nim
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import std/[options, json, times, macros, strutils, sequtils]
import std/[options, times, macros, strformat, strutils, sequtils, typetraits]
import ./dataentries
import ./adw
import ./widgetutils
Expand All @@ -9,34 +9,16 @@ import ./widgets
macro getField*(someType: untyped, fieldName: static string): untyped =
nnkDotExpr.newTree(someType, ident(fieldName))

proc `%`*(t: tuple): JsonNode =
result = newJObject()
for field, value in t.fieldPairs:
result.add(field, %value)

## General Fields

proc toFormField(state: auto, fieldName: static string, typ: typedesc[SomeFloat]): Widget =
return gui:
ActionRow:
title = fieldName
NumberEntry() {.addSuffix.}:
value = state.getField(fieldName)
xAlign = 1.0
maxWidth = 8
proc changed(value: float) =
state.getField(fieldName) = value

proc toFormField(state: auto, fieldName: static string, typ: typedesc[SomeInteger]): Widget =
proc toFormField[T: SomeNumber](state: auto, fieldName: static string, typ: typedesc[T]): Widget =
return gui:
ActionRow:
title = fieldName
NumberEntry() {.addSuffix.}:
FormulaEntry() {.addSuffix.}:
value = state.getField(fieldName).float
xAlign = 1.0
maxWidth = 8
proc changed(value: float) =
state.getField(fieldName) = value.int
state.getField(fieldName) = value.T

proc toFormField(state: auto, fieldName: static string, typ: typedesc[string]): Widget =
return gui:
Expand All @@ -48,43 +30,79 @@ proc toFormField(state: auto, fieldName: static string, typ: typedesc[string]):
state.getField(fieldName) = text

proc toFormField(state: auto, fieldName: static string, typ: typedesc[bool]): Widget =
return gui:
ActionRow:
title = fieldName
Box() {.addSuffix.}:
Switch() {.vAlign: AlignCenter, expand: false.}:
state = state.getField(fieldName)
proc changed(newVal: bool) =
state.getField(fieldName) = newVal
return gui:
ActionRow:
title = fieldName
Box() {.addSuffix.}:
Switch() {.vAlign: AlignCenter, expand: false.}:
state = state.getField(fieldName)
proc changed(newVal: bool) =
state.getField(fieldName) = newVal

proc toFormField(state: auto, fieldName: static string, typ: typedesc[object | ref object | tuple | seq]): Widget =
return gui:
ActionRow:
title = fieldName
Entry(text = $ %*state.getField(fieldName)) {.addSuffix.}:
proc changed(text: string) =
try:
state.getField(fieldName) = text.parseJson().to(typ)
except Exception: discard
proc toFormField(state: auto, fieldName: static string, typ: typedesc[auto]): Widget =
return gui:
ActionRow:
title = fieldName
Label():
text = fmt"Override `toFormField` for '{$typ.type}'"
tooltip = fmt"""
The type '{$typ.type}' must implement a `toFormField` proc.
`toFormField(
state: auto,
fieldName: static string,
typ: typedesc[{$typ.type}]
): Widget`
This will override this dummy Widget.
See other widget example applications for examples.
"""

proc toFormField[T: enum](state: auto, fieldName: static string, typ: typedesc[T]): Widget =
let options: seq[string] = T.items.toSeq().mapIt($it)
return gui:
ComboRow:
title = "orient"
title = fieldName
items = options
selected = ord(state.getField(fieldName))
proc select(enumIndex: int) =
state.getField(fieldName) = enumIndex.T

viewable DateDialog:
date: DateTime = now()
title: string = "Select DateTime"

method view (state: DateDialogState): Widget =
result = gui:
Dialog:
title = state.title
defaultSize = (520, 0)

DialogButton {.addButton.}:
text = "Select"
style = [ButtonSuggested]
res = DialogAccept

DialogButton {.addButton.}:
text = "Cancel"
res = DialogCancel

Box(orient = OrientY):
Calendar:
date = state.date
proc daySelected(date: DateTime) =
state.date = date

proc toFormField(state: auto, fieldName: static string, typ: typedesc[DateTime]): Widget =
return gui:
ActionRow:
title = fieldName
Calendar {.addSuffix.}:
date = state.getField(fieldName)
proc daySelected(date: DateTime) =
state.getField(fieldName) = date
title = fieldName & ": " & $state.getField(fieldName).inZone(local())
Button {.addSuffix.}:
icon = "x-office-calendar-symbolic"
text = "Select"
proc clicked() =
let (res, dialogState) = state.open(gui(DateDialog()))
if res.kind == DialogAccept:
state.getField(fieldName) = DateDialogState(dialogState).date

proc toFormField(state: auto, fieldName: static string, typ: typedesc[tuple[x,y: int]]): Widget =
## toFormField proc specifically for the tuple type of sizeRequest
Expand Down Expand Up @@ -131,5 +149,3 @@ proc toAutoForm*[T](app: T, ignoreFields: static seq[string]): Widget =
proc toAutoForm*[T](app: T): Widget =
const ignoreFields: seq[string] = @[]
return toAutoForm[T](app, ignoreFields = ignoreFields)

export AlignedChild

0 comments on commit c5a786e

Please sign in to comment.