diff --git a/mono/Assistance/Assistance.csproj b/mono/Assistance/Assistance.csproj index c23bc66..b98c551 100644 --- a/mono/Assistance/Assistance.csproj +++ b/mono/Assistance/Assistance.csproj @@ -64,11 +64,7 @@ - - False - glib-sharp-2.0 - - + False gtk-sharp-2.0 @@ -76,10 +72,14 @@ False gtk-sharp-2.0 - - + + False + glib-sharp-2.0 + + False gtk-sharp-2.0 + \ No newline at end of file diff --git a/mono/Assistance/Drawing.cs b/mono/Assistance/Drawing.cs index fa3f972..5e9e171 100644 --- a/mono/Assistance/Drawing.cs +++ b/mono/Assistance/Drawing.cs @@ -4,13 +4,13 @@ namespace Assistance { namespace Drawing { public class Helper { public static Rectangle getBounds(Cairo.Context context) { - double w = 1.0; - double h = 1.0; - if (context.GetTarget() is Cairo.ImageSurface) { - Cairo.ImageSurface surface = (Cairo.ImageSurface)context.GetTarget(); - w = surface.Width; - h = surface.Height; - } + double w = 2000; + double h = 1500; + //if (context.GetTarget() is Cairo.ImageSurface) { + // Cairo.ImageSurface surface = (Cairo.ImageSurface)context.GetTarget(); + // w = surface.Width; + // h = surface.Height; + //} Point[] corners = new Point[] { new Point(0.0, 0.0), diff --git a/mono/Assistance/DynamicSurface.cs b/mono/Assistance/DynamicSurface.cs index 9655b9d..20fdbd8 100644 --- a/mono/Assistance/DynamicSurface.cs +++ b/mono/Assistance/DynamicSurface.cs @@ -8,6 +8,7 @@ namespace Assistance { private int offsetX; private int offsetY; private Cairo.ImageSurface surface; + private Cairo.Context privateContext; public DynamicSurface(double incrementScale = 1.2) { this.incrementScale = incrementScale; } @@ -24,21 +25,20 @@ namespace Assistance { public int height { get { return isEmpty ? 0 : surface.Height; } } + public Cairo.Context context + { get { return privateContext; } } + public Rectangle getBounds() { return isEmpty ? new Rectangle() : new Rectangle((double)offsetX, (double)offsetY, (double)(offsetX + surface.Width), (double)(offsetY + surface.Height)); } - public Cairo.Context getContext() { - if (isEmpty) return null; - Cairo.Context context = new Cairo.Context(surface); - context.Antialias = Cairo.Antialias.Gray; - context.Translate(-offsetX, -offsetY); - return context; - } + public void flush() + { if (surface != null) surface.Flush(); } public void draw(Cairo.Context context, double alpha = 1.0) { if (isEmpty) return; + flush(); context.Save(); context.Translate(offsetX, offsetY); context.SetSource(surface); @@ -49,15 +49,19 @@ namespace Assistance { public void clear() { if (isEmpty) return; + privateContext.Dispose(); + privateContext = null; surface.Dispose(); surface = null; - } + } - private bool doExpand(Rectangle rect, bool noScale) { + public bool expand(Rectangle rect, bool noScale = false) { + rect = new Rectangle(rect.p0).expand(rect.p1); + int rl = (int)Math.Floor(rect.x0 + Geometry.precision); int rt = (int)Math.Floor(rect.y0 + Geometry.precision); - int rr = Math.Max(rl, (int)Math.Ceiling(rect.x1 - Geometry.precision)); - int rb = Math.Max(rt, (int)Math.Ceiling(rect.y1 - Geometry.precision)); + int rr = Math.Max(rl, (int)Math.Ceiling(rect.x1 - Geometry.precision)) + 1; + int rb = Math.Max(rt, (int)Math.Ceiling(rect.y1 - Geometry.precision)) + 1; int l, t, r, b; if (surface == null) { @@ -81,46 +85,30 @@ namespace Assistance { int h = b - t; if (surface != null && l == offsetX && t == offsetY && w == surface.Width && h == surface.Height) return false; - + if (w <= 0 || h <= 0) + return false; + Cairo.ImageSurface newSurface = new Cairo.ImageSurface(Cairo.Format.ARGB32, w, h); - Cairo.Context context = new Cairo.Context(newSurface); - if (surface != null) { - context.Translate(offsetX - l, offsetY - t); - context.SetSource(surface); - context.Paint(); - context.GetTarget().Flush(); - context.Dispose(); + Cairo.Context newContext = new Cairo.Context(newSurface); + if (!isEmpty) { + flush(); + newContext.Save(); + newContext.Translate(offsetX - l, offsetY - t); + newContext.SetSource(surface); + newContext.Paint(); + newContext.Restore(); + clear(); } - offsetX = l; offsetY = t; surface = newSurface; + privateContext = newContext; + privateContext.Antialias = Cairo.Antialias.Gray; + privateContext.Translate(-offsetX, -offsetY); return true; } - public bool expand(Rectangle rect, bool noScale = false) { - Cairo.Surface surface = this.surface; - if (doExpand(rect, noScale)) { - if (surface != null) surface.Dispose(); - return true; - } - return false; - } - - public bool expandContext(ref Cairo.Context context, Rectangle rect, bool noScale = false) { - Cairo.Surface surface = this.surface; - if (context != null) context.GetTarget().Flush(); - if (doExpand(rect, noScale)) { - Cairo.Context oldContext = context; - context = getContext(); - if (oldContext != null) oldContext.Dispose(); - surface.Dispose(); - return true; - } - return false; - } - public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) diff --git a/mono/Assistance/Geometry.cs b/mono/Assistance/Geometry.cs index e2da322..ce67232 100644 --- a/mono/Assistance/Geometry.cs +++ b/mono/Assistance/Geometry.cs @@ -10,14 +10,14 @@ namespace Assistance { public static bool isEqual(double a, double b) { return Math.Abs(b - a) <= precision; } - public static bool isGreaterOrEqual(double a, double b) - { return b - a <= precision; } - public static bool isLessOrEqual(double a, double b) - { return isGreaterOrEqual(b, a); } public static bool isLess(double a, double b) - { return !isGreaterOrEqual(a, b); } + { return b - a > precision; } public static bool isGreater(double a, double b) - { return !isGreaterOrEqual(b, a); } + { return a - b > precision; } + public static bool isLessOrEqual(double a, double b) + { return a - b <= precision; } + public static bool isGreaterOrEqual(double a, double b) + { return b - a <= precision; } public static double logNormalDistribuitionUnscaled(double x, double x0, double w) { return Math.Exp(-0.5*Math.Pow(Math.Log(x/x0)/w, 2.0))/x; @@ -113,5 +113,21 @@ namespace Assistance { + t0*( 3.0*ll - 4.0*l + 1.0) + t1*( 3.0*ll - 2.0*l ); } + + public static Track.Point interpolationSpline(Track.Point p0, Track.Point p1, Track.Point t0, Track.Point t1, double l) { + double ll = l*l; + double lll = ll*l; + return p0*( 2.0*lll - 3.0*ll + 1.0) + + p1*(-2.0*lll + 3.0*ll ) + + t0*( lll - 2.0*ll + l ) + + t1*( lll - 1.0*ll ); + } + + public static Track.Point interpolationSplineTangent(Track.Point p0, Track.Point p1, Track.Point t0, Track.Point t1, double l) { + double ll = l*l; + return (p0 - p1)*6.0*(ll - l) + + t0*( 3.0*ll - 4.0*l + 1.0) + + t1*( 3.0*ll - 2.0*l ); + } } } diff --git a/mono/Assistance/Guideline.cs b/mono/Assistance/Guideline.cs index d224c70..b90545a 100644 --- a/mono/Assistance/Guideline.cs +++ b/mono/Assistance/Guideline.cs @@ -8,7 +8,7 @@ namespace Assistance { public static readonly Pen penActive = new Pen("Deep Sky Blue"); public static readonly double snapLenght = 20.0; public static readonly double snapScale = 1.0; - public static readonly double maxLenght = 2.0*snapLenght*snapScale; + public static readonly double maxLenght = 20.0*snapLenght*snapScale; public virtual Track.WayPoint transformPoint(Track.WayPoint point) { return point; } @@ -48,11 +48,11 @@ namespace Assistance { } public static Guideline findBest(List guidelines, Track track) { - double bestWeight = double.PositiveInfinity; + double bestWeight = 0.0; Guideline best = null; foreach(Guideline guideline in guidelines) { double weight = guideline.calcTrackWeight(track); - if (weight < bestWeight) { + if (best == null || weight < bestWeight) { bestWeight = weight; best = guideline; } diff --git a/mono/Assistance/InputManager.cs b/mono/Assistance/InputManager.cs index dff039c..1049d36 100644 --- a/mono/Assistance/InputManager.cs +++ b/mono/Assistance/InputManager.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; namespace Assistance { public class InputManager: Track.IOwner { - public static readonly Drawing.Pen penPreview = new Drawing.Pen("Dark Green", 1.0, 0.25); + public static readonly Drawing.Pen penPreview = new Drawing.Pen("Dark Green", 3.0, 0.25); public static readonly double levelAlpha = 0.8; public class TrackHandler: Track.Handler { @@ -55,7 +55,7 @@ namespace Assistance { public interface IModifier: Track.IOwner { void activate(); void modify(List tracks, KeyPoint keyPoint, List outTracks); - void draw(Cairo.Context context, List tracks); + void draw(Cairo.Context context, List tracks, List hovers); void deactivate(); } @@ -64,9 +64,12 @@ namespace Assistance { public virtual void modify(Track track, KeyPoint keyPoint, List outTracks) { } public virtual void modify(List tracks, KeyPoint keyPoint, List outTracks) { foreach(Track track in tracks) modify(track, keyPoint, outTracks); } - public virtual void draw(Cairo.Context context, Track tracks) { } - public virtual void draw(Cairo.Context context, List tracks) - { foreach(Track track in tracks) draw(context, track); } + public virtual void drawHover(Cairo.Context context, Point hover) { } + public virtual void drawTrack(Cairo.Context context, Track track) { } + public virtual void draw(Cairo.Context context, List tracks, List hovers) { + foreach(Track track in tracks) drawTrack(context, track); + foreach(Point hover in hovers) drawHover(context, hover); + } public virtual void deactivate() { } } @@ -91,7 +94,7 @@ namespace Assistance { private void paintRollbackTo(int keyIndex, List subTracks) { if (keyIndex >= keyPoints.Count) return; - + int level = keyIndex + 1; if (level <= keyPointsSent) { if (level < keyPointsSent) @@ -114,34 +117,33 @@ namespace Assistance { private void paintApply(int count, List subTracks) { if (count <= 0) return; - + int level = keyPoints.Count - count; + bool resend = true; if (level < keyPointsSent) { // apply int applied = tool.paintApply(keyPointsSent - level); applied = Math.Max(0, Math.Min(keyPointsSent - level, applied)); keyPointsSent -= applied; - foreach(Track track in subTracks) { - TrackHandler handler = (TrackHandler)track.handler; - handler.keys.RemoveRange(keyPointsSent, handler.keys.Count - keyPointsSent); - } + if (keyPointsSent == level) resend = false; } - + if (level < keyPointsSent) { // rollback tool.paintPop(keyPointsSent - level); keyPointsSent = level; - foreach(Track track in subTracks) { - TrackHandler handler = (TrackHandler)track.handler; - int cnt = handler.keys[keyPointsSent]; - handler.keys.RemoveRange(keyPointsSent, handler.keys.Count - keyPointsSent); - track.wayPointsRemoved = 0; - track.wayPointsAdded = track.points.Count - cnt; - } } // remove keypoints + foreach(Track track in subTracks) { + TrackHandler handler = (TrackHandler)track.handler; + if (resend) { + track.wayPointsRemoved = 0; + track.wayPointsAdded = track.points.Count - handler.keys[keyPointsSent]; + } + handler.keys.RemoveRange(level, handler.keys.Count - level); + } for(int i = level; i < keyPoints.Count; ++i) keyPoints[i].available = false; keyPoints.RemoveRange(level, keyPoints.Count - level); } @@ -171,7 +173,7 @@ namespace Assistance { int rollbackIndex = keyPoints.Count; foreach(Track track in subTracks) { if (track.wayPointsRemoved > 0) { - int count = track.points.Count - track.wayPointsAdded + track.wayPointsRemoved; + int count = track.points.Count - track.wayPointsAdded; TrackHandler handler = (TrackHandler)track.handler; while(rollbackIndex > 0 && (rollbackIndex >= keyPoints.Count || handler.keys[rollbackIndex] > count)) --rollbackIndex; @@ -189,6 +191,10 @@ namespace Assistance { // send to tool if (keyPointsSent == keyPoints.Count && subTracks.Count > 0) tool.paintTracks(subTracks); + foreach(Track track in subTracks) { + track.wayPointsRemoved = 0; + track.wayPointsAdded = 0; + } // is paint finished? if (newKeyPoint.isFree) { @@ -206,11 +212,15 @@ namespace Assistance { foreach(Track track in subTracks) ((TrackHandler)track.handler).keys.Add(track.points.Count); } + } - + + private long getDeviceId(Gdk.Device device) + { return device == null ? 0 : device.Handle.ToInt64(); } + private int trackCompare(Track track, Gdk.Device device, long touchId) { - if (track.device.Handle.ToInt64() < device.Handle.ToInt64()) return -1; - if (track.device.Handle.ToInt64() > device.Handle.ToInt64()) return 1; + if (getDeviceId(track.device) < getDeviceId(device)) return -1; + if (getDeviceId(track.device) > getDeviceId(device)) return 1; if (track.touchId < touchId) return -1; if (track.touchId > touchId) return 1; return 0; @@ -227,6 +237,8 @@ namespace Assistance { } private Track getTrack(Gdk.Device device, long touchId, long ticks) { + if (tracks[0].Count == 0) + return createTrack(0, device, touchId, ticks); int cmp; int a = 0; @@ -234,7 +246,7 @@ namespace Assistance { if (cmp == 0) return tracks[0][a]; if (cmp < 0) return createTrack(a, device, touchId, ticks); - int b = tracks.Count - 1; + int b = tracks[0].Count - 1; cmp = trackCompare(tracks[0][b], device, touchId); if (cmp == 0) return tracks[0][b]; if (cmp > 0) return createTrack(b+1, device, touchId, ticks); @@ -343,7 +355,7 @@ namespace Assistance { { return tool; } public void setTool(Tool tool) { - if (this.tool == tool) { + if (this.tool != tool) { if (actualActive) { finishTracks(); this.tool.deactivate(); @@ -395,14 +407,20 @@ namespace Assistance { } - public void draw(Cairo.Context context) { + public void draw(Cairo.Context context, List hovers) { + if (!isActive()) return; + + // paint tool + tool.draw(context); + // paint not sent sub-tracks if (keyPointsSent < keyPoints.Count) { context.Save(); penPreview.apply(context); foreach(Track track in getOutputTracks()) { TrackHandler handler = (TrackHandler)track.handler; - int start = handler.keys[keyPointsSent]; + int start = handler.keys[keyPointsSent] - 1; + if (start < 0) start = 0; if (start < track.points.Count) { Drawing.Color color = penPreview.color; int level = keyPointsSent; @@ -427,7 +445,7 @@ namespace Assistance { // paint modifiers for(int i = 0; i < modifiers.Count; ++i) - modifiers[i].draw(context, tracks[i]); + modifiers[i].draw(context, tracks[i], hovers); } } } diff --git a/mono/Assistance/InputModifierAssistants.cs b/mono/Assistance/InputModifierAssistants.cs index 43a7841..915af47 100644 --- a/mono/Assistance/InputModifierAssistants.cs +++ b/mono/Assistance/InputModifierAssistants.cs @@ -6,7 +6,8 @@ namespace Assistance { public class InputModifierAssistants: InputModifierTangents { public readonly Workarea workarea; public readonly bool defaultTangents; - + public readonly List shownGuidelines = new List(); + public InputModifierAssistants(Workarea workarea, bool defaultTangents = false) { this.workarea = workarea; this.defaultTangents = defaultTangents; @@ -18,7 +19,6 @@ namespace Assistance { public InputManager.KeyPoint.Holder holder = null; public List guidelines = new List(); - public List hintGuidelines = new List(); public override Track.WayPoint calcWayPoint(double originalIndex) { Track.WayPoint p = original.calcWayPoint(originalIndex); @@ -35,7 +35,7 @@ namespace Assistance { return; Track.Handler handler = new Track.Handler(this, track); - modifier = new Modifier(track.handler); + modifier = new Modifier(handler); workarea.getGuidelines(modifier.guidelines, track.points[0].point.position); if (defaultTangents && modifier.guidelines.Count == 0) { base.modify(track, keyPoint, outTracks); return; } @@ -65,18 +65,18 @@ namespace Assistance { int start = track.points.Count - track.wayPointsAdded; if (start < 0) start = 0; if (subTrack.points.Count < start) { - subTrack.points.RemoveRange(start, subTrack.points.Count - start); subTrack.wayPointsRemoved += subTrack.points.Count - start; + subTrack.points.RemoveRange(start, subTrack.points.Count - start); } - bool trackIsLong = track.points.Count > 0 && track.getLast().length >= Guideline.maxLenght; + bool trackIsLong = track.points.Count > 0 && (track.getLast().length >= Guideline.maxLenght || track.isFinished()); if (!trackIsLong && modifier.holder != null && !modifier.holder.isHolded && modifier.holder.available) modifier.holder.reuse(); // select guideline if (modifier.holder != null && modifier.holder.isHolded) { Guideline guideline = Guideline.findBest(modifier.guidelines, track); - if (guideline != modifier.guidelines[0]) { + if (guideline != null && guideline != modifier.guidelines[0]) { modifier.guidelines[ modifier.guidelines.IndexOf(guideline) ] = modifier.guidelines[0]; modifier.guidelines[0] = guideline; start = 0; @@ -91,20 +91,23 @@ namespace Assistance { for(int i = start; i < track.points.Count; ++i) subTrack.points.Add(modifier.calcWayPoint(i)); subTrack.wayPointsAdded = subTrack.points.Count - start; + + track.wayPointsRemoved = 0; + track.wayPointsAdded = 0; } - - public override void draw(Cairo.Context context, Track track) { + + public override void drawHover(Cairo.Context context, Point hover) { + workarea.getGuidelines(shownGuidelines, hover); + foreach(Guideline guideline in shownGuidelines) + guideline.draw(context); + shownGuidelines.Clear(); + } + + public override void drawTrack(Cairo.Context context, Track track) { if (track.handler == null) return; Track subTrack = track.handler.tracks[0]; - if (!(subTrack.modifier is Modifier)) - { base.draw(context, track); return; } - Modifier modifier = (Modifier)subTrack.modifier; - if (modifier.guidelines.Count > 0 && subTrack.points.Count > 0) { - workarea.getGuidelines(modifier.hintGuidelines, subTrack.points[0].point.position); - foreach(Guideline gl in modifier.hintGuidelines) - gl.draw(context); - modifier.hintGuidelines.Clear(); - } + if (subTrack.points.Count > 0) + drawHover(context, subTrack.getLast().point.position); } } } diff --git a/mono/Assistance/InputModifierInterpolation.cs b/mono/Assistance/InputModifierInterpolation.cs index bcd4b60..4d896a0 100644 --- a/mono/Assistance/InputModifierInterpolation.cs +++ b/mono/Assistance/InputModifierInterpolation.cs @@ -3,6 +3,8 @@ using System.Collections.Generic; namespace Assistance { public class InputModifierInterpolation: InputManager.Modifier { + public static readonly int maxRecursion = 8; + public readonly double precision; public readonly double precisionSqr; @@ -11,12 +13,12 @@ namespace Assistance { this.precisionSqr = this.precision*this.precision; } - public void addSegment(Track track, Track.WayPoint p0, Track.WayPoint p1) { - if ((p1.point.position - p0.point.position).lenSqr() <= precisionSqr) + public void addSegment(Track track, Track.WayPoint p0, Track.WayPoint p1, int level = 0) { + if (level >= maxRecursion || (p1.point.position - p0.point.position).lenSqr() <= precisionSqr) { track.points.Add(p1); return; } Track.WayPoint p = track.modifier.calcWayPoint(0.5*(p0.originalIndex + p1.originalIndex)); - addSegment(track, p0, p); - addSegment(track, p, p1); + addSegment(track, p0, p, level + 1); + addSegment(track, p, p1, level + 1); } public override void modify(Track track, InputManager.KeyPoint keyPoint, List outTracks) { @@ -35,9 +37,11 @@ namespace Assistance { int start = track.points.Count - track.wayPointsAdded; if (start < 0) start = 0; int subStart = subTrack.floorIndex(subTrack.indexByOriginalIndex(start)); - if (subTrack.points.Count < subStart) { - subTrack.points.RemoveRange(subStart, subTrack.points.Count - subStart); + if (subStart < 0) subStart = 0; + + if (subStart < subTrack.points.Count) { subTrack.wayPointsRemoved += subTrack.points.Count - subStart; + subTrack.points.RemoveRange(subStart, subTrack.points.Count - subStart); } // add points @@ -48,6 +52,9 @@ namespace Assistance { p0 = p1; } subTrack.wayPointsAdded += subTrack.points.Count - subStart; + + track.wayPointsRemoved = 0; + track.wayPointsAdded = 0; } } } diff --git a/mono/Assistance/InputModifierTangents.cs b/mono/Assistance/InputModifierTangents.cs index 360448f..6725912 100644 --- a/mono/Assistance/InputModifierTangents.cs +++ b/mono/Assistance/InputModifierTangents.cs @@ -49,11 +49,11 @@ namespace Assistance { int start = track.points.Count - track.wayPointsAdded; if (start < 0) start = 0; if (start > 1) --start; - if (subTrack.points.Count < start) { - subTrack.points.RemoveRange(start, subTrack.points.Count - start); + if (start < subTrack.points.Count) { subTrack.wayPointsRemoved += subTrack.points.Count - start; + subTrack.points.RemoveRange(start, subTrack.points.Count - start); } - if (modifier.tangents.Count < start) + if (start < modifier.tangents.Count) modifier.tangents.RemoveRange(start, modifier.tangents.Count - start); // add first point diff --git a/mono/Assistance/KeyHistory.cs b/mono/Assistance/KeyHistory.cs index ef5a0b3..5dae8fd 100644 --- a/mono/Assistance/KeyHistory.cs +++ b/mono/Assistance/KeyHistory.cs @@ -63,8 +63,9 @@ namespace Assistance { private int findLock(long ticks) { // locks[a] <= ticks < locks[b] + if (locks.Count == 0) return -1; int a = 0; - int b = states.Count - 1; + int b = locks.Count - 1; if (locks[a] < ticks) return -1; if (ticks >= locks[b]) return b; while(true) { diff --git a/mono/Assistance/MainWindow.cs b/mono/Assistance/MainWindow.cs index 8a3d7ea..7e38d8a 100644 --- a/mono/Assistance/MainWindow.cs +++ b/mono/Assistance/MainWindow.cs @@ -10,9 +10,7 @@ namespace Assistance { win.Maximize(); Gtk.Application.Run(); } - - Cairo.ImageSurface surface = new Cairo.ImageSurface(Cairo.Format.ARGB32, 1, 1); - + Workarea workarea = new Workarea(); ToolFull toolFull; @@ -22,6 +20,7 @@ namespace Assistance { Point offset; Point cursor; + List hovers = new List(); long touchId; long ticksStart = 0; @@ -47,48 +46,41 @@ namespace Assistance { workarea.setTool(toolFull); } + private bool refreshOnIdle() + { QueueDraw(); return false; } + private void Refresh() + { GLib.Idle.Add(refreshOnIdle); } + protected override bool OnDeleteEvent(Gdk.Event e) { Gtk.Application.Quit(); - return true; - } - - protected override void OnSizeAllocated(Gdk.Rectangle allocation) { - if ( surface.Width != allocation.Width - || surface.Height != allocation.Height ) - { - surface.Dispose(); - surface = new Cairo.ImageSurface(Cairo.Format.ARGB32, allocation.Width, allocation.Height); - } - base.OnSizeAllocated(allocation); + return false; } protected override bool OnExposeEvent(Gdk.EventExpose e) { - Cairo.Context context = new Cairo.Context(surface); - context.Antialias = Cairo.Antialias.Gray; - + Cairo.Context context = Gdk.CairoHelper.Create(e.Window); + context.Save(); context.SetSourceRGBA(1.0, 1.0, 1.0, 1.0); - context.Rectangle(0, 0, surface.Width, surface.Height); + context.Rectangle(0, 0, Allocation.Width, Allocation.Height); context.Fill(); context.Restore(); - + + context.Save(); + context.Antialias = Cairo.Antialias.Gray; draw(context); - context.Dispose(); + context.Restore(); - context = Gdk.CairoHelper.Create(GdkWindow); - context.SetSource(surface); - context.Paint(); context.Dispose(); - - return true; + + return false; } public Point windowToWorkarea(Point p) { - return new Point(p.x - surface.Width/2.0, p.y - surface.Height/2.0); + return new Point(p.x - Allocation.Width/2.0, p.y - Allocation.Height/2.0); } public Point workareaToWindow(Point p) { - return new Point(p.x + surface.Width/2.0, p.y + surface.Height/2.0); + return new Point(p.x + Allocation.Width/2.0, p.y + Allocation.Height/2.0); } private void beginDrag() { @@ -103,6 +95,7 @@ namespace Assistance { ++touchId; ticksStart = Timer.ticks(); this.timeStart = timeStart; + painting = true; } private void endDragAndTrack() { @@ -140,7 +133,7 @@ namespace Assistance { workarea.inputManager.keyEvent(true, e.Key, Timer.ticks()); break; } - QueueDraw(); + Refresh(); return base.OnKeyPressEvent(e); } @@ -159,13 +152,12 @@ namespace Assistance { point.tilt = tilt; long ticks = ticksStart + (long)Math.Round((time - timeStart)*Timer.frequency); - workarea.inputManager.trackEvent(device, touchId, point, final, ticks); } void addTrackPoint(double x, double y, uint t, Gdk.Device device, double[] axes, bool final) { Point point = windowToWorkarea(new Point(x, y)); - double time = (double)(t - timeStart)*0.001; + double time = (double)t*0.001; double pressure = 0.5; Point tilt = new Point(0.0, 0.0); if (device != null && axes != null) { @@ -189,7 +181,6 @@ namespace Assistance { cursor = windowToWorkarea(new Point(e.X, e.Y)); workarea.inputManager.buttonEvent(true, e.Device, e.Button, Timer.ticks()); if (e.Button == 1) { - timeStart = e.Time; activePoint = workarea.findPoint(cursor); if (activePoint != null) { beginDrag(); @@ -198,8 +189,8 @@ namespace Assistance { addTrackPoint(e, true); } } - QueueDraw(); - return true; + Refresh(); + return false; } protected override bool OnButtonReleaseEvent(Gdk.EventButton e) { @@ -212,8 +203,8 @@ namespace Assistance { if (!dragging && !painting) activePoint = workarea.findPoint(cursor); } - QueueDraw(); - return true; + Refresh(); + return false; } protected override bool OnMotionNotifyEvent(Gdk.EventMotion e) { @@ -226,13 +217,15 @@ namespace Assistance { } else { activePoint = workarea.findPoint(cursor); } - QueueDraw(); - return true; + Refresh(); + return false; } public void draw(Cairo.Context context) { - context.Translate(surface.Width/2, surface.Height/2); - workarea.draw(context, activePoint); + context.Translate(Allocation.Width/2, Allocation.Height/2); + hovers.Clear(); + if (!painting) hovers.Add(cursor); + workarea.draw(context, hovers, activePoint); } } } diff --git a/mono/Assistance/Modifier.cs b/mono/Assistance/Modifier.cs index 9bc55d0..7452399 100644 --- a/mono/Assistance/Modifier.cs +++ b/mono/Assistance/Modifier.cs @@ -8,11 +8,13 @@ namespace Assistance { public Modifier(Document document): base(document) { document.modifiers.Add(this); + document.workarea.updateModifiers(); } public override void remove() { base.remove(); document.modifiers.Remove(this); + document.workarea.updateModifiers(); } public override void bringToFront() { @@ -24,9 +26,12 @@ namespace Assistance { public virtual void modify(Track track, InputManager.KeyPoint keyPoint, List outTracks) { } public virtual void modify(List tracks, InputManager.KeyPoint keyPoint, List outTracks) { foreach(Track track in tracks) modify(track, keyPoint, outTracks); } - public virtual void draw(Cairo.Context context, Track track) { } - public virtual void draw(Cairo.Context context, List tracks) - { foreach(Track track in tracks) draw(context, track); } + public virtual void drawHover(Cairo.Context context, Point hover) { } + public virtual void drawTrack(Cairo.Context context, Track track) { } + public virtual void draw(Cairo.Context context, List tracks, List hovers) { + foreach(Track track in tracks) drawTrack(context, track); + foreach(Point hover in hovers) drawHover(context, hover); + } public virtual void deactivate() { } public virtual void draw(Cairo.Context context) { } diff --git a/mono/Assistance/ModifierSnowflake.cs b/mono/Assistance/ModifierSnowflake.cs index d174366..ea9b338 100644 --- a/mono/Assistance/ModifierSnowflake.cs +++ b/mono/Assistance/ModifierSnowflake.cs @@ -71,16 +71,19 @@ namespace Assistance { if (start < 0) start = 0; foreach(Track subTrack in track.handler.tracks) { // remove points - if (subTrack.points.Count < start) { - subTrack.points.RemoveRange(start, subTrack.points.Count - start); + if (start < subTrack.points.Count) { subTrack.wayPointsRemoved += subTrack.points.Count - start; + subTrack.points.RemoveRange(start, subTrack.points.Count - start); } // add points for(int i = start; i < track.points.Count; ++i) - subTrack.points.Add( subTrack.calcWayPoint(i) ); + subTrack.points.Add( subTrack.modifier.calcWayPoint(i) ); subTrack.wayPointsAdded += subTrack.points.Count - start; } + + track.wayPointsRemoved = 0; + track.wayPointsAdded = 0; } } } diff --git a/mono/Assistance/ToolFull.cs b/mono/Assistance/ToolFull.cs index d9ea6b1..d1872c7 100644 --- a/mono/Assistance/ToolFull.cs +++ b/mono/Assistance/ToolFull.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; namespace Assistance { public class ToolFull: Tool { - public static readonly Drawing.Pen pen = new Drawing.Pen("Dark Green", 10.0); + public static readonly Drawing.Pen pen = new Drawing.Pen("Dark Green", 3.0); public static readonly double levelAlpha = 0.8; @@ -25,32 +25,36 @@ namespace Assistance { return true; } - private void paintPoint(DynamicSurface surface, Cairo.Context context, Track.WayPoint point) { + private void paintPoint(DynamicSurface surface, Track.WayPoint point) { Point p = point.point.position; double r = pen.width*point.point.pressure; + Drawing.Color color = pen.color; + if (r < 0.01) r = 0.01; + if (r > Geometry.precision && r < 0.5) + { color.a *= r/0.5; r = 0.5; } double rr = r + 1.0; - surface.expandContext(ref context, new Rectangle(p.x - rr, p.y - rr, p.x + rr, p.y + rr)); + surface.expand(new Rectangle(p.x - rr, p.y - rr, p.x + rr, p.y + rr)); - context.Save(); - pen.apply(context); - context.Arc(p.x, p.y, r, 0.0, 2.0*Math.PI); - context.Fill(); - context.Restore(); + surface.context.Save(); + pen.apply(surface.context); + color.apply(surface.context); + surface.context.Arc(p.x, p.y, r, 0.0, 2.0*Math.PI); + surface.context.Fill(); + surface.context.Restore(); } public override void paintTracks(List tracks) { DynamicSurface surface = getSurface(); - Cairo.Context context = surface.getContext(); while(true) { Track track = null; - long minTicks = long.MaxValue; + long minTicks = 0; double minTimeOffset = 0.0; foreach(Track t in tracks) { if (t.wayPointsAdded > 0) { long ticks = t.ticks; double timeOffset = t.timeOffset + t.points[t.points.Count - t.wayPointsAdded].time; - if ((ticks - minTicks)*Timer.frequency + timeOffset - minTimeOffset < 0.0) { + if (track == null || (ticks - minTicks)*Timer.frequency + timeOffset - minTimeOffset < 0.0) { track = t; minTicks = ticks; minTimeOffset = timeOffset; @@ -58,23 +62,18 @@ namespace Assistance { } } if (track == null) break; - paintPoint(surface, context, track.points[track.points.Count - track.wayPointsAdded]); + paintPoint(surface, track.points[track.points.Count - track.wayPointsAdded]); --track.wayPointsAdded; } - context.GetTarget().Flush(); - context.Dispose(); } public override int paintApply(int count) { int level = stack.Count - count; DynamicSurface surface = getSurface(level); - Cairo.Context context = surface.getContext(); for(int i = level; i < stack.Count; ++i) { - surface.expandContext(ref context, stack[i].getBounds(), true); - stack[i].draw(context); + surface.expand(stack[i].getBounds(), true); + stack[i].draw(surface.context); } - context.GetTarget().Flush(); - context.Dispose(); paintPop(count); return count; } diff --git a/mono/Assistance/Track.cs b/mono/Assistance/Track.cs index 93f0b3d..feaf1a8 100644 --- a/mono/Assistance/Track.cs +++ b/mono/Assistance/Track.cs @@ -154,7 +154,7 @@ namespace Assistance { public WayPoint getLast() { return getWayPoint(points.Count - 1); } public bool isFinished() - { return getLast().final; } + { return points.Count > 0 && getLast().final; } public int clampIndex(int index) { return Math.Min(Math.Max(index, 0), points.Count - 1); } @@ -181,7 +181,7 @@ namespace Assistance { public WayPoint floorWayPoint(double index) { return getWayPoint(floorIndex(index)); } public WayPoint ceilWayPoint(double index) - { return getWayPoint(floorIndex(index)); } + { return getWayPoint(ceilIndex(index)); } private delegate double WayPointFieldGetter(WayPoint p); private double binarySearch(double value, WayPointFieldGetter getter) { @@ -190,7 +190,7 @@ namespace Assistance { if (points.Count <= 0) return 0.0; int a = 0; double aa = getter(points[a]); - if (Geometry.isLess(aa, value)) return 0.0; + if (Geometry.isLess(value, aa)) return 0.0; int b = points.Count - 1; double bb = getter(points[b]); @@ -247,8 +247,8 @@ namespace Assistance { if (l <= Geometry.precision) return p0; if (l >= 1.0 - Geometry.precision) return p1; return new WayPoint( - Geometry.Interpolation.spline(p0.point, p1.point, p0.tangent, p1.tangent, l), - Geometry.Interpolation.splineTangent(p0.point, p1.point, p0.tangent, p1.tangent, l), + Geometry.interpolationSpline(p0.point, p1.point, p0.tangent, p1.tangent, l), + Geometry.interpolationSplineTangent(p0.point, p1.point, p0.tangent, p1.tangent, l), Geometry.interpolationLinear(p0.originalIndex, p1.originalIndex, l), Geometry.interpolationLinear(p0.time, p1.time, l), Geometry.interpolationLinear(p0.length, p1.length, l), diff --git a/mono/Assistance/Workarea.cs b/mono/Assistance/Workarea.cs index 4850dff..9fbd20b 100644 --- a/mono/Assistance/Workarea.cs +++ b/mono/Assistance/Workarea.cs @@ -47,6 +47,9 @@ namespace Assistance { inputManager.activate(); } } + + public void updateModifiers() + { setTool(getTool(), true); } public ActivePoint findPoint(Point position) { foreach(ActivePoint point in document.points.Reverse()) @@ -60,12 +63,12 @@ namespace Assistance { assistant.getGuidelines(outGuidelines, target); } - public void draw(Cairo.Context context, ActivePoint activePoint) { + public void draw(Cairo.Context context, List hovers, ActivePoint activePoint) { // canvas document.canvas.draw(context); // input manager - inputManager.draw(context); + inputManager.draw(context, hovers); // modifiers foreach(Modifier modifier in document.modifiers)