ronantakizawa/codereview-bench huggingface dataset:
Repository: fyne-io/fyne
File: widget/gridwrap.go (Go)

Code before:

// UnselectAll removes all items from the selection.
func (l *GridWrap) UnselectAll() {
	if len(l.selected) == 0 {
		return
	}

	selected := l.selected
	l.selected = nil
	l.Refresh()
	if f := l.OnUnselected; f != nil {
		for _, id := range selected {
			f(id)
		}
	}
}

func (l *GridWrap) contentMinSize() fyne.Size {
	padding := theme.Padding()
	if lenF := l.Length; lenF != nil {
		cols := l.ColumnCount()
		rows := float32(math.Ceil(float64(lenF()) / float64(cols)))
		return fyne.NewSize(l.itemMin.Width,
			(l.itemMin.Height+padding)*rows-padding)
	}
	return fyne.NewSize(0, 0)
}

// Declare conformity with WidgetRenderer interface.
var _ fyne.WidgetRenderer = (*gridWrapRenderer)(nil)

type gridWrapRenderer struct {
	objects []fyne.CanvasObject

	list     *GridWrap
	scroller *widget.Scroll
	layout   *fyne.Container
}

func newGridWrapRenderer(objects []fyne.CanvasObject, l *GridWrap, scroller *widget.Scroll, layout *fyne.Container) *gridWrapRenderer {
	lr := &gridWrapRenderer{objects: objects, list: l, scroller: scroller, layout: layout}
	lr.scroller.OnScrolled = l.offsetUpdated
	return lr
}

func (l *gridWrapRenderer) Layout(size fyne.Size) {
	l.scroller.Resize(size)
}

func (l *gridWrapRenderer) MinSize() fyne.Size {
	return l.scroller.MinSize().Max(l.list.itemMin)

Review comment (suggestion):
I realise that this just was copied from the other method more or less but lets get the logic ordered up to our usual standard with edge-cases indented and main path inline:
```suggestion
	if l.Length == nil {
		return fyne.NewSize(0, 0)
	}
	
	cols := l.ColumnCount()
	rows := float32(math.Ceil(float64(l.Length()) / float64(cols)))
	return fyne.NewSize(l.itemMin.Width, (l.itemMin.Height+padding)*rows-padding)
```

Code after:

// UnselectAll removes all items from the selection.
func (l *GridWrap) UnselectAll() {
	if len(l.selected) == 0 {
		return
	}

	selected := l.selected
	l.selected = nil
	l.Refresh()
	if f := l.OnUnselected; f != nil {
		for _, id := range selected {
			f(id)
		}
	}
}

func (l *GridWrap) contentMinSize() fyne.Size {
	padding := theme.Padding()
	if l.Length == nil {
		return fyne.NewSize(0, 0)
	}

	cols := l.ColumnCount()
	rows := float32(math.Ceil(float64(l.Length()) / float64(cols)))
	return fyne.NewSize(l.itemMin.Width, (l.itemMin.Height+padding)*rows-padding)
}

// Declare conformity with WidgetRenderer interface.
var _ fyne.WidgetRenderer = (*gridWrapRenderer)(nil)

type gridWrapRenderer struct {
	objects []fyne.CanvasObject

	list     *GridWrap
	scroller *widget.Scroll
	layout   *fyne.Container
}

func newGridWrapRenderer(objects []fyne.CanvasObject, l *GridWrap, scroller *widget.Scroll, layout *fyne.Container) *gridWrapRenderer {
	lr := &gridWrapRenderer{objects: objects, list: l, scroller: scroller, layout: layout}
	lr.scroller.OnScrolled = l.offsetUpdated
	return lr
}

func (l *gridWrapRenderer) Layout(size fyne.Size) {
	l.scroller.Resize(size)
}

func (l *gridWrapRenderer) MinSize() fyne.Size {
	return l.scroller.MinSize().Max(l.list.itemMin)
Repository: fyne-io/fyne
File: canvas/gradient.go (Go)

Code before:
		generator = func(_, y float64) float64 {
			return (h - y) / h
		}
	default: // vertical
		generator = func(_, y float64) float64 {
			return y / h
		}
	}
	return computeGradient(generator, iw, ih, g.StartColor, g.EndColor)
}

