Skip to content

Commit

Permalink
Add support for disabling Button, Checkbox, and Radio widgets (Issue f…
Browse files Browse the repository at this point in the history
  • Loading branch information
Peter Stratton committed May 24, 2019
1 parent 8d11028 commit 58fbff0
Show file tree
Hide file tree
Showing 16 changed files with 473 additions and 68 deletions.
7 changes: 7 additions & 0 deletions canvasobject.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,13 @@ type Tappable interface {
TappedSecondary(*PointEvent)
}

// Disableable describes any CanvasObject that can be disabled.
// This is primarily used with objects that also implement the Tappable interface.
type Disableable interface {
Enable()
Disable()
}

// Scrollable describes any CanvasObject that can also be scrolled.
// This is mostly used to implement the widget.ScrollContainer.
type Scrollable interface {
Expand Down
8 changes: 8 additions & 0 deletions cmd/fyne_demo/theme.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,18 @@ func (customTheme) TextColor() color.Color {
return color.White
}

func (customTheme) DisabledTextColor() color.Color {
return color.Black
}

func (customTheme) IconColor() color.Color {
return color.White
}

func (customTheme) DisabledIconColor() color.Color {
return color.Black
}

func (customTheme) PlaceHolderColor() color.Color {
return grey
}
Expand Down
8 changes: 8 additions & 0 deletions test/testapp.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,10 +123,18 @@ func (dummyTheme) TextColor() color.Color {
return color.Black
}

func (dummyTheme) DisabledTextColor() color.Color {
return color.White
}

func (dummyTheme) IconColor() color.Color {
return color.Black
}

func (dummyTheme) DisabledIconColor() color.Color {
return color.White
}

func (dummyTheme) PlaceHolderColor() color.Color {
return color.Black
}
Expand Down
2 changes: 2 additions & 0 deletions theme.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ type Theme interface {
ButtonColor() color.Color
HyperlinkColor() color.Color
TextColor() color.Color
DisabledTextColor() color.Color
IconColor() color.Color
DisabledIconColor() color.Color
PlaceHolderColor() color.Color
PrimaryColor() color.Color
HoverColor() color.Color
Expand Down
62 changes: 46 additions & 16 deletions theme/icons.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package theme
import (
"bytes"
"encoding/xml"
"fmt"
"image/color"
"log"

"fyne.io/fyne"
Expand All @@ -21,23 +23,8 @@ func (res *ThemedResource) Name() string {

// Content returns the underlying content of the correct resource for the current theme
func (res *ThemedResource) Content() []byte {
rdr := bytes.NewReader(res.source.Content())
clr := fyne.CurrentApp().Settings().Theme().IconColor()
s, err := svgFromXML(rdr)
if err != nil {
fyne.LogError("could not load SVG, falling back to static content:", err)
return res.source.Content()
}
if err := s.replaceFillColor(rdr, clr); err != nil {
fyne.LogError("could not replace fill color, falling back to static content:", err)
return res.source.Content()
}
b, err := xml.Marshal(s)
if err != nil {
fyne.LogError("could not marshal svg, falling back to static content:", err)
return res.source.Content()
}
return b
return colorizeResource(res.source, clr)
}

// NewThemedResource creates a resource that adapts to the current theme setting.
Expand All @@ -53,6 +40,49 @@ func NewThemedResource(dark, light fyne.Resource) *ThemedResource {
}
}

// DisabledResource is a resource wrapper that will return an appropriate resource colorized by
// the current theme's `DisabledIconColor` color.
type DisabledResource struct {
source fyne.Resource
}

// Name returns the resource source name prefixed with `disabled_` (used for caching)
func (res *DisabledResource) Name() string {
return fmt.Sprintf("disabled_%s", res.source.Name())
}

// Content returns the disabled style content of the correct resource for the current theme
func (res *DisabledResource) Content() []byte {
clr := fyne.CurrentApp().Settings().Theme().DisabledIconColor()
return colorizeResource(res.source, clr)
}

// NewDisabledResource creates a resource that adapts to the current theme's DisabledIconColor setting.
func NewDisabledResource(res fyne.Resource) *DisabledResource {
return &DisabledResource{
source: res,
}
}

func colorizeResource(res fyne.Resource, clr color.Color) []byte {
rdr := bytes.NewReader(res.Content())
s, err := svgFromXML(rdr)
if err != nil {
fyne.LogError("could not load SVG, falling back to static content:", err)
return res.Content()
}
if err := s.replaceFillColor(rdr, clr); err != nil {
fyne.LogError("could not replace fill color, falling back to static content:", err)
return res.Content()
}
b, err := xml.Marshal(s)
if err != nil {
fyne.LogError("could not marshal svg, falling back to static content:", err)
return res.Content()
}
return b
}

var (
cancel, confirm, delete, search, searchReplace *ThemedResource
checked, unchecked, radioButton, radioButtonChecked *ThemedResource
Expand Down
29 changes: 29 additions & 0 deletions theme/icons_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package theme

import (
"fmt"
"io/ioutil"
"path/filepath"
"testing"
Expand Down Expand Up @@ -67,6 +68,15 @@ func TestNewThemedResource_OneStaticResourceSupport(t *testing.T) {
assert.Equal(t, nm, custom.Name())
}

func TestNewDisabledResource(t *testing.T) {
fyne.CurrentApp().Settings().SetTheme(DarkTheme())
src := helperNewStaticResource()
custom := NewDisabledResource(src)
nm := custom.Name()

assert.Equal(t, nm, fmt.Sprintf("disabled_%v", src.Name()))
}

func TestThemedResource_Name(t *testing.T) {
sr := fyne.NewStaticResource("cancel_Paths.svg",
helperLoadBytes(t, "cancel_Paths.svg"))
Expand Down Expand Up @@ -127,6 +137,25 @@ func TestThemedResource_Content_BlackFillIsUpdated(t *testing.T) {
assert.NotEqual(t, sr.Content(), dr.Content())
}

func TestDisabledResource_Name(t *testing.T) {
sr := fyne.NewStaticResource("cancel_Paths.svg",
helperLoadBytes(t, "cancel_Paths.svg"))
dr := &DisabledResource{
source: sr,
}
assert.Equal(t, fmt.Sprintf("disabled_%v", sr.Name()), dr.Name())
}

func TestDisabledResource_Content_NoGroupsFile(t *testing.T) {
fyne.CurrentApp().Settings().SetTheme(DarkTheme())
sr := fyne.NewStaticResource("cancel_Paths.svg",
helperLoadBytes(t, "cancel_Paths.svg"))
dr := &DisabledResource{
source: sr,
}
assert.NotEqual(t, sr.Content(), dr.Content())
}

// Test Asset Sources
func Test_FyneLogo_FileSource(t *testing.T) {
result := FyneLogo().Name()
Expand Down
65 changes: 45 additions & 20 deletions theme/theme.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,24 @@ type builtinTheme struct {

button, text, icon, hyperlink, placeholder, primary, hover, scrollBar, shadow color.Color
regular, bold, italic, bolditalic, monospace fyne.Resource
disabledIcon, disabledText color.Color
}

// LightTheme defines the built in light theme colours and sizes
func LightTheme() fyne.Theme {
theme := &builtinTheme{
background: color.RGBA{0xf5, 0xf5, 0xf5, 0xff},
button: color.RGBA{0xd9, 0xd9, 0xd9, 0xff},
text: color.RGBA{0x21, 0x21, 0x21, 0xff},
icon: color.RGBA{0x21, 0x21, 0x21, 0xff},
hyperlink: color.RGBA{0x0, 0x0, 0xd9, 0xff},
placeholder: color.RGBA{0x88, 0x88, 0x88, 0xff},
primary: color.RGBA{0x9f, 0xa8, 0xda, 0xff},
hover: color.RGBA{0xe7, 0xe7, 0xe7, 0xff},
scrollBar: color.RGBA{0x0, 0x0, 0x0, 0x99},
shadow: color.RGBA{0x0, 0x0, 0x0, 0x99},
background: color.RGBA{0xf5, 0xf5, 0xf5, 0xff},
button: color.RGBA{0xd9, 0xd9, 0xd9, 0xff},
text: color.RGBA{0x21, 0x21, 0x21, 0xff},
disabledText: color.RGBA{0x00, 0xff, 0x00, 0xff},
icon: color.RGBA{0x21, 0x21, 0x21, 0xff},
disabledIcon: color.RGBA{0xff, 0x00, 0x00, 0xff},
hyperlink: color.RGBA{0x0, 0x0, 0xd9, 0xff},
placeholder: color.RGBA{0x88, 0x88, 0x88, 0xff},
primary: color.RGBA{0x9f, 0xa8, 0xda, 0xff},
hover: color.RGBA{0xe7, 0xe7, 0xe7, 0xff},
scrollBar: color.RGBA{0x0, 0x0, 0x0, 0x99},
shadow: color.RGBA{0x0, 0x0, 0x0, 0x99},
}

theme.initFonts()
Expand All @@ -40,16 +43,18 @@ func LightTheme() fyne.Theme {
// DarkTheme defines the built in dark theme colours and sizes
func DarkTheme() fyne.Theme {
theme := &builtinTheme{
background: color.RGBA{0x42, 0x42, 0x42, 0xff},
button: color.RGBA{0x21, 0x21, 0x21, 0xff},
text: color.RGBA{0xff, 0xff, 0xff, 0xff},
icon: color.RGBA{0xff, 0xff, 0xff, 0xff},
hyperlink: color.RGBA{0x99, 0x99, 0xff, 0xff},
placeholder: color.RGBA{0xb2, 0xb2, 0xb2, 0xff},
primary: color.RGBA{0x1a, 0x23, 0x7e, 0xff},
hover: color.RGBA{0x31, 0x31, 0x31, 0xff},
scrollBar: color.RGBA{0x0, 0x0, 0x0, 0x99},
shadow: color.RGBA{0x0, 0x0, 0x0, 0x99},
background: color.RGBA{0x42, 0x42, 0x42, 0xff},
button: color.RGBA{0x21, 0x21, 0x21, 0xff},
text: color.RGBA{0xff, 0xff, 0xff, 0xff},
disabledText: color.RGBA{0x60, 0x60, 0x60, 0xff},
icon: color.RGBA{0xff, 0xff, 0xff, 0xff},
disabledIcon: color.RGBA{0x60, 0x60, 0x60, 0xff},
hyperlink: color.RGBA{0x99, 0x99, 0xff, 0xff},
placeholder: color.RGBA{0xb2, 0xb2, 0xb2, 0xff},
primary: color.RGBA{0x1a, 0x23, 0x7e, 0xff},
hover: color.RGBA{0x31, 0x31, 0x31, 0xff},
scrollBar: color.RGBA{0x0, 0x0, 0x0, 0x99},
shadow: color.RGBA{0x0, 0x0, 0x0, 0x99},
}

theme.initFonts()
Expand All @@ -75,11 +80,21 @@ func (t *builtinTheme) TextColor() color.Color {
return t.text
}

// DisabledIconColor returns the color for a disabledIcon UI element
func (t *builtinTheme) DisabledTextColor() color.Color {
return t.disabledText
}

// IconColor returns the theme's standard text colour
func (t *builtinTheme) IconColor() color.Color {
return t.icon
}

// DisabledIconColor returns the color for a disabledIcon UI element
func (t *builtinTheme) DisabledIconColor() color.Color {
return t.disabledIcon
}

// PlaceHolderColor returns the theme's placeholder text colour
func (t *builtinTheme) PlaceHolderColor() color.Color {
return t.placeholder
Expand Down Expand Up @@ -220,11 +235,21 @@ func TextColor() color.Color {
return current().TextColor()
}

// DisabledTextColor returns the color for a disabledIcon UI element
func DisabledTextColor() color.Color {
return current().DisabledTextColor()
}

// IconColor returns the theme's standard text colour
func IconColor() color.Color {
return current().IconColor()
}

// DisabledIconColor returns the color for a disabledIcon UI element
func DisabledIconColor() color.Color {
return current().DisabledIconColor()
}

// PlaceHolderColor returns the theme's standard text colour
func PlaceHolderColor() color.Color {
return current().PlaceHolderColor()
Expand Down
14 changes: 13 additions & 1 deletion theme/theme_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,13 @@ func Test_HyperlinkColor(t *testing.T) {
func Test_TextColor(t *testing.T) {
fyne.CurrentApp().Settings().SetTheme(DarkTheme())
c := TextColor()
assert.Equal(t, DarkTheme().TextColor(), c, "wrong hyperlink color")
assert.Equal(t, DarkTheme().TextColor(), c, "wrong text color")
}

func Test_DisabledTextColor(t *testing.T) {
fyne.CurrentApp().Settings().SetTheme(DarkTheme())
c := DisabledTextColor()
assert.Equal(t, DarkTheme().DisabledTextColor(), c, "wrong disabled text color")
}

func Test_PlaceHolderColor(t *testing.T) {
Expand Down Expand Up @@ -94,6 +100,12 @@ func Test_IconColor(t *testing.T) {
assert.Equal(t, DarkTheme().IconColor(), c, "wrong icon color")
}

func Test_DisabledIconColor(t *testing.T) {
fyne.CurrentApp().Settings().SetTheme(DarkTheme())
c := DisabledIconColor()
assert.Equal(t, DarkTheme().DisabledIconColor(), c, "wrong disabled icon color")
}

func Test_TextSize(t *testing.T) {
fyne.CurrentApp().Settings().SetTheme(DarkTheme())
assert.Equal(t, DarkTheme().TextSize(), TextSize(), "wrong text size")
Expand Down
Loading

0 comments on commit 58fbff0

Please sign in to comment.