2020-06-17 07:06:34 +00:00
|
|
|
package rich
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
|
|
|
|
"github.com/diamondburned/cchat"
|
|
|
|
"github.com/diamondburned/cchat-gtk/internal/gts"
|
|
|
|
"github.com/diamondburned/cchat-gtk/internal/ui/primitives"
|
2020-07-14 07:24:55 +00:00
|
|
|
"github.com/diamondburned/cchat-gtk/internal/ui/rich/parser/markup"
|
2020-06-17 07:06:34 +00:00
|
|
|
"github.com/diamondburned/cchat/text"
|
|
|
|
"github.com/gotk3/gotk3/gtk"
|
|
|
|
"github.com/gotk3/gotk3/pango"
|
2020-12-20 09:48:52 +00:00
|
|
|
"github.com/pkg/errors"
|
2020-06-17 07:06:34 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type Labeler interface {
|
|
|
|
// thread-safe
|
|
|
|
cchat.LabelContainer // thread-safe
|
|
|
|
|
|
|
|
// not thread-safe
|
|
|
|
SetLabelUnsafe(text.Rich)
|
|
|
|
GetLabel() text.Rich
|
|
|
|
GetText() string
|
|
|
|
}
|
|
|
|
|
2020-07-14 07:24:55 +00:00
|
|
|
// SuperLabeler represents a label that inherits the current labeler.
|
|
|
|
type SuperLabeler interface {
|
|
|
|
SetLabelUnsafe(text.Rich)
|
|
|
|
}
|
|
|
|
|
2020-06-30 03:39:42 +00:00
|
|
|
type LabelerFn = func(context.Context, cchat.LabelContainer) (func(), error)
|
|
|
|
|
2020-06-17 07:06:34 +00:00
|
|
|
type Label struct {
|
|
|
|
gtk.Label
|
2020-07-14 07:24:55 +00:00
|
|
|
Current text.Rich
|
2020-06-17 07:06:34 +00:00
|
|
|
|
2020-07-14 07:24:55 +00:00
|
|
|
// super unexported field for inheritance
|
|
|
|
super SuperLabeler
|
2020-06-17 07:06:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
var (
|
|
|
|
_ gtk.IWidget = (*Label)(nil)
|
|
|
|
_ Labeler = (*Label)(nil)
|
|
|
|
)
|
|
|
|
|
|
|
|
func NewLabel(content text.Rich) *Label {
|
|
|
|
label, _ := gtk.LabelNew("")
|
2020-07-14 07:24:55 +00:00
|
|
|
label.SetMarkup(markup.Render(content))
|
2020-06-17 07:06:34 +00:00
|
|
|
label.SetXAlign(0) // left align
|
|
|
|
label.SetEllipsize(pango.ELLIPSIZE_END)
|
|
|
|
|
2020-07-04 04:41:12 +00:00
|
|
|
l := &Label{
|
2020-06-17 07:06:34 +00:00
|
|
|
Label: *label,
|
2020-07-14 07:24:55 +00:00
|
|
|
Current: content,
|
2020-06-17 07:06:34 +00:00
|
|
|
}
|
2020-07-04 04:41:12 +00:00
|
|
|
|
|
|
|
return l
|
2020-06-17 07:06:34 +00:00
|
|
|
}
|
|
|
|
|
2020-07-14 07:24:55 +00:00
|
|
|
// NewInheritLabel creates a new label wrapper for structs that inherit this
|
|
|
|
// label.
|
|
|
|
func NewInheritLabel(super SuperLabeler) *Label {
|
|
|
|
l := NewLabel(text.Rich{})
|
|
|
|
l.super = super
|
|
|
|
return l
|
|
|
|
}
|
|
|
|
|
|
|
|
func (l *Label) validsuper() bool {
|
|
|
|
_, ok := l.super.(*Label)
|
|
|
|
// supers must not be the current struct and must not be nil.
|
|
|
|
return !ok && l.super != nil
|
|
|
|
}
|
|
|
|
|
2020-06-30 03:39:42 +00:00
|
|
|
func (l *Label) AsyncSetLabel(fn LabelerFn, info string) {
|
2020-12-20 09:48:52 +00:00
|
|
|
ctx := primitives.HandleDestroyCtx(context.Background(), l)
|
|
|
|
gts.Async(func() (func(), error) {
|
|
|
|
f, err := fn(ctx, l)
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrap(err, "failed to load iconer")
|
|
|
|
}
|
|
|
|
|
|
|
|
return func() { l.Connect("destroy", f) }, nil
|
2020-06-17 07:06:34 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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
|
2020-07-14 07:24:55 +00:00
|
|
|
// thread-safe. If this label has a super, then it will call that struct's
|
|
|
|
// SetLabelUnsafe instead of its own.
|
2020-06-17 07:06:34 +00:00
|
|
|
func (l *Label) SetLabelUnsafe(content text.Rich) {
|
2020-07-14 07:24:55 +00:00
|
|
|
l.Current = content
|
|
|
|
|
|
|
|
if l.validsuper() {
|
|
|
|
l.super.SetLabelUnsafe(content)
|
|
|
|
} else {
|
|
|
|
l.SetMarkup(markup.Render(content))
|
|
|
|
}
|
2020-06-17 07:06:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// GetLabel is NOT thread-safe.
|
|
|
|
func (l *Label) GetLabel() text.Rich {
|
2020-07-14 07:24:55 +00:00
|
|
|
return l.Current
|
2020-06-17 07:06:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// GetText is NOT thread-safe.
|
|
|
|
func (l *Label) GetText() string {
|
2020-07-14 07:24:55 +00:00
|
|
|
return l.Current.Content
|
2020-06-17 07:06:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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}
|
|
|
|
}
|