WorkflowLayouts.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / cdf / src / WF / Common / AuthoringOM / Design / WorkflowLayouts.cs / 1305376 / WorkflowLayouts.cs

                            namespace System.Workflow.ComponentModel.Design 
{
 	using System;
	using System.Drawing;
	using System.Diagnostics; 
	using System.Collections;
 	using System.Windows.Forms; 
	using System.Drawing.Imaging; 
 	using System.Drawing.Printing;
 	using System.Drawing.Drawing2D; 
	using System.ComponentModel.Design;

 	#region Class WorkflowLayout
	//All the coordinates and sizes are in logical coordinate system 
	internal abstract class WorkflowLayout : IDisposable
	{ 
 		#region Members and Constructor/Destruction 
		public enum LayoutUpdateReason { LayoutChanged, ZoomChanged }
 		protected IServiceProvider			serviceProvider; 
 		protected WorkflowView				parentView;

		public WorkflowLayout(IServiceProvider serviceProvider)
 		{ 
			Debug.Assert(serviceProvider != null);
			if (serviceProvider == null) 
				throw new ArgumentNullException("serviceProvider"); 

 			this.serviceProvider = serviceProvider; 

			this.parentView = this.serviceProvider.GetService(typeof(WorkflowView)) as WorkflowView;
 			Debug.Assert(this.parentView != null);
 			if (this.parentView == null) 
				throw new InvalidOperationException(SR.GetString(SR.General_MissingService, typeof(WorkflowView).FullName));
 		} 
 
		public virtual void Dispose()
		{ 
		}
 		#endregion

		#region Public Interface 
 		public abstract float Scaling { get; }
 		public abstract Size Extent { get; } 
		public abstract Point RootDesignerAlignment { get; } 

 		public abstract bool IsCoOrdInLayout(Point logicalCoOrd); 
		public abstract Rectangle MapInRectangleToLayout(Rectangle logicalRectangle);
		public abstract Rectangle MapOutRectangleFromLayout(Rectangle logicalRectangle);
		public abstract Point MapInCoOrdToLayout(Point logicalPoint);
 		public abstract Point MapOutCoOrdFromLayout(Point logicalPoint); 

		public abstract void OnPaint(PaintEventArgs e, ViewPortData viewPortData); 
 		public abstract void OnPaintWorkflow(PaintEventArgs e, ViewPortData viewPortData); 
 		public abstract void Update(Graphics graphics, LayoutUpdateReason reason);
		#endregion 
 	}
	#endregion

    #region Class DefaultWorkflowLayout: For rendering Root without any customization 
    internal abstract class DefaultWorkflowLayout : WorkflowLayout
	{ 
		#region Members and Constructor 
 		public static Size Separator = new Size(30, 30);
 
        public DefaultWorkflowLayout(IServiceProvider serviceProvider)
			: base(serviceProvider)
 		{
 		} 
		#endregion
 
 		#region WorkflowLayout Overrides 
		public override float Scaling
		{ 
			get
 			{
				return 1.0f;
 			} 
 		}
 
		public override Size Extent 
 		{
			get 
			{
				Size rootDesignerSize = (this.parentView.RootDesigner != null) ? this.parentView.RootDesigner.Size : Size.Empty;
                Size totalSize = new Size(rootDesignerSize.Width + DefaultWorkflowLayout.Separator.Width * 2, rootDesignerSize.Height + DefaultWorkflowLayout.Separator.Height * 2);
 				Size clientSize = this.parentView.ViewPortSize; 
				return new Size(Math.Max(totalSize.Width, clientSize.Width), Math.Max(totalSize.Height, clientSize.Height));
 			} 
 		} 

		public override Point RootDesignerAlignment 
 		{
			get
			{
                return new Point(DefaultWorkflowLayout.Separator); 
            }
		} 
 
 		public override bool IsCoOrdInLayout(Point logicalCoOrd)
		{ 
 			return true;
 		}

		public override Rectangle MapInRectangleToLayout(Rectangle logicalRectangle) 
 		{
            return logicalRectangle; 
        } 

		public override Rectangle MapOutRectangleFromLayout(Rectangle logicalRectangle) 
		{
            return logicalRectangle;
        }
 
        public override Point MapInCoOrdToLayout(Point logicalPoint)
		{ 
            return logicalPoint; 
        }
 
        public override Point MapOutCoOrdFromLayout(Point logicalPoint)
 		{
            return logicalPoint;
        } 

        public override void Update(Graphics graphics, LayoutUpdateReason reason) 
		{ 
 			//We dont do anything as our layout is simple
 		} 

		//
 
