This commit is contained in:
5684185+vsariola@users.noreply.github.com
2025-07-05 18:54:51 +03:00
parent 3c6c24c6af
commit 53af773815
12 changed files with 336 additions and 600 deletions

View File

@ -2,7 +2,6 @@ package gioui
import (
"bytes"
"fmt"
"image"
"image/color"
"io"
@ -371,79 +370,45 @@ func MakeUnitList(m *tracker.Model) UnitList {
func (ul *UnitList) Layout(gtx C) D {
t := TrackerFromContext(gtx)
ul.update(gtx, t)
var units [256]tracker.UnitListItem
for i, item := range (*tracker.Units)(t.Model).Iterate {
if i >= 256 {
break
}
units[i] = item
}
count := min(ul.dragList.TrackerList.Count(), 256)
element := func(gtx C, i int) D {
gtx.Constraints.Max.Y = gtx.Dp(20)
gtx.Constraints.Min.Y = gtx.Constraints.Max.Y
if i < 0 || i > 255 {
return layout.Dimensions{Size: gtx.Constraints.Min}
}
u := units[i]
u := t.Units().Item(i)
editorStyle := t.Theme.InstrumentEditor.UnitList.Name
if u.Disabled {
signalError := t.RailError()
switch {
case u.Disabled:
editorStyle = t.Theme.InstrumentEditor.UnitList.NameDisabled
}
stackText := strconv.FormatInt(int64(u.StackAfter), 10)
if u.StackNeed > u.StackBefore {
case signalError.Err != nil && signalError.UnitIndex == i:
editorStyle.Color = t.Theme.InstrumentEditor.UnitList.Error
(*tracker.Alerts)(t.Model).AddNamed("UnitNeedsInputs", fmt.Sprintf("%v needs at least %v input signals, got %v", u.Type, u.StackNeed, u.StackBefore), tracker.Error)
} else if i == count-1 && u.StackAfter != 0 {
editorStyle.Color = t.Theme.InstrumentEditor.UnitList.Warning
(*tracker.Alerts)(t.Model).AddNamed("InstrumentLeavesSignals", fmt.Sprintf("Instrument leaves %v signal(s) on the stack", u.StackAfter), tracker.Warning)
}
stackLabel := Label(t.Theme, &t.Theme.InstrumentEditor.UnitList.Stack, stackText)
rightMargin := layout.Inset{Right: unit.Dp(10)}
return layout.Flex{Axis: layout.Horizontal}.Layout(gtx,
layout.Rigid(func(gtx C) D {
if i == ul.dragList.TrackerList.Selected() {
defer clip.Rect(image.Rect(0, 0, gtx.Constraints.Max.X, gtx.Constraints.Max.Y)).Push(gtx.Ops).Pop()
str := t.Model.UnitSearch()
for ev := ul.searchEditor.Update(gtx, str); ev != EditorEventNone; ev = ul.searchEditor.Update(gtx, str) {
if ev == EditorEventSubmit {
if str.Value() != "" {
for _, n := range sointu.UnitNames {
if strings.HasPrefix(n, str.Value()) {
t.Units().SetSelectedType(n)
break
}
}
} else {
t.Units().SetSelectedType("")
}
}
ul.dragList.Focus()
t.UnitSearching().SetValue(false)
}
return ul.searchEditor.Layout(gtx, str, t.Theme, &editorStyle, "---")
} else {
text := u.Type
if text == "" {
text = "---"
}
l := editorStyle.AsLabelStyle()
return Label(t.Theme, &l, text).Layout(gtx)
unitName := func(gtx C) D {
if i == ul.dragList.TrackerList.Selected() {
defer clip.Rect(image.Rect(0, 0, gtx.Constraints.Max.X, gtx.Constraints.Max.Y)).Push(gtx.Ops).Pop()
return ul.searchEditor.Layout(gtx, t.Model.UnitSearch(), t.Theme, &editorStyle, "---")
} else {
text := u.Type
if text == "" {
text = "---"
}
}),
layout.Flexed(1, func(gtx C) D {
unitNameLabel := Label(t.Theme, &t.Theme.InstrumentEditor.UnitList.Comment, u.Comment)
inset := layout.Inset{Left: unit.Dp(5)}
return inset.Layout(gtx, unitNameLabel.Layout)
}),
layout.Rigid(func(gtx C) D {
return rightMargin.Layout(gtx, stackLabel.Layout)
}),
l := editorStyle.AsLabelStyle()
return Label(t.Theme, &l, text).Layout(gtx)
}
}
stackText := strconv.FormatInt(int64(u.Signals.StackAfter()), 10)
commentLabel := Label(t.Theme, &t.Theme.InstrumentEditor.UnitList.Comment, u.Comment)
stackLabel := Label(t.Theme, &t.Theme.InstrumentEditor.UnitList.Stack, stackText)
return layout.Flex{Axis: layout.Horizontal}.Layout(gtx,
layout.Rigid(unitName),
layout.Rigid(layout.Spacer{Width: 5}.Layout),
layout.Flexed(1, commentLabel.Layout),
layout.Rigid(stackLabel.Layout),
layout.Rigid(layout.Spacer{Width: 10}.Layout),
)
}
defer op.Offset(image.Point{}).Push(gtx.Ops).Pop()
unitList := FilledDragList(t.Theme, ul.dragList)
return Surface{Gray: 30, Focus: t.PatchPanel.TreeFocused(gtx)}.Layout(gtx, func(gtx C) D {
surface := func(gtx C) 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()
@ -458,7 +423,8 @@ func (ul *UnitList) Layout(gtx C) D {
return margin.Layout(gtx, addUnitBtn.Layout)
}),
)
})
}
return Surface{Gray: 30, Focus: t.PatchPanel.TreeFocused(gtx)}.Layout(gtx, surface)
}
func (ul *UnitList) update(gtx C, t *Tracker) {
@ -490,6 +456,23 @@ func (ul *UnitList) update(gtx C, t *Tracker) {
}
}
}
str := t.Model.UnitSearch()
for ev := ul.searchEditor.Update(gtx, str); ev != EditorEventNone; ev = ul.searchEditor.Update(gtx, str) {
if ev == EditorEventSubmit {
if str.Value() != "" {
for _, n := range sointu.UnitNames {
if strings.HasPrefix(n, str.Value()) {
t.Units().SetSelectedType(n)
break
}
}
} else {
t.Units().SetSelectedType("")
}
}
ul.dragList.Focus()
t.UnitSearching().SetValue(false)
}
}
func (ul *UnitList) Tags(curLevel int, yield TagYieldFunc) bool {

View File

@ -25,12 +25,12 @@ type (
SignalRailWidget struct {
Style *SignalRailStyle
Signal tracker.Signal
Signal tracker.Rail
Height unit.Dp
}
)
func SignalRail(th *Theme, signal tracker.Signal) SignalRailWidget {
func SignalRail(th *Theme, signal tracker.Rail) SignalRailWidget {
return SignalRailWidget{
Style: &th.SignalRail,
Signal: signal,
@ -41,6 +41,9 @@ func SignalRail(th *Theme, signal tracker.Signal) SignalRailWidget {
func (s SignalRailWidget) Layout(gtx C) D {
sw := gtx.Dp(s.Style.SignalWidth)
h := gtx.Dp(s.Height)
if s.Signal.PassThrough == 0 && len(s.Signal.StackUse.Inputs) == 0 && s.Signal.StackUse.NumOutputs == 0 {
return D{Size: image.Pt(sw, h)}
}
lw := gtx.Dp(s.Style.LineWidth)
pd := gtx.Dp(s.Style.PortDiameter)
center := sw / 2

View File

@ -85,14 +85,14 @@ type Theme struct {
}
}
UnitEditor struct {
Name LabelStyle
Chooser LabelStyle
Hint LabelStyle
InvalidParam color.NRGBA
SendTarget color.NRGBA
Width unit.Dp
Height unit.Dp
UnitList struct {
Name LabelStyle
Chooser LabelStyle
Hint LabelStyle
WireColor color.NRGBA
WireHint LabelStyle
Width unit.Dp
Height unit.Dp
UnitList struct {
LabelWidth unit.Dp
Name LabelStyle
Disabled LabelStyle

View File

@ -210,8 +210,8 @@ uniteditor:
chooser: { textsize: 12, color: *white, shadowcolor: *black }
name:
{ textsize: 12, alignment: 2, color: *highemphasis, shadowcolor: *black }
invalidparam: { r: 120, g: 120, b: 120, a: 190 }
sendtarget: *secondarycolor
wirecolor: *secondarycolor
wirehint: { textsize: 12, color: *disabled, shadowcolor: *black }
width: 60
height: 70
unitlist:

View File

@ -162,9 +162,9 @@ func (pe *UnitEditor) layoutRack(gtx C) D {
cellWidth := gtx.Dp(t.Theme.UnitEditor.Width)
cellHeight := gtx.Dp(t.Theme.UnitEditor.Height)
rowTitleLabelWidth := gtx.Dp(t.Theme.UnitEditor.UnitList.LabelWidth)
rowTitleSignalWidth := gtx.Dp(t.Theme.SignalRail.SignalWidth) * t.SignalRail().MaxWidth()
rowTitleSignalWidth := gtx.Dp(t.Theme.SignalRail.SignalWidth) * t.RailWidth()
rowTitleWidth := rowTitleLabelWidth + rowTitleSignalWidth
signalError := t.SignalRail().Error()
signalError := t.RailError()
columnTitleHeight := gtx.Dp(0)
for i := range pe.Parameters {
for len(pe.Parameters[i]) < width {
@ -182,11 +182,11 @@ func (pe *UnitEditor) layoutRack(gtx C) D {
if y < 0 || y >= len(pe.Parameters) {
return D{}
}
sr := SignalRail(t.Theme, t.SignalRail().Item(y))
label := Label(t.Theme, &t.Theme.UnitEditor.UnitList.Name, t.Units().Item(y).Type)
item := t.Units().Item(y)
sr := SignalRail(t.Theme, item.Signals)
label := Label(t.Theme, &t.Theme.UnitEditor.UnitList.Name, item.Type)
switch {
case t.Units().Item(y).Disabled:
case item.Disabled:
label.LabelStyle = t.Theme.UnitEditor.UnitList.Disabled
case signalError.Err != nil && signalError.UnitIndex == y:
label.Color = t.Theme.UnitEditor.UnitList.Error
@ -230,7 +230,6 @@ func (pe *UnitEditor) layoutRack(gtx C) D {
func (pe *UnitEditor) drawSignals(gtx C, rowTitleWidth int) {
t := TrackerFromContext(gtx)
units := t.Units()
colP := pe.paramTable.ColTitleList.List.Position
rowP := pe.paramTable.RowTitleList.List.Position
p := image.Pt(rowTitleWidth, 0)
@ -238,16 +237,25 @@ func (pe *UnitEditor) drawSignals(gtx C, rowTitleWidth int) {
gtx.Constraints.Max = gtx.Constraints.Max.Sub(p)
defer clip.Rect(image.Rectangle{Max: gtx.Constraints.Max}).Push(gtx.Ops).Pop()
defer op.Offset(image.Pt(-colP.Offset, -rowP.Offset)).Push(gtx.Ops).Pop()
for i := 0; i < units.Count(); i++ {
item := units.Item(i)
if item.TargetOk {
pe.drawSignal(gtx, i-rowP.First, item.TargetX-colP.First, item.TargetY-rowP.First)
}
for wire := range t.Wires {
pe.drawSignal(gtx, wire, colP.First, rowP.First)
}
}
func (pe *UnitEditor) drawSignal(gtx C, sy, ex, ey int) {
func (pe *UnitEditor) drawSignal(gtx C, wire tracker.Wire, col, row int) {
sy := wire.From - row
ex := wire.To.X - col
ey := wire.To.Y - row
t := TrackerFromContext(gtx)
if wire.FromSet && !wire.ToSet {
defer op.Offset(image.Pt(0, (sy+1)*gtx.Dp(t.Theme.UnitEditor.Height)-gtx.Dp(16))).Push(gtx.Ops).Pop()
Label(t.Theme, &t.Theme.UnitEditor.WireHint, wire.Hint).Layout(gtx)
return
}
if !wire.FromSet && wire.ToSet {
Label(t.Theme, &t.Theme.UnitEditor.WireHint, wire.Hint).Layout(gtx)
return
}
width := float32(gtx.Dp(t.Theme.UnitEditor.Width))
height := float32(gtx.Dp(t.Theme.UnitEditor.Height))
diam := gtx.Dp(t.Theme.Knob.Diameter)
@ -278,7 +286,7 @@ func (pe *UnitEditor) drawSignal(gtx C, sy, ex, ey int) {
path.MoveTo(from)
path.CubeTo(from.Add(fromTan), p1.Sub(p1Tan), p1)
path.CubeTo(p1.Add(p1Tan), p2, to)
paint.FillShape(gtx.Ops, t.Theme.UnitEditor.SendTarget,
paint.FillShape(gtx.Ops, t.Theme.UnitEditor.WireColor,
clip.Stroke{
Path: path.End(),
Width: float32(gtx.Dp(t.Theme.SignalRail.LineWidth)),