Skip to content

Commit

Permalink
Merge branch 'develop' into themed-resource-colorize
Browse files Browse the repository at this point in the history
  • Loading branch information
dweymouth authored Jan 24, 2024
2 parents 717a5e1 + 8c59d6e commit b949478
Show file tree
Hide file tree
Showing 95 changed files with 774 additions and 557 deletions.
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,26 @@
This file lists the main changes with each version of the Fyne toolkit.
More detailed release notes can be found on the [releases page](https://github.com/fyne-io/fyne/releases).

## 2.5.0 - Ongoing

### Added

* Activity indicator widget
* InnerWindow and MultipleWindows containers

### Changed

### Fixed


## 2.4.4 - Ongoing

### Fixed

* Spaces could be appended to linux Exec command during packaging
* Secondary mobile windows would not size correctly when padded


## 2.4.3 - 23 December 2023

### Fixed
Expand Down
44 changes: 14 additions & 30 deletions canvas/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,15 @@ import (
"sync"

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

type baseObject struct {
size fyne.Size // The current size of the canvas object
position fyne.Position // The current position of the object
Hidden bool // Is this object currently hidden
size async.Size // The current size of the canvas object
position async.Position // The current position of the object
Hidden bool // Is this object currently hidden

min fyne.Size // The minimum size this object can be
min async.Size // The minimum size this object can be

propertyLock sync.RWMutex
}
Expand All @@ -33,46 +34,32 @@ func (o *baseObject) Hide() {

// MinSize returns the specified minimum size, if set, or {1, 1} otherwise.
func (o *baseObject) MinSize() fyne.Size {
o.propertyLock.RLock()
defer o.propertyLock.RUnlock()

if o.min.Width == 0 && o.min.Height == 0 {
return fyne.NewSize(1, 1)
min := o.min.Load()
if min.IsZero() {
return fyne.Size{Width: 1, Height: 1}
}

return o.min
return min
}

// Move the object to a new position, relative to its parent.
func (o *baseObject) Move(pos fyne.Position) {
o.propertyLock.Lock()
defer o.propertyLock.Unlock()

o.position = pos
o.position.Store(pos)
}

// Position gets the current position of this canvas object, relative to its parent.
func (o *baseObject) Position() fyne.Position {
o.propertyLock.RLock()
defer o.propertyLock.RUnlock()

return o.position
return o.position.Load()
}

// Resize sets a new size for the canvas object.
func (o *baseObject) Resize(size fyne.Size) {
o.propertyLock.Lock()
defer o.propertyLock.Unlock()

o.size = size
o.size.Store(size)
}

// SetMinSize specifies the smallest size this object should be.
func (o *baseObject) SetMinSize(size fyne.Size) {
o.propertyLock.Lock()
defer o.propertyLock.Unlock()

o.min = size
o.min.Store(size)
}

// Show will set this object to be visible.
Expand All @@ -85,10 +72,7 @@ func (o *baseObject) Show() {

// Size returns the current size of this canvas object.
func (o *baseObject) Size() fyne.Size {
o.propertyLock.RLock()
defer o.propertyLock.RUnlock()

return o.size
return o.size.Load()
}

// Visible returns true if this object is visible, false otherwise.
Expand Down
2 changes: 1 addition & 1 deletion canvas/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ func (i *Image) Resize(s fyne.Size) {
return
}
i.baseObject.Resize(s)
if i.FillMode == ImageFillOriginal && i.size.Height > 2 { // we can just ask for a GPU redraw to align
if i.FillMode == ImageFillOriginal && i.Size().Height > 2 { // we can just ask for a GPU redraw to align
Refresh(i)
return
}
Expand Down
2 changes: 2 additions & 0 deletions cmd/fyne_demo/tutorials/icons.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,10 @@ func loadIcons() []iconInfo {
{"SearchReplaceIcon", theme.SearchReplaceIcon()},

{"CheckButtonIcon", theme.CheckButtonIcon()},
{"CheckButtonFillIcon", theme.CheckButtonFillIcon()},
{"CheckButtonCheckedIcon", theme.CheckButtonCheckedIcon()},
{"RadioButtonIcon", theme.RadioButtonIcon()},
{"RadioButtonFillIcon", theme.RadioButtonFillIcon()},
{"RadioButtonCheckedIcon", theme.RadioButtonCheckedIcon()},

{"ColorAchromaticIcon", theme.ColorAchromaticIcon()},
Expand Down
27 changes: 0 additions & 27 deletions container/tabs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,9 @@ import (

"github.com/stretchr/testify/assert"

"fyne.io/fyne/v2"
"fyne.io/fyne/v2/canvas"
"fyne.io/fyne/v2/internal/cache"
intTest "fyne.io/fyne/v2/internal/test"
"fyne.io/fyne/v2/test"
"fyne.io/fyne/v2/theme"
"fyne.io/fyne/v2/widget"
)

func TestTabButton_Icon_Change(t *testing.T) {
Expand All @@ -24,26 +20,3 @@ func TestTabButton_Icon_Change(t *testing.T) {
b.Refresh()
assert.NotEqual(t, oldResource, icon.Resource)
}

func TestTab_ThemeChange(t *testing.T) {
a := test.NewApp()
defer test.NewApp()
firstTheme := a.Settings().Theme()

tabs := NewAppTabs(
NewTabItem("a", widget.NewLabel("a")),
NewTabItem("b", widget.NewLabel("b")))
w := test.NewWindow(tabs)
w.Resize(fyne.NewSquareSize(150))

initial := w.Canvas().Capture()

a.Settings().SetTheme(intTest.DarkTheme(theme.DefaultTheme()))
tabs.SelectIndex(1)
second := w.Canvas().Capture()
assert.NotEqual(t, initial, second)

a.Settings().SetTheme(firstTheme)
tabs.SelectIndex(0)
assert.Equal(t, initial, w.Canvas().Capture())
}
52 changes: 52 additions & 0 deletions internal/async/vector.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package async

import (
"math"
"sync/atomic"

"fyne.io/fyne/v2"
)

// Position is an atomic version of fyne.Position.
// Loads and stores are guaranteed to happen using a single atomic operation.
type Position struct {
pos atomic.Uint64
}

// Load performs an atomic load on the fyne.Position value.
func (p *Position) Load() fyne.Position {
return fyne.NewPos(twoFloat32FromUint64(p.pos.Load()))
}

// Store performs an atomic store on the fyne.Position value.
func (p *Position) Store(pos fyne.Position) {
p.pos.Store(uint64fromTwoFloat32(pos.X, pos.Y))
}

// Size is an atomic version of fyne.Size.
// Loads and stores are guaranteed to happen using a single atomic operation.
type Size struct {
size atomic.Uint64
}

// Load performs an atomic load on the fyne.Size value.
func (s *Size) Load() fyne.Size {
return fyne.NewSize(twoFloat32FromUint64(s.size.Load()))
}

// Store performs an atomic store on the fyne.Size value.
func (s *Size) Store(size fyne.Size) {
s.size.Store(uint64fromTwoFloat32(size.Width, size.Height))
}

func uint64fromTwoFloat32(a, b float32) uint64 {
x := uint64(math.Float32bits(a))
y := uint64(math.Float32bits(b))
return (y << 32) | x
}

func twoFloat32FromUint64(combined uint64) (float32, float32) {
x := uint32(combined)
y := uint32(combined >> 32)
return math.Float32frombits(x), math.Float32frombits(y)
}
62 changes: 62 additions & 0 deletions internal/async/vector_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package async_test

import (
"testing"

"fyne.io/fyne/v2"
"fyne.io/fyne/v2/internal/async"
"github.com/stretchr/testify/assert"
)

var globalSize fyne.Size

func BenchmarkAtomicLoadAndStore(b *testing.B) {
local := fyne.Size{}
size := async.Size{}

// Each loop iteration replicates how .Resize() in BaseWidget checks size changes.
for i := 0; i < b.N; i++ {
new := fyne.Size{Width: float32(i), Height: float32(i)}
if new == size.Load() {
continue
}

size.Store(new)
}

globalSize = local
}

func TestSize(t *testing.T) {
size := async.Size{}
assert.Equal(t, fyne.Size{}, size.Load())

square := fyne.NewSquareSize(100)
size.Store(square)
assert.Equal(t, square, size.Load())

uneven := fyne.NewSize(125, 600)
size.Store(uneven)
assert.Equal(t, uneven, size.Load())

floats := fyne.NewSize(-22.565, 133.333)
size.Store(floats)
assert.Equal(t, floats, size.Load())
}

func TestPosition(t *testing.T) {
pos := async.Position{}
assert.Equal(t, fyne.Position{}, pos.Load())

even := fyne.NewSquareOffsetPos(100)
pos.Store(even)
assert.Equal(t, even, pos.Load())

uneven := fyne.NewPos(125, 600)
pos.Store(uneven)
assert.Equal(t, uneven, pos.Load())

floats := fyne.NewPos(-22.565, 133.333)
pos.Store(floats)
assert.Equal(t, floats, pos.Load())
}
6 changes: 5 additions & 1 deletion internal/driver/mobile/canvas.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,11 @@ func (c *mobileCanvas) sizeContent(size fyne.Size) {
if c.windowHead != nil {
topHeight := c.windowHead.MinSize().Height

if len(c.windowHead.(*fyne.Container).Objects) > 1 {
chromeBox := c.windowHead.(*fyne.Container)
if c.padded {
chromeBox = chromeBox.Objects[0].(*fyne.Container) // the padded container
}
if len(chromeBox.Objects) > 1 {
c.windowHead.Resize(fyne.NewSize(areaSize.Width, topHeight))
offset = fyne.NewPos(0, topHeight)
areaSize = areaSize.Subtract(offset)
Expand Down
Loading

0 comments on commit b949478

Please sign in to comment.