		public override void OnPaint(PaintEventArgs e, ViewPortData viewPortData) 
		{
			Graphics graphics = e.Graphics; 
 			Debug.Assert(graphics != null); 

			//Get the drawing canvas 
 			Bitmap memoryBitmap = viewPortData.MemoryBitmap;
 			Debug.Assert(memoryBitmap != null);

			//Fill the background using the workspace color so that we communicate the paging concept 
 			Rectangle workspaceRectangle = new Rectangle(Point.Empty, memoryBitmap.Size);
			graphics.FillRectangle(AmbientTheme.WorkspaceBackgroundBrush, workspaceRectangle); 
			if (this.parentView.RootDesigner != null && 
                this.parentView.RootDesigner.Bounds.Width >= 0 && this.parentView.RootDesigner.Bounds.Height >= 0)
			{ 
 				GraphicsContainer graphicsState = graphics.BeginContainer();

				//Create the scaling matrix
 				Matrix transformationMatrix = new Matrix(); 
 				transformationMatrix.Scale(viewPortData.Scaling.Width, viewPortData.Scaling.Height, MatrixOrder.Prepend);
 
				//When we draw on the viewport we draw in scaled and translated. 
 				//So that we minimize the calls to DrawImage
				//Make sure that we scale down the logical view port origin in order to take care of scaling factor 
				//Before we select the transform factor we make sure that logicalviewport origin is scaled down
				Point[] logicalViewPortOrigin = new Point[] { viewPortData.LogicalViewPort.Location };
 				transformationMatrix.TransformPoints(logicalViewPortOrigin);
 
				//For performance improvement and to eliminate one extra DrawImage...we draw the designers on the viewport
 				//bitmap with visual depth consideration 
 				transformationMatrix.Translate(-logicalViewPortOrigin[0].X + viewPortData.ShadowDepth.Width, -logicalViewPortOrigin[0].Y + viewPortData.ShadowDepth.Height, MatrixOrder.Append); 

				//Select the transform into viewport graphics. 
 				//Viewport bitmap has the scaled and translated designers which we then map to
				//the actual graphics based on page layout
				graphics.Transform = transformationMatrix;
 
				using (Region clipRegion = new Region(ActivityDesignerPaint.GetDesignerPath(this.parentView.RootDesigner, false)))
                { 
 					Region oldRegion = graphics.Clip; 
					graphics.Clip = clipRegion;
 
                    AmbientTheme ambientTheme = WorkflowTheme.CurrentTheme.AmbientTheme;
                    graphics.FillRectangle(Brushes.White, this.parentView.RootDesigner.Bounds);

                    if (ambientTheme.WorkflowWatermarkImage != null) 
 						ActivityDesignerPaint.DrawImage(graphics, ambientTheme.WorkflowWatermarkImage, this.parentView.RootDesigner.Bounds, new Rectangle(Point.Empty, ambientTheme.WorkflowWatermarkImage.Size), ambientTheme.Watermar----gnment, AmbientTheme.WatermarkTransparency, false);
 
                    graphics.Clip = oldRegion; 
 				}
 
				graphics.EndContainer(graphicsState);
 			}
		}
 
        public override void OnPaintWorkflow(PaintEventArgs e, ViewPortData viewPortData)
        { 
			Graphics graphics = e.Graphics; 
			Debug.Assert(graphics != null);
 
 			//Get the drawing canvas
			Bitmap memoryBitmap = viewPortData.MemoryBitmap;
 			Debug.Assert(memoryBitmap != null);
 			Rectangle bitmapArea = new Rectangle(Point.Empty, memoryBitmap.Size); 
			ActivityDesignerPaint.DrawImage(graphics, memoryBitmap, bitmapArea, bitmapArea, DesignerContentAlignment.Fill, 1.0f, WorkflowTheme.CurrentTheme.AmbientTheme.DrawGrayscale);
        } 
 		#endregion 
	}
	#endregion 

    #region Class ActivityRootLayout: For rendering when Activity is Root
    internal sealed class ActivityRootLayout : DefaultWorkflowLayout
    { 
        #region Members and Constructor
        internal ActivityRootLayout(IServiceProvider serviceProvider) 
            : base(serviceProvider) 
        {
        } 
        #endregion

		public override Size Extent
 		{ 
			get
 			{ 
 				Size rootDesignerSize = (this.parentView.RootDesigner != null) ? this.parentView.RootDesigner.Size : Size.Empty; 
				Size totalSize = new Size(rootDesignerSize.Width + DefaultWorkflowLayout.Separator.Width * 2, rootDesignerSize.Height + DefaultWorkflowLayout.Separator.Height * 2);
 				Size clientSize = this.parentView.ViewPortSize; 
				//since the activity designer doesnt take the full viewport area, we need to scale available viewport back by the zoom factor
				clientSize.Width = (int)(clientSize.Width / ((float)this.parentView.Zoom / 100.0f));
				clientSize.Height = (int)(clientSize.Height / ((float)this.parentView.Zoom / 100.0f));
 
 				return new Size(Math.Max(totalSize.Width, clientSize.Width), Math.Max(totalSize.Height, clientSize.Height));
			} 
 		} 

        public override void OnPaint(PaintEventArgs e, ViewPortData viewPortData) 
        {
 			base.OnPaint(e, viewPortData);

			Graphics graphics = e.Graphics; 
            if (this.parentView.RootDesigner != null &&
                this.parentView.RootDesigner.Bounds.Width >= 0 && this.parentView.RootDesigner.Bounds.Height >= 0) 
            { 
                GraphicsContainer graphicsState = graphics.BeginContainer();
 
 				//Create the scaling matrix
				Matrix transformationMatrix = new Matrix();
				transformationMatrix.Scale(viewPortData.Scaling.Width, viewPortData.Scaling.Height, MatrixOrder.Prepend);
 
				//When we draw on the viewport we draw in scaled and translated.
 				//So that we minimize the calls to DrawImage 
				//Make sure that we scale down the logical view port origin in order to take care of scaling factor 
 				//Before we select the transform factor we make sure that logicalviewport origin is scaled down
 				Point[] logicalViewPortOrigin = new Point[] { viewPortData.LogicalViewPort.Location }; 
				transformationMatrix.TransformPoints(logicalViewPortOrigin);

 				//For performance improvement and to eliminate one extra DrawImage...we draw the designers on the viewport
				//bitmap with visual depth consideration 
				transformationMatrix.Translate(-logicalViewPortOrigin[0].X + viewPortData.ShadowDepth.Width, -logicalViewPortOrigin[0].Y + viewPortData.ShadowDepth.Height, MatrixOrder.Append);
 
				//Select the transform into viewport graphics. 
 				//Viewport bitmap has the scaled and translated designers which we then map to
				//the actual graphics based on page layout 
 				graphics.Transform = transformationMatrix;

 				Rectangle rootBounds = this.parentView.RootDesigner.Bounds;
                graphics.ExcludeClip(rootBounds); 
                rootBounds.Inflate(ActivityRootLayout.Separator.Width / 2, ActivityRootLayout.Separator.Height / 2);
                ActivityDesignerPaint.DrawDropShadow(graphics, rootBounds, AmbientTheme.WorkflowBorderPen.Color, AmbientTheme.DropShadowWidth, LightSourcePosition.Left | LightSourcePosition.Top, 0.2f, false); 
 
                graphics.FillRectangle(WorkflowTheme.CurrentTheme.AmbientTheme.BackgroundBrush, rootBounds);
                graphics.DrawRectangle(AmbientTheme.WorkflowBorderPen, rootBounds); 

                graphics.EndContainer(graphicsState);
            }
        } 
    }
    #endregion 
 
