Render of widgets implementing layout.SpacerObject look bad
chran554 opened this issue · comments
Checklist
- I have searched the issue tracker for open issues that relate to the same problem, before opening a new one.
- This issue only relates to a single bug. I will open new issues for any other problems.
Describe the bug
Widgets implementing the layout.SpacerObject
interface seem to be rendered badly.
Documentation for the interface state "any object" can be used for spacing.
// SpacerObject is any object that can be used to space out child objects
type SpacerObject interface {
ExpandVertical() bool
ExpandHorizontal() bool
}
(In my case I wanted an expanding button on each side of a label i a Horizontal box. It was "increase zoom" and "decrease zoom" around a "current zoom" label.)
How to reproduce
Make a widget implement the layout.SpacerObject
interface and insert into Vertical or Horizontal box.
(In the code example below and in the the screen shot there is no "tapping"-events at all on the buttons on the empty areas to left and right of the "middle" button.)
Screenshots
Example code
package main
import (
"fmt"
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/app"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/widget"
)
type SpacingButton struct {
widget.Button
}
type SpacingLabel struct {
widget.Label
}
func NewSpacingLabel(text string) *SpacingLabel {
label := &SpacingLabel{}
label.Text = text
label.ExtendBaseWidget(label)
return label
}
func (sb *SpacingLabel) ExpandVertical() bool {
return false
}
func (sb *SpacingLabel) ExpandHorizontal() bool {
return true
}
func NewSpacingButton(label string, tapped func()) *SpacingButton {
button := &SpacingButton{}
button.Text = label
button.OnTapped = tapped
button.ExtendBaseWidget(button)
return button
}
func (sb *SpacingButton) ExpandVertical() bool {
return false
}
func (sb *SpacingButton) ExpandHorizontal() bool {
return true
}
func main() {
application := app.New()
window := application.NewWindow("Spacing button")
window.Resize(fyne.NewSize(200, 50))
c := container.NewHBox(
NewSpacingButton("left", func() { fmt.Println("tapped left") }),
widget.NewButton("middle", nil),
NewSpacingButton("right", func() { fmt.Println("tapped right") }),
)
window.SetContent(c)
window.ShowAndRun()
}
Fyne version
fyne cli version: v2.4.4
Go compiler version
go version go1.22.1 darwin/arm64
Operating system and version
macOS Sonoma Version 14.2.1 (23C71)
Additional Information
No response
The objects you are building are not spacers though... (spacers are the blank area between elements packed into a box).
You should not use HBox if you want items to expand in width - it is designed to compress widgets to their smallest width.
Hmm, it would seem that the layout code is treating spacers as data structures and ignoring whether or not they are widgets...
It was never intended that a full widget would be used as a "spacer" but I suppose the API does allow it so we should fix this up.
func main() {
a := app.New()
w := a.NewWindow("Hello")
w.SetContent(container.NewHBox(
layout.NewSpacer(),
widget.NewLabel("Middle"),
layout.NewSpacer(),
))
w.ShowAndRun()
}
It was never intended that a full widget would be used as a "spacer" but I suppose the API does allow it so we should fix this up.
I think that could be a brilliant addition to the layout functionality for VBox and HBox.
FYI: I've been using ordinary spacer with VBox and HBox, but I tried out the interface on buttons for the first time as I needed expanding buttons on each side of a label, and there is no layout that provide that behaviour.
Quick idea:
In addition to let all widgets, the standard fyne or your own, implement layout.SpacerObject
you could also provide a wrapper container(?) for a widget. The wrapper implement layout.SpacerObject
and your widget would fully expand within that wrapper.
Something like a function layout.NewSpacerObject(fyne.CanvasObject)
:
leftButton := widget.NewButton("I am greedy, nil)
w.SetContent(container.NewHBox(
layout.NewSpacerObject(leftButton),
widget.NewLabel("Middle"),
layout.NewSpacer(),
))
Quick idea:
In addition to let all widgets, the standard fyne or your own, implement
layout.SpacerObject
you could also provide a wrapper container(?) for a widget. The wrapper implementlayout.SpacerObject
and your widget would fully expand within that wrapper.Something like a function
layout.NewSpacerObject(fyne.CanvasObject)
:leftButton := widget.NewButton("I am greedy, nil) w.SetContent(container.NewHBox( layout.NewSpacerObject(leftButton), widget.NewLabel("Middle"), layout.NewSpacer(), ))
I see how that could feel like a nice shorthand but it actually goes against how the standard layouts and constructors work. There are wrappers in the fyne-x repo where the design principles are less strict - it could probably be added there.