github.com/Seikaijyu/gio@v0.0.1/widget/dnd.go (about) 1 package widget 2 3 import ( 4 "io" 5 6 "github.com/Seikaijyu/gio/f32" 7 "github.com/Seikaijyu/gio/gesture" 8 "github.com/Seikaijyu/gio/io/pointer" 9 "github.com/Seikaijyu/gio/io/transfer" 10 "github.com/Seikaijyu/gio/layout" 11 "github.com/Seikaijyu/gio/op" 12 "github.com/Seikaijyu/gio/op/clip" 13 ) 14 15 // Draggable makes a widget draggable. 16 type Draggable struct { 17 // Type contains the MIME type and matches transfer.SourceOp. 18 Type string 19 20 handle struct{} 21 drag gesture.Drag 22 click f32.Point 23 pos f32.Point 24 } 25 26 func (d *Draggable) Layout(gtx layout.Context, w, drag layout.Widget) layout.Dimensions { 27 if gtx.Queue == nil { 28 return w(gtx) 29 } 30 dims := w(gtx) 31 32 stack := clip.Rect{Max: dims.Size}.Push(gtx.Ops) 33 d.drag.Add(gtx.Ops) 34 transfer.SourceOp{ 35 Tag: &d.handle, 36 Type: d.Type, 37 }.Add(gtx.Ops) 38 stack.Pop() 39 40 if drag != nil && d.drag.Pressed() { 41 rec := op.Record(gtx.Ops) 42 op.Offset(d.pos.Round()).Add(gtx.Ops) 43 drag(gtx) 44 op.Defer(gtx.Ops, rec.Stop()) 45 } 46 47 return dims 48 } 49 50 // Dragging returns whether d is being dragged. 51 func (d *Draggable) Dragging() bool { 52 return d.drag.Dragging() 53 } 54 55 // Update the draggable and returns the MIME type for which the Draggable was 56 // requested to offer data, if any 57 func (d *Draggable) Update(gtx layout.Context) (mime string, requested bool) { 58 pos := d.pos 59 for _, ev := range d.drag.Update(gtx.Metric, gtx.Queue, gesture.Both) { 60 switch ev.Kind { 61 case pointer.Press: 62 d.click = ev.Position 63 pos = f32.Point{} 64 case pointer.Drag, pointer.Release: 65 pos = ev.Position.Sub(d.click) 66 } 67 } 68 d.pos = pos 69 70 for _, ev := range gtx.Queue.Events(&d.handle) { 71 if e, ok := ev.(transfer.RequestEvent); ok { 72 return e.Type, true 73 } 74 } 75 return "", false 76 } 77 78 // Offer the data ready for a drop. Must be called after being Requested. 79 // The mime must be one in the requested list. 80 func (d *Draggable) Offer(ops *op.Ops, mime string, data io.ReadCloser) { 81 transfer.OfferOp{ 82 Tag: &d.handle, 83 Type: mime, 84 Data: data, 85 }.Add(ops) 86 } 87 88 // Pos returns the drag position relative to its initial click position. 89 func (d *Draggable) Pos() f32.Point { 90 return d.pos 91 }