2022-12-23 05:45:09 +00:00
// +build gui all
2021-11-09 06:50:26 +00:00
package main
2022-04-26 05:31:25 +00:00
/ *
TODO :
Add clipboard stuff : https : //developer.fyne.io/api/v2.1/clipboard.html
* /
2021-11-09 06:50:26 +00:00
import (
"fmt"
2021-12-23 23:06:55 +00:00
"image/color"
"net/url"
2022-04-21 22:05:33 +00:00
"reflect"
2022-04-21 03:39:15 +00:00
"strconv"
"strings"
2021-11-09 06:50:26 +00:00
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/app"
2022-04-22 16:59:48 +00:00
"fyne.io/fyne/v2/canvas"
2021-11-09 06:50:26 +00:00
"fyne.io/fyne/v2/container"
2021-11-10 00:07:13 +00:00
"fyne.io/fyne/v2/dialog"
2022-04-26 03:26:33 +00:00
"fyne.io/fyne/v2/driver/desktop"
2021-12-23 23:06:55 +00:00
"fyne.io/fyne/v2/layout"
2022-04-22 16:59:48 +00:00
"fyne.io/fyne/v2/storage"
2021-12-23 23:06:55 +00:00
"fyne.io/fyne/v2/theme"
2021-11-09 06:50:26 +00:00
"fyne.io/fyne/v2/widget"
)
type GUI struct {
gui fyne . App
windows map [ string ] fyne . Window
}
func ( g GUI ) String ( ) string {
2022-04-21 03:39:15 +00:00
return "GUI-Root"
2021-11-09 06:50:26 +00:00
}
type guiWidget fyne . Widget
2022-04-21 03:39:15 +00:00
2021-12-23 23:06:55 +00:00
type guiContainer fyne . CanvasObject
2022-04-21 03:39:15 +00:00
2021-12-23 23:06:55 +00:00
type guiObject interface { }
type slopeTheme struct { }
2022-04-21 03:39:15 +00:00
func ( t slopeTheme ) String ( ) string {
return "GUI-Theme"
}
// Dev note: no memory of why this is
// done this way.
2021-12-23 23:06:55 +00:00
var _ fyne . Theme = ( * slopeTheme ) ( nil )
func ( m slopeTheme ) Color ( name fyne . ThemeColorName , variant fyne . ThemeVariant ) color . Color {
if name == theme . ColorNameBackground {
if variant == theme . VariantLight {
return color . RGBA { 200 , 200 , 200 , 255 }
}
return color . RGBA { 60 , 60 , 60 , 255 }
}
return theme . DefaultTheme ( ) . Color ( name , variant )
}
func ( m slopeTheme ) Icon ( name fyne . ThemeIconName ) fyne . Resource {
return theme . DefaultTheme ( ) . Icon ( name )
}
func ( m slopeTheme ) Font ( style fyne . TextStyle ) fyne . Resource {
return theme . DefaultTheme ( ) . Font ( style )
}
func ( m slopeTheme ) Size ( name fyne . ThemeSizeName ) float32 {
return theme . DefaultTheme ( ) . Size ( name ) * 0.9
}
2021-11-09 06:50:26 +00:00
var guiLib = vars {
"gui-create" : func ( a ... expression ) expression {
2021-12-23 23:06:55 +00:00
app := & GUI { app . New ( ) , make ( map [ string ] fyne . Window ) }
app . gui . Settings ( ) . SetTheme ( & slopeTheme { } )
return app
2021-11-09 06:50:26 +00:00
} ,
"gui-add-window" : func ( a ... expression ) expression {
if len ( a ) < 2 {
2022-04-26 03:26:33 +00:00
return exception ( "'gui-add-window' expects a gui-root and a window name string as arguments, too few arguments were given" )
2021-11-09 06:50:26 +00:00
}
g , ok := a [ 0 ] . ( * GUI )
if ! ok {
2022-04-26 03:26:33 +00:00
return exception ( "'gui-add-window' was given a non-gui-root value as its first argument" )
2021-11-09 06:50:26 +00:00
}
s := String ( a [ 1 ] , false )
g . windows [ s ] = g . gui . NewWindow ( s )
return true
} ,
2022-04-26 03:26:33 +00:00
"gui-set-char-handlers" : func ( a ... expression ) expression {
if len ( a ) < 3 {
2022-04-28 23:15:45 +00:00
return exception ( "'gui-set-char-handlers' expects a gui-root, a window-name string, a callback lambda, a key string, and an optional modifier string; too few arguments were given" )
2022-04-26 03:26:33 +00:00
}
g , ok := a [ 0 ] . ( * GUI )
if ! ok {
2022-04-28 23:15:45 +00:00
return exception ( "'gui-set-char-handlers' was given a non-gui-root value as its first argument" )
2022-04-26 03:26:33 +00:00
}
s := String ( a [ 1 ] , false )
window , ok := g . windows [ s ]
if ! ok {
2022-04-28 23:15:45 +00:00
return exception ( "'gui-set-char-handlers' was given a window name that does not exist in the given gui-root" )
2022-04-26 03:26:33 +00:00
}
// Callback
switch f := a [ 2 ] . ( type ) {
case func ( ... expression ) expression :
window . Canvas ( ) . SetOnTypedRune ( func ( r rune ) { f ( string ( r ) ) } )
return true
case proc :
2022-06-22 04:04:24 +00:00
window . Canvas ( ) . SetOnTypedRune ( func ( r rune ) { apply ( f , [ ] expression { string ( r ) } , "Custom gui-char-handler" ) } )
2022-04-26 03:26:33 +00:00
return true
default :
2022-04-28 23:15:45 +00:00
return exception ( "'gui-set-char-handlers' was given a non-procedure (lambda or builtin) value for its third argument" )
2022-04-26 03:26:33 +00:00
}
} ,
"gui-add-shortcut" : func ( a ... expression ) expression {
// (gui-add-shortcut [gui-root] [window-id] [callback] [key: string] [modifier: string])
if len ( a ) < 5 {
return exception ( "'gui-add-shortcut' expects a gui-root, a window-name string, a callback lambda, a key string, and a modifier string; too few arguments were given" )
}
g , ok := a [ 0 ] . ( * GUI )
if ! ok {
return exception ( "'gui-add-shortcut' was given a non-gui-root value as its first argument" )
}
s := String ( a [ 1 ] , false )
window , ok := g . windows [ s ]
if ! ok {
return exception ( "'gui-add-shortcut' was given a window name that does not exist in the given gui-root" )
}
key := String ( a [ 3 ] , false )
modStr := strings . ToLower ( String ( a [ 4 ] , false ) )
mod := desktop . ShiftModifier
switch modStr {
case "shift" , "sh" :
mod = desktop . ShiftModifier
case "control" , "ctrl" , "ctl" , "strg" :
mod = desktop . ControlModifier
case "alt" :
mod = desktop . AltModifier
case "super" , "sup" , "windows" , "win" , "com" , "command" :
mod = desktop . SuperModifier
default :
return exception ( "'gui-add-shortcut' was given an unknown modifier" )
}
// Callback
switch f := a [ 2 ] . ( type ) {
case func ( ... expression ) expression :
window . Canvas ( ) . AddShortcut ( & desktop . CustomShortcut { fyne . KeyName ( key ) , mod } , func ( shortcut fyne . Shortcut ) { f ( ) } )
return true
case proc :
2022-06-22 04:04:24 +00:00
window . Canvas ( ) . AddShortcut ( & desktop . CustomShortcut { fyne . KeyName ( key ) , desktop . Modifier ( 2 ) } , func ( shortcut fyne . Shortcut ) { apply ( f , [ ] expression { } , "Custom gui-shortcut-handler" ) } )
2022-04-26 03:26:33 +00:00
return true
default :
return exception ( "'gui-add-shortcut' was given a non-procedure (lambda or builtin) value for its third argument" )
}
} ,
2021-11-09 06:50:26 +00:00
"gui-list-windows" : func ( a ... expression ) expression {
if len ( a ) == 0 {
2022-04-26 03:26:33 +00:00
return exception ( "'gui-list-windows' expects a gui-root as an argument, no arguments were given" )
2021-11-09 06:50:26 +00:00
}
g , ok := a [ 0 ] . ( * GUI )
if ! ok {
2022-04-26 03:26:33 +00:00
return exception ( "'gui-list-windows' was given a non-gui-root argument" )
2021-11-09 06:50:26 +00:00
}
out := make ( [ ] expression , 0 , len ( g . windows ) )
for k := range g . windows {
out = append ( out , k )
}
return out
} ,
2021-12-23 23:06:55 +00:00
"gui-use-light-theme" : func ( a ... expression ) expression {
2022-04-21 22:05:33 +00:00
if len ( a ) == 0 {
return exception ( "'gui-use-light-theme' expects a gui-root as its first argument and, optionally, a bool as its second argument, no arguments were given" )
}
app , ok := a [ 0 ] . ( * GUI )
if ! ok {
return exception ( "'gui-use-light-theme' expects a gui-root as its first argument, a non-gui-root value was given" )
2021-12-23 23:06:55 +00:00
}
2022-04-21 22:05:33 +00:00
// If the current theme is == to the light theme return true, else false
if len ( a ) == 1 {
return reflect . DeepEqual ( app . gui . Settings ( ) . Theme ( ) , theme . LightTheme ( ) )
}
b := AnythingToBool ( a [ 1 ] ) . ( bool )
2021-12-23 23:06:55 +00:00
if b {
2022-04-21 22:05:33 +00:00
app . gui . Settings ( ) . SetTheme ( theme . LightTheme ( ) )
2021-12-23 23:06:55 +00:00
} else {
2022-04-21 22:05:33 +00:00
app . gui . Settings ( ) . SetTheme ( theme . DarkTheme ( ) )
2021-12-23 23:06:55 +00:00
}
return b
} ,
2021-11-09 06:50:26 +00:00
"window-set-content" : func ( a ... expression ) expression {
// (window-set-content window-id content...)
if len ( a ) < 3 {
2022-04-21 03:39:15 +00:00
return exception ( "'window-set-content' expects a gui-root and a string as arguments, too few arguments were given" )
2021-11-09 06:50:26 +00:00
}
g , ok := a [ 0 ] . ( * GUI )
if ! ok {
2022-04-21 03:39:15 +00:00
return exception ( "'window-set-content' was given a non-gui-root value as its first argument" )
2021-11-09 06:50:26 +00:00
}
s := String ( a [ 1 ] , false )
w , ok := g . windows [ s ]
if ! ok {
2022-04-21 03:39:15 +00:00
return exception ( "'window-set-content' was given a window-id that does not exist: " + s )
2021-11-09 06:50:26 +00:00
}
2021-11-10 00:07:13 +00:00
content , ok := a [ 2 ] . ( fyne . CanvasObject )
if ! ok {
2022-04-21 03:39:15 +00:00
return exception ( "'window-set-content' was given invalid content" )
2021-11-10 00:07:13 +00:00
}
w . SetContent ( content )
2021-11-09 06:50:26 +00:00
return true
} ,
2021-11-10 00:07:13 +00:00
"window-resize" : func ( a ... expression ) expression {
if len ( a ) < 4 {
return exception ( "'window-resize' expects a GUI, a string, and two numbers as arguments; too few arguments were given" )
}
g , ok := a [ 0 ] . ( * GUI )
if ! ok {
return exception ( "'window-resize' was given a non-GUI value as its first argument" )
}
s := String ( a [ 1 ] , false )
w , ok := g . windows [ s ]
if ! ok {
2022-04-21 03:39:15 +00:00
return exception ( "'window-resize' was given a window-id that does not exist: " + s )
2021-11-10 00:07:13 +00:00
}
width , ok := a [ 2 ] . ( number )
height , ok2 := a [ 3 ] . ( number )
if ! ok || ! ok2 {
return exception ( "'window-resize' was given a non-number value for height or width" )
}
w . Resize ( fyne . NewSize ( float32 ( width ) , float32 ( height ) ) )
return true
} ,
"window-show" : func ( a ... expression ) expression {
if len ( a ) < 2 {
return exception ( "'window-show' expects a GUI and a string; too few arguments were given" )
}
g , ok := a [ 0 ] . ( * GUI )
if ! ok {
return exception ( "'window-show' was given a non-GUI value as its first argument" )
}
s := String ( a [ 1 ] , false )
w , ok := g . windows [ s ]
if ! ok {
2022-04-21 03:39:15 +00:00
return exception ( "'window-show' was given a window-id that does not exist: " + s )
2021-11-10 00:07:13 +00:00
}
w . Show ( )
return true
} ,
"window-hide" : func ( a ... expression ) expression {
if len ( a ) < 2 {
return exception ( "'window-hide' expects a GUI and a string; too few arguments were given" )
}
g , ok := a [ 0 ] . ( * GUI )
if ! ok {
return exception ( "'window-hide' was given a non-GUI value as its first argument" )
}
s := String ( a [ 1 ] , false )
w , ok := g . windows [ s ]
if ! ok {
2022-04-21 03:39:15 +00:00
return exception ( "'window-hide' was given a window-id that does not exist: " + s )
2021-11-10 00:07:13 +00:00
}
w . Hide ( )
return true
} ,
"window-close" : func ( a ... expression ) expression {
if len ( a ) < 2 {
return exception ( "'window-close' expects a GUI and a string; too few arguments were given" )
}
g , ok := a [ 0 ] . ( * GUI )
if ! ok {
return exception ( "'window-close' was given a non-GUI value as its first argument" )
}
s := String ( a [ 1 ] , false )
w , ok := g . windows [ s ]
if ! ok {
2022-04-21 03:39:15 +00:00
return exception ( "'window-close' was given a window-id that does not exist: " + s )
2021-11-10 00:07:13 +00:00
}
w . Close ( )
return true
} ,
"window-set-title" : func ( a ... expression ) expression {
if len ( a ) < 3 {
return exception ( "'window-set-title' expects a GUI and two strings; too few arguments were given" )
}
g , ok := a [ 0 ] . ( * GUI )
if ! ok {
return exception ( "'window-set-title' was given a non-GUI value as its first argument" )
}
s := String ( a [ 1 ] , false )
w , ok := g . windows [ s ]
if ! ok {
2022-04-21 03:39:15 +00:00
return exception ( "'window-set-title' was given a window-id that does not exist: " + s )
2021-11-10 00:07:13 +00:00
}
w . SetTitle ( String ( a [ 2 ] , false ) )
return true
} ,
"window-set-fullscreen" : func ( a ... expression ) expression {
if len ( a ) < 3 {
return exception ( "'window-set-fullscreen' expects a GUI, a string, and a bool; too few arguments were given" )
}
g , ok := a [ 0 ] . ( * GUI )
if ! ok {
return exception ( "'window-set-fullscreen' was given a non-GUI value as its first argument" )
}
s := String ( a [ 1 ] , false )
w , ok := g . windows [ s ]
if ! ok {
2022-04-21 03:39:15 +00:00
return exception ( "'window-set-fullscreen' was given a window-id that does not exist: " + s )
2021-11-10 00:07:13 +00:00
}
w . SetFullScreen ( AnythingToBool ( a [ 2 ] ) . ( bool ) )
return true
} ,
2021-11-09 06:50:26 +00:00
"window-show-and-run" : func ( a ... expression ) expression {
// (window-show-and-run window-id)
if len ( a ) < 2 {
return exception ( "'window-show-and-run' expects a GUI and a string as arguments, too few arguments were given" )
}
g , ok := a [ 0 ] . ( * GUI )
if ! ok {
return exception ( "'window-show-and-run' was given a non-GUI value as its first argument" )
}
s := String ( a [ 1 ] , false )
w , ok := g . windows [ s ]
if ! ok {
2022-04-21 03:39:15 +00:00
return exception ( "'window-show-and-run' was given a window-id that does not exist: " + s )
2021-11-09 06:50:26 +00:00
}
w . ShowAndRun ( )
return true
} ,
2021-11-10 00:07:13 +00:00
"window-center" : func ( a ... expression ) expression {
if len ( a ) < 2 {
return exception ( "'window-center' expects a GUI and a string as arguments, too few arguments were given" )
}
g , ok := a [ 0 ] . ( * GUI )
if ! ok {
return exception ( "'window-center' was given a non-GUI value as its first argument" )
}
s := String ( a [ 1 ] , false )
w , ok := g . windows [ s ]
if ! ok {
2022-04-21 03:39:15 +00:00
return exception ( "'window-center' was given a window-id that does not exist: " + s )
2021-11-10 00:07:13 +00:00
}
w . CenterOnScreen ( )
return true
} ,
"window-allow-resize" : func ( a ... expression ) expression {
if len ( a ) < 3 {
return exception ( "'window-allow-resize' expects a GUI, a string, and a bool; too few arguments were given" )
}
g , ok := a [ 0 ] . ( * GUI )
if ! ok {
return exception ( "'window-allow-resize' was given a non-GUI value as its first argument" )
}
s := String ( a [ 1 ] , false )
w , ok := g . windows [ s ]
if ! ok {
2022-04-21 03:39:15 +00:00
return exception ( "'window-allow-resize' was given a window-id that does not exist: " + s )
2021-11-10 00:07:13 +00:00
}
w . SetFixedSize ( ! AnythingToBool ( a [ 2 ] ) . ( bool ) )
return true
} ,
2022-04-26 21:49:00 +00:00
"widget-disable" : func ( a ... expression ) expression {
if len ( a ) == 0 {
return exception ( "'widget-disable' expects a gui-widget and an optional bool, no value was given" )
}
wid , ok := a [ 0 ] . ( guiWidget )
if ! ok {
return exception ( "'widget-disable' expects a gui-widget, a non gui-widget value was given" )
}
switch w := wid . ( fyne . Disableable ) . ( type ) {
case * widget . Entry , * widget . Button , * widget . Select , * widget . Check :
if len ( a ) == 1 {
return w . Disabled ( )
} else {
b := AnythingToBool ( a [ 1 ] ) . ( bool )
if b {
w . Disable ( )
} else {
w . Enable ( )
}
}
default :
fmt . Printf ( "%T - %v" , w ) // TODO: remove this line
return false
}
return true
} ,
2021-11-10 00:07:13 +00:00
"widget-show" : func ( a ... expression ) expression {
if len ( a ) == 0 {
return exception ( "'widget-show' expects a widget, no value was given" )
}
wid , ok := a [ 0 ] . ( guiWidget )
if ! ok {
return exception ( "'widget-show' expects a widget, a non-widget value was given" )
}
wid . Show ( )
return true
} ,
"widget-hide" : func ( a ... expression ) expression {
if len ( a ) == 0 {
return exception ( "'widget-hide' expects a widget, no value was given" )
}
wid , ok := a [ 0 ] . ( guiWidget )
if ! ok {
return exception ( "'widget-hide' expects a widget, a non-widget value was given" )
}
wid . Hide ( )
return true
} ,
2021-12-23 23:06:55 +00:00
"widget-resize" : func ( a ... expression ) expression {
if len ( a ) < 3 {
return exception ( "'widget-rsize' expects a widget and two numbers, insufficient values were given" )
}
2022-04-22 16:59:48 +00:00
canvas := false
var wid2 fyne . CanvasObject
2021-12-23 23:06:55 +00:00
wid , ok := a [ 0 ] . ( guiWidget )
if ! ok {
2022-04-22 16:59:48 +00:00
wid2 , ok = a [ 0 ] . ( fyne . CanvasObject )
if ! ok {
return exception ( "'widget-resize' expects a widget, a non-widget value was given" )
}
canvas = true
2021-12-23 23:06:55 +00:00
}
width , ok := a [ 1 ] . ( number )
if ! ok {
return exception ( "'widget-resize' expects a width number, a non-number value was given" )
}
height , ok := a [ 2 ] . ( number )
if ! ok {
return exception ( "'widget-resize' expects a height number, a non-number value was given" )
}
2022-04-22 16:59:48 +00:00
if ! canvas {
wid . Resize ( fyne . NewSize ( float32 ( width ) , float32 ( height ) ) )
return guiWidget ( wid )
}
wid2 . Resize ( fyne . NewSize ( float32 ( width ) , float32 ( height ) ) )
return wid2
2021-12-23 23:06:55 +00:00
} ,
"widget-size" : func ( a ... expression ) expression {
if len ( a ) == 0 {
return exception ( "'widget-sze' expects a widget, no value was given" )
}
wid , ok := a [ 0 ] . ( guiWidget )
if ! ok {
return exception ( "'widget-size' expects a widget, a non-widget value was given" )
}
s := wid . Size ( )
return [ ] expression { number ( s . Width ) , number ( s . Height ) }
} ,
"widget-add-to-size" : func ( a ... expression ) expression {
if len ( a ) < 3 {
return exception ( "'widget-add-to-size' expects a widget and two numbers, insufficient values were given" )
}
wid , ok := a [ 0 ] . ( guiWidget )
if ! ok {
return exception ( "'widget-add-to-size' expects a widget, a non-widget value was given" )
}
width , ok := a [ 1 ] . ( number )
if ! ok {
return exception ( "'widget-add-to-size' expects a width number, a non-number value was given" )
}
height , ok := a [ 2 ] . ( number )
if ! ok {
return exception ( "'widget-add-to-size' expects a height number, a non-number value was given" )
}
s := wid . Size ( )
wid . Resize ( s . Add ( fyne . NewSize ( float32 ( width ) , float32 ( height ) ) ) )
return guiWidget ( wid )
} ,
2021-11-10 00:07:13 +00:00
"widget-make-entry" : func ( a ... expression ) expression {
if len ( a ) == 0 {
return exception ( "'widget-make-entry' expects at least one argument, a string representing the text of the label, no arguments were given" )
}
var e guiWidget = widget . NewEntry ( )
2021-12-23 23:06:55 +00:00
2021-11-10 00:07:13 +00:00
// Set placeholder
if len ( a ) > 0 {
2021-12-23 23:06:55 +00:00
e . ( * widget . Entry ) . SetPlaceHolder ( String ( a [ 0 ] , false ) )
2021-11-10 00:07:13 +00:00
}
2021-12-23 23:06:55 +00:00
// Set wrapping
if len ( a ) > 1 && AnythingToBool ( a [ 1 ] ) . ( bool ) {
e . ( * widget . Entry ) . Wrapping = fyne . TextWrapWord
} else {
e . ( * widget . Entry ) . Wrapping = fyne . TextTruncate
2021-11-10 00:07:13 +00:00
}
2021-12-23 23:06:55 +00:00
// Handle validation
2021-11-10 00:07:13 +00:00
if len ( a ) > 2 {
2022-04-21 03:39:15 +00:00
cb , ok := a [ 2 ] . ( proc )
2021-12-23 23:06:55 +00:00
if ! ok {
2022-04-21 03:39:15 +00:00
return exception ( "'widget-make-entry' expects a lambdaas its optional third argument, a non-lambda value was given" )
2021-12-23 23:06:55 +00:00
}
e . ( * widget . Entry ) . Validator = func ( in string ) error {
2022-06-22 04:04:24 +00:00
result := apply ( cb , [ ] expression { in } , "Entry widget validator" )
2021-12-23 23:06:55 +00:00
switch t := result . ( type ) {
case string :
return fmt . Errorf ( t )
default :
return nil
}
2021-11-10 00:07:13 +00:00
}
}
2021-12-23 23:06:55 +00:00
return e
} ,
2022-04-27 22:36:30 +00:00
"widget-make-text-grid" : func ( a ... expression ) expression {
// (widget-make-text-grid [[text: string]] [[show-line-nums: bool]] [[show-whitespace: bool]] [[tabwidth: number]])
if len ( a ) == 0 {
return guiWidget ( widget . NewTextGrid ( ) )
}
te := widget . NewTextGridFromString ( String ( a [ 0 ] , false ) )
if len ( a ) >= 4 {
n , ok := a [ 3 ] . ( number )
if ! ok {
return exception ( "'widget-make-text-grid' expected a number as its fourth argument, a non-number value was given" )
}
te . TabWidth = int ( n )
}
if len ( a ) >= 3 {
te . ShowWhitespace = AnythingToBool ( a [ 2 ] ) . ( bool )
}
if len ( a ) >= 3 {
te . ShowLineNumbers = AnythingToBool ( a [ 1 ] ) . ( bool )
}
return guiWidget ( te )
} ,
2021-12-23 23:06:55 +00:00
"widget-make-password" : func ( a ... expression ) expression {
if len ( a ) == 0 {
return exception ( "'widget-make-password' expects at least one argument, a string representing the text of the label, no arguments were given" )
}
var e guiWidget = widget . NewPasswordEntry ( )
// Set placeholder
if len ( a ) > 0 {
e . ( * widget . Entry ) . SetPlaceHolder ( String ( a [ 0 ] , false ) )
}
2021-11-10 00:07:13 +00:00
// Set wrapping
2021-12-23 23:06:55 +00:00
if len ( a ) > 1 && AnythingToBool ( a [ 1 ] ) . ( bool ) {
2021-11-10 00:07:13 +00:00
e . ( * widget . Entry ) . Wrapping = fyne . TextWrapWord
2021-12-23 23:06:55 +00:00
} else {
e . ( * widget . Entry ) . Wrapping = fyne . TextTruncate
}
// Handle validation
if len ( a ) > 2 {
2022-04-21 03:39:15 +00:00
cb , ok := a [ 2 ] . ( proc )
2021-12-23 23:06:55 +00:00
if ! ok {
return exception ( "'widget-make-entry' expects a callback as its optional third argument, a non-callback value was given" )
}
e . ( * widget . Entry ) . Validator = func ( in string ) error {
2022-06-22 04:04:24 +00:00
result := apply ( cb , [ ] expression { in } , "Password widget validator" )
2021-12-23 23:06:55 +00:00
switch t := result . ( type ) {
case string :
return fmt . Errorf ( t )
default :
return nil
}
}
}
return e
} ,
"widget-make-multiline" : func ( a ... expression ) expression {
if len ( a ) == 0 {
return exception ( "'widget-make-multiline' expects at least one argument, a string representing the text of the label, no arguments were given" )
}
var e guiWidget = widget . NewMultiLineEntry ( )
// Set placeholder
if len ( a ) > 0 {
e . ( * widget . Entry ) . SetPlaceHolder ( String ( a [ 0 ] , false ) )
}
// Set wrapping
if len ( a ) > 1 && AnythingToBool ( a [ 1 ] ) . ( bool ) {
e . ( * widget . Entry ) . Wrapping = fyne . TextWrapWord
} else {
e . ( * widget . Entry ) . Wrapping = fyne . TextTruncate
}
if len ( a ) > 2 {
2022-04-28 22:42:02 +00:00
b := AnythingToBool ( a [ 2 ] ) . ( bool )
if b {
e . ( * widget . Entry ) . TextStyle = fyne . TextStyle { false , false , true , 4 }
}
}
// Handle validation
if len ( a ) > 3 {
cb , ok := a [ 3 ] . ( proc )
2021-12-23 23:06:55 +00:00
if ! ok {
2022-04-28 22:42:02 +00:00
return exception ( "'widget-make-entry' expects a callback as its optional fourth argument, a non-callback value was given" )
2021-12-23 23:06:55 +00:00
}
e . ( * widget . Entry ) . Validator = func ( in string ) error {
2022-06-22 04:04:24 +00:00
result := apply ( cb , [ ] expression { in } , "Multiline widget validator" )
2021-12-23 23:06:55 +00:00
switch t := result . ( type ) {
case string :
return fmt . Errorf ( t )
default :
return nil
}
}
2021-11-10 00:07:13 +00:00
}
2022-04-28 22:42:02 +00:00
2021-11-10 00:07:13 +00:00
return e
} ,
"widget-make-label" : func ( a ... expression ) expression {
2021-11-09 06:50:26 +00:00
// (widget-label text:string alignment:number wrap:bool)
if len ( a ) == 0 {
2021-11-10 00:07:13 +00:00
return exception ( "'widget-make-label' expects at least one argument, a string representing the text of the label, no arguments were given" )
2021-11-09 06:50:26 +00:00
}
var l guiWidget = widget . NewLabel ( String ( a [ 0 ] , false ) )
if len ( a ) >= 2 {
align , ok := a [ 1 ] . ( number )
if ! ok {
2021-11-10 00:07:13 +00:00
return exception ( "'widget-make-label' expects a number (-1, 0, or 1) as its optional second argument (alignment), a non-number value was given" )
2021-11-09 06:50:26 +00:00
}
switch int ( align ) {
case - 1 :
l . ( * widget . Label ) . Alignment = fyne . TextAlignLeading
case 0 :
l . ( * widget . Label ) . Alignment = fyne . TextAlignCenter
case 1 :
l . ( * widget . Label ) . Alignment = fyne . TextAlignTrailing
default :
2021-11-10 00:07:13 +00:00
return exception ( "'widget-make-label' expects a number (-1, 0, or 1) as its optional second argument (alignment), a number outside of the range was given" )
2021-11-09 06:50:26 +00:00
}
}
if len ( a ) >= 3 {
2022-04-21 03:39:15 +00:00
wrap := AnythingToBool ( a [ 0 ] ) . ( bool )
2021-11-09 06:50:26 +00:00
if wrap {
l . ( * widget . Label ) . Wrapping = fyne . TextWrapWord
}
}
return l
} ,
2022-04-21 22:05:33 +00:00
"widget-make-select" : func ( a ... expression ) expression {
if len ( a ) < 2 {
return exception ( "'widget-make-select' expects a list of options as strings, a callback (lambda), and an optional alignment number too few arguments were given" )
}
elist , ok := a [ 0 ] . ( [ ] expression )
if ! ok {
return exception ( "'widget-make-select' expected a list as its first argument, but was given a non-list value" )
}
list := ExpressionSliceToStringSlice ( elist )
var b guiWidget
switch f := a [ 1 ] . ( type ) {
case func ( ... expression ) expression :
b = widget . NewSelect ( list , func ( in string ) { f ( in ) } )
case proc :
2022-06-22 04:04:24 +00:00
b = widget . NewSelect ( list , func ( in string ) { apply ( f , [ ] expression { in } , "Select widget callback" ) } )
2022-04-21 22:05:33 +00:00
default :
return exception ( "'widget-make-select' was given a non-procedure value as its second argument" )
}
if len ( a ) >= 3 {
align , ok := a [ 2 ] . ( number )
if ! ok {
2022-04-26 21:49:00 +00:00
return exception ( "'widget-make-select' expects a number (-1, 0, or 1) as its optional third argument (alignment), a non-number value was given" )
2022-04-21 22:05:33 +00:00
}
switch int ( align ) {
case - 1 :
b . ( * widget . Select ) . Alignment = fyne . TextAlignLeading
case 0 :
b . ( * widget . Select ) . Alignment = fyne . TextAlignCenter
case 1 :
b . ( * widget . Select ) . Alignment = fyne . TextAlignTrailing
default :
return exception ( "'widget-make-select' expects a number (-1, 0, or 1) as its optional third argument (alignment), a number outside of the range was given" )
}
}
return b
} ,
"widget-make-markdown" : func ( a ... expression ) expression {
if len ( a ) == 0 {
return exception ( "'widget-make-markdown' expects a string but was given no arguments" )
}
var b guiWidget
b = widget . NewRichTextFromMarkdown ( String ( a [ 0 ] , false ) )
if len ( a ) >= 2 {
wrap := AnythingToBool ( a [ 1 ] ) . ( bool )
if wrap {
b . ( * widget . RichText ) . Wrapping = fyne . TextWrapWord
}
}
return b
} ,
2022-04-22 16:59:48 +00:00
"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" )
}
} ,
2022-04-21 22:05:33 +00:00
"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" )
}
var b guiWidget
switch f := a [ 1 ] . ( type ) {
case func ( ... expression ) expression :
b = widget . NewCheck ( String ( a [ 0 ] , false ) , func ( in bool ) { f ( in ) } )
case proc :
2022-06-22 04:04:24 +00:00
b = widget . NewCheck ( String ( a [ 0 ] , false ) , func ( in bool ) { apply ( f , [ ] expression { in } , "Checkbox widget callback" ) } )
2022-04-21 22:05:33 +00:00
default :
return exception ( "'widget-make-checkbox' was given a non-procedure value as its second argument" )
}
return b
} ,
2021-12-23 23:06:55 +00:00
"widget-make-hyperlink" : func ( a ... expression ) expression {
if len ( a ) < 2 {
return exception ( "'widget-make-hyperlink' expects a text string and a URL string, too few arguments were given" )
}
u , err := url . Parse ( String ( a [ 1 ] , false ) )
if err != nil {
return exception ( "'widget-make-hyperlink' expects a valid URL as its second argument, could not parse URL from the given string" )
}
return guiWidget ( widget . NewHyperlink ( String ( a [ 0 ] , false ) , u ) )
} ,
2021-11-10 00:07:13 +00:00
"widget-make-button" : func ( a ... expression ) expression {
2021-11-09 06:50:26 +00:00
if len ( a ) < 2 {
2022-04-21 03:39:15 +00:00
return exception ( "'widget-make-button' expects at least two argument, a string representing the text of the label and a lambda, too few arguments were given" )
2021-11-09 06:50:26 +00:00
}
var b guiWidget
switch f := a [ 1 ] . ( type ) {
case func ( ... expression ) expression :
b = widget . NewButton ( String ( a [ 0 ] , false ) , func ( ) { f ( ) } )
2022-04-21 03:39:15 +00:00
case proc :
2022-06-22 04:04:24 +00:00
b = widget . NewButton ( String ( a [ 0 ] , false ) , func ( ) { apply ( f , [ ] expression { } , "Button widget callback" ) } )
2021-11-09 06:50:26 +00:00
default :
2021-11-10 00:07:13 +00:00
return exception ( "'widget-make-button' was given a non-procedure value as its second argument" )
2021-11-09 06:50:26 +00:00
}
if len ( a ) >= 3 {
align , ok := a [ 2 ] . ( number )
if ! ok {
2021-11-10 00:07:13 +00:00
return exception ( "'widget-make-button' expects a number (-1, 0, or 1) as its optional third argument (alignment), a non-number value was given" )
2021-11-09 06:50:26 +00:00
}
switch int ( align ) {
case - 1 :
b . ( * widget . Button ) . Alignment = widget . ButtonAlignLeading
case 0 :
b . ( * widget . Button ) . Alignment = widget . ButtonAlignCenter
case 1 :
b . ( * widget . Button ) . Alignment = widget . ButtonAlignTrailing
default :
2021-11-10 00:07:13 +00:00
return exception ( "'widget-make-button' expects a number (-1, 0, or 1) as its optional third argument (alignment), a number outside of the range was given" )
2021-11-09 06:50:26 +00:00
}
}
2022-04-26 21:49:00 +00:00
if len ( a ) >= 4 {
im , ok := a [ 3 ] . ( number )
if ! ok {
return exception ( "'widget-make-button' was given a non-number value for 'importance'" )
}
importance := int ( im )
switch true {
case ( importance < 1 ) :
b . ( * widget . Button ) . Importance = widget . LowImportance
case ( importance > 1 ) :
b . ( * widget . Button ) . Importance = widget . HighImportance
default :
b . ( * widget . Button ) . Importance = widget . MediumImportance
}
}
2021-11-09 06:50:26 +00:00
return b
} ,
2021-11-10 00:07:13 +00:00
"widget-get-text" : func ( a ... expression ) expression {
if len ( a ) < 1 {
return exception ( "'widget-get-text' expects a widget argument, no arguments were given" )
}
w , ok := a [ 0 ] . ( guiWidget )
if ! ok {
return exception ( "'widget-get-text' expects a widget as its first argument, a non-widget value was given" )
}
switch wid := w . ( fyne . Widget ) . ( type ) {
case * widget . Label :
return wid . Text
2022-04-27 22:36:30 +00:00
case * widget . TextGrid :
return wid . Text ( )
2021-11-10 00:07:13 +00:00
case * widget . Button :
return wid . Text
case * widget . Entry :
return wid . Text
2022-04-21 03:39:15 +00:00
case * widget . Hyperlink :
return wid . Text
2022-04-25 05:34:54 +00:00
case * widget . Check :
return wid . Text
case * widget . RichText :
return wid . String ( )
case * widget . Select :
return wid . Selected
2021-11-10 00:07:13 +00:00
default :
2022-04-21 03:39:15 +00:00
return exception ( "'widget-get-text' received a widget that it does not support" )
2021-11-10 00:07:13 +00:00
}
} ,
"widget-set-text" : func ( a ... expression ) expression {
if len ( a ) < 2 {
return exception ( "'widget-set-text' expects two arguments, a widget and a string representing the text of the label, no arguments were given" )
}
w , ok := a [ 0 ] . ( guiWidget )
if ! ok {
return exception ( "'widget-set-text' expects a widget as its first argument, a non-widget value was given" )
}
txt := String ( a [ 1 ] , false )
switch wid := w . ( fyne . Widget ) . ( type ) {
case * widget . Label :
wid . SetText ( txt )
2022-04-27 22:36:30 +00:00
case * widget . TextGrid :
wid . SetText ( txt )
2021-11-10 00:07:13 +00:00
case * widget . Button :
wid . SetText ( txt )
case * widget . Entry :
wid . SetText ( txt )
2022-04-21 03:39:15 +00:00
case * widget . Hyperlink :
wid . SetText ( txt )
2022-04-25 05:34:54 +00:00
case * widget . Check :
wid . Text = txt
wid . Refresh ( )
case * widget . RichText :
wid . ParseMarkdown ( txt )
case * widget . Select :
wid . SetSelected ( txt )
2021-11-10 00:07:13 +00:00
default :
2022-04-25 05:34:54 +00:00
return exception ( "'widget-set-text' does not support setting the text of the given value" )
2021-11-10 00:07:13 +00:00
}
return txt
} ,
2021-12-23 23:06:55 +00:00
"widget-make-separator" : func ( a ... expression ) expression {
return guiWidget ( widget . NewSeparator ( ) )
} ,
"widget-make-spacer" : func ( a ... expression ) expression {
var spacer guiObject = layout . NewSpacer ( )
return spacer
} ,
2022-04-21 22:05:33 +00:00
"container-scroll" : func ( a ... expression ) expression {
if len ( a ) < 1 {
return exception ( "'container-scroll' expects at least one widget or layout, no values were given" )
}
list , err := ExpToCanvasObjectList ( a )
if err != nil || len ( list ) < 1 {
return exception ( "'container-scroll' was given a non-widget value" )
}
return guiContainer ( container . NewScroll ( list [ 0 ] ) )
} ,
2021-12-23 23:06:55 +00:00
"container" : func ( a ... expression ) expression {
if len ( a ) < 2 {
2022-04-21 22:05:33 +00:00
return exception ( "'container' expects at least two arguments, a string representing the layout type and at least one widget or layout (or in some layout types an additional value), no values were given" )
}
containerType := String ( a [ 0 ] , false )
widgetStart := 1
cols := 0
if containerType == "grid" {
if len ( a ) < 3 {
return exception ( "'container' with layout 'grid' expects at least three arguments, a string representing the layout type, a number representing the column count, and at least one widget or layout, no values were given" )
}
if count , ok := a [ 1 ] . ( number ) ; ok {
widgetStart = 2
cols = int ( float64 ( count ) )
}
2021-12-23 23:06:55 +00:00
}
2022-04-21 22:05:33 +00:00
list , err := ExpToCanvasObjectList ( a [ widgetStart : ] )
2021-11-09 06:50:26 +00:00
if err != nil {
2022-04-21 03:39:15 +00:00
return exception ( "'container' was given a non-widget value" )
2021-12-23 23:06:55 +00:00
}
2022-04-21 22:05:33 +00:00
switch containerType {
2021-12-23 23:06:55 +00:00
case "none" :
return guiContainer ( container . NewWithoutLayout ( list ... ) )
case "hbox" :
return guiContainer ( container . NewHBox ( list ... ) )
case "vbox" :
return guiContainer ( container . NewVBox ( list ... ) )
case "form" :
return guiContainer ( container . New ( layout . NewFormLayout ( ) , list ... ) )
case "center" :
return guiContainer ( container . NewCenter ( list ... ) )
case "max" :
return guiContainer ( container . NewMax ( list ... ) )
case "padded" :
return guiContainer ( container . NewPadded ( list ... ) )
2022-04-21 22:05:33 +00:00
case "grid" :
return guiContainer ( container . NewGridWithColumns ( cols , list ... ) )
2022-04-28 05:59:02 +00:00
case "vsplit" :
if len ( list ) < 2 {
return exception ( "'container' of type 'vsplit' expects three arguments, a string representing the layout type ('vsplit') and two widgets or layouts, too few arguments were given" )
}
return guiContainer ( container . NewVSplit ( list [ 0 ] , list [ 1 ] ) )
case "hsplit" :
if len ( list ) < 2 {
return exception ( "'container' of type 'hsplit' expects three arguments, a string representing the layout type ('hsplit') and two widgets or layouts, too few arguments were given" )
}
return guiContainer ( container . NewHSplit ( list [ 0 ] , list [ 1 ] ) )
2022-04-27 03:30:14 +00:00
case "border" :
if len ( a ) < 4 {
return exception ( "'container' expects at least four elements when set to 'border', too few elements were given" )
} else if len ( a ) == 4 {
return guiContainer ( container . NewBorder ( list [ 0 ] , list [ 1 ] , list [ 2 ] , list [ 3 ] ) )
} else {
return guiContainer ( container . NewBorder ( list [ 0 ] , list [ 1 ] , list [ 2 ] , list [ 3 ] , list [ 4 : ] ... ) )
}
2021-12-23 23:06:55 +00:00
default :
return exception ( "'container-with-layout' was given an invalid layout type" )
2021-11-09 06:50:26 +00:00
}
} ,
2021-12-23 23:06:55 +00:00
"container-size" : func ( a ... expression ) expression {
if len ( a ) < 1 {
return exception ( "'container-size' expects a container, no value was given" )
}
c , ok := a [ 0 ] . ( guiContainer )
if ! ok {
return exception ( "'container-size' expects a container, a non-container value was given" )
}
s := c . Size ( )
return [ ] expression { number ( s . Width ) , number ( s . Height ) }
} ,
"container-add-to" : func ( a ... expression ) expression {
if len ( a ) < 2 {
return exception ( "'container-add-to' expects a container and either a widget or another container, insufficient values were given" )
}
c , ok := a [ 0 ] . ( guiContainer )
if ! ok {
return exception ( "'container-add-to' expects a container, a non-container value was given" )
}
switch obj := a [ 1 ] . ( type ) {
case guiContainer :
c . ( * fyne . Container ) . Add ( obj )
case guiWidget :
c . ( * fyne . Container ) . Add ( obj )
default :
return exception ( "'container-add-to' expects a container or a widget as its second argument, a non-widget/non-container value was given" )
2021-11-10 00:07:13 +00:00
}
2021-12-23 23:06:55 +00:00
return true
2021-11-10 00:07:13 +00:00
} ,
2021-12-23 23:06:55 +00:00
"dialog-open-file" : func ( a ... expression ) expression {
2021-11-10 00:07:13 +00:00
if len ( a ) < 3 {
2022-04-21 03:39:15 +00:00
return exception ( "'dialog-open-file' expected three arguments: a GUI, a string representing a gui-window-id and a callback that takes a string as an argument; an insufficient number of arguments was given" )
2021-11-10 00:07:13 +00:00
}
app , ok := a [ 0 ] . ( * GUI )
if ! ok {
2021-12-23 23:06:55 +00:00
return exception ( "'dialog-open-file' expected a GUI as its first argument, a non-GUI value was given" )
2021-11-10 00:07:13 +00:00
}
window := String ( a [ 1 ] , false )
if _ , ok := app . windows [ window ] ; ! ok {
2022-04-21 03:39:15 +00:00
return exception ( "'dialog-open-file' was given an invalid window-id: " + window )
2021-11-10 00:07:13 +00:00
}
2022-04-21 03:39:15 +00:00
cb , ok := a [ 2 ] . ( proc )
2021-11-10 00:07:13 +00:00
if ! ok {
2021-12-23 23:06:55 +00:00
return exception ( "'dialog-open-file' expected a callback as its second argument, a non-callback value was given" )
2021-11-10 00:07:13 +00:00
}
fd := dialog . NewFileOpen ( func ( reader fyne . URIReadCloser , err error ) {
if err != nil || reader == nil {
return
}
defer reader . Close ( )
u := reader . URI ( ) . Path ( )
2022-06-22 04:04:24 +00:00
apply ( cb , [ ] expression { u } , "Open file dialog callback" )
2021-11-10 00:07:13 +00:00
return
} , app . windows [ window ] )
fd . Show ( )
return [ ] expression { }
} ,
2021-12-23 23:06:55 +00:00
"dialog-save-file" : func ( a ... expression ) expression {
if len ( a ) < 3 {
2022-04-21 03:39:15 +00:00
return exception ( "'dialog-save-file' expected three arguments: a GUI, a string representing a gui-window-id and a callback that takes a string as an argument; an insufficient number of arguments was given" )
2021-12-23 23:06:55 +00:00
}
app , ok := a [ 0 ] . ( * GUI )
if ! ok {
return exception ( "'dialog-save-file' expected a GUI as its first argument, a non-GUI value was given" )
}
window := String ( a [ 1 ] , false )
if _ , ok := app . windows [ window ] ; ! ok {
2022-04-21 03:39:15 +00:00
return exception ( "'dialog-save-file' was given an invalid window-id: " + window )
2021-12-23 23:06:55 +00:00
}
2022-04-21 03:39:15 +00:00
cb , ok := a [ 2 ] . ( proc )
2021-12-23 23:06:55 +00:00
if ! ok {
return exception ( "'dialog-save-file' expected a callback as its second argument, a non-callback value was given" )
}
fd := dialog . NewFileSave ( func ( writer fyne . URIWriteCloser , err error ) {
if err != nil || writer == nil {
return
}
defer writer . Close ( )
u := writer . URI ( ) . Path ( )
2022-06-22 04:04:24 +00:00
apply ( cb , [ ] expression { u } , "Save file dialog callback" )
2021-12-23 23:06:55 +00:00
return
} , app . windows [ window ] )
fd . Show ( )
return [ ] expression { }
} ,
"dialog-info" : func ( a ... expression ) expression {
if len ( a ) < 4 {
2022-04-21 22:05:33 +00:00
return exception ( "'dialog-info' expected four arguments: a GUI, a string representing a window-name, a title string, and a message string; an insufficient number of arguments was given" )
2021-12-23 23:06:55 +00:00
}
app , ok := a [ 0 ] . ( * GUI )
if ! ok {
return exception ( "'dialog-info' expected a GUI as its first argument, a non-GUI value was given" )
}
window := String ( a [ 1 ] , false )
if _ , ok := app . windows [ window ] ; ! ok {
2022-04-21 03:39:15 +00:00
return exception ( "'dialog-info' was given an invalid window-id: " + window )
2021-12-23 23:06:55 +00:00
}
dialog . ShowInformation ( String ( a [ 2 ] , false ) , String ( a [ 3 ] , false ) , app . windows [ window ] )
return [ ] expression { }
} ,
"dialog-error" : func ( a ... expression ) expression {
if len ( a ) < 3 {
2022-04-21 03:39:15 +00:00
return exception ( "'dialog-error' expected three arguments: a GUI, a string representing a gui-window-id, an error string; an insufficient number of arguments was given" )
2021-12-23 23:06:55 +00:00
}
app , ok := a [ 0 ] . ( * GUI )
if ! ok {
return exception ( "'dialog-error' expected a GUI as its first argument, a non-GUI value was given" )
}
window := String ( a [ 1 ] , false )
if _ , ok := app . windows [ window ] ; ! ok {
2022-04-21 03:39:15 +00:00
return exception ( "'dialog-error' was given an invalid window-id: " + window )
2021-12-23 23:06:55 +00:00
}
dialog . ShowError ( fmt . Errorf ( String ( a [ 2 ] , false ) ) , app . windows [ window ] )
return [ ] expression { }
} ,
2021-11-09 06:50:26 +00:00
}
2022-04-21 03:39:15 +00:00
// - BEGIN helpers
2021-11-09 06:50:26 +00:00
func ExpToCanvasObjectList ( e [ ] expression ) ( [ ] fyne . CanvasObject , error ) {
out := make ( [ ] fyne . CanvasObject , len ( e ) )
for i , v := range e {
2021-12-23 23:06:55 +00:00
switch obj := v . ( type ) {
2022-04-27 03:30:14 +00:00
case bool :
out [ i ] = nil
2021-12-23 23:06:55 +00:00
case guiWidget :
out [ i ] = obj . ( fyne . Widget ) . ( fyne . CanvasObject )
case fyne . CanvasObject :
out [ i ] = obj
case * fyne . Container :
out [ i ] = obj
case guiObject :
out [ i ] = obj . ( fyne . CanvasObject )
case guiContainer :
out [ i ] = obj . ( fyne . CanvasObject )
default :
2021-11-09 06:50:26 +00:00
return out , fmt . Errorf ( "Invalid list" )
}
}
return out , nil
}
2022-04-21 03:39:15 +00:00
// String converts any value to a string
// if rawString is true escapes will be
// shown visually and quotes will be around
// a string. rawString has no effect on
// values that are not already strings
func String ( v expression , rawString bool ) string {
switch v := v . ( type ) {
case [ ] expression :
l := make ( [ ] string , len ( v ) )
for i , x := range v {
l [ i ] = String ( x , true )
}
return "(" + strings . Join ( l , " " ) + ")"
case string :
if rawString {
return fmt . Sprintf ( "\"%s\"" , escapeString ( v ) )
}
return v
case exception :
return string ( v )
case bool :
if v {
return "#t"
}
return "#f"
case number :
return strconv . FormatFloat ( float64 ( v ) , 'f' , - 1 , 64 )
case proc :
var b strings . Builder
b . WriteString ( "(lambda " )
2023-05-04 21:21:07 +00:00
params , ok := v . params . ( [ ] expression )
if len ( v . predicates ) > 0 {
if ok {
newParams := make ( [ ] expression , len ( params ) )
copy ( newParams , params )
for i := range newParams {
if pred , ok := v . predicates [ newParams [ i ] . ( symbol ) ] ; ok {
newParams [ i ] = symbol ( fmt . Sprintf ( "%s@%s" , newParams [ i ] . ( symbol ) , pred ) )
}
}
b . WriteString ( String ( newParams , true ) )
} else {
val := String ( v . params , false )
b . WriteString ( val )
b . WriteString ( "@" )
b . WriteString ( string ( v . predicates [ symbol ( val ) ] ) )
}
} else {
b . WriteString ( String ( v . params , true ) )
}
2022-04-21 03:39:15 +00:00
b . WriteRune ( ' ' )
body := String ( v . body , true )
if strings . HasPrefix ( body , "(begin " ) {
body = body [ 7 : ]
}
b . WriteString ( body )
return b . String ( )
2022-07-06 22:54:23 +00:00
case macro :
var b strings . Builder
b . WriteString ( "(macro " )
b . WriteString ( String ( v . params , true ) )
b . WriteRune ( ' ' )
body := String ( v . body , true )
if strings . HasPrefix ( body , "(begin " ) {
body = body [ 7 : ]
}
b . WriteString ( body )
return b . String ( )
2022-04-21 03:39:15 +00:00
case func ( ... expression ) expression :
return fmt . Sprint ( "Built-in: " , & v )
case * IOHandle :
return fmt . Sprintf ( "%+v" , v )
case guiWidget :
return "gui-widget"
case fyne . Widget :
return "gui-widget"
2022-04-22 16:59:48 +00:00
case canvas . Image :
return "gui-widget"
case * canvas . Image :
return "gui-widget"
2022-04-21 03:39:15 +00:00
case fyne . Container :
return "gui-container"
case guiContainer :
return "gui-container"
2022-04-25 05:34:54 +00:00
case fyne . CanvasObject :
return "gui-widget"
2022-04-21 03:39:15 +00:00
case GUI :
return "gui-root"
case * GUI :
return "gui-root"
default :
return fmt . Sprint ( v )
}
}