diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index a3a21f725a..006afafe82 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1 +1 @@ -github: [fyne-io, andydotxyz, toaster, okratitan] +github: [fyne-io, andydotxyz, toaster, okratitan, Jacalz] diff --git a/CHANGELOG.md b/CHANGELOG.md index b083d6cf66..5f6ca0cecd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,13 +7,42 @@ More detailed release notes can be found on the [releases page](https://github.c ### Added -### Updated +### Changed * Focusable widgets are no longer focused on tap, add canvas.Focus(obj) in Tapped handler if required ### Fixed +## 2.0.4 - 6 August 2021 + +### Changed + +* Disable Form labels when the element it applys to is disabled (#1530) +* Entry popup menu now fires shortcuts so extended widgets can intercept +* Update Android builds to SDK 30 + +### Fixed + +* sendnotification show appID for name on windows (#1940) +* Fix accidental removal of windows builds during cross-compile +* Removing an item from a container did not update layout +* Update title bar on Windows 10 to match OS theme (#2184) +* Tapped triggered after Drag (#2235) +* Improved documentation and example code for file dialog (#2156) +* Preferences file gets unexpectedly cleared (#2241) +* Extra row dividers rendered on using SetColumnWidth to update a table (#2266) +* Fix resizing fullscreen issue +* Fullscreen changes my display resolution when showing a dialog (#1832) +* Entry validation does not work for empty field (#2179) +* Tab support for focus handling missing on mobile +* ScrollToBottom not always scrolling all the way when items added to container.Scroller +* Fixed scrollbar disappearing after changing content (#2303) +* Calling SetContent a second time with the same content will not show +* Drawing text can panic when Color is nil (#2347) +* Optimisations when drawing transparent rectangle or whitespace strings + + ## 2.0.3 - 30 April 2021 ### Fixed diff --git a/README.md b/README.md index e23bafe647..ad3985419a 100644 --- a/README.md +++ b/README.md @@ -154,3 +154,23 @@ More documentation is available at the [Fyne developer website](https://develope You can find many example applications in the [examples repository](https://github.com/fyne-io/examples/). Alternatively a list of applications using fyne can be found at [our website](https://apps.fyne.io/). + +# Shipping the Fyne Toolkit + +All Fyne apps will work without pre-installed libraries, this is one reason the apps are so portable. +However, if looking to support Fyne in a bigger way on your operating system then you can install some utilities that help to make a more complete experience. + +## Additional apps + +It is recommended that you install the following additional apps: + +| app | go get | description | +| --- | ------ | ----------- | +| fyne_settings | `fyne.io/fyne/v2/cmd/fyne_settings` | A GUI for managing your global Fyne settings like theme and scaling | +| apps | `github.com/fyne-io/apps` | A graphical installer for the Fyne apps listed at https://apps.fyne.io | + +These are optional applications but can help to create a more complete desktop experience. + +## FyneDesk (Linux / BSD) + +To go all the way with Fyne on your desktop / laptop computer you could install [FyneDesk](https://github.com/fyne-io/fynedesk) as well :) diff --git a/canvas/image.go b/canvas/image.go index fed8b1d9d8..f2aa8efaa5 100644 --- a/canvas/image.go +++ b/canvas/image.go @@ -74,6 +74,9 @@ func (i *Image) Resize(s fyne.Size) { if s == i.Size() { return } + if i.FillMode == ImageFillOriginal && i.size.Height > 2 { // don't refresh original scale images after first draw + return + } i.baseObject.Resize(s) diff --git a/canvas/text.go b/canvas/text.go index 81c05a5f98..a172733133 100644 --- a/canvas/text.go +++ b/canvas/text.go @@ -40,9 +40,13 @@ func (t *Text) Refresh() { // NewText returns a new Text implementation func NewText(text string, color color.Color) *Text { + size := float32(0) + if fyne.CurrentApp() != nil { // nil app possible if app not started + size = fyne.CurrentApp().Settings().Theme().Size("text") // manually name the size to avoid import loop + } return &Text{ Color: color, Text: text, - TextSize: fyne.CurrentApp().Settings().Theme().Size("text"), // manually name the size to avoid import loop + TextSize: size, } } diff --git a/cmd/fyne/internal/mobile/binres/binres.go b/cmd/fyne/internal/mobile/binres/binres.go index ec67ea0405..e855385c1a 100644 --- a/cmd/fyne/internal/mobile/binres/binres.go +++ b/cmd/fyne/internal/mobile/binres/binres.go @@ -210,7 +210,7 @@ type ltoken struct { // UnmarshalXML decodes an AndroidManifest.xml document returning type XML // containing decoded resources. -func UnmarshalXML(r io.Reader, withIcon bool) (*XML, error) { +func UnmarshalXML(r io.Reader, withIcon bool, targetSDK int) (*XML, error) { lr := &lineReader{r: r} dec := xml.NewDecoder(lr) @@ -273,7 +273,7 @@ func UnmarshalXML(r io.Reader, withIcon bool) (*XML, error) { Space: androidSchema, Local: "targetSdkVersion", }, - Value: "29", + Value: strconv.Itoa(targetSDK), }, }, } diff --git a/cmd/fyne/internal/mobile/binres/binres_test.go b/cmd/fyne/internal/mobile/binres/binres_test.go index b56877a6da..feab9ed73c 100644 --- a/cmd/fyne/internal/mobile/binres/binres_test.go +++ b/cmd/fyne/internal/mobile/binres/binres_test.go @@ -155,7 +155,7 @@ func TestEncode(t *testing.T) { f, err := os.Open("testdata/bootstrap.xml") r.NoError(err) - bx, err := UnmarshalXML(f, false) + bx, err := UnmarshalXML(f, false, 30) r.NoError(err) bin, err := ioutil.ReadFile("testdata/bootstrap.bin") @@ -183,7 +183,7 @@ func TestRawValueByName(t *testing.T) { f, err := os.Open("testdata/bootstrap.xml") r.NoError(err) - bx, err := UnmarshalXML(f, false) + bx, err := UnmarshalXML(f, false, 30) r.NoError(err) pkgname, err := bx.RawValueByName("manifest", xml.Name{Local: "package"}) diff --git a/cmd/fyne/internal/mobile/build.go b/cmd/fyne/internal/mobile/build.go index 76b11d28ea..392eb0585c 100644 --- a/cmd/fyne/internal/mobile/build.go +++ b/cmd/fyne/internal/mobile/build.go @@ -143,7 +143,11 @@ func runBuildImpl(cmd *command) (*packages.Package, error) { } return pkg, nil } - nmpkgs, err = goAndroidBuild(pkg, buildBundleID, targetArchs, cmd.IconPath, cmd.AppName, cmd.Version, cmd.Build) + target := 30 + if !buildRelease { + target = 29 // TODO once we have gomobile debug signing working for v2 android signs + } + nmpkgs, err = goAndroidBuild(pkg, buildBundleID, targetArchs, cmd.IconPath, cmd.AppName, cmd.Version, cmd.Build, target, buildRelease) if err != nil { return nil, err } diff --git a/cmd/fyne/internal/mobile/build_androidapp.go b/cmd/fyne/internal/mobile/build_androidapp.go index dc2298ac40..16c3945595 100644 --- a/cmd/fyne/internal/mobile/build_androidapp.go +++ b/cmd/fyne/internal/mobile/build_androidapp.go @@ -24,7 +24,7 @@ import ( ) func goAndroidBuild(pkg *packages.Package, bundleID string, androidArchs []string, - iconPath, appName, version string, build int) (map[string]bool, error) { + iconPath, appName, version string, build, target int, release bool) (map[string]bool, error) { ndkRoot, err := ndkRoot() if err != nil { return nil, err @@ -117,7 +117,7 @@ func goAndroidBuild(pkg *packages.Package, bundleID string, androidArchs []strin if err != nil { return nil, err } - err = addAssets(apkw, manifestData, dir, iconPath) + err = addAssets(apkw, manifestData, dir, iconPath, target) if err != nil { return nil, err } @@ -134,7 +134,7 @@ func goAndroidBuild(pkg *packages.Package, bundleID string, androidArchs []strin return nmpkgs[androidArchs[0]], nil } -func addAssets(apkw *Writer, manifestData []byte, dir, iconPath string) error { +func addAssets(apkw *Writer, manifestData []byte, dir, iconPath string, target int) error { // Add any assets. var arsc struct { iconPath string @@ -186,7 +186,7 @@ func addAssets(apkw *Writer, manifestData []byte, dir, iconPath string) error { } } - bxml, err := binres.UnmarshalXML(bytes.NewReader(manifestData), arsc.iconPath != "") + bxml, err := binres.UnmarshalXML(bytes.NewReader(manifestData), arsc.iconPath != "", target) if err != nil { return err } diff --git a/cmd/fyne_demo/tutorials/widget.go b/cmd/fyne_demo/tutorials/widget.go index 4c429c7a26..58c06f9cb8 100644 --- a/cmd/fyne_demo/tutorials/widget.go +++ b/cmd/fyne_demo/tutorials/widget.go @@ -325,6 +325,9 @@ func makeFormTab(_ fyne.Window) fyne.CanvasObject { password := widget.NewPasswordEntry() password.SetPlaceHolder("Password") + disabled := widget.NewRadioGroup([]string{"Option 1", "Option 2"}, func(string) {}) + disabled.Horizontal = true + disabled.Disable() largeText := widget.NewMultiLineEntry() form := &widget.Form{ @@ -344,6 +347,7 @@ func makeFormTab(_ fyne.Window) fyne.CanvasObject { }, } form.Append("Password", password) + form.Append("Disabled", disabled) form.Append("Message", largeText) return form } diff --git a/internal/driver/glfw/window.go b/internal/driver/glfw/window.go index f7df9284ba..7279ff76e5 100644 --- a/internal/driver/glfw/window.go +++ b/internal/driver/glfw/window.go @@ -484,6 +484,10 @@ func (w *window) SetContent(content fyne.CanvasObject) { } w.canvas.SetContent(content) + // show new canvas element + if content != nil { + content.Show() + } w.RescaleContext() } @@ -596,7 +600,6 @@ func (w *window) mouseMoved(viewport *glfw.Window, xpos float64, ypos float64) { w.mousePos = fyne.NewPos(internal.UnscaleInt(w.canvas, int(xpos)), internal.UnscaleInt(w.canvas, int(ypos))) mousePos := w.mousePos mouseButton := w.mouseButton - mouseDragStarted := w.mouseDragStarted mouseOver := w.mouseOver w.mouseLock.Unlock() @@ -631,7 +634,7 @@ func (w *window) mouseMoved(viewport *glfw.Window, xpos float64, ypos float64) { } } - if mouseButton != 0 && mouseButton != desktop.MouseButtonSecondary && !mouseDragStarted { + if w.mouseButton != 0 && w.mouseButton != desktop.MouseButtonSecondary && !w.mouseDragStarted { obj, pos, _ := w.findObjectAtPositionMatching(w.canvas, previousPos, func(object fyne.CanvasObject) bool { _, ok := object.(fyne.Draggable) return ok @@ -690,14 +693,16 @@ func (w *window) mouseMoved(viewport *glfw.Window, xpos float64, ypos float64) { mouseDraggedOffset := w.mouseDraggedOffset mouseDragPos := w.mouseDragPos w.mouseLock.RUnlock() - if mouseDragged != nil && mouseButton > 0 && mouseButton != desktop.MouseButtonSecondary { - draggedObjDelta := mouseDraggedObjStart.Subtract(mouseDragged.(fyne.CanvasObject).Position()) - ev := new(fyne.DragEvent) - ev.AbsolutePosition = mousePos - ev.Position = mousePos.Subtract(mouseDraggedOffset).Add(draggedObjDelta) - ev.Dragged = fyne.NewDelta(mousePos.X-mouseDragPos.X, mousePos.Y-mouseDragPos.Y) - wd := mouseDragged - w.QueueEvent(func() { wd.Dragged(ev) }) + if w.mouseDragged != nil && w.mouseButton != desktop.MouseButtonSecondary { + if w.mouseButton > 0 { + draggedObjDelta := mouseDraggedObjStart.Subtract(mouseDragged.(fyne.CanvasObject).Position()) + ev := new(fyne.DragEvent) + ev.AbsolutePosition = mousePos + ev.Position = mousePos.Subtract(mouseDraggedOffset).Add(draggedObjDelta) + ev.Dragged = fyne.NewDelta(mousePos.X-mouseDragPos.X, mousePos.Y-mouseDragPos.Y) + wd := mouseDragged + w.QueueEvent(func() { wd.Dragged(ev) }) + } w.mouseLock.Lock() w.mouseDragStarted = true diff --git a/internal/driver/glfw/window_test.go b/internal/driver/glfw/window_test.go index 26f745190b..b3cfe61a0d 100644 --- a/internal/driver/glfw/window_test.go +++ b/internal/driver/glfw/window_test.go @@ -349,6 +349,30 @@ func TestWindow_HandleDragging(t *testing.T) { assert.Nil(t, d1.popDragEvent()) assert.Nil(t, d2.popDragEvent()) + // no drag event on secondary mouseDown + w.mouseClicked(w.viewport, glfw.MouseButton2, glfw.Press, 0) + w.WaitForEvents() + assert.Nil(t, d1.popDragEvent()) + assert.Nil(t, d2.popDragEvent()) + + // no drag start and no drag event with pressed secondary mouse button + w.mouseMoved(w.viewport, 8, 8) + w.WaitForEvents() + assert.Nil(t, d1.popDragEvent()) + assert.Nil(t, d2.popDragEvent()) + + // no drag end event on secondary mouseUp + w.mouseClicked(w.viewport, glfw.MouseButton2, glfw.Release, 0) + w.WaitForEvents() + assert.Nil(t, d1.popDragEndEvent()) + assert.Nil(t, d2.popDragEndEvent()) + + // no drag event in simple move + w.mouseMoved(w.viewport, 9, 9) + w.WaitForEvents() + assert.Nil(t, d1.popDragEvent()) + assert.Nil(t, d2.popDragEvent()) + // no drag event on mouseDown w.mouseClicked(w.viewport, glfw.MouseButton1, glfw.Press, 0) w.WaitForEvents() @@ -1594,6 +1618,20 @@ func TestWindow_CloseInterception(t *testing.T) { assert.True(t, onClosed) // Close is called if the interceptor is not set. } +func TestWindow_SetContent_Twice(t *testing.T) { + w := createWindow("Test").(*window) + + e1 := widget.NewLabel("1") + e2 := widget.NewLabel("2") + + w.SetContent(e1) + assert.True(t, e1.Visible()) + w.SetContent(e2) + assert.True(t, e2.Visible()) + w.SetContent(e1) + assert.True(t, e1.Visible()) +} + // This test makes our developer screens flash, let's not run it regularly... //func TestWindow_Shortcut(t *testing.T) { // w := createWindow("Test") diff --git a/internal/driver/gomobile/driver.go b/internal/driver/gomobile/driver.go index f1aa31b926..77c63c752b 100644 --- a/internal/driver/gomobile/driver.go +++ b/internal/driver/gomobile/driver.go @@ -197,9 +197,9 @@ func (d *mobileDriver) Run() { } case key.Event: if e.Direction == key.DirPress { - d.typeDownCanvas(c, e.Rune, e.Code) + d.typeDownCanvas(c, e.Rune, e.Code, e.Modifiers) } else if e.Direction == key.DirRelease { - d.typeUpCanvas(c, e.Rune, e.Code) + d.typeUpCanvas(c, e.Rune, e.Code, e.Modifiers) } } } @@ -471,8 +471,26 @@ func runeToPrintable(r rune) rune { return 0 } -func (d *mobileDriver) typeDownCanvas(canvas *mobileCanvas, r rune, code key.Code) { +func (d *mobileDriver) typeDownCanvas(canvas *mobileCanvas, r rune, code key.Code, mod key.Modifiers) { keyName := keyToName(code) + switch keyName { + case fyne.KeyTab: + capture := false + if ent, ok := canvas.Focused().(fyne.Tabbable); ok { + capture = ent.AcceptsTab() + } + if !capture { + switch mod { + case 0: + canvas.FocusNext() + return + case key.ModShift: + canvas.FocusPrevious() + return + } + } + } + r = runeToPrintable(r) keyEvent := &fyne.KeyEvent{Name: keyName} @@ -501,8 +519,7 @@ func (d *mobileDriver) typeDownCanvas(canvas *mobileCanvas, r rune, code key.Cod } } -func (d *mobileDriver) typeUpCanvas(canvas *mobileCanvas, r rune, code key.Code) { - +func (d *mobileDriver) typeUpCanvas(_ *mobileCanvas, _ rune, _ key.Code, _ key.Modifiers) { } func (d *mobileDriver) Device() fyne.Device { diff --git a/internal/painter/gl/draw.go b/internal/painter/gl/draw.go index 6a4be0c7ad..77487b63d6 100644 --- a/internal/painter/gl/draw.go +++ b/internal/painter/gl/draw.go @@ -1,6 +1,7 @@ package gl import ( + "image/color" "math" "fyne.io/fyne/v2" @@ -55,12 +56,15 @@ func (p *glPainter) drawGradient(o fyne.CanvasObject, texCreator func(fyne.Canva } func (p *glPainter) drawRectangle(rect *canvas.Rectangle, pos fyne.Position, frame fyne.Size) { + if (rect.FillColor == color.Transparent || rect.FillColor == nil) && (rect.StrokeColor == color.Transparent || rect.FillColor == nil || rect.StrokeWidth == 0) { + return + } p.drawTextureWithDetails(rect, p.newGlRectTexture, pos, rect.Size(), frame, canvas.ImageFillStretch, 1.0, painter.VectorPad(rect)) } func (p *glPainter) drawText(text *canvas.Text, pos fyne.Position, frame fyne.Size) { - if text.Text == "" { + if text.Text == "" || text.Text == " " { return } diff --git a/internal/painter/gl/gl_common.go b/internal/painter/gl/gl_common.go index 63981802f3..ecd54817cc 100644 --- a/internal/painter/gl/gl_common.go +++ b/internal/painter/gl/gl_common.go @@ -5,6 +5,7 @@ import ( "log" "runtime" + "fyne.io/fyne/v2/theme" "github.com/goki/freetype" "github.com/goki/freetype/truetype" @@ -63,6 +64,10 @@ func (p *glPainter) newGlStrokedRectTexture(obj fyne.CanvasObject) Texture { func (p *glPainter) newGlTextTexture(obj fyne.CanvasObject) Texture { text := obj.(*canvas.Text) + color := text.Color + if color == nil { + color = theme.ForegroundColor() + } bounds := text.MinSize() width := int(p.textureScale(bounds.Width)) @@ -77,7 +82,7 @@ func (p *glPainter) newGlTextTexture(obj fyne.CanvasObject) Texture { d := painter.FontDrawer{} d.Dst = img - d.Src = &image.Uniform{C: text.Color} + d.Src = &image.Uniform{C: color} d.Face = face d.Dot = freetype.Pt(0, height-face.Metrics().Descent.Ceil()) d.DrawString(text.Text, text.TextStyle.TabWidth) diff --git a/internal/painter/software/draw.go b/internal/painter/software/draw.go index c22fa5b3ba..7a1130eaa3 100644 --- a/internal/painter/software/draw.go +++ b/internal/painter/software/draw.go @@ -9,6 +9,7 @@ import ( "fyne.io/fyne/v2/canvas" "fyne.io/fyne/v2/internal" "fyne.io/fyne/v2/internal/painter" + "fyne.io/fyne/v2/theme" "github.com/goki/freetype" "github.com/goki/freetype/truetype" @@ -138,6 +139,11 @@ func drawText(c fyne.Canvas, text *canvas.Text, pos fyne.Position, base *image.N height := internal.ScaleInt(c, bounds.Height) txtImg := image.NewRGBA(image.Rect(0, 0, width, height)) + color := text.Color + if color == nil { + color = theme.ForegroundColor() + } + var opts truetype.Options fontSize := text.TextSize * c.Scale() opts.Size = float64(fontSize) @@ -146,7 +152,7 @@ func drawText(c fyne.Canvas, text *canvas.Text, pos fyne.Position, base *image.N d := painter.FontDrawer{} d.Dst = txtImg - d.Src = &image.Uniform{C: text.Color} + d.Src = &image.Uniform{C: color} d.Face = face d.Dot = freetype.Pt(0, height-face.Metrics().Descent.Ceil()) d.DrawString(text.Text, text.TextStyle.TabWidth) diff --git a/internal/widget/scroller.go b/internal/widget/scroller.go index 38249ce745..ecc377f850 100644 --- a/internal/widget/scroller.go +++ b/internal/widget/scroller.go @@ -390,7 +390,7 @@ func (s *Scroll) CreateRenderer() fyne.WidgetRenderer { //ScrollToBottom will scroll content to container bottom - to show latest info which end user just added func (s *Scroll) ScrollToBottom() { - s.Offset.Y = s.Content.Size().Height - s.Size().Height + s.Offset.Y = s.Content.MinSize().Height - s.Size().Height s.Refresh() } diff --git a/layout/formlayout.go b/layout/formlayout.go index 7695dcf7b6..46c75b2c0d 100644 --- a/layout/formlayout.go +++ b/layout/formlayout.go @@ -2,6 +2,7 @@ package layout import ( "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" "fyne.io/fyne/v2/theme" ) @@ -53,6 +54,9 @@ func (f *formLayout) tableCellsSize(objects []fyne.CanvasObject, containerWidth } labelCell := currentRow[0].MinSize() + if _, ok := currentRow[0].(*canvas.Text); ok { + labelCell.Width += theme.Padding() * 4 + } labelCellMaxWidth = fyne.Max(labelCellMaxWidth, labelCell.Width) contentCell := currentRow[1].MinSize() @@ -92,8 +96,13 @@ func (f *formLayout) Layout(objects []fyne.CanvasObject, size fyne.Size) { } tableRow := table[row] - objects[i].Move(fyne.NewPos(0, y)) - objects[i].Resize(fyne.NewSize(tableRow[0].Width, tableRow[0].Height)) + if _, ok := objects[i].(*canvas.Text); ok { + objects[i].Move(fyne.NewPos(theme.Padding()*2, y+theme.Padding()*2)) + objects[i].Resize(fyne.NewSize(tableRow[0].Width-theme.Padding()*4, objects[i].MinSize().Height)) + } else { + objects[i].Move(fyne.NewPos(0, y)) + objects[i].Resize(fyne.NewSize(tableRow[0].Width, tableRow[0].Height)) + } if i+1 < len(objects) { objects[i+1].Move(fyne.NewPos(theme.Padding()+tableRow[0].Width, y)) diff --git a/widget/form.go b/widget/form.go index ff184788cc..77b2920cec 100644 --- a/widget/form.go +++ b/widget/form.go @@ -137,8 +137,12 @@ func (f *Form) createInput(item *FormItem) fyne.CanvasObject { return fyne.NewContainerWithLayout(layout.NewVBoxLayout(), item.Widget, fyne.NewContainerWithoutLayout(text)) } -func (f *Form) createLabel(text string) *Label { - return NewLabelWithStyle(text, fyne.TextAlignTrailing, fyne.TextStyle{Bold: true}) +func (f *Form) createLabel(text string) *canvas.Text { + return &canvas.Text{Text: text, + Alignment: fyne.TextAlignTrailing, + Color: theme.ForegroundColor(), + TextSize: theme.TextSize(), + TextStyle: fyne.TextStyle{Bold: true}} } func (f *Form) updateButtons() { @@ -234,12 +238,18 @@ func (f *Form) updateHelperText(item *FormItem) { func (f *Form) updateLabels() { for i, item := range f.Items { - l := f.itemGrid.Objects[i*2].(*Label) - if l.Text == item.Text { - continue + l := f.itemGrid.Objects[i*2].(*canvas.Text) + l.TextSize = theme.TextSize() + if dis, ok := item.Widget.(fyne.Disableable); ok { + if dis.Disabled() { + l.Color = theme.DisabledColor() + } else { + l.Color = theme.ForegroundColor() + } } - l.SetText(item.Text) + l.Text = item.Text + l.Refresh() f.updateHelperText(item) } } @@ -263,8 +273,9 @@ func (f *Form) CreateRenderer() fyne.WidgetRenderer { f.itemGrid = fyne.NewContainerWithLayout(layout.NewFormLayout(), objects...) renderer := NewSimpleRenderer(fyne.NewContainerWithLayout(layout.NewVBoxLayout(), f.itemGrid, f.buttonBox)) - f.updateButtons() // will set correct visibility on the submit/cancel btns - f.checkValidation(nil) // will trigger a validation check for correct initial validation status + f.updateButtons() + f.updateLabels() + f.checkValidation(nil) // will trigger a validation check for correct intial validation status return renderer } diff --git a/widget/form_test.go b/widget/form_test.go index d441865a62..c2012d4e77 100644 --- a/widget/form_test.go +++ b/widget/form_test.go @@ -5,6 +5,7 @@ import ( "testing" "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" "fyne.io/fyne/v2/data/validation" "fyne.io/fyne/v2/test" "fyne.io/fyne/v2/theme" @@ -104,11 +105,11 @@ func TestForm_ChangeText(t *testing.T) { renderer := test.WidgetRenderer(form) c := renderer.Objects()[0].(*fyne.Container).Objects[0].(*fyne.Container) - assert.Equal(t, "Test", c.Objects[0].(*Label).Text) + assert.Equal(t, "Test", c.Objects[0].(*canvas.Text).Text) item.Text = "Changed" form.Refresh() - assert.Equal(t, "Changed", c.Objects[0].(*Label).Text) + assert.Equal(t, "Changed", c.Objects[0].(*canvas.Text).Text) } func TestForm_ChangeTheme(t *testing.T) { @@ -133,6 +134,23 @@ func TestForm_ChangeTheme(t *testing.T) { }) } +func TestForm_Disabled(t *testing.T) { + app := test.NewApp() + defer test.NewApp() + app.Settings().SetTheme(theme.LightTheme()) + + disabled := NewEntry() + disabled.Disable() + f := NewForm( + NewFormItem("Form Item 1", NewEntry()), + NewFormItem("Form Item 2", disabled)) + + w := test.NewWindow(f) + defer w.Close() + + test.AssertImageMatches(t, "form/disabled.png", w.Canvas().Capture()) +} + func TestForm_Hints(t *testing.T) { test.NewApp() defer test.NewApp() diff --git a/widget/testdata/form/disabled.png b/widget/testdata/form/disabled.png new file mode 100644 index 0000000000..dd8dde2456 Binary files /dev/null and b/widget/testdata/form/disabled.png differ diff --git a/widget/testdata/form/layout.xml b/widget/testdata/form/layout.xml index da4116d911..1cb5f9e9ff 100644 --- a/widget/testdata/form/layout.xml +++ b/widget/testdata/form/layout.xml @@ -3,9 +3,7 @@ - - test1 - + test1 @@ -20,9 +18,7 @@ - - test2 - + test2