mirror of
https://github.com/vsariola/sointu.git
synced 2025-05-28 03:10:24 -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,
|
return layout.Stack{Alignment: layout.SE}.Layout(gtx,
|
||||||
layout.Expanded(func(gtx C) D {
|
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()
|
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) {
|
for _, event := range gtx.Events(ie.unitDragList) {
|
||||||
switch e := event.(type) {
|
switch e := event.(type) {
|
||||||
case key.Event:
|
case key.Event:
|
||||||
@ -480,6 +480,19 @@ func (ie *InstrumentEditor) layoutInstrumentEditor(gtx C, t *Tracker) D {
|
|||||||
ie.unitTypeEditor.SetCaret(l, l)
|
ie.unitTypeEditor.SetCaret(l, l)
|
||||||
case key.NameDeleteForward:
|
case key.NameDeleteForward:
|
||||||
t.DeleteUnit(true)
|
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:
|
case key.NameReturn:
|
||||||
if e.Modifiers.Contain(key.ModShortcut) {
|
if e.Modifiers.Contain(key.ModShortcut) {
|
||||||
t.AddUnit(true)
|
t.AddUnit(true)
|
||||||
|
@ -4,7 +4,9 @@ import (
|
|||||||
"image"
|
"image"
|
||||||
"image/color"
|
"image/color"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"gioui.org/io/clipboard"
|
||||||
"gioui.org/io/key"
|
"gioui.org/io/key"
|
||||||
"gioui.org/io/pointer"
|
"gioui.org/io/pointer"
|
||||||
"gioui.org/layout"
|
"gioui.org/layout"
|
||||||
@ -15,6 +17,7 @@ import (
|
|||||||
"gioui.org/widget"
|
"gioui.org/widget"
|
||||||
"github.com/vsariola/sointu/tracker"
|
"github.com/vsariola/sointu/tracker"
|
||||||
"golang.org/x/exp/shiny/materialdesign/icons"
|
"golang.org/x/exp/shiny/materialdesign/icons"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ParamEditor struct {
|
type ParamEditor struct {
|
||||||
@ -22,6 +25,7 @@ type ParamEditor struct {
|
|||||||
scrollBar *ScrollBar
|
scrollBar *ScrollBar
|
||||||
Parameters []*ParameterWidget
|
Parameters []*ParameterWidget
|
||||||
DeleteUnitBtn *widget.Clickable
|
DeleteUnitBtn *widget.Clickable
|
||||||
|
CopyUnitBtn *widget.Clickable
|
||||||
ClearUnitBtn *widget.Clickable
|
ClearUnitBtn *widget.Clickable
|
||||||
ChooseUnitTypeBtns []*widget.Clickable
|
ChooseUnitTypeBtns []*widget.Clickable
|
||||||
tag bool
|
tag bool
|
||||||
@ -41,6 +45,7 @@ func NewParamEditor() *ParamEditor {
|
|||||||
ret := &ParamEditor{
|
ret := &ParamEditor{
|
||||||
DeleteUnitBtn: new(widget.Clickable),
|
DeleteUnitBtn: new(widget.Clickable),
|
||||||
ClearUnitBtn: new(widget.Clickable),
|
ClearUnitBtn: new(widget.Clickable),
|
||||||
|
CopyUnitBtn: new(widget.Clickable),
|
||||||
list: &layout.List{Axis: layout.Vertical},
|
list: &layout.List{Axis: layout.Vertical},
|
||||||
scrollBar: &ScrollBar{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)
|
op.InvalidateOp{}.Add(gtx.Ops)
|
||||||
t.InstrumentEditor.unitDragList.Focus()
|
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())
|
deleteUnitBtnStyle := IconButton(t.Theme, pe.DeleteUnitBtn, icons.ActionDelete, t.CanDeleteUnit())
|
||||||
text := t.Unit().Type
|
text := t.Unit().Type
|
||||||
if text == "" {
|
if text == "" {
|
||||||
@ -188,6 +202,7 @@ func (pe *ParamEditor) layoutUnitFooter(t *Tracker) layout.Widget {
|
|||||||
hintText := Label(text, white)
|
hintText := Label(text, white)
|
||||||
return layout.Flex{Axis: layout.Horizontal, Alignment: layout.Middle}.Layout(gtx,
|
return layout.Flex{Axis: layout.Horizontal, Alignment: layout.Middle}.Layout(gtx,
|
||||||
layout.Rigid(deleteUnitBtnStyle.Layout),
|
layout.Rigid(deleteUnitBtnStyle.Layout),
|
||||||
|
layout.Rigid(copyUnitBtnStyle.Layout),
|
||||||
layout.Rigid(func(gtx C) D {
|
layout.Rigid(func(gtx C) D {
|
||||||
var dims D
|
var dims D
|
||||||
if t.Unit().Type != "" {
|
if t.Unit().Type != "" {
|
||||||
|
@ -67,6 +67,15 @@ type Tracker struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *Tracker) UnmarshalContent(bytes []byte) error {
|
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
|
var instr sointu.Instrument
|
||||||
if errJSON := json.Unmarshal(bytes, &instr); errJSON == nil {
|
if errJSON := json.Unmarshal(bytes, &instr); errJSON == nil {
|
||||||
if t.SetInstrument(instr) {
|
if t.SetInstrument(instr) {
|
||||||
|
@ -641,6 +641,24 @@ func (m *Model) SetUnitType(t string) {
|
|||||||
m.notifyPatchChange()
|
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) {
|
func (m *Model) SetUnitIndex(value int) {
|
||||||
m.unitIndex = value
|
m.unitIndex = value
|
||||||
m.paramIndex = 0
|
m.paramIndex = 0
|
||||||
|
Loading…
Reference in New Issue
Block a user