// Hide will set this gradient to not be visible
func (g *LinearGradient) Hide() {
	g.baseObject.Hide()

	repaint(g)
}

// Move the gradient to a new position, relative to its parent / canvas
func (g *LinearGradient) Move(pos fyne.Position) {
	g.baseObject.Move(pos)

	repaint(g)
}

// Resize the gradient to a new size. Causes a refresh, as cached textures become invalid on resize.
func (g *LinearGradient) Resize(size fyne.Size) {
	if size == g.Size() {
		return
	}
	g.baseObject.Resize(size)

	g.Refresh()
}

// Refresh causes this gradient to be redrawn with its configured state.
func (g *LinearGradient) Refresh() {
	Refresh(g)
}

// RadialGradient defines a Gradient travelling radially from a center point outward.
type RadialGradient struct {
	baseObject

	StartColor color.Color // The beginning color of the gradient
	EndColor   color.Color // The end color of the gradient
	// The offset of the center for generation of the gradient.
	// This is not a DP measure but relates to the width/height.
	// A value of 0.5 would move the center by the half width/height.
	CenterOffsetX, CenterOffsetY float64
}

Review comment (suggestion):
Ah, sorry I have one more suggestion - the second sentence about refreshing should just be moved to an inline code comment just above the g.Refresh() call, as it's more of an internal implementation detail than an API documentation. (And in RadialGradient too)

Code after:
		generator = func(_, y float64) float64 {
			return (h - y) / h
		}
	default: // vertical
		generator = func(_, y float64) float64 {
			return y / h
		}
	}
	return computeGradient(generator, iw, ih, g.StartColor, g.EndColor)
}

// Hide will set this gradient to not be visible
func (g *LinearGradient) Hide() {
	g.baseObject.Hide()

	repaint(g)
}

// Move the gradient to a new position, relative to its parent / canvas
func (g *LinearGradient) Move(pos fyne.Position) {
	g.baseObject.Move(pos)

	repaint(g)
}

// Resize resizes the gradient to a new size.
func (g *LinearGradient) Resize(size fyne.Size) {
	if size == g.Size() {
		return
	}
	g.baseObject.Resize(size)

	// refresh needed to invalidate cached textures
	g.Refresh()
}

// Refresh causes this gradient to be redrawn with its configured state.
func (g *LinearGradient) Refresh() {
	Refresh(g)
}