    #region Class WorkflowRootLayout: For rendering when Sequential Workflow is Root, by always centering it
    internal sealed class WorkflowRootLayout : DefaultWorkflowLayout 
    {
        #region Members and Constructor
        public WorkflowRootLayout(IServiceProvider serviceProvider)
            : base(serviceProvider) 
        {
        } 
        #endregion 

        #region WorkflowLayout Overrides 
        public override Rectangle MapInRectangleToLayout(Rectangle logicalRectangle)
        {
            Size offSet = Offset;
            logicalRectangle.X -= offSet.Width; 
            logicalRectangle.Y -= offSet.Height;
            return logicalRectangle; 
        } 

        public override Rectangle MapOutRectangleFromLayout(Rectangle logicalRectangle) 
        {
            Size offSet = Offset;
            logicalRectangle.X += offSet.Width;
            logicalRectangle.Y += offSet.Height; 
            return logicalRectangle;
        } 
 
        public override Point MapInCoOrdToLayout(Point logicalPoint)
        { 
            Size offSet = Offset;
            logicalPoint.Offset(-offSet.Width, -offSet.Height);
            return logicalPoint;
        } 

        public override Point MapOutCoOrdFromLayout(Point logicalPoint) 
        { 
            Size offSet = Offset;
            logicalPoint.Offset(offSet.Width, offSet.Height); 
            return logicalPoint;
        }
		#endregion
 
        #region Helpers
        private Size Offset 
        { 
            get
            { 
                //This logic is needed in order to keep the service root designer centered
                Size layoutExtent = Extent;
 				Size totalSize = this.parentView.ClientSizeToLogical(this.parentView.ViewPortSize);
                totalSize.Width = Math.Max(totalSize.Width, layoutExtent.Width); 
                totalSize.Height = Math.Max(totalSize.Height, layoutExtent.Height);
                return new Size(Math.Max(0, (totalSize.Width - layoutExtent.Width) / 2), Math.Max(0, (totalSize.Height - layoutExtent.Height) / 2)); 
            } 
        }
        #endregion 
    }
    #endregion

	#region Class PrintPreviewLayout: For rendering print preview layout 
	internal sealed class PrintPreviewLayout : WorkflowLayout
	{ 
 		#region Members and Constructor 
		private static Size				DefaultPageSeparator = new Size(30, 30);
 		private static Margins			DefaultPageMargins = new Margins(20, 20, 20, 20); 

 		private WorkflowPrintDocument	printDocument = null;
		private ArrayList				pageLayoutInfo = new ArrayList();
 
 		//We calculate the following variables when we perform layout, we store these variables
		//so that drawing will be faster 
		private Margins					headerFooterMargins = new Margins(0, 0, 0, 0); 
		private Size					pageSeparator = PrintPreviewLayout.DefaultPageSeparator;
 		private Margins					pageMargins = PrintPreviewLayout.DefaultPageMargins; 
		private Size					rowColumns = new Size(1, 1); //Width = Columns, Height = Rows
 		private float					scaling = 1.0f;
 		private Size					pageSize = Size.Empty;
		private DateTime				previewTime = DateTime.Now; 

 		internal PrintPreviewLayout(IServiceProvider serviceProvider, WorkflowPrintDocument printDoc) 
			: base(serviceProvider) 
		{
			this.printDocument = printDoc; 
 		}
		#endregion

 		#region WorkflowLayout Overrides 
 		public override float Scaling
		{ 
 			get 
			{
				return this.scaling; 
			}
 		}

		public override Size Extent 
 		{
 			get 
			{ 
 				//RowColumns Width = Columns, Height = Rows
				Size maxSize = Size.Empty; 
				maxSize.Width = (this.rowColumns.Width * this.pageSize.Width) + ((this.rowColumns.Width + 1) * (PageSeparator.Width));
				maxSize.Height = (this.rowColumns.Height * this.pageSize.Height) + ((this.rowColumns.Height + 1) * (PageSeparator.Height));
 				return maxSize;
			} 
 		}
 
 		public override Point RootDesignerAlignment 
		{
 			get 
			{
				Point alignment = Point.Empty;
				Size printableAreaPerPage = new Size(this.pageSize.Width - (PageMargins.Left + PageMargins.Right), this.pageSize.Height - (PageMargins.Top + PageMargins.Bottom));
 				Size totalPrintableArea = new Size(this.rowColumns.Width * printableAreaPerPage.Width, this.rowColumns.Height * printableAreaPerPage.Height); 
				Size rootDesignerSize = (this.parentView.RootDesigner != null) ? this.parentView.RootDesigner.Size : Size.Empty;
                Size selectionSize = WorkflowTheme.CurrentTheme.AmbientTheme.SelectionSize; 
 
                if (this.printDocument.PageSetupData.CenterHorizontally)
                    alignment.X = (totalPrintableArea.Width - rootDesignerSize.Width) / 2; 
                alignment.X = Math.Max(alignment.X, selectionSize.Width + selectionSize.Width / 2);

                if (this.printDocument.PageSetupData.CenterVertically)
 					alignment.Y = (totalPrintableArea.Height - rootDesignerSize.Height) / 2; 
                alignment.Y = Math.Max(alignment.Y, selectionSize.Height + selectionSize.Height / 2);
 
 				return alignment; 
			}
 		} 

