Hi all,
in the code below I’m trying to prototype a simple patchbay. I.e. when you click one of the green dots you should be able to draw a line to one of the green dots on the opposite side. However, if I draw a cable and release the mouse (in mouseUpAction
) all existing cables are redrawn again in a funky way.
I guess I still don’t quite understand how Pen
works. As I understood it a drawing in a UserView
is performed by one ‘drawFunc’, a Function
to which I incrementally add more Function
s for each new cable. Basically that approach seems to work. E.g. in mouseMoveAction
I’m drawing lines from a defined origin to my current mouse position by first removing the function for the previously drawn temporary line and then adding a function for a line from the origin to my new mouse position. Only when it comes to drawing the final cable in mouseUpAction
add a function of which I assumed it would only affect my final cable. However, it has an impact on all previously drawn cables too.
Can anyone explain what’s going on here? (sorry for the comprehensive code - you should be able to see what I mean when you paste and execute my code in SuperCollider).
Thanks, Stefan
(
var win, u, points, leftRects, rightRects,
leftPlugs, rightPlugs,
leftHitTest, rightHitTest, leftHit, rightHit,
startPoint, drawFunc, finalCables;
points = List.new;
leftRects = List.new;
rightRects = List.new;
leftPlugs = List.new;
rightPlugs = List.new;
finalCables = List.new;
12.do { |i|
points.add(Point(10, 10 + (i * 50) ))
};
win = Window(\patchbay, Rect(
Window.screenBounds.width/2-400,
Window.screenBounds.height/2-350,
800, 700
));
u = UserView(win, win.view.bounds);
u.resize = 5;
u.background_(Color(alpha: 0.7));
win.acceptsMouseOver_(true);
u.drawFunc_({ |uv|
uv.clearDrawing;
[leftRects, rightRects, leftPlugs, rightPlugs].do(_.clear);
points.do { |p, i|
Pen.strokeColor_(Color.white);
Pen.joinStyle_(1);
leftRects.add(Rect(p.x, p.y, 200, 40));
Pen.strokeRect(leftRects[i]);
rightRects.add(Rect(uv.bounds.width - 210, p.y, 200, 40));
Pen.strokeRect(rightRects[i]);
Pen.fillColor_(Color.green);
leftPlugs.add(Rect(p.x + 190, p.y + 10, 20, 20));
Pen.addOval(leftPlugs[i]);
Pen.fill;
rightPlugs.add(Rect(uv.bounds.width - 220, p.y + 10, 20, 20));
Pen.addOval(rightPlugs[i]);
Pen.fill;
}
});
u.mouseDownAction_({ |v, x, y, mod, bn, ccount|
"mouse down".postln;
// only draw if mouse is over one of the green dots
leftHit = leftHitTest.(x, y);
rightHit = rightHitTest.(x, y);
leftHit !? {
startPoint = Point(
leftPlugs[leftHit].width.div(2) + leftPlugs[leftHit].left,
leftPlugs[leftHit].height.div(2) + leftPlugs[leftHit].top
)
};
rightHit !? {
startPoint = Point(
rightPlugs[rightHit].width.div(2) + rightPlugs[rightHit].left,
rightPlugs[rightHit].height.div(2) + rightPlugs[rightHit].top
)
};
if (startPoint.notNil) {
v.drawFunc_(v.drawFunc.addFunc({ |uv|
Pen.moveTo(startPoint);
}))
};
});
u.mouseMoveAction_({ |v, x, y, mods|
// remove drawFunc for temporary line before
// drawing a new one
v.drawFunc.removeFunc(drawFunc);
drawFunc = { |uv|
Pen.width_(5);
Pen.joinStyle_(1);
Pen.moveTo(startPoint);
Pen.lineTo(Point(x, y));
Pen.stroke;
};
// draw a new temporary line
v.drawFunc.addFunc(drawFunc);
v.refresh;
});
u.mouseUpAction_({ |v, x, y, mods, bn|
var endPoint;
"mouse up".postln;
// remove drawFunc for temporary cable, drawn in mouseMoveAction
v.drawFunc.removeFunc(drawFunc);
case
// drawing a cable from the left side
{ leftHit.notNil } {
rightHit = rightHitTest.(x, y);
rightHit !? {
endPoint = Point(
rightPlugs[rightHit].width.div(2) + rightPlugs[rightHit].left,
rightPlugs[rightHit].height.div(2) + rightPlugs[rightHit].top
);
finalCables.add((
start: startPoint,
end: endPoint
));
// this function should only be added once for the last cable
// but gets applied for aleady existing ones as well, it seems
v.drawFunc.addFunc({ |uv|
Pen.width_(5);
Pen.joinStyle_(1);
// see, this function gets repeated for every existing cable
Pen.moveTo(finalCables[finalCables.size-1].start.postln);
Pen.lineTo(endPoint.postln);
Pen.stroke;
});
}
}
// drawing a cable from the right side
{ rightHit.notNil } {
"drawn from the right".postln;
leftHit = leftHitTest.(x, y);
leftHit !? {
endPoint = Point(
leftPlugs[leftHit].width.div(2) + leftPlugs[leftHit].left,
leftPlugs[leftHit].height.div(2) + leftPlugs[leftHit].top
);
finalCables.add((
start: endPoint,
end: startPoint
));
v.drawFunc.addFunc({ |uv|
Pen.width_(5);
Pen.joinStyle_(1);
// see, this function gets repeated for every existing cable
Pen.moveTo(finalCables[finalCables.size-1].end.postln);
Pen.lineTo(endPoint.postln);
Pen.stroke;
});
}
};
v.refresh;
"finalCables: %\n".postf(finalCables);
});
leftHitTest = { |x, y|
var ret;
leftPlugs.do { |p, i|
if (x > p.left and: { x < p.right and: { y > p.top and: { y < p.bottom }}}) {
ret = i;
}
};
ret;
};
rightHitTest = { |x, y|
var ret;
rightPlugs.do { |p, i|
if (x > p.left and: { x < p.right and: { y > p.top and: { y < p.bottom }}}) {
ret = i;
}
};
ret;
};
win.front;
win.view.onResize_({ |v|
u.resizeToBounds(v.bounds);
})
)