diff --git a/internal/widget/base.go b/internal/widget/base.go new file mode 100644 index 0000000000..d8d73fcea4 --- /dev/null +++ b/internal/widget/base.go @@ -0,0 +1,83 @@ +package widget + +import ( + "fyne.io/fyne" + "fyne.io/fyne/canvas" + "fyne.io/fyne/internal/cache" +) + +type base struct { + hidden bool + pos fyne.Position + size fyne.Size +} + +// Move satisfies the fyne.Widget interface. +func (b *base) Move(pos fyne.Position) { + b.pos = pos +} + +// Position satisfies the fyne.Widget interface. +func (b *base) Position() fyne.Position { + return b.pos +} + +// Size satisfies the fyne.Widget interface. +func (b *base) Size() fyne.Size { + return b.size +} + +// Visible satisfies the fyne.Widget interface. +func (b *base) Visible() bool { + return !b.hidden +} + +func (b *base) hide(w fyne.Widget) { + if b.hidden { + return + } + + b.hidden = true + canvas.Refresh(w) +} + +func (b *base) minSize(w fyne.Widget) fyne.Size { + r := cache.Renderer(w) + if r == nil { + return fyne.NewSize(0, 0) + } + + return r.MinSize() +} + +func (b *base) refresh(w fyne.Widget) { + r := cache.Renderer(w) + if r == nil { + return + } + + r.Refresh() +} + +func (b *base) resize(size fyne.Size, w fyne.Widget) { + if b.size == size { + return + } + + b.size = size + r := cache.Renderer(w) + if r == nil { + return + } + + r.Layout(size) +} + +func (b *base) show(w fyne.Widget) { + if !b.hidden { + return + } + + b.hidden = false + w.Refresh() +} diff --git a/internal/widget/base_renderer.go b/internal/widget/base_renderer.go new file mode 100644 index 0000000000..261c6f8e77 --- /dev/null +++ b/internal/widget/base_renderer.go @@ -0,0 +1,38 @@ +package widget + +import ( + "image/color" + + "fyne.io/fyne" + "fyne.io/fyne/theme" +) + +// BaseRenderer is a renderer base providing the most common implementations of a part of the +// widget.Renderer interface. +type BaseRenderer struct { + objects []fyne.CanvasObject +} + +// NewBaseRenderer creates a new BaseRenderer. +func NewBaseRenderer(objects []fyne.CanvasObject) BaseRenderer { + return BaseRenderer{objects} +} + +// BackgroundColor satisfies the fyne.WidgetRenderer interface. +func (r *BaseRenderer) BackgroundColor() color.Color { + return theme.BackgroundColor() +} + +// Destroy satisfies the fyne.WidgetRenderer interface. +func (r *BaseRenderer) Destroy() { +} + +// Objects satisfies the fyne.WidgetRenderer interface. +func (r *BaseRenderer) Objects() []fyne.CanvasObject { + return r.objects +} + +// SetObjects updates the objects of the renderer. +func (r *BaseRenderer) SetObjects(objects []fyne.CanvasObject) { + r.objects = objects +} diff --git a/internal/widget/menu_item.go b/internal/widget/menu_item.go new file mode 100644 index 0000000000..9531be0ca2 --- /dev/null +++ b/internal/widget/menu_item.go @@ -0,0 +1,129 @@ +package widget + +import ( + "image/color" + + "fyne.io/fyne" + "fyne.io/fyne/canvas" + "fyne.io/fyne/driver/desktop" + "fyne.io/fyne/theme" +) + +var _ fyne.Widget = (*MenuItem)(nil) + +// MenuItem is a widget for displaying a fyne.MenuItem. +type MenuItem struct { + base + DismissAction func() + Item *fyne.MenuItem + + hovered bool +} + +// NewMenuItem creates a new MenuItem. +func NewMenuItem(item *fyne.MenuItem) *MenuItem { + return &MenuItem{Item: item} +} + +// NewMenuItemSeparator creates a separator meant to separate MenuItems. +func NewMenuItemSeparator() fyne.CanvasObject { + s := canvas.NewRectangle(theme.DisabledTextColor()) + s.SetMinSize(fyne.NewSize(1, 2)) + return s +} + +// CreateRenderer satisfies the fyne.Widget interface. +func (i *MenuItem) CreateRenderer() fyne.WidgetRenderer { + text := canvas.NewText(i.Item.Label, theme.TextColor()) + return &menuItemRenderer{NewBaseRenderer([]fyne.CanvasObject{text}), i, text} +} + +// Hide satisfies the fyne.Widget interface. +func (i *MenuItem) Hide() { + i.hide(i) +} + +// MinSize satisfies the fyne.Widget interface. +func (i *MenuItem) MinSize() fyne.Size { + return i.minSize(i) +} + +// MouseIn satisfies the desktop.Hoverable interface. +func (i *MenuItem) MouseIn(*desktop.MouseEvent) { + i.hovered = true + i.Refresh() +} + +// MouseMoved satisfies the desktop.Hoverable interface. +func (i *MenuItem) MouseMoved(*desktop.MouseEvent) { +} + +// MouseOut satisfies the desktop.Hoverable interface. +func (i *MenuItem) MouseOut() { + i.hovered = false + i.Refresh() +} + +// Refresh satisfies the fyne.Widget interface. +func (i *MenuItem) Refresh() { + i.refresh(i) +} + +// Resize satisfies the fyne.Widget interface. +func (i *MenuItem) Resize(size fyne.Size) { + i.resize(size, i) +} + +// Show satisfies the fyne.Widget interface. +func (i *MenuItem) Show() { + i.show(i) +} + +// Tapped satisfies the fyne.Tappable interface. +func (i *MenuItem) Tapped(*fyne.PointEvent) { + i.Item.Action() + if i.DismissAction != nil { + i.DismissAction() + } +} + +type menuItemRenderer struct { + BaseRenderer + i *MenuItem + text *canvas.Text +} + +// BackgroundColor satisfies the fyne.WidgetRenderer interface. +func (r *menuItemRenderer) BackgroundColor() color.Color { + if r.i.hovered { + return theme.HoverColor() + } + + return color.Transparent +} + +// Layout satisfies the fyne.WidgetRenderer interface. +func (r *menuItemRenderer) Layout(fyne.Size) { + padding := r.padding() + r.text.Resize(r.text.MinSize()) + r.text.Move(fyne.NewPos(padding.Width/2, padding.Height/2)) +} + +// MinSize satisfies the fyne.WidgetRenderer interface. +func (r *menuItemRenderer) MinSize() fyne.Size { + return r.text.MinSize().Add(r.padding()) +} + +// Refresh satisfies the fyne.WidgetRenderer interface. +func (r *menuItemRenderer) Refresh() { + if r.text.TextSize != theme.TextSize() { + defer r.Layout(r.i.Size()) + } + r.text.TextSize = theme.TextSize() + r.text.Color = theme.TextColor() + canvas.Refresh(r.text) +} + +func (r *menuItemRenderer) padding() fyne.Size { + return fyne.NewSize(theme.Padding()*4, theme.Padding()*2) +} diff --git a/widget/shadow.go b/internal/widget/shadow.go similarity index 64% rename from widget/shadow.go rename to internal/widget/shadow.go index 0001be1c76..f272c0c74c 100644 --- a/widget/shadow.go +++ b/internal/widget/shadow.go @@ -8,134 +8,90 @@ import ( "fyne.io/fyne/theme" ) -// elevationLevel is the level of elevation of the shadow casting object. -type elevationLevel int +var _ fyne.Widget = (*Shadow)(nil) -// elevationLevel constants inspired by: +// Shadow is a widget that renders a shadow. +type Shadow struct { + base + level ElevationLevel + typ ShadowType +} + +// ElevationLevel is the level of elevation of the shadow casting object. +type ElevationLevel int + +// ElevationLevel constants inspired by: // https://storage.googleapis.com/spec-host/mio-staging%2Fmio-design%2F1584058305895%2Fassets%2F0B6xUSjjSulxceF9udnA4Sk5tdU0%2Fbaselineelevation-chart.png const ( - baseLevel elevationLevel = 0 - buttonLevel elevationLevel = 2 - popUpLevel elevationLevel = 8 - submergedContentLevel elevationLevel = 8 + BaseLevel ElevationLevel = 0 + ButtonLevel ElevationLevel = 2 + PopUpLevel ElevationLevel = 8 + SubmergedContentLevel ElevationLevel = 8 ) -type shadowType int +// ShadowType specifies the type of the shadow. +type ShadowType int +// ShadowType constants const ( - shadowAround shadowType = iota - shadowLeft - shadowRight - shadowBottom - shadowTop + ShadowAround ShadowType = iota + ShadowLeft + ShadowRight + ShadowBottom + ShadowTop ) -func newShadow(typ shadowType, level elevationLevel) *shadow { - s := &shadow{typ: typ, level: level} - s.ExtendBaseWidget(s) - return s +// NewShadow create a new Shadow. +func NewShadow(typ ShadowType, level ElevationLevel) *Shadow { + return &Shadow{typ: typ, level: level} } -var _ fyne.Widget = (*shadow)(nil) - -type shadow struct { - BaseWidget - typ shadowType - level elevationLevel -} - -func (s *shadow) CreateRenderer() fyne.WidgetRenderer { +// CreateRenderer satisfies the fyne.Widget interface. +func (s *Shadow) CreateRenderer() fyne.WidgetRenderer { r := &shadowRenderer{s: s} r.createShadows() return r } -type shadowRenderer struct { - baseRenderer - b, l, r, t *canvas.LinearGradient - bl, br, tl, tr *canvas.RadialGradient - minSize fyne.Size - s *shadow +// Hide satisfies the fyne.Widget interface. +func (s *Shadow) Hide() { + s.hide(s) } -func (r *shadowRenderer) createShadows() { - switch r.s.typ { - case shadowLeft: - r.l = canvas.NewHorizontalGradient(color.Transparent, theme.ShadowColor()) - r.setObjects([]fyne.CanvasObject{r.l}) - case shadowRight: - r.r = canvas.NewHorizontalGradient(theme.ShadowColor(), color.Transparent) - r.setObjects([]fyne.CanvasObject{r.r}) - case shadowBottom: - r.b = canvas.NewVerticalGradient(theme.ShadowColor(), color.Transparent) - r.setObjects([]fyne.CanvasObject{r.b}) - case shadowTop: - r.t = canvas.NewVerticalGradient(color.Transparent, theme.ShadowColor()) - r.setObjects([]fyne.CanvasObject{r.t}) - case shadowAround: - r.tl = canvas.NewRadialGradient(theme.ShadowColor(), color.Transparent) - r.tl.CenterOffsetX = 0.5 - r.tl.CenterOffsetY = 0.5 - r.t = canvas.NewVerticalGradient(color.Transparent, theme.ShadowColor()) - r.tr = canvas.NewRadialGradient(theme.ShadowColor(), color.Transparent) - r.tr.CenterOffsetX = -0.5 - r.tr.CenterOffsetY = 0.5 - r.r = canvas.NewHorizontalGradient(theme.ShadowColor(), color.Transparent) - r.br = canvas.NewRadialGradient(theme.ShadowColor(), color.Transparent) - r.br.CenterOffsetX = -0.5 - r.br.CenterOffsetY = -0.5 - r.b = canvas.NewVerticalGradient(theme.ShadowColor(), color.Transparent) - r.bl = canvas.NewRadialGradient(theme.ShadowColor(), color.Transparent) - r.bl.CenterOffsetX = 0.5 - r.bl.CenterOffsetY = -0.5 - r.l = canvas.NewHorizontalGradient(color.Transparent, theme.ShadowColor()) - r.setObjects([]fyne.CanvasObject{r.tl, r.t, r.tr, r.r, r.br, r.b, r.bl, r.l}) - } +// MinSize satisfies the fyne.Widget interface. +func (s *Shadow) MinSize() fyne.Size { + return s.minSize(s) } -func updateShadowStart(g *canvas.LinearGradient) { - if g == nil { - return - } - - g.StartColor = theme.ShadowColor() - g.Refresh() +// Refresh satisfies the fyne.Widget interface. +func (s *Shadow) Refresh() { + s.refresh(s) } -func updateShadowEnd(g *canvas.LinearGradient) { - if g == nil { - return - } - - g.EndColor = theme.ShadowColor() - g.Refresh() +// Resize satisfies the fyne.Widget interface. +func (s *Shadow) Resize(size fyne.Size) { + s.resize(size, s) } -func updateShadowRadial(g *canvas.RadialGradient) { - if g == nil { - return - } - - g.StartColor = theme.ShadowColor() - g.Refresh() +// Show satisfies the fyne.Widget interface. +func (s *Shadow) Show() { + s.show(s) } -func (r *shadowRenderer) refreshShadows() { - updateShadowEnd(r.l) - updateShadowStart(r.r) - updateShadowStart(r.b) - updateShadowEnd(r.t) - - updateShadowRadial(r.tl) - updateShadowRadial(r.tr) - updateShadowRadial(r.bl) - updateShadowRadial(r.br) +type shadowRenderer struct { + BaseRenderer + b, l, r, t *canvas.LinearGradient + bl, br, tl, tr *canvas.RadialGradient + minSize fyne.Size + s *Shadow } +// BackgroundColor satisfies the fyne.WidgetRenderer interface. func (r *shadowRenderer) BackgroundColor() color.Color { return color.Transparent } +// Layout satisfies the fyne.WidgetRenderer interface. func (r *shadowRenderer) Layout(size fyne.Size) { depth := int(r.s.level) if r.tl != nil { @@ -172,11 +128,87 @@ func (r *shadowRenderer) Layout(size fyne.Size) { } } +// MinSize satisfies the fyne.WidgetRenderer interface. func (r *shadowRenderer) MinSize() fyne.Size { return r.minSize } +// Refresh satisfies the fyne.WidgetRenderer interface. func (r *shadowRenderer) Refresh() { r.refreshShadows() r.Layout(r.s.Size()) } + +func (r *shadowRenderer) createShadows() { + switch r.s.typ { + case ShadowLeft: + r.l = canvas.NewHorizontalGradient(color.Transparent, theme.ShadowColor()) + r.SetObjects([]fyne.CanvasObject{r.l}) + case ShadowRight: + r.r = canvas.NewHorizontalGradient(theme.ShadowColor(), color.Transparent) + r.SetObjects([]fyne.CanvasObject{r.r}) + case ShadowBottom: + r.b = canvas.NewVerticalGradient(theme.ShadowColor(), color.Transparent) + r.SetObjects([]fyne.CanvasObject{r.b}) + case ShadowTop: + r.t = canvas.NewVerticalGradient(color.Transparent, theme.ShadowColor()) + r.SetObjects([]fyne.CanvasObject{r.t}) + case ShadowAround: + r.tl = canvas.NewRadialGradient(theme.ShadowColor(), color.Transparent) + r.tl.CenterOffsetX = 0.5 + r.tl.CenterOffsetY = 0.5 + r.t = canvas.NewVerticalGradient(color.Transparent, theme.ShadowColor()) + r.tr = canvas.NewRadialGradient(theme.ShadowColor(), color.Transparent) + r.tr.CenterOffsetX = -0.5 + r.tr.CenterOffsetY = 0.5 + r.r = canvas.NewHorizontalGradient(theme.ShadowColor(), color.Transparent) + r.br = canvas.NewRadialGradient(theme.ShadowColor(), color.Transparent) + r.br.CenterOffsetX = -0.5 + r.br.CenterOffsetY = -0.5 + r.b = canvas.NewVerticalGradient(theme.ShadowColor(), color.Transparent) + r.bl = canvas.NewRadialGradient(theme.ShadowColor(), color.Transparent) + r.bl.CenterOffsetX = 0.5 + r.bl.CenterOffsetY = -0.5 + r.l = canvas.NewHorizontalGradient(color.Transparent, theme.ShadowColor()) + r.SetObjects([]fyne.CanvasObject{r.tl, r.t, r.tr, r.r, r.br, r.b, r.bl, r.l}) + } +} + +func (r *shadowRenderer) refreshShadows() { + updateShadowEnd(r.l) + updateShadowStart(r.r) + updateShadowStart(r.b) + updateShadowEnd(r.t) + + updateShadowRadial(r.tl) + updateShadowRadial(r.tr) + updateShadowRadial(r.bl) + updateShadowRadial(r.br) +} + +func updateShadowEnd(g *canvas.LinearGradient) { + if g == nil { + return + } + + g.EndColor = theme.ShadowColor() + g.Refresh() +} + +func updateShadowRadial(g *canvas.RadialGradient) { + if g == nil { + return + } + + g.StartColor = theme.ShadowColor() + g.Refresh() +} + +func updateShadowStart(g *canvas.LinearGradient) { + if g == nil { + return + } + + g.StartColor = theme.ShadowColor() + g.Refresh() +} diff --git a/widget/shadow_test.go b/internal/widget/shadow_test.go similarity index 92% rename from widget/shadow_test.go rename to internal/widget/shadow_test.go index b6d04aa764..f0bc5fa6dc 100644 --- a/widget/shadow_test.go +++ b/internal/widget/shadow_test.go @@ -11,37 +11,22 @@ import ( "github.com/stretchr/testify/assert" ) -var shadowLevel = elevationLevel(5) +var shadowLevel = ElevationLevel(5) var shadowWidth = int(shadowLevel) -func TestShadow_TopShadow(t *testing.T) { - s := newShadow(shadowTop, shadowLevel) - r := test.WidgetRenderer(s).(*shadowRenderer) - r.Layout(fyne.NewSize(100, 100)) - - assert.Equal(t, []fyne.CanvasObject{r.t}, r.Objects()) - assert.Equal(t, fyne.NewSize(100, shadowWidth), r.t.Size()) - assert.Equal(t, fyne.NewPos(0, -shadowWidth), r.t.Position()) - assert.Equal(t, 0.0, r.t.Angle) - assert.Equal(t, color.Transparent, r.t.StartColor) - assert.Equal(t, theme.ShadowColor(), r.t.EndColor) -} - -func TestShadow_BottomShadow(t *testing.T) { - s := newShadow(shadowBottom, shadowLevel) +func TestShadow_ApplyTheme(t *testing.T) { + fyne.CurrentApp().Settings().SetTheme(theme.DarkTheme()) + s := NewShadow(ShadowAround, shadowLevel) r := test.WidgetRenderer(s).(*shadowRenderer) - r.Layout(fyne.NewSize(100, 100)) + assert.Equal(t, theme.ShadowColor(), r.b.StartColor) - assert.Equal(t, []fyne.CanvasObject{r.b}, r.Objects()) - assert.Equal(t, fyne.NewSize(100, shadowWidth), r.b.Size()) - assert.Equal(t, fyne.NewPos(0, 100), r.b.Position()) - assert.Equal(t, 0.0, r.b.Angle) + fyne.CurrentApp().Settings().SetTheme(theme.LightTheme()) + r.Refresh() assert.Equal(t, theme.ShadowColor(), r.b.StartColor) - assert.Equal(t, color.Transparent, r.b.EndColor) } func TestShadow_AroundShadow(t *testing.T) { - s := newShadow(shadowAround, shadowLevel) + s := NewShadow(ShadowAround, shadowLevel) r := test.WidgetRenderer(s).(*shadowRenderer) r.Layout(fyne.NewSize(100, 100)) @@ -104,27 +89,29 @@ func TestShadow_AroundShadow(t *testing.T) { assert.Equal(t, theme.ShadowColor(), r.l.EndColor) } -func TestShadow_ApplyTheme(t *testing.T) { - fyne.CurrentApp().Settings().SetTheme(theme.DarkTheme()) - s := newShadow(shadowAround, shadowLevel) +func TestShadow_BackgroundColor(t *testing.T) { + assert.Equal(t, color.Transparent, test.WidgetRenderer(NewShadow(ShadowAround, 1)).BackgroundColor()) +} + +func TestShadow_BottomShadow(t *testing.T) { + s := NewShadow(ShadowBottom, shadowLevel) r := test.WidgetRenderer(s).(*shadowRenderer) - assert.Equal(t, theme.ShadowColor(), r.b.StartColor) + r.Layout(fyne.NewSize(100, 100)) - fyne.CurrentApp().Settings().SetTheme(theme.LightTheme()) - r.Refresh() + assert.Equal(t, []fyne.CanvasObject{r.b}, r.Objects()) + assert.Equal(t, fyne.NewSize(100, shadowWidth), r.b.Size()) + assert.Equal(t, fyne.NewPos(0, 100), r.b.Position()) + assert.Equal(t, 0.0, r.b.Angle) assert.Equal(t, theme.ShadowColor(), r.b.StartColor) -} - -func TestShadow_BackgroundColor(t *testing.T) { - assert.Equal(t, color.Transparent, test.WidgetRenderer(newShadow(shadowAround, 1)).BackgroundColor()) + assert.Equal(t, color.Transparent, r.b.EndColor) } func TestShadow_MinSize(t *testing.T) { - assert.Equal(t, fyne.NewSize(0, 0), newShadow(shadowAround, 1).MinSize()) + assert.Equal(t, fyne.NewSize(0, 0), NewShadow(ShadowAround, 1).MinSize()) } func TestShadow_Theme(t *testing.T) { - shadow := newShadow(shadowAround, 1) + shadow := NewShadow(ShadowAround, 1) light := theme.LightTheme() fyne.CurrentApp().Settings().SetTheme(light) shadow.Refresh() @@ -139,3 +126,16 @@ func TestShadow_Theme(t *testing.T) { assert.Equal(t, dark.ShadowColor(), test.WidgetRenderer(shadow).(*shadowRenderer).r.StartColor) assert.Equal(t, dark.ShadowColor(), test.WidgetRenderer(shadow).(*shadowRenderer).tr.StartColor) } + +func TestShadow_TopShadow(t *testing.T) { + s := NewShadow(ShadowTop, shadowLevel) + r := test.WidgetRenderer(s).(*shadowRenderer) + r.Layout(fyne.NewSize(100, 100)) + + assert.Equal(t, []fyne.CanvasObject{r.t}, r.Objects()) + assert.Equal(t, fyne.NewSize(100, shadowWidth), r.t.Size()) + assert.Equal(t, fyne.NewPos(0, -shadowWidth), r.t.Position()) + assert.Equal(t, 0.0, r.t.Angle) + assert.Equal(t, color.Transparent, r.t.StartColor) + assert.Equal(t, theme.ShadowColor(), r.t.EndColor) +} diff --git a/internal/widget/shadowing_renderer.go b/internal/widget/shadowing_renderer.go new file mode 100644 index 0000000000..d9caa56fe6 --- /dev/null +++ b/internal/widget/shadowing_renderer.go @@ -0,0 +1,41 @@ +package widget + +import ( + "fyne.io/fyne" +) + +// ShadowingRenderer is a renderer that adds a shadow arount the rendered content. +// When using the ShadowingRenderer the embedding renderer should call +// LayoutShadow(contentSize, contentPos) to lay out the shadow. +type ShadowingRenderer struct { + BaseRenderer + shadow fyne.CanvasObject +} + +// NewShadowingRenderer creates a ShadowingRenderer. +func NewShadowingRenderer(objects []fyne.CanvasObject, level ElevationLevel) *ShadowingRenderer { + var s fyne.CanvasObject + if level > 0 { + s = NewShadow(ShadowAround, level) + } + r := &ShadowingRenderer{shadow: s} + r.SetObjects(objects) + return r +} + +// LayoutShadow adjusts the size and position of the shadow if necessary. +func (r *ShadowingRenderer) LayoutShadow(size fyne.Size, pos fyne.Position) { + if r.shadow == nil { + return + } + r.shadow.Resize(size) + r.shadow.Move(pos) +} + +// SetObjects updates the renderer's objects including the shadow if necessary. +func (r *ShadowingRenderer) SetObjects(objects []fyne.CanvasObject) { + if r.shadow != nil { + objects = append([]fyne.CanvasObject{r.shadow}, objects...) + } + r.BaseRenderer.SetObjects(objects) +} diff --git a/widget/shadowing_renderer_test.go b/internal/widget/shadowing_renderer_test.go similarity index 56% rename from widget/shadowing_renderer_test.go rename to internal/widget/shadowing_renderer_test.go index 9c3ac5fdc7..d17e535759 100644 --- a/widget/shadowing_renderer_test.go +++ b/internal/widget/shadowing_renderer_test.go @@ -1,4 +1,4 @@ -package widget +package widget_test import ( "testing" @@ -6,16 +6,18 @@ import ( "github.com/stretchr/testify/assert" "fyne.io/fyne" + w "fyne.io/fyne/internal/widget" + "fyne.io/fyne/widget" ) func TestShadowingRenderer_Objects(t *testing.T) { tests := map[string]struct { - level elevationLevel + level w.ElevationLevel wantPrependedObjects []fyne.CanvasObject }{ "with shadow": { 12, - []fyne.CanvasObject{newShadow(shadowAround, 12)}, + []fyne.CanvasObject{w.NewShadow(w.ShadowAround, 12)}, }, "without shadow": { 0, @@ -24,12 +26,12 @@ func TestShadowingRenderer_Objects(t *testing.T) { } for name, tt := range tests { t.Run(name, func(t *testing.T) { - objects := []fyne.CanvasObject{NewLabel("A"), NewLabel("B")} - r := newShadowingRenderer(objects, tt.level) + objects := []fyne.CanvasObject{widget.NewLabel("A"), widget.NewLabel("B")} + r := w.NewShadowingRenderer(objects, tt.level) assert.Equal(t, append(tt.wantPrependedObjects, objects...), r.Objects()) - otherObjects := []fyne.CanvasObject{NewLabel("X"), NewLabel("Y")} - r.setObjects(otherObjects) + otherObjects := []fyne.CanvasObject{widget.NewLabel("X"), widget.NewLabel("Y")} + r.SetObjects(otherObjects) assert.Equal(t, append(tt.wantPrependedObjects, otherObjects...), r.Objects()) }) } diff --git a/widget/base_renderer.go b/widget/base_renderer.go deleted file mode 100644 index 507619609a..0000000000 --- a/widget/base_renderer.go +++ /dev/null @@ -1,27 +0,0 @@ -package widget - -import ( - "image/color" - - "fyne.io/fyne" - "fyne.io/fyne/theme" -) - -type baseRenderer struct { - objects []fyne.CanvasObject -} - -func (r *baseRenderer) BackgroundColor() color.Color { - return theme.BackgroundColor() -} - -func (r *baseRenderer) Destroy() { -} - -func (r *baseRenderer) Objects() []fyne.CanvasObject { - return r.objects -} - -func (r *baseRenderer) setObjects(objects []fyne.CanvasObject) { - r.objects = objects -} diff --git a/widget/box.go b/widget/box.go index a94add3d6f..597afd1716 100644 --- a/widget/box.go +++ b/widget/box.go @@ -5,6 +5,7 @@ import ( "fyne.io/fyne" "fyne.io/fyne/canvas" + "fyne.io/fyne/internal/widget" "fyne.io/fyne/layout" "fyne.io/fyne/theme" ) @@ -58,7 +59,7 @@ func (b *Box) CreateRenderer() fyne.WidgetRenderer { lay = layout.NewVBoxLayout() } - return &boxRenderer{baseRenderer: baseRenderer{b.Children}, layout: lay, box: b} + return &boxRenderer{BaseRenderer: widget.NewBaseRenderer(b.Children), layout: lay, box: b} } func (b *Box) setBackgroundColor(bg color.Color) { @@ -76,7 +77,7 @@ func NewVBox(children ...fyne.CanvasObject) *Box { } type boxRenderer struct { - baseRenderer + widget.BaseRenderer layout fyne.Layout box *Box } @@ -98,7 +99,7 @@ func (b *boxRenderer) BackgroundColor() color.Color { } func (b *boxRenderer) Refresh() { - b.setObjects(b.box.Children) + b.SetObjects(b.box.Children) for _, child := range b.Objects() { child.Refresh() } diff --git a/widget/button.go b/widget/button.go index 447dbf4628..faecb4f300 100644 --- a/widget/button.go +++ b/widget/button.go @@ -7,11 +7,12 @@ import ( "fyne.io/fyne" "fyne.io/fyne/canvas" "fyne.io/fyne/driver/desktop" + "fyne.io/fyne/internal/widget" "fyne.io/fyne/theme" ) type buttonRenderer struct { - *shadowingRenderer + *widget.ShadowingRenderer icon *canvas.Image label *canvas.Text @@ -46,7 +47,7 @@ func (b *buttonRenderer) MinSize() fyne.Size { // Layout the components of the button widget func (b *buttonRenderer) Layout(size fyne.Size) { - b.layoutShadow(size, fyne.NewPos(0, 0)) + b.LayoutShadow(size, fyne.NewPos(0, 0)) if b.button.Text != "" { padding := b.padding() innerSize := size.Subtract(padding) @@ -99,7 +100,7 @@ func (b *buttonRenderer) Refresh() { if b.button.Icon != nil && b.button.Visible() { if b.icon == nil { b.icon = canvas.NewImageFromResource(b.button.Icon) - b.setObjects(append(b.Objects(), b.icon)) + b.SetObjects(append(b.Objects(), b.icon)) } else { if b.button.Disabled() { // if the icon has changed, create a new disabled version @@ -188,15 +189,15 @@ func (b *Button) CreateRenderer() fyne.WidgetRenderer { objects := []fyne.CanvasObject{ text, } - shadowLevel := buttonLevel + shadowLevel := widget.ButtonLevel if b.HideShadow { - shadowLevel = baseLevel + shadowLevel = widget.BaseLevel } if icon != nil { objects = append(objects, icon) } - return &buttonRenderer{newShadowingRenderer(objects, shadowLevel), icon, text, b} + return &buttonRenderer{widget.NewShadowingRenderer(objects, shadowLevel), icon, text, b} } // SetText allows the button label to be changed diff --git a/widget/button_test.go b/widget/button_test.go index fc1898933e..a30cfe8ce5 100644 --- a/widget/button_test.go +++ b/widget/button_test.go @@ -7,6 +7,7 @@ import ( "fyne.io/fyne" "fyne.io/fyne/driver/desktop" + "fyne.io/fyne/internal/widget" "fyne.io/fyne/test" "fyne.io/fyne/theme" @@ -232,9 +233,8 @@ func TestButton_Shadow(t *testing.T) { button := NewButton("Test", func() {}) shadowFound := false for _, o := range test.LaidOutObjects(button) { - if s, ok := o.(*shadow); ok { + if _, ok := o.(*widget.Shadow); ok { shadowFound = true - assert.Equal(t, elevationLevel(2), s.level) } } if !shadowFound { @@ -245,7 +245,7 @@ func TestButton_Shadow(t *testing.T) { button := NewButton("Test", func() {}) button.HideShadow = true for _, o := range test.LaidOutObjects(button) { - if _, ok := o.(*shadow); ok { + if _, ok := o.(*widget.Shadow); ok { assert.Fail(t, "button with HideShadow == true should not create a shadow") } } diff --git a/widget/check.go b/widget/check.go index 0737184a45..b7f1c9db32 100644 --- a/widget/check.go +++ b/widget/check.go @@ -4,11 +4,12 @@ import ( "fyne.io/fyne" "fyne.io/fyne/canvas" "fyne.io/fyne/driver/desktop" + "fyne.io/fyne/internal/widget" "fyne.io/fyne/theme" ) type checkRenderer struct { - baseRenderer + widget.BaseRenderer icon *canvas.Image label *canvas.Text focusIndicator *canvas.Circle @@ -158,7 +159,13 @@ func (c *Check) CreateRenderer() fyne.WidgetRenderer { text.Alignment = fyne.TextAlignLeading focusIndicator := canvas.NewCircle(theme.BackgroundColor()) - return &checkRenderer{baseRenderer{[]fyne.CanvasObject{focusIndicator, icon, text}}, icon, text, focusIndicator, c} + return &checkRenderer{ + widget.NewBaseRenderer([]fyne.CanvasObject{focusIndicator, icon, text}), + icon, + text, + focusIndicator, + c, + } } // NewCheck creates a new check widget with the set label and change handler diff --git a/widget/entry.go b/widget/entry.go index 541cc42482..dfdbe2f1c7 100644 --- a/widget/entry.go +++ b/widget/entry.go @@ -10,6 +10,7 @@ import ( "fyne.io/fyne" "fyne.io/fyne/canvas" "fyne.io/fyne/driver/desktop" + "fyne.io/fyne/internal/widget" "fyne.io/fyne/theme" ) @@ -1154,7 +1155,7 @@ func NewPasswordEntry() *Entry { } type passwordRevealerRenderer struct { - baseRenderer + widget.BaseRenderer entry *Entry icon *canvas.Image } @@ -1189,7 +1190,7 @@ type passwordRevealer struct { func (pr *passwordRevealer) CreateRenderer() fyne.WidgetRenderer { return &passwordRevealerRenderer{ - baseRenderer: baseRenderer{[]fyne.CanvasObject{pr.icon}}, + BaseRenderer: widget.NewBaseRenderer([]fyne.CanvasObject{pr.icon}), icon: pr.icon, entry: pr.entry, } diff --git a/widget/group.go b/widget/group.go index 8c14f4db07..d6a0ccfaa0 100644 --- a/widget/group.go +++ b/widget/group.go @@ -3,6 +3,7 @@ package widget import ( "fyne.io/fyne" "fyne.io/fyne/canvas" + "fyne.io/fyne/internal/widget" "fyne.io/fyne/theme" ) @@ -42,7 +43,7 @@ func (g *Group) CreateRenderer() fyne.WidgetRenderer { labelBg := canvas.NewRectangle(theme.BackgroundColor()) line := canvas.NewRectangle(theme.ButtonColor()) return &groupRenderer{ - baseRenderer: baseRenderer{[]fyne.CanvasObject{line, labelBg, label, g.content}}, + BaseRenderer: widget.NewBaseRenderer([]fyne.CanvasObject{line, labelBg, label, g.content}), label: label, line: line, labelBg: labelBg, @@ -70,7 +71,7 @@ func NewGroupWithScroller(title string, children ...fyne.CanvasObject) *Group { } type groupRenderer struct { - baseRenderer + widget.BaseRenderer label *Label line, labelBg *canvas.Rectangle group *Group diff --git a/widget/icon.go b/widget/icon.go index 247869bbf2..816efd17d3 100644 --- a/widget/icon.go +++ b/widget/icon.go @@ -5,11 +5,12 @@ import ( "fyne.io/fyne" "fyne.io/fyne/canvas" + "fyne.io/fyne/internal/widget" "fyne.io/fyne/theme" ) type iconRenderer struct { - baseRenderer + widget.BaseRenderer image *Icon } @@ -31,13 +32,13 @@ func (i *iconRenderer) BackgroundColor() color.Color { } func (i *iconRenderer) Refresh() { - i.setObjects(nil) + i.SetObjects(nil) if i.image.Resource != nil { raster := canvas.NewImageFromResource(i.image.Resource) raster.FillMode = canvas.ImageFillContain - i.setObjects([]fyne.CanvasObject{raster}) + i.SetObjects([]fyne.CanvasObject{raster}) } i.Layout(i.image.Size()) diff --git a/widget/icon_test.go b/widget/icon_test.go index 56e0f5f763..b2a3e9c58c 100644 --- a/widget/icon_test.go +++ b/widget/icon_test.go @@ -40,8 +40,8 @@ func TestIcon_MinSize(t *testing.T) { func TestIconRenderer_ApplyTheme(t *testing.T) { icon := NewIcon(theme.CancelIcon()) render := test.WidgetRenderer(icon).(*iconRenderer) - visible := render.objects[0].Visible() + visible := render.Objects()[0].Visible() render.Refresh() - assert.Equal(t, visible, render.objects[0].Visible()) + assert.Equal(t, visible, render.Objects()[0].Visible()) } diff --git a/widget/menu.go b/widget/menu.go index cd15f7550c..de55516190 100644 --- a/widget/menu.go +++ b/widget/menu.go @@ -1,12 +1,8 @@ package widget import ( - "image/color" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/driver/desktop" - "fyne.io/fyne/theme" + "fyne.io/fyne/internal/widget" ) // NewPopUpMenuAtPosition creates a PopUp widget populated with menu items from the passed menu structure. @@ -15,16 +11,16 @@ func NewPopUpMenuAtPosition(menu *fyne.Menu, c fyne.Canvas, pos fyne.Position) * options := NewVBox() for _, item := range menu.Items { if item.IsSeparator { - options.Append(newSeparator()) + options.Append(widget.NewMenuItemSeparator()) } else { - options.Append(newMenuItemWidget(item)) + options.Append(widget.NewMenuItem(item)) } } pop := newPopUp(options, c) pop.NotPadded = true focused := c.Focused() for _, o := range options.Children { - if item, ok := o.(*menuItemWidget); ok { + if item, ok := o.(*widget.MenuItem); ok { item.DismissAction = func() { if c.Focused() == nil { c.Focus(focused) @@ -42,88 +38,3 @@ func NewPopUpMenuAtPosition(menu *fyne.Menu, c fyne.Canvas, pos fyne.Position) * func NewPopUpMenu(menu *fyne.Menu, c fyne.Canvas) *PopUp { return NewPopUpMenuAtPosition(menu, c, fyne.NewPos(0, 0)) } - -type menuItemWidget struct { - BaseWidget - DismissAction func() - Item *fyne.MenuItem - - hovered bool -} - -func (t *menuItemWidget) Tapped(*fyne.PointEvent) { - t.Item.Action() - if t.DismissAction != nil { - t.DismissAction() - } -} - -func (t *menuItemWidget) CreateRenderer() fyne.WidgetRenderer { - text := canvas.NewText(t.Item.Label, theme.TextColor()) - return &menuItemWidgetRenderer{baseRenderer{[]fyne.CanvasObject{text}}, text, t} -} - -// MouseIn is called when a desktop pointer enters the widget -func (t *menuItemWidget) MouseIn(*desktop.MouseEvent) { - t.hovered = true - t.Refresh() -} - -// MouseOut is called when a desktop pointer exits the widget -func (t *menuItemWidget) MouseOut() { - t.hovered = false - t.Refresh() -} - -// MouseMoved is called when a desktop pointer hovers over the widget -func (t *menuItemWidget) MouseMoved(*desktop.MouseEvent) { -} - -func newMenuItemWidget(item *fyne.MenuItem) *menuItemWidget { - ret := &menuItemWidget{Item: item} - ret.ExtendBaseWidget(ret) - return ret -} - -type menuItemWidgetRenderer struct { - baseRenderer - text *canvas.Text - w *menuItemWidget -} - -func (r *menuItemWidgetRenderer) Layout(size fyne.Size) { - padding := r.padding() - r.text.Resize(r.text.MinSize()) - r.text.Move(fyne.NewPos(padding.Width/2, padding.Height/2)) -} - -func (r *menuItemWidgetRenderer) MinSize() fyne.Size { - return r.text.MinSize().Add(r.padding()) -} - -func (r *menuItemWidgetRenderer) Refresh() { - if r.text.TextSize != theme.TextSize() { - defer r.Layout(r.w.Size()) - } - r.text.TextSize = theme.TextSize() - r.text.Color = theme.TextColor() - canvas.Refresh(r.text) -} - -func (r *menuItemWidgetRenderer) BackgroundColor() color.Color { - if r.w.hovered { - return theme.HoverColor() - } - - return color.Transparent -} - -func (r *menuItemWidgetRenderer) padding() fyne.Size { - return fyne.NewSize(theme.Padding()*4, theme.Padding()*2) -} - -func newSeparator() fyne.CanvasObject { - s := canvas.NewRectangle(theme.DisabledTextColor()) - s.SetMinSize(fyne.NewSize(1, 2)) - return s -} diff --git a/widget/menu_test.go b/widget/menu_test.go index 1754ece4e8..ff905632fe 100644 --- a/widget/menu_test.go +++ b/widget/menu_test.go @@ -6,6 +6,7 @@ import ( "fyne.io/fyne" "fyne.io/fyne/canvas" + "fyne.io/fyne/internal/widget" "fyne.io/fyne/test" "fyne.io/fyne/theme" @@ -41,7 +42,7 @@ func TestPopUpMenu_Size(t *testing.T) { assert.Equal(t, expectedSize, pop.Content.Size()) for _, o := range test.LaidOutObjects(pop) { - if s, ok := o.(*shadow); ok { + if s, ok := o.(*widget.Shadow); ok { assert.Equal(t, expectedSize, s.Size(), "infer pop-up’s inner size from shadow’s size") } } diff --git a/widget/popup.go b/widget/popup.go index 547c2d1cc9..c3744a02a2 100644 --- a/widget/popup.go +++ b/widget/popup.go @@ -5,6 +5,7 @@ import ( "fyne.io/fyne" "fyne.io/fyne/canvas" + "fyne.io/fyne/internal/widget" "fyne.io/fyne/theme" ) @@ -98,10 +99,16 @@ func (p *PopUp) CreateRenderer() fyne.WidgetRenderer { bg := canvas.NewRectangle(theme.BackgroundColor()) objects := []fyne.CanvasObject{bg, p.Content} if p.modal { - return &modalPopUpRenderer{baseRenderer{objects}, popUpBaseRenderer{popUp: p, bg: bg}} + return &modalPopUpRenderer{ + widget.NewBaseRenderer(objects), + popUpBaseRenderer{popUp: p, bg: bg}, + } } - return &popUpRenderer{newShadowingRenderer(objects, popUpLevel), popUpBaseRenderer{popUp: p, bg: bg}} + return &popUpRenderer{ + widget.NewShadowingRenderer(objects, widget.PopUpLevel), + popUpBaseRenderer{popUp: p, bg: bg}, + } } // NewPopUpAtPosition creates a new popUp for the specified content at the specified absolute position. @@ -178,7 +185,7 @@ func (r *popUpBaseRenderer) offset() fyne.Position { } type popUpRenderer struct { - *shadowingRenderer + *widget.ShadowingRenderer popUpBaseRenderer } @@ -210,7 +217,7 @@ func (r *popUpRenderer) Layout(_ fyne.Size) { r.bg.Resize(r.popUp.innerSize) r.bg.Move(innerPos) - r.layoutShadow(r.popUp.innerSize, innerPos) + r.LayoutShadow(r.popUp.innerSize, innerPos) } func (r *popUpRenderer) MinSize() fyne.Size { @@ -229,7 +236,7 @@ func (r *popUpRenderer) BackgroundColor() color.Color { } type modalPopUpRenderer struct { - baseRenderer + widget.BaseRenderer popUpBaseRenderer } diff --git a/widget/progressbar.go b/widget/progressbar.go index 8605c73dca..4c76eb2a62 100644 --- a/widget/progressbar.go +++ b/widget/progressbar.go @@ -6,13 +6,14 @@ import ( "fyne.io/fyne" "fyne.io/fyne/canvas" + "fyne.io/fyne/internal/widget" "fyne.io/fyne/theme" ) const defaultText = "%d%%" type progressRenderer struct { - baseRenderer + widget.BaseRenderer bar *canvas.Rectangle label *canvas.Text progress *ProgressBar @@ -97,7 +98,7 @@ func (p *ProgressBar) CreateRenderer() fyne.WidgetRenderer { bar := canvas.NewRectangle(theme.PrimaryColor()) label := canvas.NewText("0%", theme.TextColor()) label.Alignment = fyne.TextAlignCenter - return &progressRenderer{baseRenderer{[]fyne.CanvasObject{bar, label}}, bar, label, p} + return &progressRenderer{widget.NewBaseRenderer([]fyne.CanvasObject{bar, label}), bar, label, p} } // NewProgressBar creates a new progress bar widget. diff --git a/widget/progressbarinfinite.go b/widget/progressbarinfinite.go index 510f2d4f8e..cffe5a97a3 100644 --- a/widget/progressbarinfinite.go +++ b/widget/progressbarinfinite.go @@ -8,6 +8,7 @@ import ( "fyne.io/fyne" "fyne.io/fyne/canvas" "fyne.io/fyne/internal/cache" + "fyne.io/fyne/internal/widget" "fyne.io/fyne/theme" ) @@ -19,7 +20,7 @@ const ( ) type infProgressRenderer struct { - baseRenderer + widget.BaseRenderer bar *canvas.Rectangle ticker *time.Ticker running atomic.Value @@ -173,7 +174,7 @@ func (p *ProgressBarInfinite) CreateRenderer() fyne.WidgetRenderer { p.ExtendBaseWidget(p) bar := canvas.NewRectangle(theme.PrimaryColor()) render := &infProgressRenderer{ - baseRenderer: baseRenderer{[]fyne.CanvasObject{bar}}, + BaseRenderer: widget.NewBaseRenderer([]fyne.CanvasObject{bar}), bar: bar, progress: p, } diff --git a/widget/radio.go b/widget/radio.go index c6ed27584a..2281656c07 100644 --- a/widget/radio.go +++ b/widget/radio.go @@ -6,6 +6,7 @@ import ( "fyne.io/fyne" "fyne.io/fyne/canvas" "fyne.io/fyne/driver/desktop" + "fyne.io/fyne/internal/widget" "fyne.io/fyne/theme" ) @@ -19,7 +20,7 @@ type radioRenderItem struct { } type radioRenderer struct { - baseRenderer + widget.BaseRenderer items []*radioRenderItem radio *Radio } @@ -112,14 +113,14 @@ func (r *radioRenderer) Refresh() { focusIndicator := canvas.NewCircle(theme.BackgroundColor()) - r.setObjects(append(r.Objects(), focusIndicator, icon, text)) + r.SetObjects(append(r.Objects(), focusIndicator, icon, text)) r.items = append(r.items, &radioRenderItem{icon, text, focusIndicator}) } r.Layout(r.radio.Size()) } else if len(r.items) > len(r.radio.Options) { total := len(r.radio.Options) r.items = r.items[:total] - r.setObjects(r.Objects()[:total*2]) + r.SetObjects(r.Objects()[:total*2]) } for i, item := range r.items { @@ -263,7 +264,7 @@ func (r *Radio) CreateRenderer() fyne.WidgetRenderer { items = append(items, &radioRenderItem{icon, text, focusIndicator}) } - return &radioRenderer{baseRenderer{objects}, items, r} + return &radioRenderer{widget.NewBaseRenderer(objects), items, r} } // SetSelected sets the radio option, it can be used to set a default option. diff --git a/widget/scroller.go b/widget/scroller.go index 97812e59d0..54ba0197d7 100644 --- a/widget/scroller.go +++ b/widget/scroller.go @@ -6,6 +6,7 @@ import ( "fyne.io/fyne" "fyne.io/fyne/canvas" "fyne.io/fyne/driver/desktop" + "fyne.io/fyne/internal/widget" "fyne.io/fyne/theme" ) @@ -29,7 +30,7 @@ const ( ) type scrollBarRenderer struct { - baseRenderer + widget.BaseRenderer scrollBar *scrollBar minSize fyne.Size } @@ -106,7 +107,7 @@ func newScrollBar(area *scrollBarArea) *scrollBar { } type scrollBarAreaRenderer struct { - baseRenderer + widget.BaseRenderer area *scrollBarArea bar *scrollBar } @@ -177,7 +178,7 @@ type scrollBarArea struct { func (a *scrollBarArea) CreateRenderer() fyne.WidgetRenderer { bar := newScrollBar(a) - return &scrollBarAreaRenderer{baseRenderer: baseRenderer{[]fyne.CanvasObject{bar}}, area: a, bar: bar} + return &scrollBarAreaRenderer{BaseRenderer: widget.NewBaseRenderer([]fyne.CanvasObject{bar}), area: a, bar: bar} } func (a *scrollBarArea) MouseIn(*desktop.MouseEvent) { @@ -222,12 +223,12 @@ func newScrollBarArea(scroll *ScrollContainer, orientation scrollBarOrientation) } type scrollContainerRenderer struct { - baseRenderer + widget.BaseRenderer scroll *ScrollContainer vertArea *scrollBarArea horizArea *scrollBarArea - leftShadow, rightShadow *shadow - topShadow, bottomShadow *shadow + leftShadow, rightShadow *widget.Shadow + topShadow, bottomShadow *widget.Shadow } func (r *scrollContainerRenderer) Layout(size fyne.Size) { @@ -324,20 +325,20 @@ type ScrollContainer struct { func (s *ScrollContainer) CreateRenderer() fyne.WidgetRenderer { s.ExtendBaseWidget(s) scr := &scrollContainerRenderer{ - baseRenderer: baseRenderer{[]fyne.CanvasObject{s.Content}}, + BaseRenderer: widget.NewBaseRenderer([]fyne.CanvasObject{s.Content}), scroll: s, } if s.Direction != ScrollHorizontalOnly { scr.vertArea = newScrollBarArea(s, scrollBarOrientationVertical) - scr.topShadow = newShadow(shadowBottom, submergedContentLevel) - scr.bottomShadow = newShadow(shadowTop, submergedContentLevel) - scr.setObjects(append(scr.Objects(), scr.vertArea, scr.topShadow, scr.bottomShadow)) + scr.topShadow = widget.NewShadow(widget.ShadowBottom, widget.SubmergedContentLevel) + scr.bottomShadow = widget.NewShadow(widget.ShadowTop, widget.SubmergedContentLevel) + scr.SetObjects(append(scr.Objects(), scr.vertArea, scr.topShadow, scr.bottomShadow)) } if s.Direction != ScrollVerticalOnly { scr.horizArea = newScrollBarArea(s, scrollBarOrientationHorizontal) - scr.leftShadow = newShadow(shadowRight, submergedContentLevel) - scr.rightShadow = newShadow(shadowLeft, submergedContentLevel) - scr.setObjects(append(scr.Objects(), scr.horizArea, scr.leftShadow, scr.rightShadow)) + scr.leftShadow = widget.NewShadow(widget.ShadowRight, widget.SubmergedContentLevel) + scr.rightShadow = widget.NewShadow(widget.ShadowLeft, widget.SubmergedContentLevel) + scr.SetObjects(append(scr.Objects(), scr.horizArea, scr.leftShadow, scr.rightShadow)) } return scr } diff --git a/widget/select.go b/widget/select.go index 18d8d48b28..40e409812a 100644 --- a/widget/select.go +++ b/widget/select.go @@ -6,13 +6,14 @@ import ( "fyne.io/fyne" "fyne.io/fyne/canvas" "fyne.io/fyne/driver/desktop" + "fyne.io/fyne/internal/widget" "fyne.io/fyne/theme" ) const defaultPlaceHolder string = "(Select one)" type selectRenderer struct { - *shadowingRenderer + *widget.ShadowingRenderer icon *Icon label *canvas.Text @@ -35,7 +36,7 @@ func (s *selectRenderer) MinSize() fyne.Size { // Layout the components of the button widget func (s *selectRenderer) Layout(size fyne.Size) { - s.layoutShadow(size, fyne.NewPos(0, 0)) + s.LayoutShadow(size, fyne.NewPos(0, 0)) inner := size.Subtract(fyne.NewSize(theme.Padding()*4, theme.Padding()*2)) offset := fyne.NewSize(theme.IconInlineSize(), 0) @@ -187,7 +188,7 @@ func (s *Select) CreateRenderer() fyne.WidgetRenderer { text.Alignment = fyne.TextAlignLeading objects := []fyne.CanvasObject{text, icon} - return &selectRenderer{newShadowingRenderer(objects, buttonLevel), icon, text, s} + return &selectRenderer{widget.NewShadowingRenderer(objects, widget.ButtonLevel), icon, text, s} } // ClearSelected clears the current option of the select widget. After diff --git a/widget/shadowing_renderer.go b/widget/shadowing_renderer.go deleted file mode 100644 index 5297544af5..0000000000 --- a/widget/shadowing_renderer.go +++ /dev/null @@ -1,37 +0,0 @@ -package widget - -import ( - "fyne.io/fyne" -) - -// When using the shadowingRenderer the embedding renderer should call -// layoutShadow(contentSize, contentPos) to lay out the shadow. -type shadowingRenderer struct { - baseRenderer - shadow fyne.CanvasObject -} - -func newShadowingRenderer(objects []fyne.CanvasObject, level elevationLevel) *shadowingRenderer { - var s fyne.CanvasObject - if level > 0 { - s = newShadow(shadowAround, level) - } - r := &shadowingRenderer{shadow: s} - r.setObjects(objects) - return r -} - -func (r *shadowingRenderer) layoutShadow(size fyne.Size, pos fyne.Position) { - if r.shadow == nil { - return - } - r.shadow.Resize(size) - r.shadow.Move(pos) -} - -func (r *shadowingRenderer) setObjects(objects []fyne.CanvasObject) { - if r.shadow != nil { - objects = append([]fyne.CanvasObject{r.shadow}, objects...) - } - r.baseRenderer.setObjects(objects) -} diff --git a/widget/slider.go b/widget/slider.go index 9b8a60e6de..7bee062080 100644 --- a/widget/slider.go +++ b/widget/slider.go @@ -5,6 +5,7 @@ import ( "fyne.io/fyne" "fyne.io/fyne/canvas" + "fyne.io/fyne/internal/widget" "fyne.io/fyne/theme" ) @@ -128,7 +129,7 @@ func (s *Slider) CreateRenderer() fyne.WidgetRenderer { objects := []fyne.CanvasObject{track, active, thumb} - return &sliderRenderer{baseRenderer{objects}, track, active, thumb, s} + return &sliderRenderer{widget.NewBaseRenderer(objects), track, active, thumb, s} } const ( @@ -137,7 +138,7 @@ const ( ) type sliderRenderer struct { - baseRenderer + widget.BaseRenderer track *canvas.Rectangle active *canvas.Rectangle thumb *canvas.Circle diff --git a/widget/text.go b/widget/text.go index 65c674f21b..489e72e90f 100644 --- a/widget/text.go +++ b/widget/text.go @@ -8,6 +8,7 @@ import ( "fyne.io/fyne" "fyne.io/fyne/canvas" "fyne.io/fyne/internal/cache" + "fyne.io/fyne/internal/widget" "fyne.io/fyne/theme" ) @@ -226,7 +227,7 @@ func (t *textProvider) lineSizeToColumn(col, row int) fyne.Size { // Renderer type textRenderer struct { - baseRenderer + widget.BaseRenderer texts []*canvas.Text provider *textProvider } @@ -304,7 +305,7 @@ func (r *textRenderer) Refresh() { if add { r.texts = append(r.texts, textCanvas) - r.setObjects(append(r.Objects(), textCanvas)) + r.SetObjects(append(r.Objects(), textCanvas)) } } diff --git a/widget/text_test.go b/widget/text_test.go index e51fac5b05..8fb50c847d 100644 --- a/widget/text_test.go +++ b/widget/text_test.go @@ -248,8 +248,8 @@ func TestTextRenderer_ApplyTheme(t *testing.T) { label := NewLabel("Test\nLine2") render := test.WidgetRenderer(label).(*textRenderer) - text1 := render.objects[0].(*canvas.Text) - text2 := render.objects[0].(*canvas.Text) + text1 := render.Objects()[0].(*canvas.Text) + text2 := render.Objects()[0].(*canvas.Text) customTextSize1 := text1.TextSize customTextSize2 := text2.TextSize withTestTheme(func() { diff --git a/widget/toolbar.go b/widget/toolbar.go index 0d25cf92d5..33b32ff4b7 100644 --- a/widget/toolbar.go +++ b/widget/toolbar.go @@ -5,6 +5,7 @@ import ( "fyne.io/fyne" "fyne.io/fyne/canvas" + "fyne.io/fyne/internal/widget" "fyne.io/fyne/layout" "fyne.io/fyne/theme" ) @@ -106,7 +107,7 @@ func NewToolbar(items ...ToolbarItem) *Toolbar { } type toolbarRenderer struct { - baseRenderer + widget.BaseRenderer layout fyne.Layout objs []fyne.CanvasObject toolbar *Toolbar @@ -143,5 +144,5 @@ func (r *toolbarRenderer) resetObjects() { r.objs = append(r.objs, item.ToolbarObject()) } } - r.setObjects(r.objs) + r.SetObjects(r.objs) }