		public override bool IsCoOrdInLayout(Point logicalCoOrd)
		{
			foreach (PageLayoutData pageLayoutData in this.pageLayoutInfo) 
 			{
				if (pageLayoutData.ViewablePageBounds.Contains(logicalCoOrd)) 
 					return true; 
 			}
 
			return false;
 		}

		public override Rectangle MapInRectangleToLayout(Rectangle logicalRectangle) 
		{
			Rectangle transformedViewPort = Rectangle.Empty; 
 
 			//Now we start mapping the rectangle based on page layout
			foreach (PageLayoutData pageLayoutData in this.pageLayoutInfo) 
 			{
 				Rectangle intersectedPhysicalViewPort = logicalRectangle;
				intersectedPhysicalViewPort.Intersect(pageLayoutData.ViewablePageBounds);
 				if (!intersectedPhysicalViewPort.IsEmpty) 
				{
					Point deltaLocation = new Point(intersectedPhysicalViewPort.X - pageLayoutData.ViewablePageBounds.X, intersectedPhysicalViewPort.Y - pageLayoutData.ViewablePageBounds.Y); 
 
					Size deltaSize = new Size(pageLayoutData.ViewablePageBounds.Width - intersectedPhysicalViewPort.Width, pageLayoutData.ViewablePageBounds.Height - intersectedPhysicalViewPort.Height);
 					deltaSize.Width -= deltaLocation.X; 
					deltaSize.Height -= deltaLocation.Y;

 					//Get the intersecting rectangle
 					Rectangle insersectedLogicalViewPort = Rectangle.Empty; 
					insersectedLogicalViewPort.X = pageLayoutData.LogicalPageBounds.X + deltaLocation.X;
 					insersectedLogicalViewPort.Y = pageLayoutData.LogicalPageBounds.Y + deltaLocation.Y; 
 
					insersectedLogicalViewPort.Width = pageLayoutData.LogicalPageBounds.Width - deltaLocation.X;
					insersectedLogicalViewPort.Width -= deltaSize.Width; 

					insersectedLogicalViewPort.Height = pageLayoutData.LogicalPageBounds.Height - deltaLocation.Y;
 					insersectedLogicalViewPort.Height -= deltaSize.Height;
 
					transformedViewPort = (transformedViewPort.IsEmpty) ? insersectedLogicalViewPort : Rectangle.Union(transformedViewPort, insersectedLogicalViewPort);
 				} 
 			} 

			return transformedViewPort; 
 		}

		public override Rectangle MapOutRectangleFromLayout(Rectangle logicalRectangle)
		{ 
			Rectangle transformedViewPort = Rectangle.Empty;
 
 			//Now we start mapping the rectangle based on page layout 
			foreach (PageLayoutData pageLayoutData in this.pageLayoutInfo)
 			{ 
 				Rectangle intersectedLogicalViewPort = logicalRectangle;
				intersectedLogicalViewPort.Intersect(pageLayoutData.LogicalPageBounds);
 				if (!intersectedLogicalViewPort.IsEmpty)
				{ 
					Point deltaLocation = new Point(intersectedLogicalViewPort.X - pageLayoutData.LogicalPageBounds.X, intersectedLogicalViewPort.Y - pageLayoutData.LogicalPageBounds.Y);
 
					Size deltaSize = new Size(pageLayoutData.LogicalPageBounds.Width - intersectedLogicalViewPort.Width, pageLayoutData.LogicalPageBounds.Height - intersectedLogicalViewPort.Height); 
 					deltaSize.Width -= deltaLocation.X;
					deltaSize.Height -= deltaLocation.Y; 

 					//Get the intersecting rectangle
 					Rectangle insersectedPhysicalViewPort = Rectangle.Empty;
					insersectedPhysicalViewPort.X = pageLayoutData.ViewablePageBounds.X + deltaLocation.X; 
 					insersectedPhysicalViewPort.Y = pageLayoutData.ViewablePageBounds.Y + deltaLocation.Y;
 
					insersectedPhysicalViewPort.Width = pageLayoutData.ViewablePageBounds.Width - deltaLocation.X; 
					insersectedPhysicalViewPort.Width -= deltaSize.Width;
 
					insersectedPhysicalViewPort.Height = pageLayoutData.ViewablePageBounds.Height - deltaLocation.Y;
 					insersectedPhysicalViewPort.Height -= deltaSize.Height;

					transformedViewPort = (transformedViewPort.IsEmpty) ? insersectedPhysicalViewPort : Rectangle.Union(transformedViewPort, insersectedPhysicalViewPort); 
 				}
 			} 
 
			return transformedViewPort;
 		} 

		public override Point MapInCoOrdToLayout(Point logicalPoint)
		{
			//Only for default layout we scale the coordinates outside the pageboundry for all other cases scaling fails 
 			foreach (PageLayoutData pageLayoutData in this.pageLayoutInfo)
			{ 
 				if (pageLayoutData.PageBounds.Contains(logicalPoint)) 
 				{
					Point delta = new Point(logicalPoint.X - pageLayoutData.ViewablePageBounds.Left, logicalPoint.Y - pageLayoutData.ViewablePageBounds.Top); 
 					logicalPoint = new Point(pageLayoutData.LogicalPageBounds.Left + delta.X, pageLayoutData.LogicalPageBounds.Top + delta.Y);
					break;
				}
			} 

 			return logicalPoint; 
		} 

 		public override Point MapOutCoOrdFromLayout(Point logicalPoint) 
 		{
			foreach (PageLayoutData pageLayoutData in this.pageLayoutInfo)
 			{
				if (pageLayoutData.LogicalPageBounds.Contains(logicalPoint)) 
				{
					Point delta = new Point(logicalPoint.X - pageLayoutData.LogicalPageBounds.Left, logicalPoint.Y - pageLayoutData.LogicalPageBounds.Top); 
 					logicalPoint = new Point(pageLayoutData.ViewablePageBounds.Left + delta.X, pageLayoutData.ViewablePageBounds.Top + delta.Y); 
					break;
 				} 
 			}

			return logicalPoint;
 		} 

