feat(tracker/gioui): add tooltips

Currently, only iconbtns and numeric updowns have tooltips. Closes #84
This commit is contained in:
5684185+vsariola@users.noreply.github.com 2023-07-18 23:20:52 +03:00
parent cafb43f8c8
commit 5884a8d195
6 changed files with 116 additions and 80 deletions

View File

@ -5,10 +5,28 @@ import (
"gioui.org/unit"
"gioui.org/widget"
"gioui.org/widget/material"
"gioui.org/x/component"
)
func IconButton(th *material.Theme, w *widget.Clickable, icon []byte, enabled bool) material.IconButtonStyle {
ret := material.IconButton(th, w, widgetForIcon(icon), "")
type TipClickable struct {
Clickable widget.Clickable
TipArea component.TipArea
}
type TipIconButtonStyle struct {
IconButtonStyle material.IconButtonStyle
Tooltip component.Tooltip
tipArea *component.TipArea
}
func Tooltip(th *material.Theme, tip string) component.Tooltip {
tooltip := component.PlatformTooltip(th, tip)
tooltip.Bg = black
return tooltip
}
func IconButton(th *material.Theme, w *TipClickable, icon []byte, enabled bool, tip string) TipIconButtonStyle {
ret := material.IconButton(th, &w.Clickable, widgetForIcon(icon), "")
ret.Background = transparent
ret.Inset = layout.UniformInset(unit.Dp(6))
if enabled {
@ -16,7 +34,15 @@ func IconButton(th *material.Theme, w *widget.Clickable, icon []byte, enabled bo
} else {
ret.Color = disabledTextColor
}
return ret
return TipIconButtonStyle{
IconButtonStyle: ret,
Tooltip: Tooltip(th, tip),
tipArea: &w.TipArea,
}
}
func (t *TipIconButtonStyle) Layout(gtx C) D {
return t.tipArea.Layout(gtx, t.Tooltip, t.IconButtonStyle.Layout)
}
func LowEmphasisButton(th *material.Theme, w *widget.Clickable, text string) material.ButtonStyle {

View File

@ -26,14 +26,14 @@ import (
)
type InstrumentEditor struct {
newInstrumentBtn *widget.Clickable
enlargeBtn *widget.Clickable
deleteInstrumentBtn *widget.Clickable
copyInstrumentBtn *widget.Clickable
saveInstrumentBtn *widget.Clickable
loadInstrumentBtn *widget.Clickable
addUnitBtn *widget.Clickable
commentExpandBtn *widget.Clickable
newInstrumentBtn *TipClickable
enlargeBtn *TipClickable
deleteInstrumentBtn *TipClickable
copyInstrumentBtn *TipClickable
saveInstrumentBtn *TipClickable
loadInstrumentBtn *TipClickable
addUnitBtn *TipClickable
commentExpandBtn *TipClickable
commentEditor *widget.Editor
nameEditor *widget.Editor
unitTypeEditor *widget.Editor
@ -52,14 +52,14 @@ type InstrumentEditor struct {
func NewInstrumentEditor() *InstrumentEditor {
return &InstrumentEditor{
newInstrumentBtn: new(widget.Clickable),
enlargeBtn: new(widget.Clickable),
deleteInstrumentBtn: new(widget.Clickable),
copyInstrumentBtn: new(widget.Clickable),
saveInstrumentBtn: new(widget.Clickable),
loadInstrumentBtn: new(widget.Clickable),
addUnitBtn: new(widget.Clickable),
commentExpandBtn: new(widget.Clickable),
newInstrumentBtn: new(TipClickable),
enlargeBtn: new(TipClickable),
deleteInstrumentBtn: new(TipClickable),
copyInstrumentBtn: new(TipClickable),
saveInstrumentBtn: new(TipClickable),
loadInstrumentBtn: new(TipClickable),
addUnitBtn: new(TipClickable),
commentExpandBtn: new(TipClickable),
commentEditor: new(widget.Editor),
nameEditor: &widget.Editor{SingleLine: true, Submit: true, Alignment: text.Middle},
unitTypeEditor: &widget.Editor{SingleLine: true, Submit: true, Alignment: text.Start},
@ -103,30 +103,28 @@ func (ie *InstrumentEditor) Layout(gtx C, t *Tracker) D {
}.Add(gtx.Ops)
area.Pop()
var icon []byte
enlargeTip := "Enlarge"
icon := icons.NavigationFullscreen
if t.InstrEnlarged() {
icon = icons.NavigationFullscreenExit
} else {
icon = icons.NavigationFullscreen
enlargeTip = "Shrink"
}
fullscreenBtnStyle := IconButton(t.Theme, ie.enlargeBtn, icon, true)
for ie.enlargeBtn.Clicked() {
fullscreenBtnStyle := IconButton(t.Theme, ie.enlargeBtn, icon, true, enlargeTip)
for ie.enlargeBtn.Clickable.Clicked() {
t.SetInstrEnlarged(!t.InstrEnlarged())
}
for ie.newInstrumentBtn.Clicked() {
for ie.newInstrumentBtn.Clickable.Clicked() {
t.AddInstrument(true)
}
octave := func(gtx C) D {
in := layout.UniformInset(unit.Dp(1))
t.OctaveNumberInput.Value = t.Octave()
numStyle := NumericUpDown(t.Theme, t.OctaveNumberInput, 0, 9)
gtx.Constraints.Min.Y = gtx.Dp(unit.Dp(20))
gtx.Constraints.Min.X = gtx.Dp(unit.Dp(70))
numStyle := NumericUpDown(t.Theme, t.OctaveNumberInput, 0, 9, "Octave down (<) or up (>)")
dims := in.Layout(gtx, numStyle.Layout)
t.SetOctave(t.OctaveNumberInput.Value)
return dims
}
newBtnStyle := IconButton(t.Theme, ie.newInstrumentBtn, icons.ContentAdd, t.CanAddInstrument())
newBtnStyle := IconButton(t.Theme, ie.newInstrumentBtn, icons.ContentAdd, t.CanAddInstrument(), "Add\ninstrument")
ret := layout.Flex{Axis: layout.Vertical}.Layout(gtx,
layout.Rigid(func(gtx C) D {
return layout.Flex{}.Layout(
@ -170,15 +168,17 @@ func (ie *InstrumentEditor) Layout(gtx C, t *Tracker) D {
func (ie *InstrumentEditor) layoutInstrumentHeader(gtx C, t *Tracker) D {
header := func(gtx C) D {
collapseIcon := icons.NavigationExpandLess
commentTip := "Collapse comment"
if !ie.commentExpanded {
collapseIcon = icons.NavigationExpandMore
commentTip = "Expand comment"
}
commentExpandBtnStyle := IconButton(t.Theme, ie.commentExpandBtn, collapseIcon, true)
copyInstrumentBtnStyle := IconButton(t.Theme, ie.copyInstrumentBtn, icons.ContentContentCopy, true)
saveInstrumentBtnStyle := IconButton(t.Theme, ie.saveInstrumentBtn, icons.ContentSave, true)
loadInstrumentBtnStyle := IconButton(t.Theme, ie.loadInstrumentBtn, icons.FileFolderOpen, true)
deleteInstrumentBtnStyle := IconButton(t.Theme, ie.deleteInstrumentBtn, icons.ActionDelete, t.CanDeleteInstrument())
commentExpandBtnStyle := IconButton(t.Theme, ie.commentExpandBtn, collapseIcon, true, commentTip)
copyInstrumentBtnStyle := IconButton(t.Theme, ie.copyInstrumentBtn, icons.ContentContentCopy, true, "Copy instrument")
saveInstrumentBtnStyle := IconButton(t.Theme, ie.saveInstrumentBtn, icons.ContentSave, true, "Save instrument")
loadInstrumentBtnStyle := IconButton(t.Theme, ie.loadInstrumentBtn, icons.FileFolderOpen, true, "Load instrument")
deleteInstrumentBtnStyle := IconButton(t.Theme, ie.deleteInstrumentBtn, icons.ActionDelete, t.CanDeleteInstrument(), "Delete\ninstrument")
header := func(gtx C) D {
return layout.Flex{Axis: layout.Horizontal, Alignment: layout.Middle}.Layout(gtx,
@ -186,9 +186,7 @@ func (ie *InstrumentEditor) layoutInstrumentHeader(gtx C, t *Tracker) D {
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
maxRemain := t.MaxInstrumentVoices()
t.InstrumentVoices.Value = t.Instrument().NumVoices
numStyle := NumericUpDown(t.Theme, t.InstrumentVoices, 0, maxRemain)
gtx.Constraints.Min.Y = gtx.Dp(unit.Dp(20))
gtx.Constraints.Min.X = gtx.Dp(unit.Dp(70))
numStyle := NumericUpDown(t.Theme, t.InstrumentVoices, 0, maxRemain, "Number of voices for this instrument")
dims := numStyle.Layout(gtx)
t.SetInstrumentVoices(t.InstrumentVoices.Value)
return dims
@ -200,7 +198,7 @@ func (ie *InstrumentEditor) layoutInstrumentHeader(gtx C, t *Tracker) D {
layout.Rigid(copyInstrumentBtnStyle.Layout),
layout.Rigid(deleteInstrumentBtnStyle.Layout))
}
for ie.commentExpandBtn.Clicked() {
for ie.commentExpandBtn.Clickable.Clicked() {
ie.commentExpanded = !ie.commentExpanded
if !ie.commentExpanded {
key.FocusOp{Tag: &ie.tag}.Add(gtx.Ops) // clear focus
@ -236,14 +234,14 @@ func (ie *InstrumentEditor) layoutInstrumentHeader(gtx C, t *Tracker) D {
}
return header(gtx)
}
for ie.copyInstrumentBtn.Clicked() {
for ie.copyInstrumentBtn.Clickable.Clicked() {
contents, err := yaml.Marshal(t.Instrument())
if err == nil {
clipboard.WriteOp{Text: string(contents)}.Add(gtx.Ops)
t.Alert.Update("Instrument copied to clipboard", Notify, time.Second*3)
}
}
for ie.deleteInstrumentBtn.Clicked() {
for ie.deleteInstrumentBtn.Clickable.Clicked() {
if t.CanDeleteInstrument() {
dialogStyle := ConfirmDialog(t.Theme, ie.confirmInstrDelete, "Are you sure you want to delete this instrument?")
ie.confirmInstrDelete.Visible = true
@ -257,11 +255,11 @@ func (ie *InstrumentEditor) layoutInstrumentHeader(gtx C, t *Tracker) D {
for ie.confirmInstrDelete.BtnCancel.Clicked() {
t.ModalDialog = nil
}
for ie.saveInstrumentBtn.Clicked() {
for ie.saveInstrumentBtn.Clickable.Clicked() {
t.SaveInstrument()
}
for ie.loadInstrumentBtn.Clicked() {
for ie.loadInstrumentBtn.Clickable.Clicked() {
t.LoadInstrument()
}
return Surface{Gray: 37, Focus: ie.wasFocused}.Layout(gtx, header)
@ -362,14 +360,14 @@ func (ie *InstrumentEditor) layoutInstrumentNames(gtx C, t *Tracker) D {
return dims
}
func (ie *InstrumentEditor) layoutInstrumentEditor(gtx C, t *Tracker) D {
for ie.addUnitBtn.Clicked() {
for ie.addUnitBtn.Clickable.Clicked() {
t.AddUnit(true)
ie.unitDragList.Focus()
}
addUnitBtnStyle := material.IconButton(t.Theme, ie.addUnitBtn, widgetForIcon(icons.ContentAdd), "Add unit")
addUnitBtnStyle.Color = t.Theme.ContrastFg
addUnitBtnStyle.Background = t.Theme.Fg
addUnitBtnStyle.Inset = layout.UniformInset(unit.Dp(4))
addUnitBtnStyle := IconButton(t.Theme, ie.addUnitBtn, icons.ContentAdd, true, "Add unit (Ctrl+Enter)")
addUnitBtnStyle.IconButtonStyle.Color = t.Theme.ContrastFg
addUnitBtnStyle.IconButtonStyle.Background = t.Theme.Fg
addUnitBtnStyle.IconButtonStyle.Inset = layout.UniformInset(unit.Dp(4))
units := t.Instrument().Units
for len(ie.stackUse) < len(units) {

View File

@ -11,6 +11,7 @@ import (
"gioui.org/op/clip"
"gioui.org/op/paint"
"gioui.org/widget"
"gioui.org/x/component"
"gioui.org/gesture"
"gioui.org/io/pointer"
@ -27,6 +28,7 @@ type NumberInput struct {
dragStartXY float32
clickDecrease gesture.Click
clickIncrease gesture.Click
tipArea component.TipArea
}
type NumericUpDownStyle struct {
@ -43,10 +45,13 @@ type NumericUpDownStyle struct {
Border unit.Dp
ButtonWidth unit.Dp
UnitsPerStep unit.Dp
Tooltip component.Tooltip
Width unit.Dp
Height unit.Dp
shaper text.Shaper
}
func NumericUpDown(th *material.Theme, number *NumberInput, min, max int) NumericUpDownStyle {
func NumericUpDown(th *material.Theme, number *NumberInput, min, max int, tooltip string) NumericUpDownStyle {
bgColor := th.Palette.Fg
bgColor.R /= 4
bgColor.G /= 4
@ -64,12 +69,23 @@ func NumericUpDown(th *material.Theme, number *NumberInput, min, max int) Numeri
Border: unit.Dp(1),
UnitsPerStep: unit.Dp(8),
TextSize: th.TextSize * 14 / 16,
Tooltip: Tooltip(th, tooltip),
Width: unit.Dp(70),
Height: unit.Dp(20),
shaper: *th.Shaper,
}
}
func (s NumericUpDownStyle) Layout(gtx C) D {
size := gtx.Constraints.Min
if s.Tooltip.Text.Text != "" {
return s.NumberInput.tipArea.Layout(gtx, s.Tooltip, s.actualLayout)
}
return s.actualLayout(gtx)
}
func (s NumericUpDownStyle) actualLayout(gtx C) D {
size := image.Pt(gtx.Dp(s.Width), gtx.Dp(s.Height))
gtx.Constraints.Min = size
rr := gtx.Dp(s.CornerRadius)
border := gtx.Dp(s.Border)
c := clip.UniformRRect(image.Rectangle{Max: gtx.Constraints.Min}, rr).Push(gtx.Ops)

View File

@ -24,9 +24,9 @@ type ParamEditor struct {
list *layout.List
scrollBar *ScrollBar
Parameters []*ParameterWidget
DeleteUnitBtn *widget.Clickable
CopyUnitBtn *widget.Clickable
ClearUnitBtn *widget.Clickable
DeleteUnitBtn *TipClickable
CopyUnitBtn *TipClickable
ClearUnitBtn *TipClickable
ChooseUnitTypeBtns []*widget.Clickable
tag bool
focused bool
@ -43,9 +43,9 @@ func (pe *ParamEditor) Focused() bool {
func NewParamEditor() *ParamEditor {
ret := &ParamEditor{
DeleteUnitBtn: new(widget.Clickable),
ClearUnitBtn: new(widget.Clickable),
CopyUnitBtn: new(widget.Clickable),
DeleteUnitBtn: new(TipClickable),
ClearUnitBtn: new(TipClickable),
CopyUnitBtn: new(TipClickable),
list: &layout.List{Axis: layout.Vertical},
scrollBar: &ScrollBar{Axis: layout.Vertical},
}
@ -173,17 +173,17 @@ func (pe *ParamEditor) layoutUnitSliders(gtx C, t *Tracker) D {
func (pe *ParamEditor) layoutUnitFooter(t *Tracker) layout.Widget {
return func(gtx C) D {
for pe.ClearUnitBtn.Clicked() {
for pe.ClearUnitBtn.Clickable.Clicked() {
t.SetUnitType("")
op.InvalidateOp{}.Add(gtx.Ops)
t.InstrumentEditor.unitDragList.Focus()
}
for pe.DeleteUnitBtn.Clicked() {
for pe.DeleteUnitBtn.Clickable.Clicked() {
t.DeleteUnit(false)
op.InvalidateOp{}.Add(gtx.Ops)
t.InstrumentEditor.unitDragList.Focus()
}
for pe.CopyUnitBtn.Clicked() {
for pe.CopyUnitBtn.Clickable.Clicked() {
op.InvalidateOp{}.Add(gtx.Ops)
contents, err := yaml.Marshal(t.Unit())
if err == nil {
@ -191,8 +191,8 @@ func (pe *ParamEditor) layoutUnitFooter(t *Tracker) layout.Widget {
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())
copyUnitBtnStyle := IconButton(t.Theme, pe.CopyUnitBtn, icons.ContentContentCopy, true, "Copy unit (Ctrl+C)")
deleteUnitBtnStyle := IconButton(t.Theme, pe.DeleteUnitBtn, icons.ActionDelete, t.CanDeleteUnit(), "Delete unit (Del)")
text := t.Unit().Type
if text == "" {
text = "Choose unit type"
@ -206,7 +206,7 @@ func (pe *ParamEditor) layoutUnitFooter(t *Tracker) layout.Widget {
layout.Rigid(func(gtx C) D {
var dims D
if t.Unit().Type != "" {
clearUnitBtnStyle := IconButton(t.Theme, pe.ClearUnitBtn, icons.ContentClear, true)
clearUnitBtnStyle := IconButton(t.Theme, pe.ClearUnitBtn, icons.ContentClear, true, "Clear unit")
dims = clearUnitBtnStyle.Layout(gtx)
}
return D{Size: image.Pt(gtx.Dp(unit.Dp(48)), dims.Size.Y)}

View File

@ -148,7 +148,7 @@ func (t *Tracker) layoutSongOptions(gtx C) D {
layout.Rigid(Label("LEN:", white)),
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
t.SongLength.Value = t.Song().Score.Length
numStyle := NumericUpDown(t.Theme, t.SongLength, 1, math.MaxInt32)
numStyle := NumericUpDown(t.Theme, t.SongLength, 1, math.MaxInt32, "Song length")
gtx.Constraints.Min.Y = gtx.Dp(unit.Dp(20))
gtx.Constraints.Min.X = gtx.Dp(unit.Dp(70))
dims := in.Layout(gtx, numStyle.Layout)
@ -162,7 +162,7 @@ func (t *Tracker) layoutSongOptions(gtx C) D {
layout.Rigid(Label("BPM:", white)),
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
t.BPM.Value = t.Song().BPM
numStyle := NumericUpDown(t.Theme, t.BPM, 1, 999)
numStyle := NumericUpDown(t.Theme, t.BPM, 1, 999, "Beats per minute")
gtx.Constraints.Min.Y = gtx.Dp(unit.Dp(20))
gtx.Constraints.Min.X = gtx.Dp(unit.Dp(70))
dims := in.Layout(gtx, numStyle.Layout)
@ -176,7 +176,7 @@ func (t *Tracker) layoutSongOptions(gtx C) D {
layout.Rigid(Label("RPP:", white)),
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
t.RowsPerPattern.Value = t.Song().Score.RowsPerPattern
numStyle := NumericUpDown(t.Theme, t.RowsPerPattern, 1, 255)
numStyle := NumericUpDown(t.Theme, t.RowsPerPattern, 1, 255, "Rows per pattern")
gtx.Constraints.Min.Y = gtx.Dp(unit.Dp(20))
gtx.Constraints.Min.X = gtx.Dp(unit.Dp(70))
dims := in.Layout(gtx, numStyle.Layout)
@ -190,7 +190,7 @@ func (t *Tracker) layoutSongOptions(gtx C) D {
layout.Rigid(Label("RPB:", white)),
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
t.RowsPerBeat.Value = t.Song().RowsPerBeat
numStyle := NumericUpDown(t.Theme, t.RowsPerBeat, 1, 32)
numStyle := NumericUpDown(t.Theme, t.RowsPerBeat, 1, 32, "Rows per beat")
gtx.Constraints.Min.Y = gtx.Dp(unit.Dp(20))
gtx.Constraints.Min.X = gtx.Dp(unit.Dp(70))
dims := in.Layout(gtx, numStyle.Layout)
@ -203,10 +203,8 @@ func (t *Tracker) layoutSongOptions(gtx C) D {
return layout.Flex{Axis: layout.Horizontal}.Layout(gtx,
layout.Rigid(Label("STP:", white)),
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
numStyle := NumericUpDown(t.Theme, t.Step, 0, 8)
numStyle := NumericUpDown(t.Theme, t.Step, 0, 8, "Cursor step")
numStyle.UnitsPerStep = unit.Dp(20)
gtx.Constraints.Min.Y = gtx.Dp(unit.Dp(20))
gtx.Constraints.Min.X = gtx.Dp(unit.Dp(70))
dims := in.Layout(gtx, numStyle.Layout)
return dims
}),

View File

@ -25,8 +25,8 @@ const patmarkWidth = 16
type TrackEditor struct {
TrackVoices *NumberInput
NewTrackBtn *widget.Clickable
DeleteTrackBtn *widget.Clickable
NewTrackBtn *TipClickable
DeleteTrackBtn *TipClickable
AddSemitoneBtn *widget.Clickable
SubtractSemitoneBtn *widget.Clickable
AddOctaveBtn *widget.Clickable
@ -42,8 +42,8 @@ type TrackEditor struct {
func NewTrackEditor() *TrackEditor {
return &TrackEditor{
TrackVoices: new(NumberInput),
NewTrackBtn: new(widget.Clickable),
DeleteTrackBtn: new(widget.Clickable),
NewTrackBtn: new(TipClickable),
DeleteTrackBtn: new(TipClickable),
AddSemitoneBtn: new(widget.Clickable),
SubtractSemitoneBtn: new(widget.Clickable),
AddOctaveBtn: new(widget.Clickable),
@ -61,7 +61,7 @@ func (te *TrackEditor) Focused() bool {
}
func (te *TrackEditor) ChildFocused() bool {
return te.AddOctaveBtn.Focused() || te.AddSemitoneBtn.Focused() || te.DeleteTrackBtn.Focused() || te.NewTrackBtn.Focused() || te.NoteOffBtn.Focused() || te.SubtractOctaveBtn.Focused() || te.SubtractSemitoneBtn.Focused() || te.SubtractSemitoneBtn.Focused() || te.SubtractSemitoneBtn.Focused()
return te.AddOctaveBtn.Focused() || te.AddSemitoneBtn.Focused() || te.DeleteTrackBtn.Clickable.Focused() || te.NewTrackBtn.Clickable.Focused() || te.NoteOffBtn.Focused() || te.SubtractOctaveBtn.Focused() || te.SubtractSemitoneBtn.Focused() || te.SubtractSemitoneBtn.Focused() || te.SubtractSemitoneBtn.Focused()
}
var trackerEditorKeys key.Set = "+|-|←|→|↑|↓|Ctrl-←|Ctrl-→|Ctrl-↑|Ctrl-↓|Shift-←|Shift-→|Shift-↑|Shift-↓|⏎|⇱|⇲|⌫|⌦|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|0|1|2|3|4|5|6|7|8|9|,|."
@ -191,11 +191,11 @@ func (te *TrackEditor) Layout(gtx layout.Context, t *Tracker) layout.Dimensions
rowMarkers := layout.Rigid(t.layoutRowMarkers)
for te.NewTrackBtn.Clicked() {
for te.NewTrackBtn.Clickable.Clicked() {
t.AddTrack(true)
}
for te.DeleteTrackBtn.Clicked() {
for te.DeleteTrackBtn.Clickable.Clicked() {
t.DeleteTrack(false)
}
@ -234,15 +234,13 @@ func (te *TrackEditor) Layout(gtx layout.Context, t *Tracker) layout.Dimensions
addOctaveBtnStyle := LowEmphasisButton(t.Theme, te.AddOctaveBtn, "+12")
subtractOctaveBtnStyle := LowEmphasisButton(t.Theme, te.SubtractOctaveBtn, "-12")
noteOffBtnStyle := LowEmphasisButton(t.Theme, te.NoteOffBtn, "Note Off")
deleteTrackBtnStyle := IconButton(t.Theme, te.DeleteTrackBtn, icons.ActionDelete, t.CanDeleteTrack())
newTrackBtnStyle := IconButton(t.Theme, te.NewTrackBtn, icons.ContentAdd, t.CanAddTrack())
deleteTrackBtnStyle := IconButton(t.Theme, te.DeleteTrackBtn, icons.ActionDelete, t.CanDeleteTrack(), "Delete track")
newTrackBtnStyle := IconButton(t.Theme, te.NewTrackBtn, icons.ContentAdd, t.CanAddTrack(), "Add track")
n := t.Song().Score.Tracks[t.Cursor().Track].NumVoices
te.TrackVoices.Value = n
in := layout.UniformInset(unit.Dp(1))
voiceUpDown := func(gtx C) D {
numStyle := NumericUpDown(t.Theme, te.TrackVoices, 1, t.MaxTrackVoices())
gtx.Constraints.Min.Y = gtx.Dp(unit.Dp(20))
gtx.Constraints.Min.X = gtx.Dp(unit.Dp(70))
numStyle := NumericUpDown(t.Theme, te.TrackVoices, 1, t.MaxTrackVoices(), "Number of voices for this track")
return in.Layout(gtx, numStyle.Layout)
}
t.TrackHexCheckBox.Value = t.Song().Score.Tracks[t.Cursor().Track].Effect