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  }