package rich import ( "context" "github.com/diamondburned/cchat" "github.com/diamondburned/cchat-gtk/internal/gts" "github.com/diamondburned/cchat-gtk/internal/ui/primitives" "github.com/diamondburned/cchat-gtk/internal/ui/rich/parser" "github.com/diamondburned/cchat/text" "github.com/gotk3/gotk3/gtk" "github.com/gotk3/gotk3/pango" ) type Labeler interface { // thread-safe cchat.LabelContainer // thread-safe // not thread-safe SetLabelUnsafe(text.Rich) GetLabel() text.Rich GetText() string Reset() } type LabelerFn = func(context.Context, cchat.LabelContainer) (func(), error) type Label struct { gtk.Label current text.Rich // Reusable primitive. r gts.Reusable } var ( _ gtk.IWidget = (*Label)(nil) _ Labeler = (*Label)(nil) ) func NewLabel(content text.Rich) *Label { label, _ := gtk.LabelNew("") label.SetMarkup(parser.RenderMarkup(content)) label.SetXAlign(0) // left align label.SetEllipsize(pango.ELLIPSIZE_END) return &Label{ Label: *label, current: content, // reusable primitive, take reference r: *gts.NewReusable(), } } // Reset wipes the state to be just after construction. func (l *Label) Reset() { l.current = text.Rich{} l.r.Invalidate() l.Label.SetText("") } // swapResource is reserved for internal use only. func (l *Label) swapResource(v interface{}) { l.SetLabelUnsafe(v.(*nullLabel).Rich) } func (l *Label) AsyncSetLabel(fn LabelerFn, info string) { gts.AsyncUse(&l.r, l.swapResource, func(ctx context.Context) (interface{}, error) { nl := &nullLabel{} f, err := fn(ctx, nl) nl.cancel = f return nl, err }) } // SetLabel is thread-safe. func (l *Label) SetLabel(content text.Rich) { gts.ExecAsync(func() { l.SetLabelUnsafe(content) }) } // SetLabelUnsafe sets the label in the current thread, meaning it's not // thread-safe. func (l *Label) SetLabelUnsafe(content text.Rich) { l.current = content l.SetMarkup(parser.RenderMarkup(content)) } // GetLabel is NOT thread-safe. func (l *Label) GetLabel() text.Rich { return l.current } // GetText is NOT thread-safe. func (l *Label) GetText() string { return l.current.Content } type ToggleButton struct { gtk.ToggleButton Label } var ( _ gtk.IWidget = (*ToggleButton)(nil) _ cchat.LabelContainer = (*ToggleButton)(nil) ) func NewToggleButton(content text.Rich) *ToggleButton { l := NewLabel(content) l.Show() b, _ := gtk.ToggleButtonNew() primitives.BinLeftAlignLabel(b) b.Add(l) return &ToggleButton{*b, *l} }