		public override void OnPaint(PaintEventArgs e, ViewPortData viewPortData) 
		{ 
			Graphics graphics = e.Graphics;
 			Debug.Assert(graphics != null); 
			AmbientTheme ambientTheme = WorkflowTheme.CurrentTheme.AmbientTheme;

 			//Get the drawing canvas			
 			Bitmap memoryBitmap = viewPortData.MemoryBitmap; 
			Debug.Assert(memoryBitmap != null);
 
 			//Fill the background using the workspace color so that we communicate the paging concept 
			graphics.FillRectangle(Brushes.White, new Rectangle(Point.Empty, memoryBitmap.Size));
 
			//Fill the background using the workspace color so that we communicate the paging concept
			//if there is no workflow watermark, just return
 			if (ambientTheme.WorkflowWatermarkImage == null)
				return; 

 			//Create the transformation matrix and calculate the physical viewport without translation and scaling 
 			//We need to get the physical view port due to the fact that there can be circustances when zoom percentage 
			//is very high, logical view port can be empty in such cases
 			GraphicsContainer graphicsState = graphics.BeginContainer(); 
			Matrix coOrdTxMatrix = new Matrix();
			coOrdTxMatrix.Scale(viewPortData.Scaling.Width, viewPortData.Scaling.Height, MatrixOrder.Prepend);
			coOrdTxMatrix.Invert();
 
 			Point[] points = new Point[] { viewPortData.Translation, new Point(viewPortData.ViewPortSize) };
			coOrdTxMatrix.TransformPoints(points); 
 			Rectangle physicalViewPort = new Rectangle(points[0], new Size(points[1])); 

 			//because the watermark image needs to be scaled according to the zoom level, we 
			//a) scale the graphics of the bitmap up by the zoom factor
 			//a) scale the coordinates transform matrix down by the zoom factor
			coOrdTxMatrix = new Matrix();
			coOrdTxMatrix.Scale(viewPortData.Scaling.Width / (float)this.parentView.Zoom * 100.0f, viewPortData.Scaling.Height / (float)this.parentView.Zoom * 100.0f); 

			//Make sure that we now clear the translation factor 
 			Matrix graphicsMatrics = new Matrix(); 
			graphicsMatrics.Scale((float)this.parentView.Zoom / 100.0f, (float)this.parentView.Zoom / 100.0f);
 			graphics.Transform = graphicsMatrics; 

 			foreach (PageLayoutData pageLayoutData in this.pageLayoutInfo)
			{
 				//We do not draw the non intersecting pages, get the intersected viewport 
				//We purposely use the physical viewport here because, there are cases in which the viewport
				//will not contain any logical bitmap areas in which case we atleast need to draw the pages properly 
				if (!pageLayoutData.PageBounds.IntersectsWith(physicalViewPort)) 
 					continue;
 
				//Draw the watermark into the in-memory bitmap
 				//This is the area of the viewport bitmap we need to copy on the page
 				Rectangle viewPortBitmapArea = Rectangle.Empty;
				viewPortBitmapArea.X = pageLayoutData.LogicalPageBounds.X - viewPortData.LogicalViewPort.X; 
 				viewPortBitmapArea.Y = pageLayoutData.LogicalPageBounds.Y - viewPortData.LogicalViewPort.Y;
				viewPortBitmapArea.Width = pageLayoutData.LogicalPageBounds.Width; 
				viewPortBitmapArea.Height = pageLayoutData.LogicalPageBounds.Height; 

				//This rectangle is in translated logical units, we need to scale it down 
 				points = new Point[] { viewPortBitmapArea.Location, new Point(viewPortBitmapArea.Size) };
				coOrdTxMatrix.TransformPoints(points);
 				viewPortBitmapArea.Location = points[0];
 				viewPortBitmapArea.Size = new Size(points[1]); 

                ActivityDesignerPaint.DrawImage(graphics, ambientTheme.WorkflowWatermarkImage, viewPortBitmapArea, new Rectangle(Point.Empty, ambientTheme.WorkflowWatermarkImage.Size), ambientTheme.Watermar----gnment, AmbientTheme.WatermarkTransparency, false); 
            } 

			//Now clear the matrix 
 			graphics.EndContainer(graphicsState);
		}