// RadialGradient defines a Gradient travelling radially from a center point outward.
type RadialGradient struct {
	baseObject

	StartColor color.Color // The beginning color of the gradient
	EndColor   color.Color // The end color of the gradient
	// The offset of the center for generation of the gradient.
	// This is not a DP measure but relates to the width/height.
	// A value of 0.5 would move the center by the half width/height.
	CenterOffsetX, CenterOffsetY float64
Repository: fyne-io/fyne
File: app/meta_development.go (Go)

Code before:
//go:build !no_metadata

package app

import (
	"os"
	"path/filepath"

	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/internal/metadata"
)

func checkLocalMetadata() {
	file, _ := filepath.Abs("FyneApp.toml")
	ref, err := os.Open(file)
	if err != nil { // no worries, this is just an optional fallback
		return
	}

	data, err := metadata.Load(ref)
	if err != nil || data == nil {
		fyne.LogError("failed to parse FyneApp.toml", err)
		return
	}

	meta.ID = data.Details.ID

Review comment (performance):
Instead of more complexity (more files) in the `app/` folder, can you not use the new `internal/build` package and add a `build.NoMetadata` constant?

You can then just to an `if build.NoMetadata` before calling the function. Mates things a bit clearer, I think :)

Code after:
package app

import (
	"os"
	"path/filepath"
	"strings"

	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/internal/build"
	"fyne.io/fyne/v2/internal/metadata"
)

func checkLocalMetadata() {
	if build.NoMetadata || build.Mode == fyne.BuildRelease {
		return
	}

	dir := getProjectPath()
	file := filepath.Join(dir, "FyneApp.toml")
	ref, err := os.Open(file)
	if err != nil { // no worries, this is just an optional fallback
		return
	}
	defer ref.Close()

	data, err := metadata.Load(ref)
Repository: fyne-io/fyne
File: widget/richtext.go (Go)

Code before:
}

// cachedSegmentVisual returns a cached segment visual representation.
// The offset value is > 0 if the segment had been split and so we need multiple objects.
func (t *RichText) cachedSegmentVisual(seg RichTextSegment, offset int) fyne.CanvasObject {
	t.cacheLock.Lock()
	defer t.cacheLock.Unlock()
	if t.visualCache == nil {
		t.visualCache = make(map[RichTextSegment][]fyne.CanvasObject)
	}

	if vis, ok := t.visualCache[seg]; ok && offset < len(vis) {
		return vis[offset]
	}

	vis := seg.Visual()
	if offset < len(t.visualCache[seg]) {
		t.visualCache[seg][offset] = vis
	} else {
		t.visualCache[seg] = append(t.visualCache[seg], vis)
	}
	return vis
}

// insertAt inserts the text at the specified position
func (t *RichText) insertAt(pos int, runes string) {
	index := 0
	start := 0
	var into *TextSegment
	for i, seg := range t.Segments {
		if _, ok := seg.(*TextSegment); !ok {
			continue
		}
		end := start + len([]rune(seg.(*TextSegment).Text))
		into = seg.(*TextSegment)
		index = i
		if end > pos {
			break
		}

		start = end
	}

	if into == nil {
		return
	}
	r := ([]rune)(into.Text)
	if pos > len(r) { // safety in case position is out of bounds for the segment
		pos = len(r)
	}
	r2 := append(r[:pos], append([]rune(runes), r[pos:]...)...)

Review comment (suggestion):
With this things may still leak once... is that OK?
(i.e. if you replace 1 or 2 or more with exactly the same number then it will expand to fit the new items, which will get removed later.
Probably a fair trade-off, just wanted to check

Code after:
}

// cachedSegmentVisual returns a cached segment visual representation.
// The offset value is > 0 if the segment had been split and so we need multiple objects.
func (t *RichText) cachedSegmentVisual(seg RichTextSegment, offset int) fyne.CanvasObject {
	t.cacheLock.Lock()
	defer t.cacheLock.Unlock()
	if t.visualCache == nil {
		t.visualCache = make(map[RichTextSegment][]fyne.CanvasObject)
	}

	if vis, ok := t.visualCache[seg]; ok && offset < len(vis) {
		return vis[offset]
	}

	vis := seg.Visual()
	if offset < len(t.visualCache[seg]) {
		t.visualCache[seg][offset] = vis
	} else {
		t.visualCache[seg] = append(t.visualCache[seg], vis)
	}
	return vis
}

func (t *RichText) cleanVisualCache() {
	if len(t.visualCache) <= len(t.Segments) {
		return
	}
	var deletingSegs []RichTextSegment
	for seg1 := range t.visualCache {
		found := false
		for _, seg2 := range t.Segments {
			if seg1 == seg2 {
				found = true
				break
			}
		}
		if !found {
			// cached segment is not currently in t.Segments, clear it
			deletingSegs = append(deletingSegs, seg1)
		}
	}
	for _, seg := range deletingSegs {
		delete(t.visualCache, seg)
	}
}

// insertAt inserts the text at the specified position
func (t *RichText) insertAt(pos int, runes string) {
	index := 0
	start := 0
Repository: fyne-io/fyne
File: data/binding/gen.go (Go)

Code before:

		writeFile(listFile, list, b)
		writeFile(treeFile, tree, b)
		if b.Name == "Untyped" {
			continue // any is special, we have it in binding.go instead
		}

		writeFile(itemFile, item, b)
		if b.SupportsPreferences {
			writeFile(prefFile, preference, b)
		}
		if b.Format != "" || b.ToString != "" {
			writeFile(convertFile, toString, b)
		}
	}
	// add StringTo... at the bottom of the convertFile for correct ordering
	for _, b := range binds {
		if b.Since == "" {
			b.Since = "2.0"
		}

		if b.Format != "" || b.FromString != "" {
			writeFile(convertFile, fromString, b)
		}
	}
	for _, b := range binds {
		if b.Since == "" {
			b.Since = "2.5"
		}

		if b.FromInt != "" {
			writeFile(convertFile, fromInt, b)
		}
	}
	for _, b := range binds {
		if b.Since == "" {
			b.Since = "2.5"
		}

		if b.ToInt != "" {
			writeFile(convertFile, toInt, b)
		}
	}
}


Review comment (performance):
We don't need to iterate the binds both times. These two could be added in one iteration.
Also, see the note above about string being last. We try to maintain alphabetical ordering, so these should come before it.

It is also possible you're making life a little harder with "{{ .Since }}" - won't it always be 2.5 (at least for now, so why add the complexity)

Code after:

		writeFile(listFile, list, b)
		writeFile(treeFile, tree, b)
		if b.Name == "Untyped" {
			continue // any is special, we have it in binding.go instead
		}

		writeFile(itemFile, item, b)
		if b.SupportsPreferences {
			writeFile(prefFile, preference, b)
		}
		if b.Format != "" || b.ToString != "" {
			writeFile(convertFile, toString, b)
		}
		if b.FromInt != "" {
			writeFile(convertFile, fromInt, b)
		}
		if b.ToInt != "" {
			writeFile(convertFile, toInt, b)
		}
	}
	// add StringTo... at the bottom of the convertFile for correct ordering
	for _, b := range binds {
		if b.Since == "" {
			b.Since = "2.0"
		}

		if b.Format != "" || b.FromString != "" {
			writeFile(convertFile, fromString, b)
		}
	}
}
Repository: fyne-io/fyne
File: dialog/fileitem.go (Go)

