package mujica import ( "fmt" "log/slog" "github.com/egoist/mygo/ui" "mujicaui/internal" "mujicaui/theme" ) // TagOptions configure a Tag. The zero value is a plain label. type TagOptions struct { // Icon names an icon of the icons package shown before the label. Icon string // Clickable makes the label a button reported by TagView.Clicked. Clickable bool // Closable adds a remove button reported by TagView.Closed. Closable bool Disabled bool } // TagView is a shown Tag and what the user did to it this frame. type TagView struct { Element *ui.Element // Clicked reports the label was activated; never set by the remove button. Clicked bool // Closed reports the remove button, or Delete or Backspace on the label. Closed bool } // Tag shows a short label. Clicking the label and removing the tag are // separate actions with separate focus stops. func Tag(c *ui.Context, label string, opts TagOptions) TagView { if label == "" { panic("mujica: Tag needs a label") } k := Tokens(c) u := Density(c).Unit() var v TagView box := ui.Row(c).AlignItems(ui.Center).MinHeight(theme.MinHitSize).Radius(theme.ControlRadius). Background(k.Surface).Border(theme.BorderWidth, k.Border).Shrink(0).Disabled(opts.Disabled) v.Element = box box.Children(func() { var main *ui.Element if opts.Clickable { main = ui.ButtonBase(c).Label(label) internal.Ring(main, k.Focus, theme.ControlRadius) } else { main = ui.Row(c).AlignItems(ui.Center) } main.Gap(u*1.5).Padding(0, u*2).FillHeight().Radius(theme.ControlRadius).TextColor(k.Text) if opts.Clickable && !opts.Disabled { if main.Pressed() { main.Background(k.Selection) } else if main.Hovered() { main.Background(k.SurfaceHover) } internal.Fade(main, Motion(c, theme.StateDuration)) } if opts.Closable { main.Padding(0, u, 0, u*2) } main.Children(func() { if opts.Icon != "" { Icon(c, opts.Icon, IconOptions{Size: 14}) } ui.Text(c, label).FontSize(theme.BodySize - 1).SingleLine() }) if opts.Clickable && main.Clicked() { v.Clicked = true } if opts.Closable { if opts.Clickable && !opts.Disabled && (main.Shortcut(0, ui.KeyDelete) || main.Shortcut(0, ui.KeyBackspace)) { v.Closed = true } if tagClose(c, k, label).Clicked() { v.Closed = true } } }) if v.Clicked { slog.Debug("mujica: tag click", "label", label) } if v.Closed { slog.Debug("mujica: tag close", "label", label) } return v } func tagClose(c *ui.Context, k theme.Tokens, label string) *ui.Element { b := ui.ButtonBase(c).Size(theme.MinHitSize, theme.MinHitSize). Radius(theme.ControlRadius).Label(fmt.Sprintf(msg(c, "tag.remove"), label)) fg := k.TextMuted if b.Pressed() { b.Background(k.Selection) fg = k.Text } else if b.Hovered() { b.Background(k.SurfaceHover) fg = k.Text } internal.Ring(b, k.Focus, theme.ControlRadius) internal.Fade(b, Motion(c, theme.StateDuration)) b.TextColor(fg).Children(func() { Icon(c, "x", IconOptions{Size: 12}) }) return b }