|
|
61bedf |
using System;
|
|
|
61bedf |
using System.Collections.Generic;
|
|
|
61bedf |
|
|
|
61bedf |
namespace Assistance {
|
|
|
589f9a |
public class InputManager: Track.IOwner {
|
|
|
0f2bf8 |
public static readonly Drawing.Pen penPreview = new Drawing.Pen("Dark Green", 3.0, 0.25);
|
|
|
720280 |
public static readonly double levelAlpha = 0.8;
|
|
|
61bedf |
|
|
|
61bedf |
public class TrackHandler: Track.Handler {
|
|
|
61bedf |
public readonly List<int> keys = new List<int>();</int></int>
|
|
|
c3ebff |
public TrackHandler(InputManager owner, Track original, int keysCount = 0):
|
|
|
589f9a |
base(owner, original)
|
|
|
c3ebff |
{ for(int i = 0; i < keysCount; ++i) keys.Add(0); }
|
|
|
61bedf |
}
|
|
|
61bedf |
|
|
|
61bedf |
public class KeyPoint {
|
|
|
61bedf |
public class Holder: IDisposable {
|
|
|
61bedf |
public readonly KeyPoint keyPoint;
|
|
|
1d3aae |
private bool holded = false;
|
|
|
1d3aae |
|
|
|
61bedf |
public Holder(KeyPoint keyPoint)
|
|
|
1d3aae |
{ this.keyPoint = keyPoint; reuse(); }
|
|
|
1d3aae |
|
|
|
1d3aae |
public bool available
|
|
|
1d3aae |
{ get { return keyPoint.available; } }
|
|
|
1d3aae |
public bool isHolded
|
|
|
1d3aae |
{ get { return holded; } }
|
|
|
1d3aae |
public bool reuse() {
|
|
|
1d3aae |
if (!holded) ++keyPoint.refCount;
|
|
|
1d3aae |
holded = true;
|
|
|
1d3aae |
return keyPoint.available;
|
|
|
1d3aae |
}
|
|
|
1d3aae |
public void release() {
|
|
|
1d3aae |
if (holded) --keyPoint.refCount;
|
|
|
1d3aae |
holded = false;
|
|
|
1d3aae |
}
|
|
|
1d3aae |
|
|
|
61bedf |
public void Dispose()
|
|
|
61bedf |
{ Dispose(true); GC.SuppressFinalize(this); }
|
|
|
61bedf |
protected virtual void Dispose(bool disposing)
|
|
|
1d3aae |
{ release(); }
|
|
|
61bedf |
~Holder()
|
|
|
61bedf |
{ Dispose(false); }
|
|
|
61bedf |
}
|
|
|
1d3aae |
|
|
|
61bedf |
private int refCount = 0;
|
|
|
1d3aae |
public bool available = true;
|
|
|
1d3aae |
|
|
|
61bedf |
public Holder hold()
|
|
|
61bedf |
{ return new Holder(this); }
|
|
|
61bedf |
public bool isFree
|
|
|
61bedf |
{ get { return refCount <= 0; } }
|
|
|
61bedf |
}
|
|
|
61bedf |
|
|
|
589f9a |
public interface IModifier: Track.IOwner {
|
|
|
589f9a |
void activate();
|
|
|
589f9a |
void modify(List<track> tracks, KeyPoint keyPoint, List<track> outTracks);
|
|
|
0f2bf8 |
void draw(Cairo.Context context, List<track> tracks, List<point> hovers);</point>
|
|
|
589f9a |
void deactivate();
|
|
|
589f9a |
}
|
|
|
589f9a |
|
|
|
589f9a |
public class Modifier: IModifier {
|
|
|
c3ebff |
public virtual void activate() { }
|
|
|
589f9a |
public virtual void modify(Track track, KeyPoint keyPoint, List<track> outTracks) { }
|
|
|
c3ebff |
public virtual void modify(List<track> tracks, KeyPoint keyPoint, List<track> outTracks)
|
|
|
c3ebff |
{ foreach(Track track in tracks) modify(track, keyPoint, outTracks); }
|
|
|
0f2bf8 |
public virtual void drawHover(Cairo.Context context, Point hover) { }
|
|
|
0f2bf8 |
public virtual void drawTrack(Cairo.Context context, Track track) { }
|
|
|
0f2bf8 |
public virtual void draw(Cairo.Context context, List<track> tracks, List<point> hovers) {</point>
|
|
|
0f2bf8 |
foreach(Track track in tracks) drawTrack(context, track);
|
|
|
0f2bf8 |
foreach(Point hover in hovers) drawHover(context, hover);
|
|
|
0f2bf8 |
}
|
|
|
c3ebff |
public virtual void deactivate() { }
|
|
|
c3ebff |
}
|
|
|
c3ebff |
|
|
|
61bedf |
|
|
|
61bedf |
public readonly Workarea workarea;
|
|
|
61bedf |
|
|
|
61bedf |
private readonly InputState state = new InputState();
|
|
|
b9e5e0 |
|
|
|
b9e5e0 |
private bool wantActive;
|
|
|
b9e5e0 |
private bool actualActive;
|
|
|
61bedf |
private Tool tool;
|
|
|
589f9a |
private readonly List<imodifier> modifiers = new List<imodifier>();</imodifier></imodifier>
|
|
|
61bedf |
|
|
|
b9e5e0 |
private readonly List<list<track>> tracks = new List<list<track>>() { new List<track>() };</list<track></list<track>
|
|
|
61bedf |
private readonly List<keypoint> keyPoints = new List<keypoint>();</keypoint></keypoint>
|
|
|
61bedf |
private int keyPointsSent;
|
|
|
61bedf |
|
|
|
c3ebff |
|
|
|
b9e5e0 |
public InputManager(Workarea workarea)
|
|
|
61bedf |
{ this.workarea = workarea; }
|
|
|
61bedf |
|
|
|
61bedf |
private void paintRollbackTo(int keyIndex, List<track> subTracks) {
|
|
|
61bedf |
if (keyIndex >= keyPoints.Count)
|
|
|
61bedf |
return;
|
|
|
0f2bf8 |
|
|
|
61bedf |
int level = keyIndex + 1;
|
|
|
61bedf |
if (level <= keyPointsSent) {
|
|
|
589f9a |
if (level < keyPointsSent)
|
|
|
61bedf |
tool.paintPop(keyPointsSent - level);
|
|
|
61bedf |
tool.paintCancel();
|
|
|
61bedf |
keyPointsSent = level;
|
|
|
61bedf |
}
|
|
|
61bedf |
|
|
|
61bedf |
foreach(Track track in subTracks) {
|
|
|
61bedf |
TrackHandler handler = (TrackHandler)track.handler;
|
|
|
61bedf |
handler.keys.RemoveRange(level, keyPoints.Count - level);
|
|
|
589f9a |
int cnt = handler.keys[keyIndex];
|
|
|
72d2fd |
track.resetRemoved();
|
|
|
72d2fd |
track.forceAdded(track.count - cnt);
|
|
|
61bedf |
}
|
|
|
1d3aae |
for(int i = level; i < keyPoints.Count; ++i) keyPoints[i].available = false;
|
|
|
61bedf |
keyPoints.RemoveRange(level, keyPoints.Count - level);
|
|
|
61bedf |
}
|
|
|
61bedf |
|
|
|
589f9a |
private void paintApply(int count, List<track> subTracks) {
|
|
|
61bedf |
if (count <= 0)
|
|
|
61bedf |
return;
|
|
|
0f2bf8 |
|
|
|
1d3aae |
int level = keyPoints.Count - count;
|
|
|
0f2bf8 |
bool resend = true;
|
|
|
589f9a |
|
|
|
589f9a |
if (level < keyPointsSent) {
|
|
|
61bedf |
// apply
|
|
|
720280 |
int applied = tool.paintApply(keyPointsSent - level);
|
|
|
720280 |
applied = Math.Max(0, Math.Min(keyPointsSent - level, applied));
|
|
|
720280 |
keyPointsSent -= applied;
|
|
|
0f2bf8 |
if (keyPointsSent == level) resend = false;
|
|
|
589f9a |
}
|
|
|
0f2bf8 |
|
|
|
589f9a |
if (level < keyPointsSent) {
|
|
|
61bedf |
// rollback
|
|
|
61bedf |
tool.paintPop(keyPointsSent - level);
|
|
|
589f9a |
keyPointsSent = level;
|
|
|
61bedf |
}
|
|
|
61bedf |
|
|
|
589f9a |
// remove keypoints
|
|
|
0f2bf8 |
foreach(Track track in subTracks) {
|
|
|
0f2bf8 |
TrackHandler handler = (TrackHandler)track.handler;
|
|
|
0f2bf8 |
if (resend) {
|
|
|
72d2fd |
track.resetRemoved();
|
|
|
72d2fd |
track.forceAdded(track.count - handler.keys[keyPointsSent]);
|
|
|
0f2bf8 |
}
|
|
|
0f2bf8 |
handler.keys.RemoveRange(level, handler.keys.Count - level);
|
|
|
0f2bf8 |
}
|
|
|
1d3aae |
for(int i = level; i < keyPoints.Count; ++i) keyPoints[i].available = false;
|
|
|
61bedf |
keyPoints.RemoveRange(level, keyPoints.Count - level);
|
|
|
61bedf |
}
|
|
|
61bedf |
|
|
|
61bedf |
private void paintTracks() {
|
|
|
61bedf |
bool allFinished = true;
|
|
|
b9e5e0 |
foreach(Track track in tracks[0])
|
|
|
589f9a |
if (!track.isFinished())
|
|
|
61bedf |
{ allFinished = false; break; }
|
|
|
61bedf |
|
|
|
61bedf |
while(true) {
|
|
|
61bedf |
// run modifiers
|
|
|
61bedf |
KeyPoint newKeyPoint = new KeyPoint();
|
|
|
b9e5e0 |
for(int i = 0; i < modifiers.Count; ++i) {
|
|
|
b9e5e0 |
tracks[i+1].Clear();
|
|
|
b9e5e0 |
modifiers[i].modify(tracks[i], newKeyPoint, tracks[i+1]);
|
|
|
c3ebff |
}
|
|
|
b9e5e0 |
List<track> subTracks = tracks[modifiers.Count];
|
|
|
7bbf70 |
|
|
|
c3ebff |
// create handlers
|
|
|
c3ebff |
foreach(Track track in subTracks)
|
|
|
c3ebff |
if (track.handler == null)
|
|
|
c3ebff |
track.handler = new TrackHandler(this, track, keyPoints.Count);
|
|
|
7bbf70 |
|
|
|
7bbf70 |
//Console.WriteLine("--- tracks:");
|
|
|
7bbf70 |
//for(int i = 0; i < tracks.Count; ++i) {
|
|
|
7bbf70 |
// Console.WriteLine(" level " + i);
|
|
|
7bbf70 |
// foreach(Track t in tracks[i])
|
|
|
7bbf70 |
// t.print();
|
|
|
7bbf70 |
//}
|
|
|
61bedf |
|
|
|
61bedf |
if (keyPoints.Count > 0) {
|
|
|
61bedf |
// rollback
|
|
|
61bedf |
int rollbackIndex = keyPoints.Count;
|
|
|
61bedf |
foreach(Track track in subTracks) {
|
|
|
72d2fd |
if (track.wasRemoved) {
|
|
|
72d2fd |
int count = track.count - track.pointsAdded;
|
|
|
61bedf |
TrackHandler handler = (TrackHandler)track.handler;
|
|
|
61bedf |
while(rollbackIndex > 0 && (rollbackIndex >= keyPoints.Count || handler.keys[rollbackIndex] > count))
|
|
|
61bedf |
--rollbackIndex;
|
|
|
61bedf |
}
|
|
|
61bedf |
}
|
|
|
61bedf |
paintRollbackTo(rollbackIndex, subTracks);
|
|
|
61bedf |
|
|
|
61bedf |
// apply
|
|
|
61bedf |
int applyCount = 0;
|
|
|
61bedf |
while(applyCount < keyPoints.Count && keyPoints[keyPoints.Count - applyCount - 1].isFree)
|
|
|
61bedf |
++applyCount;
|
|
|
61bedf |
paintApply(applyCount, subTracks);
|
|
|
61bedf |
}
|
|
|
61bedf |
|
|
|
61bedf |
// send to tool
|
|
|
720280 |
if (keyPointsSent == keyPoints.Count && subTracks.Count > 0)
|
|
|
61bedf |
tool.paintTracks(subTracks);
|
|
|
72d2fd |
foreach(Track track in subTracks)
|
|
|
72d2fd |
track.resetCounters();
|
|
|
61bedf |
|
|
|
61bedf |
// is paint finished?
|
|
|
61bedf |
if (newKeyPoint.isFree) {
|
|
|
61bedf |
if (allFinished) {
|
|
|
61bedf |
paintApply(keyPoints.Count, subTracks);
|
|
|
b9e5e0 |
foreach(List<track> ts in tracks)
|
|
|
b9e5e0 |
ts.Clear();
|
|
|
61bedf |
}
|
|
|
61bedf |
break;
|
|
|
61bedf |
}
|
|
|
61bedf |
|
|
|
61bedf |
// create key point
|
|
|
61bedf |
if (tool.paintPush()) ++keyPointsSent;
|
|
|
61bedf |
keyPoints.Add(newKeyPoint);
|
|
|
61bedf |
foreach(Track track in subTracks)
|
|
|
72d2fd |
((TrackHandler)track.handler).keys.Add(track.count);
|
|
|
61bedf |
}
|
|
|
0f2bf8 |
|
|
|
61bedf |
}
|
|
|
0f2bf8 |
|
|
|
0f2bf8 |
private long getDeviceId(Gdk.Device device)
|
|
|
0f2bf8 |
{ return device == null ? 0 : device.Handle.ToInt64(); }
|
|
|
0f2bf8 |
|
|
|
61bedf |
private int trackCompare(Track track, Gdk.Device device, long touchId) {
|
|
|
0f2bf8 |
if (getDeviceId(track.device) < getDeviceId(device)) return -1;
|
|
|
0f2bf8 |
if (getDeviceId(track.device) > getDeviceId(device)) return 1;
|
|
|
61bedf |
if (track.touchId < touchId) return -1;
|
|
|
61bedf |
if (track.touchId > touchId) return 1;
|
|
|
61bedf |
return 0;
|
|
|
61bedf |
}
|
|
|
61bedf |
|
|
|
61bedf |
private Track createTrack(int index, Gdk.Device device, long touchId, long ticks) {
|
|
|
61bedf |
Track track = new Track(
|
|
|
61bedf |
device,
|
|
|
61bedf |
touchId,
|
|
|
61bedf |
state.keyHistoryHolder(ticks),
|
|
|
61bedf |
state.buttonHistoryHolder(device, ticks) );
|
|
|
b9e5e0 |
tracks[0].Insert(index, track);
|
|
|
61bedf |
return track;
|
|
|
61bedf |
}
|
|
|
61bedf |
|
|
|
61bedf |
private Track getTrack(Gdk.Device device, long touchId, long ticks) {
|
|
|
0f2bf8 |
if (tracks[0].Count == 0)
|
|
|
0f2bf8 |
return createTrack(0, device, touchId, ticks);
|
|
|
61bedf |
int cmp;
|
|
|
61bedf |
|
|
|
61bedf |
int a = 0;
|
|
|
b9e5e0 |
cmp = trackCompare(tracks[0][a], device, touchId);
|
|
|
b9e5e0 |
if (cmp == 0) return tracks[0][a];
|
|
|
61bedf |
if (cmp < 0) return createTrack(a, device, touchId, ticks);
|
|
|
61bedf |
|
|
|
0f2bf8 |
int b = tracks[0].Count - 1;
|
|
|
b9e5e0 |
cmp = trackCompare(tracks[0][b], device, touchId);
|
|
|
b9e5e0 |
if (cmp == 0) return tracks[0][b];
|
|
|
61bedf |
if (cmp > 0) return createTrack(b+1, device, touchId, ticks);
|
|
|
61bedf |
|
|
|
61bedf |
// binary search: tracks[a] < tracks[c] < tracks[b]
|
|
|
61bedf |
while(true) {
|
|
|
61bedf |
int c = (a + b)/2;
|
|
|
61bedf |
if (a == c) break;
|
|
|
b9e5e0 |
cmp = trackCompare(tracks[0][c], device, touchId);
|
|
|
61bedf |
if (cmp < 0) b = c; else
|
|
|
61bedf |
if (cmp > 0) a = c; else
|
|
|
b9e5e0 |
return tracks[0][c];
|
|
|
61bedf |
}
|
|
|
61bedf |
return createTrack(b, device, touchId, ticks);
|
|
|
61bedf |
}
|
|
|
61bedf |
|
|
|
702257 |
private void addTrackPoint(Track track, Point position, double pressure, Point tilt, double time, bool final) {
|
|
|
61bedf |
// add
|
|
|
72d2fd |
track.add( new Track.Point(
|
|
|
702257 |
position,
|
|
|
702257 |
pressure,
|
|
|
702257 |
tilt,
|
|
|
72d2fd |
(double)track.count,
|
|
|
61bedf |
time,
|
|
|
72d2fd |
0.0,
|
|
|
61bedf |
final ));
|
|
|
61bedf |
}
|
|
|
61bedf |
|
|
|
61bedf |
private void touchTracks(bool finish = false) {
|
|
|
702257 |
foreach(Track track in tracks[0]) {
|
|
|
72d2fd |
if (!track.isFinished() && !track.isEmpty) {
|
|
|
702257 |
Track.Point p = track.getLast();
|
|
|
702257 |
addTrackPoint(track, p.position, p.pressure, p.tilt, p.time, finish);
|
|
|
702257 |
}
|
|
|
702257 |
}
|
|
|
61bedf |
}
|
|
|
61bedf |
|
|
|
b9e5e0 |
private void actualActivate() {
|
|
|
b9e5e0 |
bool wasActive = actualActive;
|
|
|
b9e5e0 |
actualActive = wantActive && tool != null;
|
|
|
b9e5e0 |
if (wasActive == actualActive) return;
|
|
|
b9e5e0 |
|
|
|
b9e5e0 |
if (actualActive) {
|
|
|
b9e5e0 |
foreach(IModifier modifier in modifiers)
|
|
|
b9e5e0 |
modifier.activate();
|
|
|
b9e5e0 |
tool.activate();
|
|
|
b9e5e0 |
} else {
|
|
|
b9e5e0 |
touchTracks(true);
|
|
|
b9e5e0 |
tool.deactivate();
|
|
|
b9e5e0 |
foreach(IModifier modifier in modifiers)
|
|
|
b9e5e0 |
modifier.deactivate();
|
|
|
b9e5e0 |
}
|
|
|
b9e5e0 |
}
|
|
|
b9e5e0 |
|
|
|
b9e5e0 |
public bool isActive()
|
|
|
b9e5e0 |
{ return actualActive; }
|
|
|
b9e5e0 |
public void activate()
|
|
|
b9e5e0 |
{ wantActive = true; actualActivate(); }
|
|
|
b9e5e0 |
public void deactivate()
|
|
|
b9e5e0 |
{ wantActive = false; actualActivate(); }
|
|
|
ed66f8 |
public void processTracks()
|
|
|
ed66f8 |
{ if (isActive()) paintTracks(); }
|
|
|
b9e5e0 |
public void finishTracks()
|
|
|
ed66f8 |
{ if (isActive()) { touchTracks(true); processTracks(); } }
|
|
|
b9e5e0 |
|
|
|
b9e5e0 |
public List<track> getInputTracks()
|
|
|
b9e5e0 |
{ return tracks[0]; }
|
|
|
b9e5e0 |
public List<track> getOutputTracks()
|
|
|
b9e5e0 |
{ return tracks[modifiers.Count]; }
|
|
|
61bedf |
|
|
|
61bedf |
|
|
|
702257 |
public void trackEvent(Gdk.Device device, long touchId, Point position, double pressure, Point tilt, bool final, long ticks) {
|
|
|
b9e5e0 |
if (isActive()) {
|
|
|
589f9a |
Track track = getTrack(device, touchId, ticks);
|
|
|
589f9a |
if (!track.isFinished()) {
|
|
|
61bedf |
double time = (double)(ticks - track.keyHistory.ticks)*Timer.step - track.keyHistory.timeOffset;
|
|
|
702257 |
addTrackPoint(track, position, pressure, tilt, time, final);
|
|
|
61bedf |
}
|
|
|
61bedf |
}
|
|
|
61bedf |
}
|
|
|
61bedf |
|
|
|
61bedf |
public void keyEvent(bool press, Gdk.Key key, long ticks) {
|
|
|
61bedf |
state.keyEvent(press, key, ticks);
|
|
|
b9e5e0 |
if (isActive()) {
|
|
|
ed66f8 |
processTracks();
|
|
|
61bedf |
tool.keyEvent(press, key, state);
|
|
|
61bedf |
touchTracks();
|
|
|
ed66f8 |
processTracks();
|
|
|
61bedf |
}
|
|
|
61bedf |
}
|
|
|
61bedf |
|
|
|
61bedf |
public void buttonEvent(bool press, Gdk.Device device, uint button, long ticks) {
|
|
|
61bedf |
state.buttonEvent(press, device, button, ticks);
|
|
|
b9e5e0 |
if (isActive()) {
|
|
|
ed66f8 |
processTracks();
|
|
|
61bedf |
tool.buttonEvent(press, device, button, state);
|
|
|
61bedf |
touchTracks();
|
|
|
ed66f8 |
processTracks();
|
|
|
61bedf |
}
|
|
|
61bedf |
}
|
|
|
61bedf |
|
|
|
61bedf |
public Tool getTool()
|
|
|
61bedf |
{ return tool; }
|
|
|
61bedf |
|
|
|
61bedf |
public void setTool(Tool tool) {
|
|
|
0f2bf8 |
if (this.tool != tool) {
|
|
|
b9e5e0 |
if (actualActive) {
|
|
|
61bedf |
finishTracks();
|
|
|
61bedf |
this.tool.deactivate();
|
|
|
61bedf |
}
|
|
|
61bedf |
|
|
|
61bedf |
this.tool = tool;
|
|
|
61bedf |
|
|
|
b9e5e0 |
if (actualActive) {
|
|
|
b9e5e0 |
if (this.tool != null)
|
|
|
b9e5e0 |
this.tool.activate();
|
|
|
b9e5e0 |
else
|
|
|
b9e5e0 |
actualActivate();
|
|
|
b9e5e0 |
}
|
|
|
61bedf |
}
|
|
|
61bedf |
}
|
|
|
61bedf |
|
|
|
61bedf |
public int getModifiersCount()
|
|
|
61bedf |
{ return modifiers.Count; }
|
|
|
589f9a |
public IModifier getModifier(int index)
|
|
|
61bedf |
{ return modifiers[index]; }
|
|
|
61bedf |
|
|
|
589f9a |
public void insertModifier(int index, IModifier modifier) {
|
|
|
b9e5e0 |
if (actualActive)
|
|
|
b9e5e0 |
finishTracks();
|
|
|
61bedf |
modifiers.Insert(index, modifier);
|
|
|
b9e5e0 |
tracks.Insert(index+1, new List<track>());
|
|
|
b9e5e0 |
if (actualActive)
|
|
|
b9e5e0 |
modifier.activate();
|
|
|
61bedf |
}
|
|
|
589f9a |
public void addModifier(IModifier modifier)
|
|
|
61bedf |
{ insertModifier(getModifiersCount(), modifier); }
|
|
|
61bedf |
|
|
|
61bedf |
public void removeModifier(int index) {
|
|
|
b9e5e0 |
if (actualActive) {
|
|
|
b9e5e0 |
finishTracks();
|
|
|
b9e5e0 |
modifiers[index].deactivate();
|
|
|
b9e5e0 |
}
|
|
|
61bedf |
modifiers.RemoveAt(index);
|
|
|
b9e5e0 |
tracks.RemoveAt(index+1);
|
|
|
61bedf |
}
|
|
|
589f9a |
public void removeModifier(IModifier modifier) {
|
|
|
61bedf |
for(int i = 0; i < getModifiersCount(); ++i)
|
|
|
61bedf |
if (getModifier(i) == modifier)
|
|
|
61bedf |
{ removeModifier(i); break; }
|
|
|
61bedf |
}
|
|
|
61bedf |
public void clearModifiers() {
|
|
|
61bedf |
while(getModifiersCount() > 0)
|
|
|
b9e5e0 |
removeModifier(getModifiersCount() - 1);
|
|
|
61bedf |
}
|
|
|
61bedf |
|
|
|
61bedf |
|
|
|
0f2bf8 |
public void draw(Cairo.Context context, List<point> hovers) {</point>
|
|
|
0f2bf8 |
if (!isActive()) return;
|
|
|
0f2bf8 |
|
|
|
0f2bf8 |
// paint tool
|
|
|
0f2bf8 |
tool.draw(context);
|
|
|
0f2bf8 |
|
|
|
61bedf |
// paint not sent sub-tracks
|
|
|
b9e5e0 |
if (keyPointsSent < keyPoints.Count) {
|
|
|
61bedf |
context.Save();
|
|
|
61bedf |
penPreview.apply(context);
|
|
|
b9e5e0 |
foreach(Track track in getOutputTracks()) {
|
|
|
61bedf |
TrackHandler handler = (TrackHandler)track.handler;
|
|
|
0f2bf8 |
int start = handler.keys[keyPointsSent] - 1;
|
|
|
0f2bf8 |
if (start < 0) start = 0;
|
|
|
72d2fd |
if (start < track.count) {
|
|
|
720280 |
Drawing.Color color = penPreview.color;
|
|
|
720280 |
int level = keyPointsSent;
|
|
|
720280 |
|
|
|
720280 |
color.apply(context);
|
|
|
72d2fd |
context.MoveTo(track[start].position.x, track[start].position.y);
|
|
|
72d2fd |
for(int i = start + 1; i < track.count; ++i) {
|
|
|
720280 |
while(level < handler.keys.Count && handler.keys[level] <= i) {
|
|
|
720280 |
context.Stroke();
|
|
|
72d2fd |
context.MoveTo(track[i-1].position.x, track[i-1].position.y);
|
|
|
720280 |
color.a *= levelAlpha;
|
|
|
720280 |
color.apply(context);
|
|
|
720280 |
++level;
|
|
|
720280 |
}
|
|
|
72d2fd |
context.LineTo(track[i].position.x, track[i].position.y);
|
|
|
720280 |
}
|
|
|
61bedf |
}
|
|
|
61bedf |
}
|
|
|
61bedf |
context.Stroke();
|
|
|
61bedf |
context.Restore();
|
|
|
61bedf |
}
|
|
|
b9e5e0 |
|
|
|
b9e5e0 |
// paint modifiers
|
|
|
b9e5e0 |
for(int i = 0; i < modifiers.Count; ++i)
|
|
|
0f2bf8 |
modifiers[i].draw(context, tracks[i], hovers);
|
|
|
61bedf |
}
|
|
|
61bedf |
}
|
|
|
61bedf |
}
|
|
|
61bedf |
|