2020-06-17 07:06:34 +00:00
|
|
|
package rich
|
|
|
|
|
|
|
|
import (
|
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"
|
|
|
|
)
|
|
|
|
|
2021-03-29 21:46:52 +00:00
|
|
|
// LabelRenderer is the input/output function to render a rich text segment to
|
|
|
|
// Pango markup.
|
|
|
|
type LabelRenderer = func(text.Rich) markup.RenderOutput
|
2020-06-17 07:06:34 +00:00
|
|
|
|
2021-03-29 21:46:52 +00:00
|
|
|
// RenderSkipImages is a label renderer that skips images.
|
|
|
|
func RenderSkipImages(rich text.Rich) markup.RenderOutput {
|
|
|
|
return markup.RenderCmplxWithConfig(rich, markup.RenderConfig{
|
|
|
|
SkipImages: true,
|
|
|
|
NoMentionLinks: true,
|
|
|
|
})
|
2020-07-14 07:24:55 +00:00
|
|
|
}
|
|
|
|
|
2021-03-29 21:46:52 +00:00
|
|
|
// Label provides an abstraction around a regular GTK label that can be
|
|
|
|
// self-updated. Widgets that extend off of this (such as ToggleButton) does not
|
|
|
|
// need to manually
|
2020-06-17 07:06:34 +00:00
|
|
|
type Label struct {
|
|
|
|
gtk.Label
|
2021-03-29 21:46:52 +00:00
|
|
|
label text.Rich
|
|
|
|
output markup.RenderOutput
|
|
|
|
render LabelRenderer
|
2020-06-17 07:06:34 +00:00
|
|
|
}
|
|
|
|
|
2021-03-29 21:46:52 +00:00
|
|
|
var _ gtk.IWidget = (*Label)(nil)
|
2020-06-17 07:06:34 +00:00
|
|
|
|
2021-03-29 21:46:52 +00:00
|
|
|
// NewStaticLabel creates a static, non-updating label.
|
|
|
|
func NewStaticLabel(rich text.Rich) *Label {
|
2020-06-17 07:06:34 +00:00
|
|
|
label, _ := gtk.LabelNew("")
|
|
|
|
label.SetXAlign(0) // left align
|
|
|
|
label.SetEllipsize(pango.ELLIPSIZE_END)
|
|
|
|
|
2021-03-29 21:46:52 +00:00
|
|
|
if !rich.IsEmpty() {
|
|
|
|
label.SetMarkup(markup.Render(rich))
|
2020-06-17 07:06:34 +00:00
|
|
|
}
|
2020-07-04 04:41:12 +00:00
|
|
|
|
2021-03-29 21:46:52 +00:00
|
|
|
return &Label{Label: *label}
|
2020-06-17 07:06:34 +00:00
|
|
|
}
|
|
|
|
|
2021-03-29 21:46:52 +00:00
|
|
|
// NewLabel creates a self-updating label.
|
|
|
|
func NewLabel(state LabelStateStorer) *Label {
|
|
|
|
return NewLabelWithRenderer(state, nil)
|
2020-07-14 07:24:55 +00:00
|
|
|
}
|
|
|
|
|
2021-03-29 21:46:52 +00:00
|
|
|
// NewLabelWithRenderer creates a self-updating label using the given renderer.
|
|
|
|
func NewLabelWithRenderer(state LabelStateStorer, r LabelRenderer) *Label {
|
|
|
|
l := NewStaticLabel(text.Plain(""))
|
|
|
|
l.render = r
|
|
|
|
state.OnUpdate(func() { l.SetLabel(state.Label()) })
|
|
|
|
return l
|
2020-07-14 07:24:55 +00:00
|
|
|
}
|
|
|
|
|
2021-03-29 21:46:52 +00:00
|
|
|
// Output returns the rendered output.
|
|
|
|
func (l *Label) Output() markup.RenderOutput {
|
|
|
|
return l.output
|
2020-06-17 07:06:34 +00:00
|
|
|
}
|
|
|
|
|
2021-03-29 21:46:52 +00:00
|
|
|
// SetLabel sets the label in the current thread, meaning it's not thread-safe.
|
2020-06-17 07:06:34 +00:00
|
|
|
func (l *Label) SetLabel(content text.Rich) {
|
2021-03-29 21:46:52 +00:00
|
|
|
// Save a call if the content is empty.
|
|
|
|
if content.IsEmpty() {
|
|
|
|
l.label = content
|
|
|
|
l.output = markup.RenderOutput{}
|
2020-06-17 07:06:34 +00:00
|
|
|
|
2021-03-29 21:46:52 +00:00
|
|
|
return
|
2020-07-14 07:24:55 +00:00
|
|
|
}
|
2020-06-17 07:06:34 +00:00
|
|
|
|
2021-03-29 21:46:52 +00:00
|
|
|
l.label = content
|
2020-06-17 07:06:34 +00:00
|
|
|
|
2021-03-29 21:46:52 +00:00
|
|
|
var out markup.RenderOutput
|
|
|
|
if l.render != nil {
|
|
|
|
out = l.render(content)
|
|
|
|
} else {
|
|
|
|
out = markup.RenderCmplx(content)
|
|
|
|
}
|
2020-06-17 07:06:34 +00:00
|
|
|
|
2021-03-29 21:46:52 +00:00
|
|
|
l.output = out
|
|
|
|
l.SetMarkup(out.Markup)
|
|
|
|
l.SetTooltipMarkup(out.Markup)
|
2020-06-17 07:06:34 +00:00
|
|
|
}
|
|
|
|
|
2021-03-29 21:46:52 +00:00
|
|
|
// SetRenderer sets a custom renderer. If the given renderer is nil, then the
|
|
|
|
// default markup renderer is used instead. The label is automatically updated.
|
|
|
|
func (l *Label) SetRenderer(renderer LabelRenderer) {
|
|
|
|
l.render = renderer
|
|
|
|
l.SetLabel(l.label)
|
2020-06-17 07:06:34 +00:00
|
|
|
}
|