        public override void OnPaintWorkflow(PaintEventArgs e, ViewPortData viewPortData) 
        {
			Graphics graphics = e.Graphics; 
			Debug.Assert(graphics != null); 
 			Bitmap memoryBitmap = viewPortData.MemoryBitmap;
			Debug.Assert(memoryBitmap != null); 

 			//Get the drawing canvas
 			AmbientTheme ambientTheme = WorkflowTheme.CurrentTheme.AmbientTheme;
 
			//We set the highest quality interpolation so that we do not loose the image quality
 			GraphicsContainer graphicsState = graphics.BeginContainer(); 
 
			//Fill the background using the workspace color so that we communicate the paging concept
			Rectangle workspaceRectangle = new Rectangle(Point.Empty, memoryBitmap.Size); 
			graphics.FillRectangle(AmbientTheme.WorkspaceBackgroundBrush, workspaceRectangle);

 			using (Font headerFooterFont = new Font(ambientTheme.Font.FontFamily, ambientTheme.Font.Size / this.scaling, ambientTheme.Font.Style))
			{ 
 				int currentPage = 0;
 				Matrix emptyMatrix = new Matrix(); 
 
				//Create the transformation matrix and calculate the physical viewport without translation and scaling
 				//We need to get the physical view port due to the fact that there can be circustances when zoom percentage 
				//is very high, logical view port can be empty in such cases
				Matrix coOrdTxMatrix = new Matrix();
				coOrdTxMatrix.Scale(viewPortData.Scaling.Width, viewPortData.Scaling.Height, MatrixOrder.Prepend);
 				coOrdTxMatrix.Invert(); 
				Point[] points = new Point[] { viewPortData.Translation, new Point(viewPortData.ViewPortSize) };
 				coOrdTxMatrix.TransformPoints(points); 
 				coOrdTxMatrix.Invert(); 
				Rectangle physicalViewPort = new Rectangle(points[0], new Size(points[1]));
 
 				//Create the data for rendering header/footer
				WorkflowPrintDocument.HeaderFooterData headerFooterData = new WorkflowPrintDocument.HeaderFooterData();
				headerFooterData.HeaderFooterMargins = this.headerFooterMargins;
				headerFooterData.PrintTime = this.previewTime; 
 				headerFooterData.TotalPages = this.pageLayoutInfo.Count;
				headerFooterData.Scaling = this.scaling; 
 				headerFooterData.Font = headerFooterFont; 
 				WorkflowDesignerLoader serviceDesignerLoader = this.serviceProvider.GetService(typeof(WorkflowDesignerLoader)) as WorkflowDesignerLoader;
				headerFooterData.FileName = (serviceDesignerLoader != null) ? serviceDesignerLoader.FileName : String.Empty; 

 				//Create the viewport transformation matrix
				Matrix viewPortMatrix = new Matrix();
				viewPortMatrix.Scale(viewPortData.Scaling.Width, viewPortData.Scaling.Height, MatrixOrder.Prepend); 
				viewPortMatrix.Translate(-viewPortData.Translation.X, -viewPortData.Translation.Y, MatrixOrder.Append);
 
 				//We now have the viewport properly drawn, now we need to draw it on the actual graphics object 
				//Now that we have the designer bitmap we start splicing it based on the pages
 				//Note that this is quite expensive operation and hence one should try to use 
 				//The memory bitmap we have got is scaled appropriately
				foreach (PageLayoutData pageLayoutData in this.pageLayoutInfo)
 				{
					currentPage += 1; 

					//We do not draw the non intersecting pages, get the intersected viewport 
					//We purposely use the physical viewport here because, there are cases in which the viewport 
 					//will not contain any logical bitmap areas in which case we atleast need to draw the pages properly
                    if (!pageLayoutData.PageBounds.IntersectsWith(physicalViewPort) || pageLayoutData.PageBounds.Width <= 0 || pageLayoutData.PageBounds.Height <= 0) 
						continue;

 					//******START PAGE DRAWING, FIRST DRAW THE OUTLINE
 					//Scale and translate so that we can draw the pages 
					graphics.Transform = viewPortMatrix;
 					graphics.FillRectangle(Brushes.White, pageLayoutData.PageBounds); 
                    ActivityDesignerPaint.DrawDropShadow(graphics, pageLayoutData.PageBounds, Color.Black, AmbientTheme.DropShadowWidth, LightSourcePosition.Left | LightSourcePosition.Top, 0.2f, false); 

                    //***START BITMAP SPLICING 
					//Draw spliced bitmap for the page if we have any displayable area
					Rectangle intersectedViewPort = pageLayoutData.LogicalPageBounds;
					intersectedViewPort.Intersect(viewPortData.LogicalViewPort);
 					if (!intersectedViewPort.IsEmpty) 
					{
 						//Make sure that we now clear the translation factor 
 						graphics.Transform = emptyMatrix; 
						//Paint bitmap on the pages
 						//Now that the page rectangle is actually drawn, we will scale down the Location of page rectangle 
						//so that we can draw the viewport bitmap part on it
						Point bitmapDrawingPoint = Point.Empty;
						bitmapDrawingPoint.X = pageLayoutData.ViewablePageBounds.X + Math.Abs(pageLayoutData.LogicalPageBounds.X - intersectedViewPort.X);
 						bitmapDrawingPoint.Y = pageLayoutData.ViewablePageBounds.Y + Math.Abs(pageLayoutData.LogicalPageBounds.Y - intersectedViewPort.Y); 
						points = new Point[] { bitmapDrawingPoint };
 						coOrdTxMatrix.TransformPoints(points); 
 						bitmapDrawingPoint = new Point(points[0].X - viewPortData.Translation.X, points[0].Y - viewPortData.Translation.Y); 

						//This is the area of the viewport bitmap we need to copy on the page 
 						Rectangle viewPortBitmapArea = Rectangle.Empty;
						viewPortBitmapArea.X = intersectedViewPort.X - viewPortData.LogicalViewPort.X;
						viewPortBitmapArea.Y = intersectedViewPort.Y - viewPortData.LogicalViewPort.Y;
						viewPortBitmapArea.Width = intersectedViewPort.Width; 
 						viewPortBitmapArea.Height = intersectedViewPort.Height;
 
						//This rectangle is in translated logical units, we need to scale it down 
 						points = new Point[] { viewPortBitmapArea.Location, new Point(viewPortBitmapArea.Size) };
 						coOrdTxMatrix.TransformPoints(points); 
						viewPortBitmapArea.Location = points[0];
 						viewPortBitmapArea.Size = new Size(points[1]);

						ActivityDesignerPaint.DrawImage(graphics, memoryBitmap, new Rectangle(bitmapDrawingPoint, viewPortBitmapArea.Size), viewPortBitmapArea, DesignerContentAlignment.Fill, 1.0f, WorkflowTheme.CurrentTheme.AmbientTheme.DrawGrayscale); 
                    }
					//***END BITMAP SPLICING 
 
					//Draw the page outline
 					graphics.Transform = viewPortMatrix; 
					graphics.DrawRectangle(Pens.Black, pageLayoutData.PageBounds);

 					//Draw the printable page outline
 					graphics.DrawRectangle(ambientTheme.ForegroundPen, pageLayoutData.ViewablePageBounds.Left - 3, pageLayoutData.ViewablePageBounds.Top - 3, pageLayoutData.ViewablePageBounds.Width + 6, pageLayoutData.ViewablePageBounds.Height + 6); 

					//Draw the header and footer after we draw the actual page 
 					headerFooterData.PageBounds = pageLayoutData.PageBounds; 
					headerFooterData.PageBoundsWithoutMargin = pageLayoutData.ViewablePageBounds;
					headerFooterData.CurrentPage = currentPage; 

					//Draw the header
 					if (this.printDocument.PageSetupData.HeaderTemplate.Length > 0)
						this.printDocument.PrintHeaderFooter(graphics, true, headerFooterData); 

 					//Draw footer 
 					if (this.printDocument.PageSetupData.FooterTemplate.Length > 0) 
						this.printDocument.PrintHeaderFooter(graphics, false, headerFooterData);
 					//***END DRAWING HEADER FOOTER 
				}

				graphics.EndContainer(graphicsState);
			} 
 		}
 