Code before:
	i.name = l.Name()

	if i.picker.view == GridView {
		ext := filepath.Ext(i.name[1:])
		i.name = i.name[:len(i.name)-len(ext)]
	}

	if up {
		i.name = "(" + lang.X("file.parent", "Parent") + ")"
	}

	i.Refresh()
}
func (i *fileDialogItem) tapped() {
	if i.choose != nil {
		i.choose(i.id)
	}
	now := time.Now()
	if !i.dir && now.Sub(i.lastClick) < fyne.CurrentApp().Driver().DoubleTapDelay() && i.open != nil {
		// It is a double click, so we ask the dialog to open
		i.open()
	}
	i.lastClick = now
}

func (i *fileDialogItem) TouchDown(*mobile.TouchEvent) {}

func (i *fileDialogItem) TouchUp(*mobile.TouchEvent) {
	i.tapped()
}

func (i *fileDialogItem) TouchCancel(*mobile.TouchEvent) {}

func (i *fileDialogItem) MouseDown(*desktop.MouseEvent) {}

func (i *fileDialogItem) MouseUp(e *desktop.MouseEvent) {
	i.tapped()
}

func (f *fileDialog) newFileItem(location fyne.URI, dir, up bool) *fileDialogItem {
	item := &fileDialogItem{
		picker:   f,
		location: location,
		name:     location.Name(),
		dir:      dir,
	}

	if f.view == GridView {
		ext := filepath.Ext(item.name[1:])
		item.name = item.name[:len(item.name)-len(ext)]
	}

Review comment (suggestion):
I think you can still use Tappable instead of Mouseable/Touchable. If your object is Tappable and not DoubleTappable then there will be no delay and you can just do the same logic you already have here to treat it as a single tap to select or a double tap to open.

Code after:
		ext := filepath.Ext(i.name[1:])
		i.name = i.name[:len(i.name)-len(ext)]
	}

	if up {
		i.name = "(" + lang.X("file.parent", "Parent") + ")"
	}

	i.Refresh()
}

