diff --git a/assets/sprites/actor-tool.png b/assets/sprites/actor-tool.png index c7135bb..de13aff 100644 Binary files a/assets/sprites/actor-tool.png and b/assets/sprites/actor-tool.png differ diff --git a/assets/sprites/ellipse-tool.png b/assets/sprites/ellipse-tool.png index 044de12..2921942 100644 Binary files a/assets/sprites/ellipse-tool.png and b/assets/sprites/ellipse-tool.png differ diff --git a/assets/sprites/eraser-tool.png b/assets/sprites/eraser-tool.png index 1680502..8a999e3 100644 Binary files a/assets/sprites/eraser-tool.png and b/assets/sprites/eraser-tool.png differ diff --git a/assets/sprites/line-tool.png b/assets/sprites/line-tool.png index 460aff0..2ce6007 100644 Binary files a/assets/sprites/line-tool.png and b/assets/sprites/line-tool.png differ diff --git a/assets/sprites/link-tool.png b/assets/sprites/link-tool.png index bcd27ac..eaf3917 100644 Binary files a/assets/sprites/link-tool.png and b/assets/sprites/link-tool.png differ diff --git a/assets/sprites/pan-tool.png b/assets/sprites/pan-tool.png new file mode 100644 index 0000000..829b065 Binary files /dev/null and b/assets/sprites/pan-tool.png differ diff --git a/assets/sprites/pencil-tool.png b/assets/sprites/pencil-tool.png index 8dd76f6..a96503a 100644 Binary files a/assets/sprites/pencil-tool.png and b/assets/sprites/pencil-tool.png differ diff --git a/assets/sprites/rect-tool.png b/assets/sprites/rect-tool.png index 00afb2c..c91ace8 100644 Binary files a/assets/sprites/rect-tool.png and b/assets/sprites/rect-tool.png differ diff --git a/assets/sprites/text-tool.png b/assets/sprites/text-tool.png new file mode 100644 index 0000000..62d02bc Binary files /dev/null and b/assets/sprites/text-tool.png differ diff --git a/pkg/balance/numbers.go b/pkg/balance/numbers.go index 5dd85ee..bd2c649 100644 --- a/pkg/balance/numbers.go +++ b/pkg/balance/numbers.go @@ -59,6 +59,10 @@ var ( DefaultEraserBrushSize = 8 MaxEraserBrushSize = 32 // the bigger, the slower + // Default font filename selected for Text Tool in the editor. + // TODO: better centralize font filenames, here and in theme.go + TextToolDefaultFont = "DejaVuSans.ttf" + // Interval for auto-save in the editor AutoSaveInterval = 5 * time.Minute diff --git a/pkg/drawtool/text_tool.go b/pkg/drawtool/text_tool.go new file mode 100644 index 0000000..3eca8c1 --- /dev/null +++ b/pkg/drawtool/text_tool.go @@ -0,0 +1,56 @@ +package drawtool + +import ( + "git.kirsle.net/apps/doodle/pkg/native" + "git.kirsle.net/go/render" + "git.kirsle.net/go/ui" +) + +// TextSettings holds currently selected Text Tool settings. +type TextSettings struct { + Font string // like 'DejaVuSans.ttf' + Size int + Message string + Label *ui.Label // cached label texture +} + +// Currently active settings (global variable) +var TT TextSettings + +// IsZero checks if the TextSettings are populated. +func (tt TextSettings) IsZero() bool { + return tt.Font == "" && tt.Size == 0 && tt.Message == "" +} + +// ToStroke converts a TextSettings configuration into a Freehand +// Stroke, coloring in all of the pixels. +func (tt TextSettings) ToStroke(e render.Engine, color render.Color, at render.Point) (*Stroke, error) { + stroke := NewStroke(Freehand, color) + + // Render the text to a Go image so we can get the colors from + // it uniformly. + img, err := native.TextToImage(e, tt.Label.Font) + if err != nil { + return nil, err + } + + // Pull all its pixels. + var ( + max = img.Bounds().Max + x = 0 + y = 0 + ) + for x = 0; x < max.X; x++ { + for y = 0; y < max.Y; y++ { + hue := img.At(x, y) + r, g, b, _ := hue.RGBA() + if r == 65535 && g == r && b == r { + continue + } + + stroke.Points = append(stroke.Points, render.NewPoint(x+at.X, y+at.Y)) + } + } + + return stroke, nil +} diff --git a/pkg/drawtool/tools.go b/pkg/drawtool/tools.go index 0e0a320..83acd49 100644 --- a/pkg/drawtool/tools.go +++ b/pkg/drawtool/tools.go @@ -12,6 +12,8 @@ const ( ActorTool // drag and move actors LinkTool EraserTool + PanTool + TextTool ) var toolNames = []string{ @@ -22,6 +24,8 @@ var toolNames = []string{ "Doodad", // readable name for ActorTool "Link", "Eraser", + "PanTool", + "TextTool", } func (t Tool) String() string { diff --git a/pkg/editor_ui.go b/pkg/editor_ui.go index 2005cf5..e33a543 100644 --- a/pkg/editor_ui.go +++ b/pkg/editor_ui.go @@ -51,6 +51,7 @@ type EditorUI struct { doodadWindow *ui.Window paletteEditor *ui.Window layersWindow *ui.Window + textToolWindow *ui.Window publishWindow *ui.Window filesystemWindow *ui.Window licenseWindow *ui.Window diff --git a/pkg/editor_ui_popups.go b/pkg/editor_ui_popups.go index 440cb6a..f5d935e 100644 --- a/pkg/editor_ui_popups.go +++ b/pkg/editor_ui_popups.go @@ -7,6 +7,7 @@ import ( "git.kirsle.net/apps/doodle/pkg/balance" "git.kirsle.net/apps/doodle/pkg/doodads" + "git.kirsle.net/apps/doodle/pkg/drawtool" "git.kirsle.net/apps/doodle/pkg/level" "git.kirsle.net/apps/doodle/pkg/license" "git.kirsle.net/apps/doodle/pkg/log" @@ -49,6 +50,12 @@ func (u *EditorUI) OpenDoodadDropper() { u.Supervisor.FocusWindow(u.doodadWindow) } +// OpenTextTool opens the Text Tool window. +func (u *EditorUI) OpenTextTool() { + u.textToolWindow.Show() + u.Supervisor.FocusWindow(u.textToolWindow) +} + // OpenPublishWindow opens the Publisher window. func (u *EditorUI) OpenPublishWindow() { scene, _ := u.d.Scene.(*EditorScene) @@ -148,6 +155,23 @@ func (u *EditorUI) SetupPopups(d *Doodle) { u.ConfigureWindow(d, u.doodadWindow) } + // Text Tool window. + if u.textToolWindow == nil { + u.textToolWindow = windows.NewTextToolWindow(windows.TextTool{ + Supervisor: u.Supervisor, + Engine: d.Engine, + OnChangeSettings: func(font string, size int, message string) { + log.Info("Updated Text Tool settings: %s (%d): %s", font, size, message) + drawtool.TT = drawtool.TextSettings{ + Font: font, + Size: size, + Message: message, + } + }, + }) + u.ConfigureWindow(d, u.textToolWindow) + } + // Page Settings if u.levelSettingsWindow == nil { scene, _ := d.Scene.(*EditorScene) diff --git a/pkg/editor_ui_toolbar.go b/pkg/editor_ui_toolbar.go index 4679a22..f7dce0c 100644 --- a/pkg/editor_ui_toolbar.go +++ b/pkg/editor_ui_toolbar.go @@ -1,6 +1,8 @@ package doodle import ( + "fmt" + "git.kirsle.net/apps/doodle/pkg/balance" "git.kirsle.net/apps/doodle/pkg/drawtool" "git.kirsle.net/apps/doodle/pkg/enum" @@ -11,33 +13,54 @@ import ( "git.kirsle.net/go/ui/style" ) -// Width of the toolbar frame. -var toolbarWidth = 44 // 38px button (32px sprite + borders) + padding -var toolbarSpriteSize = 32 // 32x32 sprites. +// Global toolbarWidth, TODO: editor_ui.go wants it +var toolbarWidth int // SetupToolbar configures the UI for the Tools panel. func (u *EditorUI) SetupToolbar(d *Doodle) *ui.Frame { // Horizontal toolbar instead of vertical? var ( - isHoz = usercfg.Current.HorizontalToolbars - packAlign = ui.N - frameSize = render.NewRect(toolbarWidth, 100) - tooltipEdge = ui.Right - btnPack = ui.Pack{ + toolbarSpriteSize = 24 // size of sprite images + frameSize render.Rect + isHoz = usercfg.Current.HorizontalToolbars + buttonsPerRow = 2 + packAlign = ui.N + tooltipEdge = ui.Right + btnRowPack = ui.Pack{ Side: packAlign, - PadY: 2, + PadY: 1, + Fill: true, + } + btnPack = ui.Pack{ + Side: ui.W, + PadX: 1, } ) if isHoz { packAlign = ui.W - frameSize = render.NewRect(100, toolbarWidth) tooltipEdge = ui.Bottom - btnPack = ui.Pack{ + btnRowPack = ui.Pack{ Side: packAlign, PadX: 2, } + btnPack = ui.Pack{ + Side: ui.N, + PadY: 1, + } } + // Button Layout Controls: + // We can draw 2 buttons per row, but for very small screens + // e.g. mobile in portrait orientation, draw 1 button per row. + buttonsPerRow = 1 + if isHoz || d.width >= enum.ScreenWidthSmall { + buttonsPerRow = 2 + } + + // Compute toolbar size to accommodate all buttons (+10 for borders/padding) + toolbarWidth = buttonsPerRow * (toolbarSpriteSize + 10) + frameSize = render.NewRect(toolbarWidth, 100) + frame := ui.NewFrame("Tool Bar") frame.Resize(frameSize) frame.Configure(ui.Config{ @@ -62,6 +85,16 @@ func (u *EditorUI) SetupToolbar(d *Doodle) *ui.Frame { // Optional fields. NoDoodad bool // tool not available for Doodad editing (Levels only) }{ + { + Value: drawtool.PanTool.String(), + Icon: "assets/sprites/pan-tool.png", + Tooltip: "Pan Tool", + Click: func() { + u.Canvas.Tool = drawtool.PanTool + d.Flash("Pan Tool selected.") + }, + }, + { Value: drawtool.PencilTool.String(), Icon: "assets/sprites/pencil-tool.png", @@ -102,6 +135,17 @@ func (u *EditorUI) SetupToolbar(d *Doodle) *ui.Frame { }, }, + { + Value: drawtool.TextTool.String(), + Icon: "assets/sprites/text-tool.png", + Tooltip: "Text Tool", + Click: func() { + u.Canvas.Tool = drawtool.TextTool + u.OpenTextTool() + d.Flash("Text Tool selected.") + }, + }, + { Value: drawtool.ActorTool.String(), Icon: "assets/sprites/actor-tool.png", @@ -146,12 +190,20 @@ func (u *EditorUI) SetupToolbar(d *Doodle) *ui.Frame { }, }, } - for _, button := range buttons { + + // Arrange the buttons 2x2. + var btnRow *ui.Frame + for i, button := range buttons { button := button if button.NoDoodad && u.Scene.DrawingType == enum.DoodadDrawing { continue } + if buttonsPerRow == 1 || i%buttonsPerRow == 0 { + btnRow = ui.NewFrame(fmt.Sprintf("Button Row %d", i)) + btnFrame.Pack(btnRow, btnRowPack) + } + image, err := sprites.LoadImage(d.Engine, button.Icon) if err != nil { panic(err) @@ -168,6 +220,7 @@ func (u *EditorUI) SetupToolbar(d *Doodle) *ui.Frame { } var btnSize = btn.BoxThickness(2) + toolbarSpriteSize + btn.SetBorderSize(1) btn.Resize(render.NewRect(btnSize, btnSize)) btn.Handle(ui.Click, func(ed ui.EventData) error { @@ -181,7 +234,7 @@ func (u *EditorUI) SetupToolbar(d *Doodle) *ui.Frame { Edge: tooltipEdge, }) - btnFrame.Pack(btn, btnPack) + btnRow.Pack(btn, btnPack) } // Doodad Editor: show the Layers button. diff --git a/pkg/native/engine_sdl.go b/pkg/native/engine_sdl.go new file mode 100644 index 0000000..b3adbbc --- /dev/null +++ b/pkg/native/engine_sdl.go @@ -0,0 +1,84 @@ +// +build !js + +package native + +import ( + "image" + + "git.kirsle.net/apps/doodle/pkg/log" + "git.kirsle.net/go/render" + "git.kirsle.net/go/render/sdl" + sdl2 "github.com/veandco/go-sdl2/sdl" + "github.com/veandco/go-sdl2/ttf" +) + +// Native render engine functions (SDL2 edition), +// not for JavaScript/WASM yet. + +/* +TextToImage takes an SDL2_TTF texture and makes it into a Go image. + +Notes: +- The text is made Black & White with a white background on the image. +- Drop shadow, stroke, etc. probably not supported. +- Returns a non-antialiased image. +*/ +func TextToImage(e render.Engine, text render.Text) (image.Image, error) { + // engine, _ := e.(*sdl.Renderer) + + // Make the text black & white for ease of identifying pixels. + text.Color = render.Black + + var ( + // renderer = engine.GetSDL2Renderer() + font *ttf.Font + surface *sdl2.Surface + pixFmt *sdl2.PixelFormat + surface2 *sdl2.Surface + err error + ) + + if font, err = sdl.LoadFont(text.FontFilename, text.Size); err != nil { + return nil, err + } + + if surface, err = font.RenderUTF8Solid(text.Text, sdl.ColorToSDL(text.Color)); err != nil { + return nil, err + } + defer surface.Free() + log.Error("surf fmt: %+v", surface.Format) + + // Convert the Surface into a pixelformat that supports the .At(x,y) + // function properly, as the one we got above is "Not implemented" + if pixFmt, err = sdl2.AllocFormat(sdl2.PIXELFORMAT_RGB888); err != nil { + return nil, err + } + if surface2, err = surface.Convert(pixFmt, 0); err != nil { + return nil, err + } + defer surface2.Free() + + // Read back the pixels. + var ( + x int + y int + w = int(surface2.W) + h = int(surface2.H) + img = image.NewRGBA(image.Rect(x, y, w, h)) + ) + for x = 0; x < w; x++ { + for y = 0; y < h; y++ { + hue := surface2.At(x, y) + img.Set(x, y, hue) + // log.Warn("hue: %s", hue) + // r, g, b, _ := hue.RGBA() + // if r == 0 && g == 0 && b == 0 { + // img.Set(x, y, hue) + // } else { + // img.Set(x, y, color.Transparent) + // } + } + } + + return img, nil +} diff --git a/pkg/native/engine_wasm.go b/pkg/native/engine_wasm.go new file mode 100644 index 0000000..5fecec5 --- /dev/null +++ b/pkg/native/engine_wasm.go @@ -0,0 +1,13 @@ +// +build js,wasm + +package native + +import ( + "image" + + "git.kirsle.net/go/render" +) + +func TextToImage(e render.Engine, text render.Text) (image.Image, error) { + return nil, errors.New("not supported on WASM") +} diff --git a/pkg/uix/canvas_editable.go b/pkg/uix/canvas_editable.go index f72f519..4004f33 100644 --- a/pkg/uix/canvas_editable.go +++ b/pkg/uix/canvas_editable.go @@ -2,7 +2,9 @@ package uix import ( "git.kirsle.net/apps/doodle/pkg/drawtool" + "git.kirsle.net/apps/doodle/pkg/keybind" "git.kirsle.net/apps/doodle/pkg/level" + "git.kirsle.net/apps/doodle/pkg/shmem" "git.kirsle.net/go/render" "git.kirsle.net/go/render/event" "git.kirsle.net/go/ui" @@ -137,6 +139,30 @@ func (w *Canvas) loopEditable(ev *event.State) error { } switch w.Tool { + case drawtool.PanTool: + // Pan tool = click to pan the level. + if ev.Button1 || keybind.MiddleClick(ev) { + if !w.scrollDragging { + w.scrollDragging = true + w.scrollStartAt = shmem.Cursor + w.scrollWasAt = w.Scroll + } else { + delta := shmem.Cursor.Compare(w.scrollStartAt) + w.Scroll = w.scrollWasAt + w.Scroll.Subtract(delta) + + // TODO: if I don't call this, the user is able to (temporarily!) + // pan outside the level boundaries before it snaps-back when they + // release. But the normal middle-click to pan code doesn't let + // them do this.. investigate why later. + w.loopConstrainScroll() + } + } else { + if w.scrollDragging { + w.scrollDragging = false + } + } + case drawtool.PencilTool: // If no swatch is active, do nothing with mouse clicks. if w.Palette.ActiveSwatch == nil { @@ -253,6 +279,47 @@ func (w *Canvas) loopEditable(ev *event.State) error { } else { w.commitStroke(w.Tool, true) } + case drawtool.TextTool: + // The Text Tool popup should initialize this for us, if somehow not + // initialized skip this tool processing. + if w.Palette.ActiveSwatch == nil || drawtool.TT.IsZero() { + return nil + } + + // Do we need to create the Label? + if drawtool.TT.Label == nil { + drawtool.TT.Label = ui.NewLabel(ui.Label{ + Text: drawtool.TT.Message, + Font: render.Text{ + FontFilename: drawtool.TT.Font, + Size: drawtool.TT.Size, + Color: w.Palette.ActiveSwatch.Color, + }, + }) + } + + // Do we need to update the color of the label? + if drawtool.TT.Label.Font.Color != w.Palette.ActiveSwatch.Color { + drawtool.TT.Label.Font.Color = w.Palette.ActiveSwatch.Color + } + + // NOTE: Canvas.presentStrokes() will handle drawing the font preview + // at the cursor location while the TextTool is active. + + // On mouse click, commit the text to the drawing. + if ev.Button1 { + if stroke, err := drawtool.TT.ToStroke(shmem.CurrentRenderEngine, w.Palette.ActiveSwatch.Color, cursor); err != nil { + shmem.FlashError("Text Tool error: %s", err) + return nil + } else { + w.currentStroke = stroke + w.currentStroke.ExtraData = w.Palette.ActiveSwatch + w.commitStroke(drawtool.PencilTool, true) + } + + ev.Button1 = false + } + case drawtool.EraserTool: // Clicking? Log all the pixels while doing so. if ev.Button1 { diff --git a/pkg/uix/canvas_scrolling.go b/pkg/uix/canvas_scrolling.go index 744800d..ebf43f4 100644 --- a/pkg/uix/canvas_scrolling.go +++ b/pkg/uix/canvas_scrolling.go @@ -5,6 +5,7 @@ import ( "fmt" "git.kirsle.net/apps/doodle/pkg/balance" + "git.kirsle.net/apps/doodle/pkg/drawtool" "git.kirsle.net/apps/doodle/pkg/keybind" "git.kirsle.net/apps/doodle/pkg/level" "git.kirsle.net/apps/doodle/pkg/shmem" @@ -89,19 +90,22 @@ func (w *Canvas) loopEditorScroll(ev *event.State) error { } // Middle click of the mouse to pan the level. - if keybind.MiddleClick(ev) { - if !w.scrollDragging { - w.scrollDragging = true - w.scrollStartAt = shmem.Cursor - w.scrollWasAt = w.Scroll + // NOTE: PanTool intercepts both Left and MiddleClick. + if w.Tool != drawtool.PanTool { + if keybind.MiddleClick(ev) { + if !w.scrollDragging { + w.scrollDragging = true + w.scrollStartAt = shmem.Cursor + w.scrollWasAt = w.Scroll + } else { + delta := shmem.Cursor.Compare(w.scrollStartAt) + w.Scroll = w.scrollWasAt + w.Scroll.Subtract(delta) + } } else { - delta := shmem.Cursor.Compare(w.scrollStartAt) - w.Scroll = w.scrollWasAt - w.Scroll.Subtract(delta) - } - } else { - if w.scrollDragging { - w.scrollDragging = false + if w.scrollDragging { + w.scrollDragging = false + } } } diff --git a/pkg/uix/canvas_strokes.go b/pkg/uix/canvas_strokes.go index 350b415..c6a3a25 100644 --- a/pkg/uix/canvas_strokes.go +++ b/pkg/uix/canvas_strokes.go @@ -143,6 +143,11 @@ func (w *Canvas) presentStrokes(e render.Engine) { if w.Tool == drawtool.ActorTool || w.Tool == drawtool.LinkTool { w.presentActorLinks(e) } + + // Text Tool preview. + if w.Tool == drawtool.TextTool && drawtool.TT.Label != nil { + drawtool.TT.Label.Present(e, shmem.Cursor) + } } // presentActorLinks draws strokes connecting actors together by their links. diff --git a/pkg/uix/magic-form/magic_form.go b/pkg/uix/magic-form/magic_form.go index a652f29..74c54d0 100644 --- a/pkg/uix/magic-form/magic_form.go +++ b/pkg/uix/magic-form/magic_form.go @@ -31,6 +31,8 @@ type Form struct { // For vertical forms. Vertical bool LabelWidth int // size of left frame for labels. + PadY int // spacer between (vertical) forms + PadX int } /* @@ -61,6 +63,7 @@ type Field struct { // Variable bindings, the type may infer to be: BoolVariable *bool // Checkbox TextVariable *string // Textbox + IntVariable *int // Textbox Options []Option // Selectbox SelectValue interface{} // Selectbox default choice @@ -100,6 +103,7 @@ func (form Form) Create(into *ui.Frame, fields []Field) { into.Pack(frame, ui.Pack{ Side: ui.N, FillX: true, + PadY: form.PadY, }) // Pager row? @@ -177,6 +181,35 @@ func (form Form) Create(into *ui.Frame, fields []Field) { }) } + // Buttons and Text fields (for now). + if row.Type == Button || row.Type == Textbox { + btn := ui.NewButton("Button", ui.NewLabel(ui.Label{ + Text: row.Label, + Font: row.Font, + TextVariable: row.TextVariable, + IntVariable: row.IntVariable, + })) + form.Supervisor.Add(btn) + frame.Pack(btn, ui.Pack{ + Side: ui.W, + FillX: true, + Expand: true, + }) + + // Tooltip? TODO - make nicer. + if row.Tooltip.Text != "" || row.Tooltip.TextVariable != nil { + ui.NewTooltip(btn, row.Tooltip) + } + + // Handlers + btn.Handle(ui.Click, func(ed ui.EventData) error { + if row.OnClick != nil { + row.OnClick() + } + return nil + }) + } + // Checkbox? if row.Type == Checkbox { cb := ui.NewCheckbox("Checkbox", row.BoolVariable, ui.NewLabel(ui.Label{ @@ -266,7 +299,7 @@ func (field Field) Infer() Type { return Selectbox } - if field.TextVariable != nil { + if field.TextVariable != nil || field.IntVariable != nil { return Textbox } diff --git a/pkg/windows/text_tool.go b/pkg/windows/text_tool.go new file mode 100644 index 0000000..6237d87 --- /dev/null +++ b/pkg/windows/text_tool.go @@ -0,0 +1,124 @@ +package windows + +import ( + "strconv" + + "git.kirsle.net/apps/doodle/assets" + "git.kirsle.net/apps/doodle/pkg/balance" + "git.kirsle.net/apps/doodle/pkg/branding" + "git.kirsle.net/apps/doodle/pkg/shmem" + magicform "git.kirsle.net/apps/doodle/pkg/uix/magic-form" + "git.kirsle.net/go/render" + "git.kirsle.net/go/ui" +) + +// TextTool window. +type TextTool struct { + // Settings passed in by doodle + Supervisor *ui.Supervisor + Engine render.Engine + + // Callback when font settings are changed. + OnChangeSettings func(font string, size int, message string) +} + +// NewTextToolWindow initializes the window. +func NewTextToolWindow(cfg TextTool) *ui.Window { + window := ui.NewWindow("Text Tool") + window.SetButtons(ui.CloseButton) + window.Configure(ui.Config{ + Width: 330, + Height: 170, + Background: render.Grey, + }) + + // Text variables + var ( + currentText = branding.AppName + fontName = balance.TextToolDefaultFont + fontSize = 16 + ) + + // Get a listing of the available fonts. + fonts, _ := assets.AssetDir("assets/fonts") + var fontOption = []magicform.Option{} + for _, font := range fonts { + // Select the first font by default. + if fontName == "" { + fontName = font + } + + fontOption = append(fontOption, magicform.Option{ + Label: font, + Value: font, + }) + } + + // Send the default config out. + if cfg.OnChangeSettings != nil { + cfg.OnChangeSettings(fontName, fontSize, currentText) + } + + form := magicform.Form{ + Supervisor: cfg.Supervisor, + Engine: cfg.Engine, + Vertical: true, + LabelWidth: 100, + PadY: 2, + } + form.Create(window.ContentFrame(), []magicform.Field{ + { + Label: "Font Face:", + Font: balance.LabelFont, + Options: fontOption, + SelectValue: fontName, + OnSelect: func(v interface{}) { + fontName = v.(string) + if cfg.OnChangeSettings != nil { + cfg.OnChangeSettings(fontName, fontSize, currentText) + } + }, + }, + { + Label: "Font Size:", + Font: balance.LabelFont, + IntVariable: &fontSize, + OnClick: func() { + shmem.Prompt("Enter new font size: ", func(answer string) { + if answer != "" { + if i, err := strconv.Atoi(answer); err == nil { + fontSize = i + if cfg.OnChangeSettings != nil { + cfg.OnChangeSettings(fontName, fontSize, currentText) + } + } else { + shmem.FlashError("Not a valid font size: %s", answer) + } + } + }) + }, + }, + { + Label: "Message:", + Font: balance.LabelFont, + TextVariable: ¤tText, + OnClick: func() { + shmem.Prompt("Enter new message: ", func(answer string) { + if answer != "" { + currentText = answer + if cfg.OnChangeSettings != nil { + cfg.OnChangeSettings(fontName, fontSize, currentText) + } + } + }) + }, + }, + { + Label: "Be sure the Text Tool is selected, and click onto your\n" + + "drawing to place this text onto it.", + Font: balance.UIFont, + }, + }) + + return window +}