		public override void Update(Graphics graphics, LayoutUpdateReason reason) 
 		{
 			//do not recalculate pages when it's just a zoom change 
			if (reason == LayoutUpdateReason.ZoomChanged)
 				return;

			if (graphics == null) 
				throw new ArgumentException("graphics");
 
			//Set the scaling, pageSize, margins, pageseparator by reserse scaling; so that when we actually scale 
 			//at the time of drawing things will be correctly calculated
			Size margin = WorkflowTheme.CurrentTheme.AmbientTheme.Margin; 
 			Size paperSize = GetPaperSize(graphics);
 			Margins margins = GetAdjustedMargins(graphics);
			Size rootDesignerSize = (this.parentView.RootDesigner != null) ? this.parentView.RootDesigner.Size : Size.Empty;
            if (!rootDesignerSize.IsEmpty) 
            {
                Size selectionSize = WorkflowTheme.CurrentTheme.AmbientTheme.SelectionSize; 
                rootDesignerSize.Width += 3 * selectionSize.Width; 
                rootDesignerSize.Height += 3 * selectionSize.Height;
            } 

            //STEP1 : Calculate the scaling factor
 			if (this.printDocument.PageSetupData.AdjustToScaleFactor)
			{ 
				this.scaling = ((float)this.printDocument.PageSetupData.ScaleFactor / 100.0f);
			} 
 			else 
			{
 				Size printableArea = new Size(paperSize.Width - (margins.Left + margins.Right), paperSize.Height - (margins.Top + margins.Bottom)); 
 				printableArea.Width = Math.Max(printableArea.Width, 1);
				printableArea.Height = Math.Max(printableArea.Height, 1);

 				PointF scaleFactor = new PointF( 
				((float)this.printDocument.PageSetupData.PagesWide * (float)printableArea.Width / (float)rootDesignerSize.Width),
				((float)this.printDocument.PageSetupData.PagesTall * (float)printableArea.Height / (float)rootDesignerSize.Height)); 
 
				//Take the minimum scaling as we do not want to unevenly scale the bitmap
 				this.scaling = Math.Min(scaleFactor.X, scaleFactor.Y); 
				//leave just 3 digital points (also, that will remove potential problems with ceiling e.g. when the number of pages would be 3.00000000001 we'll get 4)
 				this.scaling = (float)(Math.Floor((double)this.scaling * 1000.0d) / 1000.0d);
 			}
 
			//STEP2 : Calculate the pagesize
 			this.pageSize = paperSize; 
			this.pageSize.Width = Convert.ToInt32(Math.Ceiling(((float)this.pageSize.Width) / this.scaling)); 
			this.pageSize.Height = Convert.ToInt32(Math.Ceiling(((float)this.pageSize.Height) / this.scaling));
 
			//STEP3 : Calculate the page separator
 			IDesignerOptionService designerOptionService = this.serviceProvider.GetService(typeof(IDesignerOptionService)) as IDesignerOptionService;
			if (designerOptionService != null)
 			{ 
 				object separator = designerOptionService.GetOptionValue("WinOEDesigner", "PageSeparator");
				PageSeparator = (separator != null) ? (Size)separator : PrintPreviewLayout.DefaultPageSeparator; 
 			} 
			PageSeparator = new Size(Convert.ToInt32(Math.Ceiling(((float)PageSeparator.Width) / this.scaling)), Convert.ToInt32(Math.Ceiling(((float)PageSeparator.Height) / this.scaling)));
 
			//STEP4: Calculate the margins after reverse scaling the margins, so that when we set the normal scalezoom we have correct margins
			PageMargins = margins;
 			PageMargins.Left = Convert.ToInt32((float)PageMargins.Left / this.scaling);
			PageMargins.Right = Convert.ToInt32((float)PageMargins.Right / this.scaling); 
 			PageMargins.Top = Convert.ToInt32((float)PageMargins.Top / this.scaling);
 			PageMargins.Bottom = Convert.ToInt32((float)PageMargins.Bottom / this.scaling); 
 
			//STEP5: Calculate the header and footer margins
 			this.headerFooterMargins.Top = Convert.ToInt32((float)this.printDocument.PageSetupData.HeaderMargin / this.scaling); 
			this.headerFooterMargins.Bottom = Convert.ToInt32((float)this.printDocument.PageSetupData.FooterMargin / this.scaling);
			this.previewTime = DateTime.Now;

			//STEP6: Calculate the the row columns 
 			Size viewablePageSize = new Size(this.pageSize.Width - (PageMargins.Left + PageMargins.Right), this.pageSize.Height - (PageMargins.Top + PageMargins.Bottom));
			viewablePageSize.Width = Math.Max(viewablePageSize.Width, 1); 
 			viewablePageSize.Height = Math.Max(viewablePageSize.Height, 1); 

 			//We check for greater than 1 here as the division might introduce rounding factor 
			//Columns
 			this.rowColumns.Width = rootDesignerSize.Width / viewablePageSize.Width;
			this.rowColumns.Width += ((rootDesignerSize.Width % viewablePageSize.Width) > 1) ? 1 : 0;
			this.rowColumns.Width = Math.Max(1, this.rowColumns.Width); 

			//Rows 
 			this.rowColumns.Height = rootDesignerSize.Height / viewablePageSize.Height; 
			this.rowColumns.Height += ((rootDesignerSize.Height % viewablePageSize.Height) > 1) ? 1 : 0;
 			this.rowColumns.Height = Math.Max(1, this.rowColumns.Height); 

 			//STEP7: Calculate the pagelayoutdata
			this.pageLayoutInfo.Clear();
 
 			//Create the layout data
			for (int row = 0; row < this.rowColumns.Height; row++) 
			{ 
				for (int column = 0; column < this.rowColumns.Width; column++)
 				{ 
					Point pageLocation = Point.Empty;
 					pageLocation.X = (column * this.pageSize.Width) + ((column + 1) * PageSeparator.Width);
 					pageLocation.Y = (row * this.pageSize.Height) + ((row + 1) * PageSeparator.Height);
 
					Point viewablePageLocation = Point.Empty;
 					viewablePageLocation.X = pageLocation.X + PageMargins.Left; 
					viewablePageLocation.Y = pageLocation.Y + PageMargins.Top; 

					Rectangle logicalBounds = new Rectangle(column * viewablePageSize.Width, row * viewablePageSize.Height, viewablePageSize.Width, viewablePageSize.Height); 
					Rectangle pageBounds = new Rectangle(pageLocation, this.pageSize);
 					Rectangle viewablePageBounds = new Rectangle(viewablePageLocation, viewablePageSize);
					this.pageLayoutInfo.Add(new PageLayoutData(logicalBounds, pageBounds, viewablePageBounds, new Point(column, row)));
 				} 
 			}
		} 
 		#endregion 