func (i *fileDialogItem) Tapped(*fyne.PointEvent) {
	if i.choose != nil {
		i.choose(i.id)
	}
	now := time.Now()
	if !i.dir && now.Sub(i.lastClick) < fyne.CurrentApp().Driver().DoubleTapDelay() && i.open != nil {
		// It is a double click, so we ask the dialog to open
		i.open()
	}
	i.lastClick = now
}

func (f *fileDialog) newFileItem(location fyne.URI, dir, up bool) *fileDialogItem {
	item := &fileDialogItem{
		picker:   f,
		location: location,
		name:     location.Name(),
		dir:      dir,
	}

	if f.view == GridView {
		ext := filepath.Ext(item.name[1:])
		item.name = item.name[:len(item.name)-len(ext)]
	}

	if up {
		item.name = "(" + lang.X("file.parent", "Parent") + ")"
	}

	item.ExtendBaseWidget(item)
	return item
}

type fileItemRenderer struct {
	item         *fileDialogItem
	fileTextSize float32

	icon    *widget.FileIcon
	text    *widget.Label
	objects []fyne.CanvasObject
Repository: fyne-io/fyne
File: dialog/fileitem.go (Go)

Code before:
	}
	i.lastClick = now
}

func (f *fileDialog) newFileItem(location fyne.URI, dir, up bool) *fileDialogItem {
	item := &fileDialogItem{
		picker:   f,
		location: location,
		name:     location.Name(),
		dir:      dir,
	}

	if f.view == GridView {
		ext := filepath.Ext(item.name[1:])
		item.name = item.name[:len(item.name)-len(ext)]
	}

	if up {
		item.name = "(" + lang.X("file.parent", "Parent") + ")"
	}

	item.ExtendBaseWidget(item)
	return item
}

func (i *fileDialogItem) setChooseAndOpenCallBack(choose func(id int), open func()) {
	i.choose = choose
	i.open = open
}

type fileItemRenderer struct {
	item         *fileDialogItem
	fileTextSize float32

	icon    *widget.FileIcon
	text    *widget.Label
	objects []fyne.CanvasObject
}

