mirror of
https://github.com/diamondburned/cchat-gtk.git
synced 2024-11-19 12:43:15 +00:00
Several minor changes and bug fixes
This commit added a confirmation dialog when clicking on links. It also fixes some bugs. I forgot the rest.
This commit is contained in:
parent
2fae6ffbb3
commit
76d4b8d69a
8
go.mod
8
go.mod
|
@ -4,13 +4,15 @@ 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.40
|
||||
github.com/diamondburned/cchat-discord v0.0.0-20200703190659-fbf95b9b6c03
|
||||
github.com/diamondburned/cchat v0.0.42
|
||||
github.com/diamondburned/cchat-discord v0.0.0-20200708083530-d0e43cc63b03
|
||||
github.com/diamondburned/cchat-mock v0.0.0-20200704044009-f587c4904aa3
|
||||
github.com/diamondburned/imgutil v0.0.0-20200704034004-40dbfc732516
|
||||
github.com/diamondburned/imgutil v0.0.0-20200708012333-53c9e45dd28b
|
||||
github.com/goodsign/monday v1.0.0
|
||||
github.com/gotk3/gotk3 v0.4.1-0.20200524052254-cb2aa31c6194
|
||||
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79
|
||||
|
|
14
go.sum
14
go.sum
|
@ -46,22 +46,36 @@ github.com/diamondburned/aqs v0.0.0-20200704043812-99b676ee44eb h1:Ja/niwykeFoSk
|
|||
github.com/diamondburned/aqs v0.0.0-20200704043812-99b676ee44eb/go.mod h1:q1MbMBfZrv7xqV8n7LgMwhHs3oBbNwWJes8exs2AmDs=
|
||||
github.com/diamondburned/arikawa v0.9.5 h1:P1ffsp+NHT22wWKYFVC8CdlGRLzPuUV9FcCBKOCJpCI=
|
||||
github.com/diamondburned/arikawa v0.9.5/go.mod h1:nIhVIatzTQhPUa7NB8w4koG1RF9gYbpAr8Fj8sKq660=
|
||||
github.com/diamondburned/arikawa v0.9.6 h1:6TpfTKa2btoVQGxojNqv8g2YC0tIc/tX5w/OCVZPF5Q=
|
||||
github.com/diamondburned/arikawa v0.9.6/go.mod h1:nIhVIatzTQhPUa7NB8w4koG1RF9gYbpAr8Fj8sKq660=
|
||||
github.com/diamondburned/cchat v0.0.40 h1:38gPyJnnDoNDHrXcV8Qchfv3y6jlS3Fzz/6FY0BPH6I=
|
||||
github.com/diamondburned/cchat v0.0.40/go.mod h1:+zXktogE45A0om4fT6B/z6Ii7FXNafjxsNspI0rlhbU=
|
||||
github.com/diamondburned/cchat v0.0.41 h1:6y32s2wWTiDw4hWN/Gna6ay3uUrRAW5V8Cj0/xLKovw=
|
||||
github.com/diamondburned/cchat v0.0.41/go.mod h1:+zXktogE45A0om4fT6B/z6Ii7FXNafjxsNspI0rlhbU=
|
||||
github.com/diamondburned/cchat v0.0.42 h1:FVMLy9hOTxKju8OWDBIStrekbgTHCaH8+GVnV4LOByg=
|
||||
github.com/diamondburned/cchat v0.0.42/go.mod h1:+zXktogE45A0om4fT6B/z6Ii7FXNafjxsNspI0rlhbU=
|
||||
github.com/diamondburned/cchat-discord v0.0.0-20200703190659-fbf95b9b6c03 h1:F5TL7GPRU/D4ldVkS0haY3SiHPtf1Kby/4nbYpm//MQ=
|
||||
github.com/diamondburned/cchat-discord v0.0.0-20200703190659-fbf95b9b6c03/go.mod h1:p0X6QUH0mxK8yEW0+a4QA77ClAmoxz8CvgbnobMtWQA=
|
||||
github.com/diamondburned/cchat-discord v0.0.0-20200708083530-d0e43cc63b03 h1:Xx4ioFTurT6qTxzTL8QlsH3E5VskLxHPJ8RwmaKhObA=
|
||||
github.com/diamondburned/cchat-discord v0.0.0-20200708083530-d0e43cc63b03/go.mod h1:hjaCeQfhSqANH+ZtxXPMWzpgobb4syy2VcqDK4PXcPU=
|
||||
github.com/diamondburned/cchat-mock v0.0.0-20200704044009-f587c4904aa3 h1:xr07/2cwINyrMqh92pQQJVDfQqG0u6gHAK+ZcGfpSew=
|
||||
github.com/diamondburned/cchat-mock v0.0.0-20200704044009-f587c4904aa3/go.mod h1:SRu3OOeggELFr2Wd3/+SpYV1eNcvSk2LBhM70NOZSG8=
|
||||
github.com/diamondburned/gotk3 v0.0.0-20200630065217-97aeb06d705d h1:Ha/I6PMKi+B4hpWclwlXj0tUMehR7Q0TNxPczzBwzPI=
|
||||
github.com/diamondburned/gotk3 v0.0.0-20200630065217-97aeb06d705d/go.mod h1:/hqFpkNa9T3JgNAE2fLvCdov7c5bw//FHNZrZ3Uv9/Q=
|
||||
github.com/diamondburned/imgutil v0.0.0-20200704034004-40dbfc732516 h1:6j4oZahbNdVhSEInRfeYbgDpx1FXDfJy6CcUVyWOuVY=
|
||||
github.com/diamondburned/imgutil v0.0.0-20200704034004-40dbfc732516/go.mod h1:kBQKaukR/LyCfhED99/T4/XxUMDNEEzf1Fx6vreD3RQ=
|
||||
github.com/diamondburned/imgutil v0.0.0-20200708012333-53c9e45dd28b h1:iYKHGvWzNFBIRTSY8Pd5g301YDGWMfs3fh1VS0iBSj0=
|
||||
github.com/diamondburned/imgutil v0.0.0-20200708012333-53c9e45dd28b/go.mod h1:kBQKaukR/LyCfhED99/T4/XxUMDNEEzf1Fx6vreD3RQ=
|
||||
github.com/diamondburned/ningen v0.1.1-0.20200621014632-6babb812b249 h1:yP7kJ+xCGpDz6XbcfACJcju4SH1XDPwlrvbofz3lP8I=
|
||||
github.com/diamondburned/ningen v0.1.1-0.20200621014632-6babb812b249/go.mod h1:xW9hpBZsGi8KpAh10TyP+YQlYBo+Xc+2w4TR6N0951A=
|
||||
github.com/diamondburned/ningen v0.1.1-0.20200708090333-227e90d19851 h1:xf1aLPnwK/Yn2z7dBIgQROSVOEc2wtivgnnwBItdEVM=
|
||||
github.com/diamondburned/ningen v0.1.1-0.20200708090333-227e90d19851/go.mod h1:FNezDLQIhoDS+RkXLSQ7dJNrt6BW/nVl1krzDgWMQwg=
|
||||
github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
|
||||
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
|
||||
github.com/dlclark/regexp2 v1.2.0 h1:8sAhBGEM0dRWogWqWyQeIJnxjWO6oIjl8FKqREDsGfk=
|
||||
github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
|
||||
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
|
||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
|
|
6
internal/c/README.md
Normal file
6
internal/c/README.md
Normal file
|
@ -0,0 +1,6 @@
|
|||
# c
|
||||
|
||||
**HERE BE DRAGONS!!**
|
||||
|
||||
This package and all its subpackages contain either C code or Cgo code. This
|
||||
bugs me and I hate it. PROCEED WITH CAUTION!
|
23
internal/c/gtkp/gtkp.go
Normal file
23
internal/c/gtkp/gtkp.go
Normal file
|
@ -0,0 +1,23 @@
|
|||
package gtkp
|
||||
|
||||
// #cgo pkg-config: gdk-3.0 gio-2.0 glib-2.0 gobject-2.0 gtk+-3.0
|
||||
// #include <glib.h>
|
||||
// #include <gtk/gtk.h>
|
||||
// #include <pango/pango.h>
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/gotk3/gotk3/gtk"
|
||||
)
|
||||
|
||||
func LabelNoHyphens(l *gtk.Label) {
|
||||
attrlist := C.pango_attr_list_new()
|
||||
defer C.pango_attr_list_unref(attrlist)
|
||||
|
||||
C.pango_attr_list_insert(attrlist, C.pango_attr_insert_hyphens_new(C.FALSE))
|
||||
|
||||
v := (*C.GtkLabel)(unsafe.Pointer(l.Native()))
|
||||
C.gtk_label_set_attributes(v, attrlist)
|
||||
}
|
101
internal/c/labelutils/labelutils.go
Normal file
101
internal/c/labelutils/labelutils.go
Normal file
|
@ -0,0 +1,101 @@
|
|||
package labelutils
|
||||
|
||||
// #cgo pkg-config: gdk-3.0 gio-2.0 glib-2.0 gobject-2.0 gtk+-3.0
|
||||
// #include <glib.h>
|
||||
// #include <gtk/gtk.h>
|
||||
// #include <pango/pango.h>
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/gotk3/gotk3/gtk"
|
||||
"github.com/gotk3/gotk3/pango"
|
||||
)
|
||||
|
||||
func gbool(b bool) C.gboolean {
|
||||
if b {
|
||||
return C.gboolean(C.TRUE)
|
||||
} else {
|
||||
return C.gboolean(C.FALSE)
|
||||
}
|
||||
}
|
||||
|
||||
type Attribute = func() *C.PangoAttribute
|
||||
|
||||
func InsertHyphens(hyphens bool) Attribute {
|
||||
return func() *C.PangoAttribute {
|
||||
return C.pango_attr_insert_hyphens_new(gbool(hyphens))
|
||||
}
|
||||
}
|
||||
|
||||
func Scale(factor float64) Attribute {
|
||||
return func() *C.PangoAttribute {
|
||||
return C.pango_attr_scale_new(C.double(factor))
|
||||
}
|
||||
}
|
||||
|
||||
func Underline(underline pango.Underline) Attribute {
|
||||
return func() *C.PangoAttribute {
|
||||
return C.pango_attr_underline_new(C.PangoUnderline(underline))
|
||||
}
|
||||
}
|
||||
|
||||
func Strikethrough(strikethrough bool) Attribute {
|
||||
return func() *C.PangoAttribute {
|
||||
return C.pango_attr_strikethrough_new(gbool(strikethrough))
|
||||
}
|
||||
}
|
||||
|
||||
const u16divu8 = 65535 / 255
|
||||
|
||||
func rgb(hex uint32) (r, g, b uint16) {
|
||||
r = uint16(hex>>16&255) * u16divu8
|
||||
g = uint16(hex>>8&255) * u16divu8
|
||||
b = uint16(hex&255) * u16divu8
|
||||
return
|
||||
}
|
||||
|
||||
func Background(hex uint32) Attribute {
|
||||
r, g, b := rgb(hex)
|
||||
|
||||
return func() *C.PangoAttribute {
|
||||
return C.pango_attr_background_new(C.guint16(r), C.guint16(g), C.guint16(b))
|
||||
}
|
||||
}
|
||||
|
||||
func Foreground(hex uint32) Attribute {
|
||||
r, g, b := rgb(hex)
|
||||
|
||||
return func() *C.PangoAttribute {
|
||||
return C.pango_attr_foreground_new(C.guint16(r), C.guint16(g), C.guint16(b))
|
||||
}
|
||||
}
|
||||
|
||||
func Style(style pango.Style) Attribute {
|
||||
return func() *C.PangoAttribute {
|
||||
return C.pango_attr_style_new(C.PangoStyle(style))
|
||||
}
|
||||
}
|
||||
|
||||
func Family(family string) Attribute {
|
||||
return func() *C.PangoAttribute {
|
||||
str := C.CString(family)
|
||||
defer C.free(unsafe.Pointer(str))
|
||||
return C.pango_attr_family_new(str)
|
||||
}
|
||||
}
|
||||
|
||||
func AddAttr(l *gtk.Label, attrs ...Attribute) {
|
||||
attrlist := C.pango_attr_list_new()
|
||||
defer C.pango_attr_list_unref(attrlist)
|
||||
|
||||
for _, attr := range attrs {
|
||||
// attr() should not unref; insert is transfer-full
|
||||
// https://discourse.gnome.org/t/pango-how-to-turn-off-hyphenation-for-char-wrapping/2101/2
|
||||
C.pango_attr_list_insert(attrlist, attr())
|
||||
}
|
||||
|
||||
v := (*C.GtkLabel)(unsafe.Pointer(l.Native()))
|
||||
C.gtk_label_set_attributes(v, attrlist)
|
||||
}
|
|
@ -6,7 +6,11 @@ import (
|
|||
"github.com/gotk3/gotk3/gtk"
|
||||
)
|
||||
|
||||
func NewModal(body gtk.IWidget, title, label string, callback func()) *gtk.Dialog {
|
||||
func ShowModal(body gtk.IWidget, title, button string, callback func()) {
|
||||
NewModal(body, title, title, callback).Show()
|
||||
}
|
||||
|
||||
func NewModal(body gtk.IWidget, title, button string, callback func()) *gtk.Dialog {
|
||||
cancel, _ := gtk.ButtonNew()
|
||||
cancel.Show()
|
||||
cancel.SetHAlign(gtk.ALIGN_START)
|
||||
|
@ -17,10 +21,12 @@ func NewModal(body gtk.IWidget, title, label string, callback func()) *gtk.Dialo
|
|||
action.Show()
|
||||
action.SetHAlign(gtk.ALIGN_END)
|
||||
action.SetRelief(gtk.RELIEF_NONE)
|
||||
action.SetLabel(label)
|
||||
action.SetLabel(button)
|
||||
|
||||
header, _ := gtk.HeaderBarNew()
|
||||
header.Show()
|
||||
header.SetMarginStart(5)
|
||||
header.SetMarginEnd(5)
|
||||
header.SetTitle(title)
|
||||
header.PackStart(cancel)
|
||||
header.PackEnd(action)
|
||||
|
@ -44,20 +50,13 @@ func NewCSD(body, header gtk.IWidget) *gtk.Dialog {
|
|||
}
|
||||
|
||||
func newCSD(body, header gtk.IWidget) *gtk.Dialog {
|
||||
dialog, _ := gtk.DialogNew()
|
||||
dialog.SetModal(true)
|
||||
dialog.SetTransientFor(gts.App.Window)
|
||||
|
||||
if area, _ := dialog.GetContentArea(); area != nil {
|
||||
dialog.Remove(area)
|
||||
}
|
||||
dialog, _ := gts.NewEmptyModalDialog()
|
||||
dialog.SetDefaultSize(450, 300)
|
||||
dialog.Add(body)
|
||||
|
||||
if oldh, _ := dialog.GetHeaderBar(); oldh != nil {
|
||||
dialog.Remove(oldh)
|
||||
}
|
||||
|
||||
dialog.Add(body)
|
||||
|
||||
dialog.SetTitlebar(header)
|
||||
|
||||
return dialog
|
||||
|
|
|
@ -1,15 +1,23 @@
|
|||
package imgview
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"html"
|
||||
"net/url"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/diamondburned/cchat-gtk/internal/c/labelutils"
|
||||
"github.com/diamondburned/cchat-gtk/internal/gts/httputil"
|
||||
"github.com/diamondburned/cchat-gtk/internal/log"
|
||||
"github.com/diamondburned/cchat-gtk/internal/ui/dialog"
|
||||
"github.com/diamondburned/cchat-gtk/internal/ui/primitives"
|
||||
"github.com/diamondburned/cchat-gtk/internal/ui/rich/parser"
|
||||
"github.com/gotk3/gotk3/gdk"
|
||||
"github.com/gotk3/gotk3/gtk"
|
||||
"github.com/gotk3/gotk3/pango"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/skratchdot/open-golang/open"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -44,7 +52,8 @@ func BindTooltip(connector WidgetConnector) {
|
|||
r.SetX(int(x))
|
||||
r.SetY(int(y))
|
||||
|
||||
// Make a new image that's asynchronously fetched.
|
||||
// Make a new image that's asynchronously fetched inside a button.
|
||||
// This allows us to make it clickable.
|
||||
img, _ := gtk.ImageNewFromIconName("image-loading", gtk.ICON_SIZE_BUTTON)
|
||||
img.SetMarginStart(5)
|
||||
img.SetMarginEnd(5)
|
||||
|
@ -56,20 +65,80 @@ func BindTooltip(connector WidgetConnector) {
|
|||
var w, h = parser.FragmentImageSize(uri, MaxWidth, MaxHeight)
|
||||
httputil.AsyncImageSized(img, uri, w, h)
|
||||
|
||||
btn, _ := gtk.ButtonNew()
|
||||
btn.Add(img)
|
||||
btn.SetRelief(gtk.RELIEF_NONE)
|
||||
btn.Connect("clicked", func() { PromptOpen(uri) })
|
||||
btn.Show()
|
||||
|
||||
p, _ := gtk.PopoverNew(c)
|
||||
p.SetPointingTo(r)
|
||||
p.Connect("closed", img.Destroy) // on close, destroy image
|
||||
p.Add(img)
|
||||
p.Add(btn)
|
||||
p.Popup()
|
||||
|
||||
return true
|
||||
|
||||
default:
|
||||
return false
|
||||
PromptOpen(uri)
|
||||
}
|
||||
|
||||
// Never let Gtk open the dialog.
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
const urlPrompt = `This link leads to the following URL:
|
||||
<span weight="bold"><a href="%[1]s">%[1]s</a></span>
|
||||
Click <b>Open</b> to proceed.`
|
||||
|
||||
var warnLabelCSS = primitives.PrepareCSS(`
|
||||
label {
|
||||
padding: 4px 8px;
|
||||
}
|
||||
`)
|
||||
|
||||
// PromptOpen shows a dialog asking if the URL should be opened.
|
||||
func PromptOpen(uri string) {
|
||||
// Format the prompt body.
|
||||
l, _ := gtk.LabelNew("")
|
||||
l.SetJustify(gtk.JUSTIFY_CENTER)
|
||||
l.SetLineWrap(true)
|
||||
l.SetLineWrapMode(pango.WRAP_WORD_CHAR)
|
||||
l.Show()
|
||||
l.SetMarkup(fmt.Sprintf(urlPrompt, html.EscapeString(uri)))
|
||||
|
||||
// Style the label.
|
||||
primitives.AttachCSS(l, warnLabelCSS)
|
||||
|
||||
// Disable hyphens on line wraps.
|
||||
labelutils.AddAttr(l, labelutils.InsertHyphens(false))
|
||||
|
||||
open := func() {
|
||||
if err := open.Start(uri); err != nil {
|
||||
log.Error(errors.Wrap(err, "Failed to open URL after confirm"))
|
||||
}
|
||||
}
|
||||
|
||||
// Prompt the user if they want to open the URL.
|
||||
dlg := dialog.NewModal(l, "Caution", "Open", open)
|
||||
dlg.SetSizeRequest(350, 100)
|
||||
|
||||
// Add a class to the dialog to allow theming.
|
||||
primitives.AddClass(dlg, "url-warning")
|
||||
|
||||
// On link click, close the dialog.
|
||||
l.Connect("activate-link", func(l *gtk.Label, uri string) bool {
|
||||
// Close the dialog.
|
||||
dlg.Destroy()
|
||||
// Open the link anyway.
|
||||
open()
|
||||
// Return true since we handled the event.
|
||||
return true
|
||||
})
|
||||
|
||||
// Show the dialog.
|
||||
dlg.Show()
|
||||
}
|
||||
|
||||
// ext parses and sanitizes the extension to something comparable.
|
||||
func ext(uri string) string {
|
||||
u, err := url.Parse(uri)
|
||||
|
|
|
@ -64,27 +64,32 @@ func RenderMarkup(content text.Rich) string {
|
|||
for _, segment := range content.Segments {
|
||||
start, end := segment.Bounds()
|
||||
|
||||
switch segment := segment.(type) {
|
||||
case text.Linker:
|
||||
if segment, ok := segment.(text.Linker); ok {
|
||||
appended.Addf(start, `<a href="%s">`, html.EscapeString(segment.Link()))
|
||||
appended.Add(end, "</a>")
|
||||
}
|
||||
|
||||
case text.Imager:
|
||||
if segment, ok := segment.(text.Imager); ok {
|
||||
// Ends don't matter with images.
|
||||
appended.Add(start, composeImageMarkup(segment))
|
||||
}
|
||||
|
||||
case text.Colorer:
|
||||
if segment, ok := segment.(text.Colorer); ok {
|
||||
appended.Span(start, end, fmt.Sprintf(`color="#%06X"`, segment.Color()))
|
||||
}
|
||||
|
||||
case text.Attributor:
|
||||
if segment, ok := segment.(text.Attributor); ok {
|
||||
appended.Span(start, end, markupAttr(segment.Attribute()))
|
||||
}
|
||||
|
||||
case text.Codeblocker:
|
||||
if segment, ok := segment.(text.Codeblocker); ok {
|
||||
// Syntax highlight the codeblock.
|
||||
hl.Segments(&appended, content.Content, segment)
|
||||
}
|
||||
|
||||
case text.Quoteblocker:
|
||||
// TODO: pls.
|
||||
// TODO: make this not shit. Maybe make it somehow not rely on green
|
||||
// arrows. Or maybe.
|
||||
if _, ok := segment.(text.Quoteblocker); ok {
|
||||
appended.Span(start, end, `color="#789922"`)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue