mirror of
				https://github.com/vsariola/sointu.git
				synced 2025-10-30 23:45:53 -04:00 
			
		
		
		
	feat(tracker): add ability to copy, cut and paste units
This commit is contained in:
		
						parent
						
							338529012a
						
					
				
				
					commit
					5a2e87982e
				
			| @ -462,7 +462,7 @@ func (ie *InstrumentEditor) layoutInstrumentEditor(gtx C, t *Tracker) D { | ||||
| 				return layout.Stack{Alignment: layout.SE}.Layout(gtx, | ||||
| 					layout.Expanded(func(gtx C) D { | ||||
| 						defer clip.Rect(image.Rect(0, 0, gtx.Constraints.Max.X, gtx.Constraints.Max.Y)).Push(gtx.Ops).Pop() | ||||
| 						key.InputOp{Tag: ie.unitDragList, Keys: "→|⏎|⌫|⌦|⎋|Ctrl-⏎"}.Add(gtx.Ops) | ||||
| 						key.InputOp{Tag: ie.unitDragList, Keys: "→|⏎|⌫|⌦|⎋|Ctrl-⏎|Ctrl-C|Ctrl-X"}.Add(gtx.Ops) | ||||
| 						for _, event := range gtx.Events(ie.unitDragList) { | ||||
| 							switch e := event.(type) { | ||||
| 							case key.Event: | ||||
| @ -480,6 +480,19 @@ func (ie *InstrumentEditor) layoutInstrumentEditor(gtx C, t *Tracker) D { | ||||
| 										ie.unitTypeEditor.SetCaret(l, l) | ||||
| 									case key.NameDeleteForward: | ||||
| 										t.DeleteUnit(true) | ||||
| 									case "C": | ||||
| 										contents, err := yaml.Marshal(t.Unit()) | ||||
| 										if err == nil { | ||||
| 											clipboard.WriteOp{Text: string(contents)}.Add(gtx.Ops) | ||||
| 											t.Alert.Update("Unit copied to clipboard", Notify, time.Second*3) | ||||
| 										} | ||||
| 									case "X": | ||||
| 										contents, err := yaml.Marshal(t.Unit()) | ||||
| 										if err == nil { | ||||
| 											clipboard.WriteOp{Text: string(contents)}.Add(gtx.Ops) | ||||
| 											t.Alert.Update("Unit cut to clipboard", Notify, time.Second*3) | ||||
| 										} | ||||
| 										t.DeleteUnit(true) | ||||
| 									case key.NameReturn: | ||||
| 										if e.Modifiers.Contain(key.ModShortcut) { | ||||
| 											t.AddUnit(true) | ||||
|  | ||||
| @ -4,7 +4,9 @@ import ( | ||||
| 	"image" | ||||
| 	"image/color" | ||||
| 	"strings" | ||||
| 	"time" | ||||
|  | ||||
| 	"gioui.org/io/clipboard" | ||||
| 	"gioui.org/io/key" | ||||
| 	"gioui.org/io/pointer" | ||||
| 	"gioui.org/layout" | ||||
| @ -15,6 +17,7 @@ import ( | ||||
| 	"gioui.org/widget" | ||||
| 	"github.com/vsariola/sointu/tracker" | ||||
| 	"golang.org/x/exp/shiny/materialdesign/icons" | ||||
| 	"gopkg.in/yaml.v3" | ||||
| ) | ||||
|  | ||||
| type ParamEditor struct { | ||||
| @ -22,6 +25,7 @@ type ParamEditor struct { | ||||
| 	scrollBar          *ScrollBar | ||||
| 	Parameters         []*ParameterWidget | ||||
| 	DeleteUnitBtn      *widget.Clickable | ||||
| 	CopyUnitBtn        *widget.Clickable | ||||
| 	ClearUnitBtn       *widget.Clickable | ||||
| 	ChooseUnitTypeBtns []*widget.Clickable | ||||
| 	tag                bool | ||||
| @ -41,6 +45,7 @@ func NewParamEditor() *ParamEditor { | ||||
| 	ret := &ParamEditor{ | ||||
| 		DeleteUnitBtn: new(widget.Clickable), | ||||
| 		ClearUnitBtn:  new(widget.Clickable), | ||||
| 		CopyUnitBtn:   new(widget.Clickable), | ||||
| 		list:          &layout.List{Axis: layout.Vertical}, | ||||
| 		scrollBar:     &ScrollBar{Axis: layout.Vertical}, | ||||
| 	} | ||||
| @ -178,6 +183,15 @@ func (pe *ParamEditor) layoutUnitFooter(t *Tracker) layout.Widget { | ||||
| 			op.InvalidateOp{}.Add(gtx.Ops) | ||||
| 			t.InstrumentEditor.unitDragList.Focus() | ||||
| 		} | ||||
| 		for pe.CopyUnitBtn.Clicked() { | ||||
| 			op.InvalidateOp{}.Add(gtx.Ops) | ||||
| 			contents, err := yaml.Marshal(t.Unit()) | ||||
| 			if err == nil { | ||||
| 				clipboard.WriteOp{Text: string(contents)}.Add(gtx.Ops) | ||||
| 				t.Alert.Update("Unit copied to clipboard", Notify, time.Second*3) | ||||
| 			} | ||||
| 		} | ||||
| 		copyUnitBtnStyle := IconButton(t.Theme, pe.CopyUnitBtn, icons.ContentContentCopy, true) | ||||
| 		deleteUnitBtnStyle := IconButton(t.Theme, pe.DeleteUnitBtn, icons.ActionDelete, t.CanDeleteUnit()) | ||||
| 		text := t.Unit().Type | ||||
| 		if text == "" { | ||||
| @ -188,6 +202,7 @@ func (pe *ParamEditor) layoutUnitFooter(t *Tracker) layout.Widget { | ||||
| 		hintText := Label(text, white) | ||||
| 		return layout.Flex{Axis: layout.Horizontal, Alignment: layout.Middle}.Layout(gtx, | ||||
| 			layout.Rigid(deleteUnitBtnStyle.Layout), | ||||
| 			layout.Rigid(copyUnitBtnStyle.Layout), | ||||
| 			layout.Rigid(func(gtx C) D { | ||||
| 				var dims D | ||||
| 				if t.Unit().Type != "" { | ||||
|  | ||||
| @ -67,6 +67,15 @@ type Tracker struct { | ||||
| } | ||||
|  | ||||
| func (t *Tracker) UnmarshalContent(bytes []byte) error { | ||||
| 	var unit sointu.Unit | ||||
| 	if errJSON := json.Unmarshal(bytes, &unit); errJSON == nil { | ||||
| 		t.PasteUnit(unit) | ||||
| 		return nil | ||||
| 	} | ||||
| 	if errYaml := yaml.Unmarshal(bytes, &unit); errYaml == nil { | ||||
| 		t.PasteUnit(unit) | ||||
| 		return nil | ||||
| 	} | ||||
| 	var instr sointu.Instrument | ||||
| 	if errJSON := json.Unmarshal(bytes, &instr); errJSON == nil { | ||||
| 		if t.SetInstrument(instr) { | ||||
|  | ||||
| @ -641,6 +641,24 @@ func (m *Model) SetUnitType(t string) { | ||||
| 	m.notifyPatchChange() | ||||
| } | ||||
|  | ||||
| func (m *Model) PasteUnit(unit sointu.Unit) { | ||||
| 	m.saveUndo("PasteUnit", 0) | ||||
| 	newUnits := make([]sointu.Unit, len(m.Instrument().Units)+1) | ||||
| 	m.unitIndex++ | ||||
| 	copy(newUnits, m.Instrument().Units[:m.unitIndex]) | ||||
| 	copy(newUnits[m.unitIndex+1:], m.Instrument().Units[m.unitIndex:]) | ||||
| 	if _, ok := m.usedIDs[unit.ID]; ok { | ||||
| 		m.maxID++ | ||||
| 		unit.ID = m.maxID | ||||
| 	} | ||||
| 	m.usedIDs[unit.ID] = true | ||||
| 	newUnits[m.unitIndex] = unit | ||||
| 	m.song.Patch[m.instrIndex].Units = newUnits | ||||
| 	m.paramIndex = 0 | ||||
| 	m.clampPositions() | ||||
| 	m.notifyPatchChange() | ||||
| } | ||||
|  | ||||
| func (m *Model) SetUnitIndex(value int) { | ||||
| 	m.unitIndex = value | ||||
| 	m.paramIndex = 0 | ||||
|  | ||||
		Reference in New Issue
	
	Block a user