|
|
b9e5e0 |
using System;
|
|
|
b9e5e0 |
using System.Collections.Generic;
|
|
|
b9e5e0 |
|
|
|
b9e5e0 |
namespace Assistance {
|
|
|
b9e5e0 |
public class DynamicSurface: IDisposable {
|
|
|
b9e5e0 |
private readonly double incrementScale;
|
|
|
b9e5e0 |
|
|
|
b9e5e0 |
private int offsetX;
|
|
|
b9e5e0 |
private int offsetY;
|
|
|
b9e5e0 |
private Cairo.ImageSurface surface;
|
|
|
0f2bf8 |
private Cairo.Context privateContext;
|
|
|
b9e5e0 |
|
|
|
b9e5e0 |
public DynamicSurface(double incrementScale = 1.2)
|
|
|
b9e5e0 |
{ this.incrementScale = incrementScale; }
|
|
|
b9e5e0 |
|
|
|
b9e5e0 |
public bool isEmpty
|
|
|
b9e5e0 |
{ get { return surface == null; } }
|
|
|
b9e5e0 |
|
|
|
b9e5e0 |
public int left
|
|
|
b9e5e0 |
{ get { return isEmpty ? 0 : offsetX; } }
|
|
|
b9e5e0 |
public int top
|
|
|
b9e5e0 |
{ get { return isEmpty ? 0 : offsetY; } }
|
|
|
b9e5e0 |
public int width
|
|
|
b9e5e0 |
{ get { return isEmpty ? 0 : surface.Width; } }
|
|
|
b9e5e0 |
public int height
|
|
|
b9e5e0 |
{ get { return isEmpty ? 0 : surface.Height; } }
|
|
|
b9e5e0 |
|
|
|
0f2bf8 |
public Cairo.Context context
|
|
|
0f2bf8 |
{ get { return privateContext; } }
|
|
|
0f2bf8 |
|
|
|
b9e5e0 |
public Rectangle getBounds() {
|
|
|
b9e5e0 |
return isEmpty ? new Rectangle()
|
|
|
b9e5e0 |
: new Rectangle((double)offsetX, (double)offsetY, (double)(offsetX + surface.Width), (double)(offsetY + surface.Height));
|
|
|
b9e5e0 |
}
|
|
|
b9e5e0 |
|
|
|
0f2bf8 |
public void flush()
|
|
|
0f2bf8 |
{ if (surface != null) surface.Flush(); }
|
|
|
b9e5e0 |
|
|
|
b9e5e0 |
public void draw(Cairo.Context context, double alpha = 1.0) {
|
|
|
b9e5e0 |
if (isEmpty) return;
|
|
|
0f2bf8 |
flush();
|
|
|
b9e5e0 |
context.Save();
|
|
|
b9e5e0 |
context.Translate(offsetX, offsetY);
|
|
|
b9e5e0 |
context.SetSource(surface);
|
|
|
b9e5e0 |
if (alpha >= 1.0 - Geometry.precision)
|
|
|
b9e5e0 |
context.Paint(); else context.PaintWithAlpha(alpha);
|
|
|
b9e5e0 |
context.Restore();
|
|
|
b9e5e0 |
}
|
|
|
b9e5e0 |
|
|
|
b9e5e0 |
public void clear() {
|
|
|
b9e5e0 |
if (isEmpty) return;
|
|
|
0f2bf8 |
privateContext.Dispose();
|
|
|
0f2bf8 |
privateContext = null;
|
|
|
b9e5e0 |
surface.Dispose();
|
|
|
b9e5e0 |
surface = null;
|
|
|
0f2bf8 |
}
|
|
|
b9e5e0 |
|
|
|
0f2bf8 |
public bool expand(Rectangle rect, bool noScale = false) {
|
|
|
0f2bf8 |
rect = new Rectangle(rect.p0).expand(rect.p1);
|
|
|
0f2bf8 |
|
|
|
b9e5e0 |
int rl = (int)Math.Floor(rect.x0 + Geometry.precision);
|
|
|
b9e5e0 |
int rt = (int)Math.Floor(rect.y0 + Geometry.precision);
|
|
|
0f2bf8 |
int rr = Math.Max(rl, (int)Math.Ceiling(rect.x1 - Geometry.precision)) + 1;
|
|
|
0f2bf8 |
int rb = Math.Max(rt, (int)Math.Ceiling(rect.y1 - Geometry.precision)) + 1;
|
|
|
b9e5e0 |
|
|
|
b9e5e0 |
int l, t, r, b;
|
|
|
b9e5e0 |
if (surface == null) {
|
|
|
b9e5e0 |
l = rl; t = rt; r = rr; b = rb;
|
|
|
b9e5e0 |
} else {
|
|
|
b9e5e0 |
l = offsetX;
|
|
|
b9e5e0 |
t = offsetY;
|
|
|
b9e5e0 |
r = l + surface.Width;
|
|
|
b9e5e0 |
b = t + surface.Height;
|
|
|
b9e5e0 |
}
|
|
|
b9e5e0 |
|
|
|
b9e5e0 |
int incX = noScale ? 0 : Math.Max(0, (int)Math.Ceiling( (incrementScale - 1.0)*(Math.Max(r, rr) - Math.Min(l, rl)) ));
|
|
|
b9e5e0 |
int incY = noScale ? 0 : Math.Max(0, (int)Math.Ceiling( (incrementScale - 1.0)*(Math.Max(b, rb) - Math.Min(t, rt)) ));
|
|
|
b9e5e0 |
|
|
|
b9e5e0 |
if (rl < l) l = rl - incX;
|
|
|
b9e5e0 |
if (rt < t) t = rt - incY;
|
|
|
b9e5e0 |
if (rr > r) r = rr + incX;
|
|
|
b9e5e0 |
if (rb > b) b = rb + incY;
|
|
|
b9e5e0 |
|
|
|
b9e5e0 |
int w = r - l;
|
|
|
b9e5e0 |
int h = b - t;
|
|
|
b9e5e0 |
if (surface != null && l == offsetX && t == offsetY && w == surface.Width && h == surface.Height)
|
|
|
b9e5e0 |
return false;
|
|
|
0f2bf8 |
if (w <= 0 || h <= 0)
|
|
|
0f2bf8 |
return false;
|
|
|
0f2bf8 |
|
|
|
b9e5e0 |
Cairo.ImageSurface newSurface = new Cairo.ImageSurface(Cairo.Format.ARGB32, w, h);
|
|
|
0f2bf8 |
Cairo.Context newContext = new Cairo.Context(newSurface);
|
|
|
0f2bf8 |
if (!isEmpty) {
|
|
|
0f2bf8 |
flush();
|
|
|
0f2bf8 |
newContext.Save();
|
|
|
0f2bf8 |
newContext.Translate(offsetX - l, offsetY - t);
|
|
|
0f2bf8 |
newContext.SetSource(surface);
|
|
|
0f2bf8 |
newContext.Paint();
|
|
|
0f2bf8 |
newContext.Restore();
|
|
|
0f2bf8 |
clear();
|
|
|
b9e5e0 |
}
|
|
|
b9e5e0 |
offsetX = l;
|
|
|
b9e5e0 |
offsetY = t;
|
|
|
b9e5e0 |
surface = newSurface;
|
|
|
0f2bf8 |
privateContext = newContext;
|
|
|
0f2bf8 |
privateContext.Antialias = Cairo.Antialias.Gray;
|
|
|
0f2bf8 |
privateContext.Translate(-offsetX, -offsetY);
|
|
|
b9e5e0 |
|
|
|
b9e5e0 |
return true;
|
|
|
b9e5e0 |
}
|
|
|
b9e5e0 |
|
|
|
b9e5e0 |
public void Dispose()
|
|
|
b9e5e0 |
{ Dispose(true); GC.SuppressFinalize(this); }
|
|
|
b9e5e0 |
protected virtual void Dispose(bool disposing)
|
|
|
b9e5e0 |
{ clear(); }
|
|
|
b9e5e0 |
~DynamicSurface()
|
|
|
b9e5e0 |
{ Dispose(false); }
|
|
|
b9e5e0 |
}
|
|
|
b9e5e0 |
}
|
|
|
b9e5e0 |
|