adam-gui/vendor/fyne.io/fyne/v2/theme/theme.go
2024-04-29 19:13:50 +02:00

374 lines
10 KiB
Go

// Package theme defines how a Fyne app should look when rendered.
package theme // import "fyne.io/fyne/v2/theme"
import (
"image/color"
"os"
"strings"
"fyne.io/fyne/v2"
)
const (
// VariantDark is the version of a theme that satisfies a user preference for a dark look.
//
// Since: 2.0
VariantDark fyne.ThemeVariant = 0
// VariantLight is the version of a theme that satisfies a user preference for a light look.
//
// Since: 2.0
VariantLight fyne.ThemeVariant = 1
// potential for adding theme types such as high visibility or monochrome...
variantNameUserPreference fyne.ThemeVariant = 2 // locally used in builtinTheme for backward compatibility
)
// DarkTheme defines the built-in dark theme colors and sizes.
//
// Deprecated: This method ignores user preference and should not be used, it will be removed in v3.0.
func DarkTheme() fyne.Theme {
theme := &builtinTheme{variant: VariantDark}
theme.initFonts()
return theme
}
// DefaultTheme returns a built-in theme that can adapt to the user preference of light or dark colors.
//
// Since: 2.0
func DefaultTheme() fyne.Theme {
if defaultTheme == nil {
defaultTheme = setupDefaultTheme()
}
return defaultTheme
}
// LightTheme defines the built-in light theme colors and sizes.
//
// Deprecated: This method ignores user preference and should not be used, it will be removed in v3.0.
func LightTheme() fyne.Theme {
theme := &builtinTheme{variant: VariantLight}
theme.initFonts()
return theme
}
var (
defaultTheme fyne.Theme
)
type builtinTheme struct {
variant fyne.ThemeVariant
regular, bold, italic, boldItalic, monospace, symbol fyne.Resource
}
func (t *builtinTheme) initFonts() {
t.regular = regular
t.bold = bold
t.italic = italic
t.boldItalic = bolditalic
t.monospace = monospace
t.symbol = symbol
font := os.Getenv("FYNE_FONT")
if font != "" {
t.regular = loadCustomFont(font, "Regular", regular)
if t.regular == regular { // failed to load
t.bold = loadCustomFont(font, "Bold", bold)
t.italic = loadCustomFont(font, "Italic", italic)
t.boldItalic = loadCustomFont(font, "BoldItalic", bolditalic)
} else { // first custom font loaded, fall back to that
t.bold = loadCustomFont(font, "Bold", t.regular)
t.italic = loadCustomFont(font, "Italic", t.regular)
t.boldItalic = loadCustomFont(font, "BoldItalic", t.regular)
}
}
font = os.Getenv("FYNE_FONT_MONOSPACE")
if font != "" {
t.monospace = loadCustomFont(font, "Regular", monospace)
}
font = os.Getenv("FYNE_FONT_SYMBOL")
if font != "" {
t.symbol = loadCustomFont(font, "Regular", symbol)
}
}
func (t *builtinTheme) Color(n fyne.ThemeColorName, v fyne.ThemeVariant) color.Color {
if t.variant != variantNameUserPreference {
v = t.variant
}
primary := fyne.CurrentApp().Settings().PrimaryColor()
if n == ColorNamePrimary || n == ColorNameHyperlink {
return primaryColorNamed(primary)
} else if n == ColorNameFocus {
return focusColorNamed(primary)
} else if n == ColorNameSelection {
return selectionColorNamed(primary)
}
if v == VariantLight {
return lightPaletColorNamed(n)
}
return darkPaletColorNamed(n)
}
func (t *builtinTheme) Font(style fyne.TextStyle) fyne.Resource {
if style.Monospace {
return t.monospace
}
if style.Bold {
if style.Italic {
return t.boldItalic
}
return t.bold
}
if style.Italic {
return t.italic
}
if style.Symbol {
return t.symbol
}
return t.regular
}
func (t *builtinTheme) Size(s fyne.ThemeSizeName) float32 {
switch s {
case SizeNameSeparatorThickness:
return 1
case SizeNameInlineIcon:
return 20
case SizeNameInnerPadding:
return 8
case SizeNameLineSpacing:
return 4
case SizeNamePadding:
return 4
case SizeNameScrollBar:
return 16
case SizeNameScrollBarSmall:
return 3
case SizeNameText:
return 14
case SizeNameHeadingText:
return 24
case SizeNameSubHeadingText:
return 18
case SizeNameCaptionText:
return 11
case SizeNameInputBorder:
return 1
case SizeNameInputRadius:
return 5
case SizeNameSelectionRadius:
return 3
default:
return 0
}
}
func current() fyne.Theme {
app := fyne.CurrentApp()
if app == nil {
return DarkTheme()
}
currentTheme := app.Settings().Theme()
if currentTheme == nil {
return DarkTheme()
}
return currentTheme
}
func currentVariant() fyne.ThemeVariant {
if std, ok := current().(*builtinTheme); ok {
if std.variant != variantNameUserPreference {
return std.variant // override if using the old LightTheme() or DarkTheme() constructor
}
}
return fyne.CurrentApp().Settings().ThemeVariant()
}
func darkPaletColorNamed(name fyne.ThemeColorName) color.Color {
switch name {
case ColorNameBackground:
return color.NRGBA{R: 0x17, G: 0x17, B: 0x18, A: 0xff}
case ColorNameButton:
return color.NRGBA{R: 0x28, G: 0x29, B: 0x2e, A: 0xff}
case ColorNameDisabled:
return color.NRGBA{R: 0x39, G: 0x39, B: 0x3a, A: 0xff}
case ColorNameDisabledButton:
return color.NRGBA{R: 0x28, G: 0x29, B: 0x2e, A: 0xff}
case ColorNameError:
return errorColor
case ColorNameForeground:
return color.NRGBA{R: 0xf3, G: 0xf3, B: 0xf3, A: 0xff}
case ColorNameHover:
return color.NRGBA{R: 0xff, G: 0xff, B: 0xff, A: 0x0f}
case ColorNameHeaderBackground:
return color.NRGBA{R: 0x1b, G: 0x1b, B: 0x1b, A: 0xff}
case ColorNameInputBackground:
return color.NRGBA{R: 0x20, G: 0x20, B: 0x23, A: 0xff}
case ColorNameInputBorder:
return color.NRGBA{R: 0x39, G: 0x39, B: 0x3a, A: 0xff}
case ColorNameMenuBackground:
return color.NRGBA{R: 0x28, G: 0x29, B: 0x2e, A: 0xff}
case ColorNameOverlayBackground:
return color.NRGBA{R: 0x18, G: 0x1d, B: 0x25, A: 0xff}
case ColorNamePlaceHolder:
return color.NRGBA{R: 0xb2, G: 0xb2, B: 0xb2, A: 0xff}
case ColorNamePressed:
return color.NRGBA{R: 0xff, G: 0xff, B: 0xff, A: 0x66}
case ColorNameScrollBar:
return color.NRGBA{R: 0xff, G: 0xff, B: 0xff, A: 0x99}
case ColorNameSeparator:
return color.NRGBA{R: 0x0, G: 0x0, B: 0x0, A: 0xff}
case ColorNameShadow:
return color.NRGBA{A: 0x66}
case ColorNameSuccess:
return successColor
case ColorNameWarning:
return warningColor
}
return color.Transparent
}
func focusColorNamed(name string) color.NRGBA {
switch name {
case ColorRed:
return color.NRGBA{R: 0xf4, G: 0x43, B: 0x36, A: 0x7f}
case ColorOrange:
return color.NRGBA{R: 0xff, G: 0x98, B: 0x00, A: 0x7f}
case ColorYellow:
return color.NRGBA{R: 0xff, G: 0xeb, B: 0x3b, A: 0x7f}
case ColorGreen:
return color.NRGBA{R: 0x8b, G: 0xc3, B: 0x4a, A: 0x7f}
case ColorPurple:
return color.NRGBA{R: 0x9c, G: 0x27, B: 0xb0, A: 0x7f}
case ColorBrown:
return color.NRGBA{R: 0x79, G: 0x55, B: 0x48, A: 0x7f}
case ColorGray:
return color.NRGBA{R: 0x9e, G: 0x9e, B: 0x9e, A: 0x7f}
}
// We return the value for ColorBlue for every other value.
// There is no need to have it in the switch above.
return color.NRGBA{R: 0x00, G: 0x6C, B: 0xff, A: 0x2a}
}
func lightPaletColorNamed(name fyne.ThemeColorName) color.Color {
switch name {
case ColorNameBackground:
return color.NRGBA{R: 0xff, G: 0xff, B: 0xff, A: 0xff}
case ColorNameButton:
return color.NRGBA{R: 0xf5, G: 0xf5, B: 0xf5, A: 0xff}
case ColorNameDisabled:
return color.NRGBA{R: 0xe3, G: 0xe3, B: 0xe3, A: 0xff}
case ColorNameDisabledButton:
return color.NRGBA{R: 0xf5, G: 0xf5, B: 0xf5, A: 0xff}
case ColorNameError:
return errorColor
case ColorNameForeground:
return color.NRGBA{R: 0x56, G: 0x56, B: 0x56, A: 0xff}
case ColorNameHover:
return color.NRGBA{A: 0x0f}
case ColorNameHeaderBackground:
return color.NRGBA{R: 0xf9, G: 0xf9, B: 0xf9, A: 0xff}
case ColorNameInputBackground:
return color.NRGBA{R: 0xf3, G: 0xf3, B: 0xf3, A: 0xff}
case ColorNameInputBorder:
return color.NRGBA{R: 0xe3, G: 0xe3, B: 0xe3, A: 0xff}
case ColorNameMenuBackground:
return color.NRGBA{R: 0xf5, G: 0xf5, B: 0xf5, A: 0xff}
case ColorNameOverlayBackground:
return color.NRGBA{R: 0xff, G: 0xff, B: 0xff, A: 0xff}
case ColorNamePlaceHolder:
return color.NRGBA{R: 0x88, G: 0x88, B: 0x88, A: 0xff}
case ColorNamePressed:
return color.NRGBA{A: 0x19}
case ColorNameScrollBar:
return color.NRGBA{A: 0x99}
case ColorNameSeparator:
return color.NRGBA{R: 0xe3, G: 0xe3, B: 0xe3, A: 0xff}
case ColorNameShadow:
return color.NRGBA{A: 0x33}
case ColorNameSuccess:
return successColor
case ColorNameWarning:
return warningColor
}
return color.Transparent
}
func loadCustomFont(env, variant string, fallback fyne.Resource) fyne.Resource {
variantPath := strings.Replace(env, "Regular", variant, -1)
res, err := fyne.LoadResourceFromPath(variantPath)
if err != nil {
fyne.LogError("Error loading specified font", err)
return fallback
}
return res
}
func primaryColorNamed(name string) color.NRGBA {
switch name {
case ColorRed:
return color.NRGBA{R: 0xf4, G: 0x43, B: 0x36, A: 0xff}
case ColorOrange:
return color.NRGBA{R: 0xff, G: 0x98, B: 0x00, A: 0xff}
case ColorYellow:
return color.NRGBA{R: 0xff, G: 0xeb, B: 0x3b, A: 0xff}
case ColorGreen:
return color.NRGBA{R: 0x8b, G: 0xc3, B: 0x4a, A: 0xff}
case ColorPurple:
return color.NRGBA{R: 0x9c, G: 0x27, B: 0xb0, A: 0xff}
case ColorBrown:
return color.NRGBA{R: 0x79, G: 0x55, B: 0x48, A: 0xff}
case ColorGray:
return color.NRGBA{R: 0x9e, G: 0x9e, B: 0x9e, A: 0xff}
}
// We return the value for ColorBlue for every other value.
// There is no need to have it in the switch above.
return color.NRGBA{R: 0x29, G: 0x6f, B: 0xf6, A: 0xff}
}
func selectionColorNamed(name string) color.NRGBA {
switch name {
case ColorRed:
return color.NRGBA{R: 0xf4, G: 0x43, B: 0x36, A: 0x3f}
case ColorOrange:
return color.NRGBA{R: 0xff, G: 0x98, B: 0x00, A: 0x3f}
case ColorYellow:
return color.NRGBA{R: 0xff, G: 0xeb, B: 0x3b, A: 0x3f}
case ColorGreen:
return color.NRGBA{R: 0x8b, G: 0xc3, B: 0x4a, A: 0x3f}
case ColorPurple:
return color.NRGBA{R: 0x9c, G: 0x27, B: 0xb0, A: 0x3f}
case ColorBrown:
return color.NRGBA{R: 0x79, G: 0x55, B: 0x48, A: 0x3f}
case ColorGray:
return color.NRGBA{R: 0x9e, G: 0x9e, B: 0x9e, A: 0x3f}
}
// We return the value for ColorBlue for every other value.
// There is no need to have it in the switch above.
return color.NRGBA{R: 0x00, G: 0x6C, B: 0xff, A: 0x40}
}
func setupDefaultTheme() fyne.Theme {
theme := &builtinTheme{variant: variantNameUserPreference}
theme.initFonts()
return theme
}