Files
MujicaUI/theme.go
T
ZacharyZhang-NY 43c96a7a81 Refactor: one colorFade transition replaces internal.Fade
textInputFade becomes colorFade in theme.go and serves AvatarGroup,
Image retry, Tag and EditableText, which used internal.Fade. MyGo already
skips element transitions under ReduceMotion, so dropping the Motion
check keeps behaviour.
2026-10-05 13:50:47 -04:00

145 lines
3.4 KiB
Go

// Package mujica is a court-gothic component library for MyGo native UI.
package mujica
import (
"fmt"
"time"
"github.com/egoist/mygo/ui"
"mujicaui/theme"
)
// Mode chooses the appearance of a window.
type Mode int
const (
System Mode = iota
Light
Dark
)
func (m Mode) String() string {
switch m {
case Light:
return "Light"
case Dark:
return "Dark"
}
return "System"
}
// Settings are a window's theme. Nil token sets use the library defaults.
type Settings struct {
Mode Mode
Density theme.Density
Light *theme.Tokens
Dark *theme.Tokens
Locale Locale
// Messages overrides built-in copy by key.
Messages map[string]string
}
type windowTheme struct {
tokens theme.Tokens
density theme.Density
locale Locale
messages map[string]string
set bool
}
type themeKey struct{}
// Use applies s to the window. Call it first in every frame of the view.
func Use(c *ui.Context, s Settings) {
if s.Mode < System || s.Mode > Dark {
panic(fmt.Sprintf("mujica: invalid Mode %d", s.Mode))
}
if s.Density < theme.Default || s.Density > theme.Comfortable {
panic(fmt.Sprintf("mujica: invalid Density %d", s.Density))
}
if s.Locale != "" && s.Locale != EnUS && s.Locale != ZhCN {
panic("mujica: unsupported Locale " + string(s.Locale))
}
dark := c.Theme().Dark
switch s.Mode {
case Light:
dark = false
case Dark:
dark = true
}
k := theme.Light()
if s.Light != nil {
k = *s.Light
}
if dark {
k = theme.Dark()
if s.Dark != nil {
k = *s.Dark
}
}
p := c.Preferences()
if p.HighContrast {
k = k.HighContrast()
}
size := FontSize(c, theme.BodySize)
c.SetTheme(&ui.Theme{
Dark: k.Dark,
Background: k.Background,
Surface: k.Surface,
SurfaceHover: k.SurfaceHover,
SurfacePressed: k.Selection,
Border: k.ControlBorder,
Text: k.Text,
TextMuted: k.TextMuted,
Accent: k.Accent,
AccentHover: k.AccentHover,
AccentPressed: k.AccentPressed,
AccentText: k.OnAccent,
Danger: k.Danger,
Warning: k.Warning,
Success: k.Success,
Selection: k.Selection,
Focus: k.Focus,
Scrollbar: k.TextMuted.Alpha(0.5),
Radius: theme.ControlRadius,
Spacing: s.Density.Unit(),
FontSize: size,
})
c.Root().LineHeight(theme.LineHeight)
*ui.Local(c.Root(), themeKey{}, func() windowTheme { return windowTheme{} }) = windowTheme{k, s.Density, s.Locale, s.Messages, true}
}
func current(c *ui.Context) windowTheme {
w := *ui.Local(c.Root(), themeKey{}, func() windowTheme { return windowTheme{} })
if !w.set {
panic("mujica: call mujica.Use at the start of the view")
}
return w
}
// Tokens returns the window's colors.
func Tokens(c *ui.Context) theme.Tokens { return current(c).tokens }
// Density returns the window's density.
func Density(c *ui.Context) theme.Density { return current(c).density }
// colorFade eases background and border colors between states; MyGo skips it under reduced motion.
var colorFade = ui.ElementTransition{Colors: true, Duration: theme.StateDuration}
// Motion returns d, or zero when the desktop asks for reduced motion.
func Motion(c *ui.Context, d time.Duration) time.Duration {
if c.Preferences().ReduceMotion {
return 0
}
return d
}
// FontSize scales a design size by the desktop's text scale.
func FontSize(c *ui.Context, size float32) float32 {
if s := c.Preferences().TextScale; s > 0 {
return size * s
}
return size
}