Compare commits

...

3 Commits

3 changed files with 78 additions and 20 deletions

View File

@ -13,6 +13,28 @@ import (
"github.com/gotk3/gotk3/gtk"
)
const appCSS = `
* {
font-family: "Noto Sans", "Cantarell", "Sans";
color: #E1EEFF;
}
window, GtkDrawingArea, box {
background-color: #0B0F1A;
}
button {
background: #171C2A;
color: #E1EEFF;
border-radius: 6px;
padding: 4px 8px;
}
button:hover {
background: #24314A;
}
label {
color: #E1EEFF;
}
`
type pane struct {
area *gtk.DrawingArea
mpv *mpvembed.Client
@ -42,6 +64,12 @@ func main() {
grid.Attach(left.area, 0, 1, 1, 1)
grid.Attach(right.area, 1, 1, 1, 1)
applyCSS()
preferDark()
setupDragDest(left, win)
setupDragDest(right, win)
win.Connect("destroy", func() {
if left.mpv != nil {
left.mpv.Destroy()
@ -215,3 +243,50 @@ func getWindowID(w *gdk.Window) uint64 {
func gdkWindowGetXID(w *gdk.Window) uint {
return uint(w.GetXID())
}
func applyCSS() {
provider, err := gtk.CssProviderNew()
if err != nil {
return
}
if err := provider.LoadFromData(appCSS); err != nil {
return
}
screen, err := gdk.ScreenGetDefault()
if err != nil {
return
}
gtk.AddProviderForScreen(screen, provider, gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
}
func preferDark() {
if settings, err := gtk.SettingsGetDefault(); err == nil && settings != nil {
_ = settings.SetProperty("gtk-application-prefer-dark-theme", true)
}
}
func setupDragDest(p *pane, win *gtk.Window) {
// Accept URI drops
p.area.DragDestSet(gtk.DEST_DEFAULT_ALL, []gtk.TargetEntry{gtk.TargetEntry{}} /* dummy */, gdk.ACTION_COPY)
p.area.Connect("drag-data-received", func(_ *gtk.DrawingArea, ctx *gdk.DragContext, x, y int, data *gtk.SelectionData, info uint, t uint32) {
uris := data.GetURIs()
if len(uris) == 0 {
return
}
// Take first URI
if path := uriToPath(uris[0]); path != "" {
loadIntoPane(p, path)
}
})
}
func uriToPath(u string) string {
if u == "" {
return ""
}
// text/uri-list format: file:///path or path\n
if len(u) >= 7 && u[:7] == "file://" {
u = u[7:]
}
return u
}

20
main.go
View File

@ -4,15 +4,12 @@ import (
"bufio"
"bytes"
"context"
"encoding/binary"
"encoding/json"
"errors"
"flag"
"fmt"
"image"
"image/color"
"image/png"
"io"
"math"
"net/url"
"os"
@ -42,7 +39,6 @@ import (
"git.leaktechnologies.dev/stu/VT_Player/internal/queue"
"git.leaktechnologies.dev/stu/VT_Player/internal/ui"
"git.leaktechnologies.dev/stu/VT_Player/internal/utils"
"github.com/hajimehoshi/oto"
)
// Module describes a high level tool surface that gets a tile on the menu.
@ -2034,7 +2030,6 @@ func runGUI() {
a.Settings().SetTheme(&ui.MonoTheme{})
logging.Debug(logging.CatUI, "created fyne app: %#v", a)
w := a.NewWindow("VT Player")
state.window = w
if icon := utils.LoadAppIcon(); icon != nil {
a.SetIcon(icon)
w.SetIcon(icon)
@ -3948,21 +3943,6 @@ func (s *appState) showFrameManual(path string, img *canvas.Image) {
}
func (s *appState) captureCoverFromCurrent() (string, error) {
// If we have a play session active, capture the current playing frame
if s.playSess != nil && s.playSess.img != nil && s.playSess.img.Image != nil {
dest := filepath.Join(os.TempDir(), fmt.Sprintf("videotools-cover-%d.png", time.Now().UnixNano()))
f, err := os.Create(dest)
if err != nil {
return "", err
}
defer f.Close()
if err := png.Encode(f, s.playSess.img.Image); err != nil {
return "", err
}
return dest, nil
}
// Otherwise use the current preview frame
if s.currentFrame == "" {
return "", fmt.Errorf("no frame available")
}

View File

@ -4,6 +4,7 @@ package mpvembed
#cgo pkg-config: mpv
#include <mpv/client.h>
#include <stdlib.h>
#include <locale.h>
static inline const char* mpv_errstr(int err) { return mpv_error_string(err); }
*/
@ -21,6 +22,8 @@ type Client struct {
// New creates a new mpv client.
func New() (*Client, error) {
// Ensure numeric locale is C to satisfy mpv.
C.setlocale(C.int(C.LC_NUMERIC), C.CString("C"))
h := C.mpv_create()
if h == nil {
return nil, errors.New("mpv_create returned nil")