Adds image widget and associated documentation and example

This commit is contained in:
sloum 2022-04-22 09:59:48 -07:00
parent b9c0a034b7
commit 42e4e98e80
4 changed files with 68 additions and 5 deletions

View File

@ -529,7 +529,7 @@ The module does not offer any free/object drawing or animation. It offers a sele
Implemented:
`dialog-error`, `dialog-info`, `dialog-open-file`, `dialog-save-file`, `container`, `container-add-to`, `conainer-scroll`, `container-size`, `gui-add-window`, `gui-create`, `gui-list-windows`, `gui-use-light-theme`, `widget-add-to-size`, `widget-get-text`, `widget-hide`, `widget-make-button`, `widget-make-checkbox`, `widget-make-entery`, `widget-make-hyperlink`, `widget-make-label`, `widget-make-markdown`, `widget-make-multiline`, `widget-make-password`, `widget-make-select`, `widget-make-separator`, `widget-make-spacer`, `widget-set-text`, `widget-resize`, `widget-show`, `widget-size`, `window-allow-resize`, `window-center`, `window-close`, `window-hide`, `window-resize`,`window-set-content`, `window-set-fullscreen`, `window-set-title`, `window-show`, `window-show-and-run`
`dialog-error`, `dialog-info`, `dialog-open-file`, `dialog-save-file`, `container`, `container-add-to`, `conainer-scroll`, `container-size`, `gui-add-window`, `gui-create`, `gui-list-windows`, `gui-use-light-theme`, `widget-add-to-size`, `widget-get-text`, `widget-hide`, `widget-make-button`, `widget-make-checkbox`, `widget-make-entery`, `widget-make-hyperlink`, `widget-make-image`, `widget-make-label`, `widget-make-markdown`, `widget-make-multiline`, `widget-make-password`, `widget-make-select`, `widget-make-separator`, `widget-make-spacer`, `widget-set-text`, `widget-resize`, `widget-show`, `widget-size`, `window-allow-resize`, `window-center`, `window-close`, `window-hide`, `window-resize`,`window-set-content`, `window-set-fullscreen`, `window-set-title`, `window-show`, `window-show-and-run`
<details>
<summary>GUI API Description</summary>
@ -555,6 +555,7 @@ Implemented:
<li><code>(widget-make-checkbox [text: string] [callback: lambda]) => gui-widget</code></li>
<li><code>(widget-make-entry [placeholder-text: string] [[wrap-text: bool]] [[validation-callback: lambda]]) => gui-widget</code></li>
<li><code>(widget-make-hyperlink [text: string] [url: string]) => gui-widget</code></li>
<li><code>(widget-make-image [source: string] [location: string] [[mode: string]] [[min-width: number]] [[min-height]]) => gui-widget</code></li>
<li><code>(widget-make-label [text: string] [[alignment: number]] [[wrap-text: bool]]) => gui-widget</code></li>
<li><code>(widget-make-markdown [markdown-text: string] [[wrap-text: bool]]) => gui-widget</code></li>
<li><code>(widget-make-multiline [placeholder-text: string] [[wrap-text: bool]] [[validation-callback: lambda]]) => gui-widget</code></li>

View File

@ -14,6 +14,7 @@
(define e1 (widget-make-entry "Link Text" #f (lambda (s) (if (regex-match? ".+" s) #t "Invalid entry"))))
(define l2 (widget-make-label "URL"))
(define e2 (widget-make-entry "Link URL" #f (lambda (s) (if (regex-match? "[http|https|gemini|gopher|ftp]://.+\..+" s) #t "URL missing scheme"))))
(define img (widget-make-image "url" "http://slope.colorfield.space/slope-logo.png" "fit" 50 50))
(define b (widget-make-button "Submit"
(lambda ()
(define t (widget-get-text e1))
@ -39,7 +40,7 @@
; Set up the container(s)
(set! contents
(container "vbox" l md (widget-make-separator) cb sel (widget-make-separator) (container "form" l1 e1 l2 e2) b (widget-make-separator) (container "hbox" (widget-make-spacer) (widget-make-hyperlink "slope.colorfield.space" "https://slope.colorfield.space/"))))
(container "vbox" img l md (widget-make-separator) cb sel (widget-make-separator) (container "form" l1 e1 l2 e2) b (widget-make-separator) (container "hbox" (widget-make-spacer) (widget-make-hyperlink "slope.colorfield.space" "https://slope.colorfield.space/"))))
; Add the containers to a scroll box
(define scroller (container-scroll contents))

66
gui.go
View File

@ -12,9 +12,11 @@ import (
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/app"
"fyne.io/fyne/v2/canvas"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/dialog"
"fyne.io/fyne/v2/layout"
"fyne.io/fyne/v2/storage"
"fyne.io/fyne/v2/theme"
"fyne.io/fyne/v2/widget"
)
@ -319,9 +321,15 @@ var guiLib = vars{
if len(a) < 3 {
return exception("'widget-rsize' expects a widget and two numbers, insufficient values were given")
}
canvas := false
var wid2 fyne.CanvasObject
wid, ok := a[0].(guiWidget)
if !ok {
return exception("'widget-resize' expects a widget, a non-widget value was given")
wid2, ok = a[0].(fyne.CanvasObject)
if !ok {
return exception("'widget-resize' expects a widget, a non-widget value was given")
}
canvas = true
}
width, ok := a[1].(number)
if !ok {
@ -331,8 +339,12 @@ var guiLib = vars{
if !ok {
return exception("'widget-resize' expects a height number, a non-number value was given")
}
wid.Resize(fyne.NewSize(float32(width), float32(height)))
return guiWidget(wid)
if !canvas {
wid.Resize(fyne.NewSize(float32(width), float32(height)))
return guiWidget(wid)
}
wid2.Resize(fyne.NewSize(float32(width), float32(height)))
return wid2
},
"widget-size": func(a ...expression) expression {
if len(a) == 0 {
@ -557,6 +569,50 @@ var guiLib = vars{
}
return b
},
"widget-make-image": func(a ...expression) expression {
if len(a) < 2 {
return exception("'widget-make-image' expects two strings, with an optional string and two numbers, too few arguments were given")
}
fillMode := canvas.ImageFillOriginal
if len(a) > 2 {
if String(a[2], false) == "fit" {
fillMode = canvas.ImageFillContain
}
}
minWidth := float32(20)
minHeight := float32(20)
if len(a) > 3 {
w, ok := a[3].(number)
if ok {
minWidth = float32(w)
}
}
if len(a) > 4 {
h, ok := a[4].(number)
if ok {
minHeight = float32(h)
}
}
switch String(a[0], false) {
case "path":
i := canvas.NewImageFromFile(String(a[1], false))
i.FillMode = fillMode
i.SetMinSize(fyne.NewSize(minWidth, minHeight))
return i
case "url":
u, err := storage.ParseURI(String(a[1], false))
if err != nil {
return exception("'widget-make-image' was given 'url' value that could not be parsed to a valid url")
}
i := canvas.NewImageFromURI(u)
i.FillMode = fillMode
i.SetMinSize(fyne.NewSize(minWidth, minHeight))
return i
default:
return exception("'widget-make-image' was given an unsupported source string; 'path' and 'url' are the vailable options")
}
},
"widget-make-checkbox": func(a ...expression) expression {
if len(a) < 2 {
return exception("'widget-make-checkbox' expects a text string and a callback (lambda), too few arguments were given")
@ -901,6 +957,10 @@ func String(v expression, rawString bool) string {
return "gui-widget"
case fyne.Widget:
return "gui-widget"
case canvas.Image:
return "gui-widget"
case *canvas.Image:
return "gui-widget"
case fyne.CanvasObject:
return "gui-widget"
case fyne.Container:

View File

@ -24,6 +24,7 @@ var guiUsageStrings = map[string]string{
"widget-make-checkbox": "(widget-make-checkbox [text: string] [callback: lambda]) => gui-widget\n\nCreates a button widget with the given text. The callback should accept one argument representing the boolean state of the checkbox and should only create side effects (the return value will be discarded)",
"widget-make-entry": "(widget-make-entry [placeholder-text: string] [[wrap-text: bool]] [[validation-callback: lambda]]) => gui-widget\n\nCreates an entry widget with the given placeholder value. For accessibility purposes it is always advised to also have a label widget describing this widget. If a validation lambda is given it should take a string value as its argument and should validate based on that string. If it successfully validates `#t` or any non-string value should be returned, otherwise a string explaining the error should be returned",
"widget-make-hyperlink": "(widget-make-hyperlink [text: string] [url: string]) => gui-widget\n\nCreates a hyperlink widget with the given text linking to the given URL. If the URL cannot be parsed as a valid URL an exception will be returned",
"widget-make-image": "(widget-make-image [source: string] [location: string] [[mode: string]] [[min-width: number]] [[min-height: number]]) => gui-widget\n\nCreates an image widget from the given source. Available sources are: \"path\" and \"url\", the later of which will actually load any available URI. The `location` string represents the address or path of the image. The optional `mode` argument defaults to \"fit\" which will keep the original aspect ratio of the image but size it to fit the container (latching to the smallest container dimension). \"original\" may be passed to over-ride the default behavior and use the original image size, expanding the container if need be. Passing a min-width or min-height will cause the resulting image widget to size to this dimension as a minimum value. The way the size minimums work may be surprising as they interact with attempts to keep the aspect ratio and size to the container, so a 50x10 image set to 10x100 will not work, since aspect ratio is being kept. One value will be chosen as the one to use in sizing, this may depend on the type of container",
"widget-make-label": "(widget-make-label [text: string] [[alignment: number]] [[wrap-text: bool]]) => gui-widget\n\nCreates a label widget with the given text. If alignment is given it should be one of:\n\n\t-1: Align Leading\n\t 0: Align Center\n\t 1: Align Trailing",
"widget-make-markdown": "(widget-make-markdown [markdown-text: string] [[wrap-text: bool]]) => gui-widget\n\nCreates a markdown text block. The markdown-text string should be markdown, which will be parsed and rendered. wrap-text defaults to #f. If set to #t the text will be wrapped at word boundaries using the minimum size of the container",
"widget-make-multiline": "(widget-make-multiline [placeholder-text: string] [[wrap-text: bool]] [[validation-callback: lambda]]) => gui-widget\n\nCreates a multiline text entry widget with the given placeholder value. For accessibility purposes it is always advised to also have a label widget describing this widget. If a validation lambda is given it should take a string value as its argument and should validate based on that string. If it successfully validates `#t` or any non-string value should be returned, otherwise a string explaining the error should be returned",