mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-01 15:45:38 +00:00
03016f0c69
This patch adds internal Drag and Drop support to app.Windows. The new package io/transfer adds the ability to define draggable and droppable targets, which are leveraged by the new widget.Draggable type. The API is generic and could handle future use cases, such as external Drag and Drop. Updates gio#153 Signed-off-by: Pierre Curto <pierre.curto@gmail.com>
96 lines
2.0 KiB
Go
96 lines
2.0 KiB
Go
package widget
|
|
|
|
import (
|
|
"io"
|
|
|
|
"gioui.org/f32"
|
|
"gioui.org/gesture"
|
|
"gioui.org/io/pointer"
|
|
"gioui.org/io/transfer"
|
|
"gioui.org/layout"
|
|
"gioui.org/op"
|
|
"gioui.org/op/clip"
|
|
)
|
|
|
|
// Draggable makes a widget draggable.
|
|
type Draggable struct {
|
|
// Type contains the MIME type and matches transfer.SourceOp.
|
|
Type string
|
|
|
|
handle struct{}
|
|
drag gesture.Drag
|
|
click f32.Point
|
|
pos f32.Point
|
|
requested bool
|
|
request string
|
|
}
|
|
|
|
func (d *Draggable) Layout(gtx layout.Context, w, drag layout.Widget) layout.Dimensions {
|
|
pos := d.pos
|
|
for _, ev := range d.drag.Events(gtx.Metric, gtx.Queue, gesture.Both) {
|
|
switch ev.Type {
|
|
case pointer.Press:
|
|
d.click = ev.Position
|
|
pos = f32.Point{}
|
|
case pointer.Drag:
|
|
pos = ev.Position.Sub(d.click)
|
|
case pointer.Release:
|
|
}
|
|
}
|
|
d.pos = pos
|
|
|
|
for _, ev := range gtx.Queue.Events(&d.handle) {
|
|
switch e := ev.(type) {
|
|
case transfer.RequestEvent:
|
|
d.requested = true
|
|
d.request = e.Type
|
|
case transfer.CancelEvent:
|
|
d.requested = false
|
|
d.request = ""
|
|
}
|
|
}
|
|
|
|
dims := w(gtx)
|
|
|
|
stack := clip.Rect{Max: dims.Size}.Push(gtx.Ops)
|
|
d.drag.Add(gtx.Ops)
|
|
transfer.SourceOp{
|
|
Tag: &d.handle,
|
|
Type: d.Type,
|
|
}.Add(gtx.Ops)
|
|
stack.Pop()
|
|
|
|
if drag != nil && d.drag.Pressed() {
|
|
rec := op.Record(gtx.Ops)
|
|
op.Offset(pos).Add(gtx.Ops)
|
|
drag(gtx)
|
|
op.Defer(gtx.Ops, rec.Stop())
|
|
}
|
|
|
|
return dims
|
|
}
|
|
|
|
// Dragging returns whether d is being dragged.
|
|
func (d *Draggable) Dragging() bool {
|
|
return d.drag.Dragging()
|
|
}
|
|
|
|
// Requested returns the MIME type, if any, for which the Draggable was requested to offer data.
|
|
func (d *Draggable) Requested() (mime string, requested bool) {
|
|
mime = d.request
|
|
requested = d.requested
|
|
d.requested = false
|
|
d.request = ""
|
|
return
|
|
}
|
|
|
|
// Offer the data ready for a drop. Must be called after being Requested.
|
|
// The mime must be one in the requested list.
|
|
func (d *Draggable) Offer(ops *op.Ops, mime string, data io.ReadCloser) {
|
|
transfer.OfferOp{
|
|
Tag: &d.handle,
|
|
Type: mime,
|
|
Data: data,
|
|
}.Add(ops)
|
|
}
|