From 3221c18658141ece1a33f8a05dacf8f829fd919d Mon Sep 17 00:00:00 2001 From: diamondburned Date: Sun, 20 Dec 2020 00:18:23 -0800 Subject: [PATCH] slight tweaks for hidpi --- go.mod | 2 +- go.sum | 2 ++ internal/gts/httputil/image.go | 24 ++++++++----- .../messages/container/cozy/message_full.go | 4 +-- internal/ui/messages/memberlist/memberlist.go | 2 +- .../ui/primitives/completion/completer.go | 2 +- internal/ui/primitives/primitives.go | 1 + internal/ui/primitives/roundimage/avatar.go | 35 ++++++++++++++++--- internal/ui/rich/image.go | 17 +++++---- internal/ui/rich/labeluri/labeluri.go | 5 +-- 10 files changed, 66 insertions(+), 28 deletions(-) diff --git a/go.mod b/go.mod index 4afbe93..4af8557 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/Xuanwo/go-locale v1.0.0 github.com/alecthomas/chroma v0.7.3 github.com/diamondburned/cchat v0.3.15 - github.com/diamondburned/cchat-discord v0.0.0-20201220054426-918719599f2d + github.com/diamondburned/cchat-discord v0.0.0-20201220081640-288591a535af github.com/diamondburned/cchat-mock v0.0.0-20201115033644-df8d1b10f9db github.com/diamondburned/gspell v0.0.0-20200830182722-77e5d27d6894 github.com/diamondburned/handy v0.0.0-20200829011954-4667e7a918f4 diff --git a/go.sum b/go.sum index b7e4476..31b5a03 100644 --- a/go.sum +++ b/go.sum @@ -58,6 +58,8 @@ github.com/diamondburned/cchat v0.3.15 h1:BJf8ZiRtDWTGMtQ3QqjNU0H+784WSrkJEpFGkK github.com/diamondburned/cchat v0.3.15/go.mod h1:IlMtF+XIvAJh0GL/2yFdf0/34w+Hdy5A1GgvSwAXtQI= github.com/diamondburned/cchat-discord v0.0.0-20201220054426-918719599f2d h1:n61DxLdX7nPj7KA1N/azaR8wa0pnDBDT6Yi1seOsBWM= github.com/diamondburned/cchat-discord v0.0.0-20201220054426-918719599f2d/go.mod h1:pvp1TOHK7NUM+GDRPixQGsKyCSbGYhiseK2jM+1I+ms= +github.com/diamondburned/cchat-discord v0.0.0-20201220081640-288591a535af h1:pTdxsrVSYCdraGormbu1t8uQJMe/OD/ZIz9KljDWAvc= +github.com/diamondburned/cchat-discord v0.0.0-20201220081640-288591a535af/go.mod h1:pvp1TOHK7NUM+GDRPixQGsKyCSbGYhiseK2jM+1I+ms= github.com/diamondburned/cchat-mock v0.0.0-20201115033644-df8d1b10f9db h1:VQI2PdbsdsRJ7d669kp35GbCUO44KZ0Xfqdu4o/oqVg= github.com/diamondburned/cchat-mock v0.0.0-20201115033644-df8d1b10f9db/go.mod h1:M87kjNzWVPlkZycFNzpGPKQXzkHNnZphuwMf3E9ckgc= github.com/diamondburned/gotk3 v0.0.0-20201209182406-e7291341a091 h1:lQpSWzbi3rQf66aMSip/rIypasIFwqCqF0Wfn5og6gw= diff --git a/internal/gts/httputil/image.go b/internal/gts/httputil/image.go index fa47cf4..7c61323 100644 --- a/internal/gts/httputil/image.go +++ b/internal/gts/httputil/image.go @@ -23,20 +23,28 @@ type ImageContainer interface { type ImageContainerSizer interface { ImageContainer + GetSizeRequest() (w, h int) SetSizeRequest(w, h int) } +type dummySizer struct { + ImageContainer +} + +func (dummySizer) GetSizeRequest() (int, int) { return -1, -1 } +func (dummySizer) SetSizeRequest(int, int) {} + // AsyncImage loads an image. This method uses the cache. func AsyncImage(img ImageContainer, url string, procs ...imgutil.Processor) { - asyncImage(img, url, 0, 0, procs) + asyncImage(dummySizer{img}, url, procs) } // AsyncImageSized resizes using GdkPixbuf. This method uses the cache. -func AsyncImageSized(img ImageContainerSizer, url string, w, h int, procs ...imgutil.Processor) { - asyncImage(img, url, w, h, procs) +func AsyncImageSized(img ImageContainerSizer, url string, procs ...imgutil.Processor) { + asyncImage(img, url, procs) } -func asyncImage(img ImageContainer, url string, w, h int, procs []imgutil.Processor) { +func asyncImage(img ImageContainerSizer, url string, procs []imgutil.Processor) { if url == "" { return } @@ -55,14 +63,12 @@ func asyncImage(img ImageContainer, url string, w, h int, procs []imgutil.Proces return } - if w > 0 && h > 0 { + if w, h := img.GetSizeRequest(); w > 0 && h > 0 { l.Connect("size-prepared", func(l *gdk.PixbufLoader, imgW, imgH int) { w, h = imgutil.MaxSize(imgW, imgH, w, h) if w != imgW || h != imgH { l.SetSize(w, h) - execIfCtx(ctx, func() { - img.(ImageContainerSizer).SetSizeRequest(w, h) - }) + execIfCtx(ctx, func() { img.SetSizeRequest(w, h) }) } }) } @@ -73,7 +79,7 @@ func asyncImage(img ImageContainer, url string, w, h int, procs []imgutil.Proces } func connectDestroyer(img ImageContainer, cancel func()) { - img.Connect("destroy", func(img ImageContainer) { + img.Connect("destroy", func() { cancel() img.SetFromPixbuf(nil) }) diff --git a/internal/ui/messages/container/cozy/message_full.go b/internal/ui/messages/container/cozy/message_full.go index 523634d..74a692c 100644 --- a/internal/ui/messages/container/cozy/message_full.go +++ b/internal/ui/messages/container/cozy/message_full.go @@ -195,8 +195,8 @@ func NewAvatar() *Avatar { img.Show() avatar, _ := roundimage.NewCustomButton(img) - avatar.SetSizeRequest(AvatarSize, AvatarSize) avatar.SetVAlign(gtk.ALIGN_START) + avatar.Image.SetSizeRequest(AvatarSize, AvatarSize) // Default icon. primitives.SetImageIcon(img, "user-available-symbolic", AvatarSize) @@ -215,7 +215,7 @@ func (a *Avatar) SetURL(url string) { } a.url = url - httputil.AsyncImageSized(a.Image, url, AvatarSize, AvatarSize) + httputil.AsyncImageSized(a.Image, url) } // ManuallySetURL sets the URL without downloading the image. It assumes the diff --git a/internal/ui/messages/memberlist/memberlist.go b/internal/ui/messages/memberlist/memberlist.go index 6d98860..86f5156 100644 --- a/internal/ui/messages/memberlist/memberlist.go +++ b/internal/ui/messages/memberlist/memberlist.go @@ -58,7 +58,7 @@ func New(ctrl Controller) *Container { sw.Show() rev, _ := gtk.RevealerNew() - rev.SetTransitionType(gtk.REVEALER_TRANSITION_TYPE_SLIDE_RIGHT) + rev.SetTransitionType(gtk.REVEALER_TRANSITION_TYPE_SLIDE_LEFT) rev.SetTransitionDuration(75) rev.SetRevealChild(false) rev.Add(sw) diff --git a/internal/ui/primitives/completion/completer.go b/internal/ui/primitives/completion/completer.go index 55c3ed2..a714b3d 100644 --- a/internal/ui/primitives/completion/completer.go +++ b/internal/ui/primitives/completion/completer.go @@ -234,7 +234,7 @@ func (c *Completer) update() []gtk.IWidget { pps = ppIcon } - httputil.AsyncImageSized(img, entry.IconURL, size, size, pps...) + httputil.AsyncImageSized(img, entry.IconURL, pps...) } widgets[i] = b diff --git a/internal/ui/primitives/primitives.go b/internal/ui/primitives/primitives.go index 2432de7..9407d4f 100644 --- a/internal/ui/primitives/primitives.go +++ b/internal/ui/primitives/primitives.go @@ -112,6 +112,7 @@ func NewImageIconPx(icon string, sizepx int) *gtk.Image { type ImageIconSetter interface { SetProperty(name string, value interface{}) error + GetSizeRequest() (w, h int) SetSizeRequest(w, h int) } diff --git a/internal/ui/primitives/roundimage/avatar.go b/internal/ui/primitives/roundimage/avatar.go index d12e348..0b2e85b 100644 --- a/internal/ui/primitives/roundimage/avatar.go +++ b/internal/ui/primitives/roundimage/avatar.go @@ -24,8 +24,11 @@ func TrySetText(imager Imager, text string) { type Avatar struct { handy.Avatar pixbuf *gdk.Pixbuf + size int } +// Make a better API that allows scaling. + var ( _ Imager = (*Avatar)(nil) _ TextSetter = (*Avatar)(nil) @@ -33,12 +36,18 @@ var ( ) func NewAvatar(size int) *Avatar { - a := handy.AvatarNew(size, "", true) - if a == nil { - return nil + avatar := Avatar{ + Avatar: *handy.AvatarNew(size, "", true), + size: size, } + // Set the load function. This should hopefully trigger a reload. + avatar.SetImageLoadFunc(avatar.loadFunc) - return &Avatar{*a, nil} + return &avatar +} + +func (a *Avatar) GetSizeRequest() (int, int) { + return a.size, a.size } // SetSizeRequest sets the avatar size. The actual size is min(w, h). @@ -52,7 +61,23 @@ func (a *Avatar) SetSizeRequest(w, h int) { a.Avatar.SetSizeRequest(w, h) } -func (a *Avatar) loadFunc(int) *gdk.Pixbuf { +func (a *Avatar) loadFunc(size int) *gdk.Pixbuf { + if a.pixbuf == nil { + a.size = size + return nil + } + + if a.size != size { + a.size = size + + p, err := a.pixbuf.ScaleSimple(size, size, gdk.INTERP_HYPER) + if err != nil { + return a.pixbuf + } + + a.pixbuf = p + } + return a.pixbuf } diff --git a/internal/ui/rich/image.go b/internal/ui/rich/image.go index 472d146..51a3261 100644 --- a/internal/ui/rich/image.go +++ b/internal/ui/rich/image.go @@ -38,7 +38,6 @@ type Icon struct { *gtk.Revealer Image RoundIconContainer procs []imgutil.Processor - size int r *Reusable @@ -93,10 +92,6 @@ func (i *Icon) URL() string { return i.url } -func (i *Icon) Size() int { - return i.size -} - func (i *Icon) CopyPixbuf(dst httputil.ImageContainer) { switch i.Image.GetStorageType() { case gtk.IMAGE_PIXBUF: @@ -120,10 +115,18 @@ func (i *Icon) SetPlaceholderIcon(iconName string, iconSzPx int) { // SetSize is not thread-safe. func (i *Icon) SetSize(szpx int) { - i.size = szpx i.Image.SetSizeRequest(szpx, szpx) } +// Size returns the minimum of the image size. It is not thread-safe. +func (i *Icon) Size() int { + w, h := i.Image.GetSizeRequest() + if h < w { + return h + } + return w +} + // AddProcessors is not thread-safe. func (i *Icon) AddProcessors(procs ...imgutil.Processor) { i.procs = append(i.procs, procs...) @@ -154,7 +157,7 @@ func (i *Icon) SetIconUnsafe(url string) { } func (i *Icon) updateAsync() { - httputil.AsyncImageSized(i.Image, i.url, i.size, i.size, i.procs...) + httputil.AsyncImageSized(i.Image, i.url, i.procs...) } type EventIcon struct { diff --git a/internal/ui/rich/labeluri/labeluri.go b/internal/ui/rich/labeluri/labeluri.go index bdc82f1..5553a25 100644 --- a/internal/ui/rich/labeluri/labeluri.go +++ b/internal/ui/rich/labeluri/labeluri.go @@ -211,7 +211,7 @@ func popoverImg(url string, round bool) gtk.IWidget { img.SetHAlign(gtk.ALIGN_CENTER) img.Show() - httputil.AsyncImageSized(idl, url, AvatarSize, AvatarSize) + httputil.AsyncImageSized(idl, url) btn.SetHAlign(gtk.ALIGN_CENTER) btn.SetRelief(gtk.RELIEF_NONE) @@ -263,11 +263,12 @@ func bind(connector WidgetConnector, activator func(uri string, r gdk.Rectangle) img = r.Image } + img.SetSizeRequest(w, h) img.SetFromIconName("image-loading", gtk.ICON_SIZE_BUTTON) img.Show() // Asynchronously fetch the image. - httputil.AsyncImageSized(img, uri, w, h) + httputil.AsyncImageSized(img, uri) btn, _ := gtk.ButtonNew() btn.Add(img)