Improvements on popovers and mentions

This commit is contained in:
diamondburned 2020-08-13 15:50:51 -07:00
parent 4c22615301
commit fdede5fc13
5 changed files with 110 additions and 15 deletions

6
go.mod
View File

@ -4,13 +4,11 @@ go 1.14
replace github.com/gotk3/gotk3 => github.com/diamondburned/gotk3 v0.0.0-20200630065217-97aeb06d705d
replace github.com/diamondburned/cchat-discord => ../cchat-discord/
require (
github.com/Xuanwo/go-locale v0.2.0
github.com/alecthomas/chroma v0.7.3
github.com/diamondburned/cchat v0.0.45
github.com/diamondburned/cchat-discord v0.0.0-20200718071554-360b34de2a71
github.com/diamondburned/cchat v0.0.46
github.com/diamondburned/cchat-discord v0.0.0-20200730000036-2c93cdc1974e
github.com/diamondburned/cchat-mock v0.0.0-20200709231652-ad222ce5a74b
github.com/diamondburned/imgutil v0.0.0-20200710174014-8a3be144a972
github.com/disintegration/imaging v1.6.2

6
go.sum
View File

@ -50,6 +50,12 @@ github.com/diamondburned/cchat v0.0.43 h1:HetAujSaUSdnQgAUZgprNLARjf/MSWXpCfWdvX
github.com/diamondburned/cchat v0.0.43/go.mod h1:+zXktogE45A0om4fT6B/z6Ii7FXNafjxsNspI0rlhbU=
github.com/diamondburned/cchat v0.0.45 h1:HMVSKx1h6lh2OenWaBTvMSK531hWaXAW7I0tKZepYug=
github.com/diamondburned/cchat v0.0.45/go.mod h1:+zXktogE45A0om4fT6B/z6Ii7FXNafjxsNspI0rlhbU=
github.com/diamondburned/cchat v0.0.46 h1:fzm2XA9uGasX0uaic1AFfUMGA53PlO+GGmkYbx49A5k=
github.com/diamondburned/cchat v0.0.46/go.mod h1:+zXktogE45A0om4fT6B/z6Ii7FXNafjxsNspI0rlhbU=
github.com/diamondburned/cchat-discord v0.0.0-20200719175346-af912db55401 h1:llmx/8UiJoTcHUw+GE5/rESVVmmnLh1HEPx3wRj+oQY=
github.com/diamondburned/cchat-discord v0.0.0-20200719175346-af912db55401/go.mod h1:+hSrIVYj5tIPLAorDsHj2Tbt2fWlZtOanzfEUHX53HM=
github.com/diamondburned/cchat-discord v0.0.0-20200730000036-2c93cdc1974e h1:EA5Vg0x57qLURJP80XhABBW+X0sbQSh2gw5qvPbZTs4=
github.com/diamondburned/cchat-discord v0.0.0-20200730000036-2c93cdc1974e/go.mod h1:+hSrIVYj5tIPLAorDsHj2Tbt2fWlZtOanzfEUHX53HM=
github.com/diamondburned/cchat-mock v0.0.0-20200709231652-ad222ce5a74b h1:sq0MXjJc3yAOZvuolRxOpKQNvpMLyTmsECxQqdYgF5E=
github.com/diamondburned/cchat-mock v0.0.0-20200709231652-ad222ce5a74b/go.mod h1:+bAf0m2o5qH54DmYJ/lR1HeITV53ol0JaoKyFFx3m3E=
github.com/diamondburned/gotk3 v0.0.0-20200630065217-97aeb06d705d h1:Ha/I6PMKi+B4hpWclwlXj0tUMehR7Q0TNxPczzBwzPI=

View File

@ -67,7 +67,7 @@ func WrapFullMessage(gc *message.GenericContainer) *FullMessage {
avatar.SetMarginStart(container.ColumnSpacing * 2)
avatar.Connect("clicked", func() {
if output := gc.Username.Output(); len(output.Mentions) > 0 {
labeluri.PopoverMentioner(avatar, output.Mentions[0])
labeluri.PopoverMentioner(avatar, output.Input, output.Mentions[0])
}
})
// We don't call avatar.Show(). That's called in Attach.

View File

@ -12,6 +12,7 @@ import (
"github.com/diamondburned/cchat-gtk/internal/ui/dialog"
"github.com/diamondburned/cchat-gtk/internal/ui/primitives"
"github.com/diamondburned/cchat-gtk/internal/ui/primitives/roundimage"
"github.com/diamondburned/cchat-gtk/internal/ui/primitives/scrollinput"
"github.com/diamondburned/cchat-gtk/internal/ui/rich"
"github.com/diamondburned/cchat-gtk/internal/ui/rich/parser/markup"
"github.com/diamondburned/cchat/text"
@ -23,8 +24,10 @@ import (
)
const (
MaxWidth = 350
MaxHeight = 350
AvatarSize = 96
PopoverWidth = 250
MaxWidth = 350
MaxHeight = 350
)
type WidgetConnector interface {
@ -88,7 +91,7 @@ func BindRichLabel(label Labeler) {
var output = label.Output()
if mention := output.IsMention(uri); mention != nil {
if p := popoverMentioner(label, mention); p != nil {
if p := popoverMentioner(label, output.Input, mention); p != nil {
p.SetPointingTo(ptr)
p.Popup()
}
@ -100,32 +103,117 @@ func BindRichLabel(label Labeler) {
})
}
func PopoverMentioner(rel gtk.IWidget, mention text.Mentioner) {
if p := popoverMentioner(rel, mention); p != nil {
func PopoverMentioner(rel gtk.IWidget, input string, mention text.Mentioner) {
if p := popoverMentioner(rel, input, mention); p != nil {
p.Popup()
}
}
func popoverMentioner(rel gtk.IWidget, mention text.Mentioner) *gtk.Popover {
func popoverMentioner(rel gtk.IWidget, input string, mention text.Mentioner) *gtk.Popover {
var info = mention.MentionInfo()
if info.Empty() {
return nil
}
start, end := mention.Bounds()
h := input[start:end]
box, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 0)
box.Show()
// Do we have an image or an avatar?
var url string
var round bool
switch v := mention.(type) {
case text.MentionerImage:
url = v.Image()
case text.MentionerAvatar:
url = v.Avatar()
round = true
}
if url != "" {
box.PackStart(popoverImg(url, round), false, false, 8)
}
head, _ := gtk.LabelNew(largeText(h))
head.SetUseMarkup(true)
head.SetLineWrap(true)
head.SetLineWrapMode(pango.WRAP_WORD_CHAR)
head.SetMarginStart(8)
head.SetMarginEnd(8)
head.Show()
box.PackStart(head, false, false, 0)
// Left-align the label if we don't have an image.
if url == "" {
head.SetXAlign(0)
}
l, _ := gtk.LabelNew(markup.Render(info))
l.SetUseMarkup(true)
l.SetLineWrapMode(pango.WRAP_WORD_CHAR)
l.SetLineWrap(true)
l.SetXAlign(0)
l.SetMarginStart(8)
l.SetMarginEnd(8)
l.SetMarginTop(8)
l.SetMarginBottom(8)
l.Show()
// Enable images???
BindActivator(l)
// Make a scrolling text.
scr := scrollinput.NewVScroll(PopoverWidth)
scr.Show()
scr.Add(l)
box.PackStart(scr, false, false, 0)
p, _ := gtk.PopoverNew(rel)
p.Add(l)
p.Connect("destroy", l.Destroy)
p.Add(box)
p.SetSizeRequest(PopoverWidth, -1)
p.Connect("destroy", box.Destroy)
return p
}
func largeText(text string) string {
return fmt.Sprintf(
`<span insert-hyphens="false" size="large">%s</span>`, html.EscapeString(text),
)
}
// popoverImg creates a new button with an image for it, which is used for the
// avatar in the user popover.
func popoverImg(url string, round bool) gtk.IWidget {
var img *gtk.Image
var btn *gtk.Button
if round {
b, _ := roundimage.NewButton()
img = b.Image.Image
btn = b.Button
} else {
img, _ = gtk.ImageNew()
btn, _ = gtk.ButtonNew()
btn.Add(img)
}
img.SetSizeRequest(AvatarSize, AvatarSize)
img.SetHAlign(gtk.ALIGN_CENTER)
img.Show()
httputil.AsyncImageSized(img, url, AvatarSize, AvatarSize)
btn.SetHAlign(gtk.ALIGN_CENTER)
btn.SetRelief(gtk.RELIEF_NONE)
btn.Connect("clicked", func() { PromptOpen(url) })
btn.Show()
return btn
}
func BindActivator(connector WidgetConnector) {
bind(connector, nil)
}

View File

@ -24,11 +24,12 @@ func hyphenate(text string) string {
// RenderOutput is the output of a render.
type RenderOutput struct {
Markup string
Input string // useless to keep parts, as Go will keep all alive anyway
Mentions []text.Mentioner
}
// f_Mention is used to print and parse mention URIs.
const f_Mention = "cchat://mention:%d" // %d == Mentions[i]
const f_Mention = "cchat://mention/%d" // %d == Mentions[i]
// IsMention returns the mention if the URI is correct, or nil if none.
func (r RenderOutput) IsMention(uri string) text.Mentioner {
@ -65,6 +66,7 @@ func RenderCmplxWithConfig(content text.Rich, cfg RenderConfig) RenderOutput {
if len(content.Segments) == 0 {
return RenderOutput{
Markup: hyphenate(html.EscapeString(content.Content)),
Input: content.Content,
}
}
@ -120,7 +122,7 @@ func RenderCmplxWithConfig(content text.Rich, cfg RenderConfig) RenderOutput {
if segment, ok := segment.(text.Mentioner); ok {
// Render the mention into "cchat://mention:0" or such. Other
// components will take care of showing the information.
if cfg.NoMentionLinks {
if !cfg.NoMentionLinks {
appended.AnchorNU(start, end, fmt.Sprintf(f_Mention, len(mentions)))
}
@ -168,6 +170,7 @@ func RenderCmplxWithConfig(content text.Rich, cfg RenderConfig) RenderOutput {
return RenderOutput{
Markup: hyphenate(buf.String()),
Input: content.Content,
Mentions: mentions,
}
}