func (s *fileItemRenderer) Layout(size fyne.Size) {
	if s.item.picker.view == GridView {
		s.icon.Resize(fyne.NewSize(fileIconSize, fileIconSize))
		s.icon.Move(fyne.NewPos((size.Width-fileIconSize)/2, 0))

		s.text.Alignment = fyne.TextAlignCenter
		s.text.Resize(fyne.NewSize(size.Width, s.fileTextSize))
		s.text.Move(fyne.NewPos(0, size.Height-s.fileTextSize))
	} else {
		s.icon.Resize(fyne.NewSize(fileInlineIconSize, fileInlineIconSize))
		s.icon.Move(fyne.NewPos(theme.Padding(), (size.Height-fileInlineIconSize)/2))


Review comment (suggestion):
A minor style thing - I'm not sure it's worth creating a function for just this. Instead what you could do is where you invoke this function now, do a cast to (*fileDialogItem) and save it to a local variable, then you can simply access .choose and .open (and .setLocation).

Code after:
	i.lastClick = now
}

func (f *fileDialog) newFileItem(location fyne.URI, dir, up bool) *fileDialogItem {
	item := &fileDialogItem{
		picker:   f,
		location: location,
		name:     location.Name(),
		dir:      dir,
	}

	if f.view == GridView {
		ext := filepath.Ext(item.name[1:])
		item.name = item.name[:len(item.name)-len(ext)]
	}

	if up {
		item.name = "(" + lang.X("file.parent", "Parent") + ")"
	}

	item.ExtendBaseWidget(item)
	return item
}

type fileItemRenderer struct {
	item         *fileDialogItem
	fileTextSize float32

	icon    *widget.FileIcon
	text    *widget.Label
	objects []fyne.CanvasObject
}

func (s *fileItemRenderer) Layout(size fyne.Size) {
	if s.item.picker.view == GridView {
		s.icon.Resize(fyne.NewSize(fileIconSize, fileIconSize))
		s.icon.Move(fyne.NewPos((size.Width-fileIconSize)/2, 0))

		s.text.Alignment = fyne.TextAlignCenter
		s.text.Resize(fyne.NewSize(size.Width, s.fileTextSize))
		s.text.Move(fyne.NewPos(0, size.Height-s.fileTextSize))
	} else {
		s.icon.Resize(fyne.NewSize(fileInlineIconSize, fileInlineIconSize))
		s.icon.Move(fyne.NewPos(theme.Padding(), (size.Height-fileInlineIconSize)/2))

		s.text.Alignment = fyne.TextAlignLeading
		textMin := s.text.MinSize()
		s.text.Resize(fyne.NewSize(size.Width, textMin.Height))
		s.text.Move(fyne.NewPos(fileInlineIconSize, (size.Height-textMin.Height)/2))
	}
}
Repository: fyne-io/fyne
File: dialog/fileitem.go (Go)

Code before:
package dialog

import (
	"path/filepath"
	"time"

	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/lang"
	"fyne.io/fyne/v2/theme"
	"fyne.io/fyne/v2/widget"
)

const (
	fileIconSize       = 64
	fileInlineIconSize = 24
	fileIconCellWidth  = fileIconSize * 1.25
)

type fileDialogItem struct {
	widget.BaseWidget
	picker *fileDialog

	name     string
	id       int // id in the father container
	choose   func(id int)
	open     func()
	location fyne.URI
	dir      bool

	lastClick time.Time
}

func (i *fileDialogItem) CreateRenderer() fyne.WidgetRenderer {
	text := widget.NewLabelWithStyle(i.name, fyne.TextAlignCenter, fyne.TextStyle{})
	text.Truncation = fyne.TextTruncateEllipsis
	text.Wrapping = fyne.TextWrapBreak
	icon := widget.NewFileIcon(i.location)

	return &fileItemRenderer{
		item:         i,
		icon:         icon,
		text:         text,
		objects:      []fyne.CanvasObject{icon, text},
		fileTextSize: widget.NewLabel("M\nM").MinSize().Height, // cache two-line label height,
	}
}

func (i *fileDialogItem) setLocation(l fyne.URI, dir, up bool, id int) {
	i.id = id

Review comment (suggestion):
```suggestion
	id       int // id in the parent container
```

Code after:
package dialog

import (
	"path/filepath"
	"time"

	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/lang"
	"fyne.io/fyne/v2/theme"
	"fyne.io/fyne/v2/widget"
)

const (
	fileIconSize       = 64
	fileInlineIconSize = 24
	fileIconCellWidth  = fileIconSize * 1.25
)

type fileDialogItem struct {
	widget.BaseWidget
	picker *fileDialog

	name     string
	id       int // id in the parent container
	choose   func(id int)
	open     func()
	location fyne.URI
	dir      bool

	lastClick time.Time
}

func (i *fileDialogItem) CreateRenderer() fyne.WidgetRenderer {
	text := widget.NewLabelWithStyle(i.name, fyne.TextAlignCenter, fyne.TextStyle{})
	text.Truncation = fyne.TextTruncateEllipsis
	text.Wrapping = fyne.TextWrapBreak
	icon := widget.NewFileIcon(i.location)

	return &fileItemRenderer{
		item:         i,
		icon:         icon,
		text:         text,
		objects:      []fyne.CanvasObject{icon, text},
		fileTextSize: widget.NewLabel("M\nM").MinSize().Height, // cache two-line label height,
	}
}

func (i *fileDialogItem) setLocation(l fyne.URI, dir, up bool) {
	i.dir = dir
Repository: fyne-io/fyne
File: widget/slider.go (Go)

Code before:
			trackPos.X-(diameter-trackSize.Width)/2, activeOffset-(diameter/2))
	case Horizontal:
		activePos = trackPos
		activeSize = fyne.NewSize(activeOffset-endPad, trackWidth)

		thumbPos = fyne.NewPos(
			activeOffset-(diameter/2), trackPos.Y-(diameter-trackSize.Height)/2)
	}

	s.active.Move(activePos)
	s.active.Resize(activeSize)

	s.thumb.Move(thumbPos)
	s.thumb.Resize(fyne.NewSize(diameter, diameter))

	focusIndicatorSize := fyne.NewSquareSize(inlineIconSize + innerPadding)
	delta := (focusIndicatorSize.Width - diameter) / 2
	s.focusIndicator.Resize(focusIndicatorSize)
	s.focusIndicator.Move(thumbPos.SubtractXY(delta, delta))
}