		#region Helpers 
		private Size GetPaperSize(Graphics graphics)
		{
 			Size size = Size.Empty;
			PaperSize paperSize = this.printDocument.DefaultPageSettings.PaperSize; 
 			this.printDocument.DefaultPageSettings.PaperSize = paperSize;
 			if (this.printDocument.PageSetupData.Landscape) 
			{ 
 				size.Width = Math.Max(paperSize.Height, 1);
				size.Height = Math.Max(paperSize.Width, 1); 
			}
			else
 			{
				size.Width = Math.Max(paperSize.Width, 1); 
 				size.Height = Math.Max(paperSize.Height, 1);
 			} 
			 
 			return size;
		} 

        private Margins GetAdjustedMargins(Graphics graphics)
        {
			Margins margins = this.printDocument.PageSetupData.Margins; 
			if (this.printDocument.PageSetupData.Landscape)
 			{ 
				int temp = margins.Left; 
 				margins.Left = margins.Right;
 				margins.Right = temp; 

				temp = margins.Bottom;
 				margins.Bottom = margins.Top;
				margins.Top = temp; 
			}
 
			//Read the unprintable margins 
 			Margins hardMargins = new Margins();
			using (Graphics printerGraphics = this.printDocument.PrinterSettings.CreateMeasurementGraphics()) 
                hardMargins = this.printDocument.GetHardMargins(printerGraphics);

            Margins adjustedMargins = new Margins(Math.Max(margins.Left, hardMargins.Left),
 												  Math.Max(margins.Right, hardMargins.Right), 
 												  Math.Max(margins.Top, hardMargins.Top),
												  Math.Max(margins.Bottom, hardMargins.Bottom)); 
 
 			return adjustedMargins;
		} 

		private Size PageSeparator
		{
 			get 
			{
 				return this.pageSeparator; 
 			} 
			set
 			{ 
				this.pageSeparator = value;
			}
		}
 
 		private Margins PageMargins
		{ 
 			get 
 			{
				return this.pageMargins; 
 			}

			set
			{ 
				this.pageMargins = value;
 			} 
		} 
 		#endregion
 
 		#region Struct PageLayoutData
		///	Please note that all the page bounds in here are in scaled coordinates
 		/// PageBounds are the bounds of the page in scaled coordinates with margins
		/// ViewablePageBounds are the bounds in scaled coordinates without margins 
		/// LogicalBounds are the page bounds when mapped to our logical coordinate system.
		///				|-----------------------| 
 		///				|PageBounds				| 
		///				|	|---------------|...........Mapped to logical page bounds
 		///				|	|Viewable		|	| 
 		///				|	|PageBounds		|	|
		///				|	|				|	|
 		///				|	|				|	|
		///				|	|				|	| 
		///				|	|				|	|
		///				|	|				|	| 
 		///				|	|				|	| 
		///				|	|				|	|
 		///				|	|---------------|........... 
 		///				|						|
		///				-------------------------
 		private struct PageLayoutData
		{ 
			//logical page bounds start from 0,0 and go to the size of the designer
			public Rectangle LogicalPageBounds; 
 			//Page bounds are used to draw the complete page in the layout with margin 
			public Rectangle PageBounds;
 			//screen viewable page bounds (Excludes the margin area) 
 			public Rectangle ViewablePageBounds;
			//row column position contains the row column position of the page
 			public Point Position;
 
			public PageLayoutData(Rectangle logicalPageBounds, Rectangle pageBounds, Rectangle viewablePageBounds, Point rowColumnPos)
			{ 
				this.LogicalPageBounds = logicalPageBounds; 
 				this.PageBounds = pageBounds;
 
				//Exclude the margins themselves
 				this.ViewablePageBounds = viewablePageBounds;
 				this.Position = rowColumnPos;
			} 
 		}
		#endregion 
	} 
	#endregion
} 


// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK