Blame mono/Assistance/DynamicSurface.cs

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