89 lines
2.9 KiB
Go
89 lines
2.9 KiB
Go
package mujica
|
|
|
|
import (
|
|
"fmt"
|
|
"log/slog"
|
|
|
|
"github.com/egoist/mygo/ui"
|
|
|
|
"mujicaui/icons"
|
|
"mujicaui/internal"
|
|
"mujicaui/theme"
|
|
)
|
|
|
|
// ThemeSelectorOptions configure a ThemeSelector.
|
|
type ThemeSelectorOptions struct {
|
|
Disabled bool
|
|
}
|
|
|
|
// ThemeSelector selects an appearance using preview cards.
|
|
func ThemeSelector(c *ui.Context, mode *Mode, opts ThemeSelectorOptions) ChoiceResult {
|
|
if *mode != System && *mode != Light && *mode != Dark {
|
|
panic(fmt.Sprintf("mujica: ThemeSelector mode %d is not System, Light or Dark", *mode))
|
|
}
|
|
k := Tokens(c)
|
|
d := Density(c)
|
|
var r ChoiceResult
|
|
r.Element = ui.Row(c).Gap(d.Unit() * 3).Wrap().Role(ui.RoleRadioGroup).Label(msg(c, "theme_selector.label")).
|
|
FocusGroup(ui.Horizontal).Disabled(opts.Disabled)
|
|
selected := mode
|
|
if r.Element.IsDisabled() {
|
|
copy := *mode
|
|
selected = ©
|
|
}
|
|
r.Element.Children(func() {
|
|
for _, m := range []Mode{System, Light, Dark} {
|
|
card := ui.RadioBase(c, selected, m).Column().Gap(d.Unit() * 2).Padding(d.Unit() * 2).Radius(theme.CardRadius).AlignItems(ui.Stretch).Transition(colorFade)
|
|
if card.Changed() && !card.IsDisabled() {
|
|
r.changed = true
|
|
slog.Debug("mujica: theme_selector chose", "mode", m.String())
|
|
}
|
|
on := *mode == m
|
|
internal.Ring(card, k.Focus, theme.CardRadius)
|
|
border, width := k.Border, theme.BorderWidth
|
|
switch {
|
|
case on:
|
|
border, width = k.AccentText, 2
|
|
card.Background(k.Selection)
|
|
case card.Hovered():
|
|
card.Background(k.SurfaceHover)
|
|
}
|
|
card.Border(width, border)
|
|
card.Children(func() {
|
|
ui.Box(c).Size(132, 84).Role(ui.RoleNone).Draw(func(p *ui.Painter, rect ui.Rect) {
|
|
switch m {
|
|
case Light:
|
|
themePreview(p, rect, theme.Light())
|
|
case Dark:
|
|
themePreview(p, rect, theme.Dark())
|
|
default:
|
|
half := ui.Rect{X: rect.X, Y: rect.Y, W: rect.W / 2, H: rect.H}
|
|
p.Clip(half, 0, func() { themePreview(p, rect, theme.Light()) })
|
|
p.Clip(ui.Rect{X: half.X + half.W, Y: rect.Y, W: rect.W / 2, H: rect.H}, 0, func() { themePreview(p, rect, theme.Dark()) })
|
|
}
|
|
})
|
|
ui.Row(c).Gap(d.Unit()).AlignItems(ui.Center).Children(func() {
|
|
if on {
|
|
ui.Icon(c, icons.Must("check")).Size(14, 14).TextColor(k.AccentText)
|
|
}
|
|
ui.Text(c, msg(c, "theme_selector."+m.String())).SingleLine()
|
|
})
|
|
})
|
|
}
|
|
})
|
|
return r
|
|
}
|
|
|
|
// themePreview paints a miniature themed window.
|
|
func themePreview(p *ui.Painter, r ui.Rect, t theme.Tokens) {
|
|
p.Fill(r, t.Background, theme.ControlRadius)
|
|
p.Stroke(r, t.Border, theme.ControlRadius, 1)
|
|
p.Fill(ui.Rect{X: r.X + 1, Y: r.Y + 1, W: r.W - 2, H: 12}, t.Surface, theme.ControlRadius)
|
|
p.Fill(ui.Rect{X: r.X + 1, Y: r.Y + 13, W: r.W * 0.28, H: r.H - 14}, t.Surface, 0)
|
|
x := r.X + r.W*0.36
|
|
for i, w := range []float32{0.5, 0.38, 0.44} {
|
|
p.Fill(ui.Rect{X: x, Y: r.Y + 22 + float32(i)*10, W: r.W * w, H: 4}, t.TextMuted, 2)
|
|
}
|
|
p.Fill(ui.Rect{X: x, Y: r.Y + r.H - 20, W: 30, H: 12}, t.Accent, 2)
|
|
}
|