Added simple drop (files) addon.
This commit is contained in:
parent
4cff23cd37
commit
302ae1c338
7
addons/drop/drop.go
Normal file
7
addons/drop/drop.go
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
// +build !windows
|
||||||
|
|
||||||
|
package drop
|
||||||
|
|
||||||
|
func Register(dropper Dropper) error {
|
||||||
|
return nil
|
||||||
|
}
|
52
addons/drop/drop_windows.c
Normal file
52
addons/drop/drop_windows.c
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <shellapi.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "_cgo_export.h"
|
||||||
|
|
||||||
|
#define droppedFilePathSize 32767
|
||||||
|
|
||||||
|
HHOOK nextHook;
|
||||||
|
uint32_t nextDropID = 0;
|
||||||
|
|
||||||
|
LRESULT CALLBACK DragAndDropHook(
|
||||||
|
_In_ int nCode,
|
||||||
|
_In_ WPARAM wParam,
|
||||||
|
_In_ LPARAM lParam)
|
||||||
|
{
|
||||||
|
if (nCode < 0 || wParam == 0)
|
||||||
|
return CallNextHookEx(nextHook, nCode, wParam, lParam);
|
||||||
|
|
||||||
|
LPMSG message = (LPMSG)lParam;
|
||||||
|
switch (message->message)
|
||||||
|
{
|
||||||
|
case WM_DROPFILES:
|
||||||
|
{
|
||||||
|
wchar_t droppedFilePath[droppedFilePathSize];
|
||||||
|
uint32_t dropID = nextDropID++;
|
||||||
|
|
||||||
|
HDROP drop = (HDROP)message->wParam;
|
||||||
|
POINT position;
|
||||||
|
DragQueryPoint(drop, &position);
|
||||||
|
droppedFilesPosition(dropID, position.x, position.y);
|
||||||
|
UINT numberOfFiles = DragQueryFile(drop, 0xFFFFFFFF, NULL, 0);
|
||||||
|
for (UINT fileIndex = 0; fileIndex < numberOfFiles; fileIndex++)
|
||||||
|
{
|
||||||
|
UINT length = DragQueryFileW(drop, fileIndex, droppedFilePath, droppedFilePathSize);
|
||||||
|
droppedFilesFile(dropID, &droppedFilePath[0], length);
|
||||||
|
}
|
||||||
|
droppedFilesDrop(dropID);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return CallNextHookEx(nextHook, nCode, wParam, lParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetDragAndDropHook(void *window)
|
||||||
|
{
|
||||||
|
HWND windowHandle = (HWND)window;
|
||||||
|
DragAcceptFiles(windowHandle, TRUE);
|
||||||
|
DWORD threadId = GetWindowThreadProcessId(windowHandle, NULL);
|
||||||
|
nextHook = SetWindowsHookEx(WH_GETMESSAGE, DragAndDropHook, NULL, threadId);
|
||||||
|
}
|
70
addons/drop/drop_windows.go
Normal file
70
addons/drop/drop_windows.go
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
// +build windows
|
||||||
|
|
||||||
|
package drop
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"golang.org/x/text/encoding/unicode"
|
||||||
|
"opslag.de/schobers/geom"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
void SetDragAndDropHook(void* window);
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
var handler Dropper = nil
|
||||||
|
var drops map[uint32]droppedFiles = map[uint32]droppedFiles{}
|
||||||
|
|
||||||
|
type droppedFiles struct {
|
||||||
|
X, Y int
|
||||||
|
Files []string
|
||||||
|
}
|
||||||
|
|
||||||
|
//export droppedFilesPosition
|
||||||
|
func droppedFilesPosition(id C.uint32_t, x, y C.INT) {
|
||||||
|
files := drops[uint32(id)]
|
||||||
|
files.X = int(x)
|
||||||
|
files.Y = int(y)
|
||||||
|
drops[uint32(id)] = files
|
||||||
|
}
|
||||||
|
|
||||||
|
//export droppedFilesFile
|
||||||
|
func droppedFilesFile(id C.uint32_t, filePath *C.wchar_t, filePathLength C.UINT) {
|
||||||
|
files := drops[uint32(id)]
|
||||||
|
pathBytes := C.GoBytes(unsafe.Pointer(filePath), C.int(filePathLength)*C.sizeof_wchar_t)
|
||||||
|
decoder := unicode.UTF16(unicode.LittleEndian, unicode.UseBOM).NewDecoder()
|
||||||
|
path, err := decoder.Bytes(pathBytes)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
files.Files = append(files.Files, string(path))
|
||||||
|
drops[uint32(id)] = files
|
||||||
|
}
|
||||||
|
|
||||||
|
//export droppedFilesDrop
|
||||||
|
func droppedFilesDrop(id C.uint32_t) {
|
||||||
|
h := handler
|
||||||
|
if h == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
drop, ok := drops[uint32(id)]
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
h.FilesDropped(geom.Pt(drop.X, drop.Y).ToF32(), drop.Files)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Register(dropper Dropper) error {
|
||||||
|
if handler != nil {
|
||||||
|
return errors.New(`can only register single dropper`)
|
||||||
|
}
|
||||||
|
handler = dropper
|
||||||
|
C.SetDragAndDropHook(unsafe.Pointer(dropper.WindowHandle()))
|
||||||
|
return nil
|
||||||
|
}
|
9
addons/drop/dropper.go
Normal file
9
addons/drop/dropper.go
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package drop
|
||||||
|
|
||||||
|
import "opslag.de/schobers/geom"
|
||||||
|
|
||||||
|
type Dropper interface {
|
||||||
|
WindowHandle() uintptr
|
||||||
|
|
||||||
|
FilesDropped(geom.PointF32, []string)
|
||||||
|
}
|
5
allg5ui/renderer_default.go
Normal file
5
allg5ui/renderer_default.go
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
// +build !windows
|
||||||
|
|
||||||
|
package allg5ui
|
||||||
|
|
||||||
|
func (r *Renderer) WindowHandle() uintptr { return 0 }
|
7
allg5ui/renderer_windows.go
Normal file
7
allg5ui/renderer_windows.go
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
// +build windows
|
||||||
|
|
||||||
|
package allg5ui
|
||||||
|
|
||||||
|
func (r *Renderer) WindowHandle() uintptr {
|
||||||
|
return uintptr(r.disp.WindowHandle())
|
||||||
|
}
|
@ -499,6 +499,26 @@ func (r *Renderer) TextTexture(font ui.Font, color color.Color, text string) (ui
|
|||||||
return r.text(font, color, text)
|
return r.text(font, color, text)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Renderer) WindowHandle() uintptr {
|
||||||
|
info, err := r.window.GetWMInfo()
|
||||||
|
if err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
switch info.Subsystem {
|
||||||
|
case sdl.SYSWM_COCOA:
|
||||||
|
return uintptr(info.GetCocoaInfo().Window)
|
||||||
|
case sdl.SYSWM_DIRECTFB:
|
||||||
|
return uintptr(info.GetDFBInfo().Window)
|
||||||
|
case sdl.SYSWM_UIKIT:
|
||||||
|
return uintptr(info.GetUIKitInfo().Window)
|
||||||
|
case sdl.SYSWM_WINDOWS:
|
||||||
|
return uintptr(info.GetWindowsInfo().Window)
|
||||||
|
case sdl.SYSWM_X11:
|
||||||
|
return uintptr(info.GetX11Info().Window)
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
// Resources
|
// Resources
|
||||||
|
|
||||||
func (r *Renderer) Resources() ui.Resources { return r.resources }
|
func (r *Renderer) Resources() ui.Resources { return r.resources }
|
||||||
|
111
ui/examples/02_drop/drop.go
Normal file
111
ui/examples/02_drop/drop.go
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"image/color"
|
||||||
|
"log"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"opslag.de/schobers/geom"
|
||||||
|
"opslag.de/schobers/zntg/addons/drop"
|
||||||
|
_ "opslag.de/schobers/zntg/allg5ui" // import the renderer for the UI
|
||||||
|
|
||||||
|
"opslag.de/schobers/zntg/ui"
|
||||||
|
)
|
||||||
|
|
||||||
|
type dropFiles struct {
|
||||||
|
ui.StackPanel
|
||||||
|
|
||||||
|
ctx ui.Context
|
||||||
|
files *ui.Paragraph
|
||||||
|
ping *ping
|
||||||
|
}
|
||||||
|
|
||||||
|
type ping struct {
|
||||||
|
ui.OverlayBase
|
||||||
|
|
||||||
|
circle ui.Texture
|
||||||
|
position geom.PointF32
|
||||||
|
tick time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ping) Render(ctx ui.Context) {
|
||||||
|
elapsed := time.Since(p.tick)
|
||||||
|
const animationDuration = 500 * time.Millisecond
|
||||||
|
if elapsed > animationDuration {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
tint := color.Gray{Y: uint8(elapsed * 255 / animationDuration)}
|
||||||
|
center := geom.PtF32(float32(p.circle.Width()), float32(p.circle.Height())).Mul(.5)
|
||||||
|
ctx.Renderer().DrawTexturePointOptions(p.circle, p.position.Sub(center), ui.DrawOptions{Tint: tint})
|
||||||
|
ctx.Animate()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *dropFiles) WindowHandle() uintptr { return d.ctx.Renderer().WindowHandle() }
|
||||||
|
|
||||||
|
func (d *dropFiles) FilesDropped(position geom.PointF32, files []string) {
|
||||||
|
d.files.Text = "Files dropped:\n" + strings.Join(files, "\n")
|
||||||
|
d.ping.tick = time.Now()
|
||||||
|
d.ping.position = position
|
||||||
|
d.ctx.Animate()
|
||||||
|
}
|
||||||
|
|
||||||
|
func newCircle() ui.ImageSource {
|
||||||
|
const side = 16
|
||||||
|
center := geom.PtF32(.5*side, .5*side)
|
||||||
|
return &ui.AlphaPixelImageSource{
|
||||||
|
ImageAlphaPixelTestFn: func(p geom.PointF32) uint8 {
|
||||||
|
dist := p.Distance(center)
|
||||||
|
if dist < 7 {
|
||||||
|
return 255
|
||||||
|
} else if dist > 8 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return uint8((8 - dist) * 255 * 0.5)
|
||||||
|
},
|
||||||
|
Size: geom.Pt(side, side),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *dropFiles) Init(ctx ui.Context) error {
|
||||||
|
d.ctx = ctx
|
||||||
|
drop.Register(d)
|
||||||
|
|
||||||
|
_, err := ctx.Fonts().CreateFontPath("default", "../resources/font/OpenSans-Regular.ttf", 14)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.files = ui.BuildParagraph("", nil)
|
||||||
|
|
||||||
|
pingCircle, err := ctx.Renderer().CreateTexture(newCircle())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
d.ping = &ping{circle: pingCircle}
|
||||||
|
ctx.Overlays().AddOnTop("ping", d.ping, true)
|
||||||
|
|
||||||
|
d.Background = color.White
|
||||||
|
d.Children = []ui.Control{
|
||||||
|
&ui.Label{Text: "Drop files on this window!"},
|
||||||
|
d.files,
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func run() error {
|
||||||
|
var render, err = ui.NewRendererDefault("Files Drop Example", 800, 600)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer render.Destroy()
|
||||||
|
|
||||||
|
return ui.RunWait(render, ui.DefaultStyle(), &dropFiles{}, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var err = run()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
@ -41,6 +41,7 @@ type Renderer interface {
|
|||||||
Text(font Font, p geom.PointF32, color color.Color, text string)
|
Text(font Font, p geom.PointF32, color color.Color, text string)
|
||||||
TextAlign(font Font, p geom.PointF32, color color.Color, text string, align HorizontalAlignment)
|
TextAlign(font Font, p geom.PointF32, color color.Color, text string, align HorizontalAlignment)
|
||||||
TextTexture(font Font, color color.Color, text string) (Texture, error)
|
TextTexture(font Font, color color.Color, text string) (Texture, error)
|
||||||
|
WindowHandle() uintptr
|
||||||
|
|
||||||
// Resources
|
// Resources
|
||||||
Resources() Resources
|
Resources() Resources
|
||||||
|
Loading…
Reference in New Issue
Block a user