// MinSize calculates the minimum size of a widget.
func (s *sliderRenderer) MinSize() fyne.Size {
	th := s.slider.Theme()
	pad := th.Size(theme.SizeNameInnerPadding)
	dia := s.slider.buttonDiameter(th.Size(theme.SizeNameInlineIcon))
	tap := th.Size(theme.SizeNameInlineIcon)
	s1, s2 := minLongSide+dia, tap+pad*2

	switch s.slider.Orientation {
	case Vertical:
		return fyne.NewSize(s2, s1)
	default:
		return fyne.NewSize(s1, s2)
	}
}

func (s *sliderRenderer) getOffset(iconInlineSize, innerPadding float32) float32 {
	endPad := s.slider.endOffset(iconInlineSize, innerPadding)
	w := s.slider
	size := s.track.Size()
	if w.Value == w.Min || w.Min == w.Max {
		switch w.Orientation {
		case Vertical:
			return size.Height + endPad
		case Horizontal:
			return endPad
		}
	}
	ratio := float32((w.Value - w.Min) / (w.Max - w.Min))


Review comment (suggestion):
Switching the order of this and the line below it allows you to only invoke `th.Size(theme.SizeNameInlineIcon)` once and just pass the computed value to buttonDiameter

Code after:
			trackPos.X-(diameter-trackSize.Width)/2, activeOffset-(diameter/2))
	case Horizontal:
		activePos = trackPos
		activeSize = fyne.NewSize(activeOffset-endPad, trackWidth)

		thumbPos = fyne.NewPos(
			activeOffset-(diameter/2), trackPos.Y-(diameter-trackSize.Height)/2)
	}

	s.active.Move(activePos)
	s.active.Resize(activeSize)

	s.thumb.Move(thumbPos)
	s.thumb.Resize(fyne.NewSize(diameter, diameter))

	focusIndicatorSize := fyne.NewSquareSize(inlineIconSize + innerPadding)
	delta := (focusIndicatorSize.Width - diameter) / 2
	s.focusIndicator.Resize(focusIndicatorSize)
	s.focusIndicator.Move(thumbPos.SubtractXY(delta, delta))
}

// MinSize calculates the minimum size of a widget.
func (s *sliderRenderer) MinSize() fyne.Size {
	th := s.slider.Theme()
	pad := th.Size(theme.SizeNameInnerPadding)
	tap := th.Size(theme.SizeNameInlineIcon)
	dia := s.slider.buttonDiameter(tap)
	s1, s2 := minLongSide+dia, tap+pad*2

	switch s.slider.Orientation {
	case Vertical:
		return fyne.NewSize(s2, s1)
	default:
		return fyne.NewSize(s1, s2)
	}
}

func (s *sliderRenderer) getOffset(iconInlineSize, innerPadding float32) float32 {
	endPad := s.slider.endOffset(iconInlineSize, innerPadding)
	w := s.slider
	size := s.track.Size()
	if w.Value == w.Min || w.Min == w.Max {
		switch w.Orientation {
		case Vertical:
			return size.Height + endPad
		case Horizontal:
			return endPad
		}
	}
	ratio := float32((w.Value - w.Min) / (w.Max - w.Min))