GraphicsPath Front – Vector drawing software

GraphicsPath Front is vector drawing software based upon the GraphicsPath .net class.
Download (source and binaries) — Execute \bin\debug\GraphicsPathFront.exe or compile from source.
Some of the notable features include:
- Save/load vectorized graphics, or save in numerous rasterized formats.
- Configurable and snap-to'able grid.
- Live preview of what's being drawn, including rendering in real-time.
- The ability to render as mouse input. (Need to see the videos to understand!)
There are several limitations in this program due to the limits of the underlying GraphicsPath class. Though the code is in place to do so, nodes can not be directly edited once created, for example. Nor can different paths be drawn using different pens.
Contents
Below are some samples of the code from the project. Note that some of the limitations of the code highlighting plugin are apparent in generics being passed as generic types, and with XML comments.
DrawingGrid class
The class which manages the drawing of and mouse handling for the grid.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;
namespace CrayonAutomaton {
///
/// Create a GraphicsPath based grid in memory.
///
class DrawingGrid {
///
An event that is triggered when ever the grid is regenerated and needs to be redisplayed.
public event Action GridUpdated;
///
Gets or Sets the total area of the grid.
public Size GridSize {
get { return _gridSize; }
set {
_gridSize = value;
makeGrid();
}
}
///
Gets or Sets the size of each grid cell.
public Size CellSize {
get { return _cellSize; }
set {
_cellSize = value;
makeGrid();
}
}
///
Gets or Sets the color of the drawn grid.
public Color GridColor {
get { return _gridColor; }
set {
_gridColor = value;
makeGrid();
}
}
///
Gets the grid vector
public GraphicsPath Grid { get { return path; } }
///
Gets or Sets if 'GridPositionFromPoint()' snaps passed Point to the grid.
public bool SnapPointsToGrid { get; set; }
///
Gets or Sets if grid is drawn when asked to
public bool Visible {
get { return _visible; }
set {
_visible = value;
if (GridUpdated != null)
GridUpdated();
}
}
private Size _gridSize;
private Size _cellSize;
private Color _gridColor;
private bool _visible;
private bool noRendering = false;
private GraphicsPath path = new GraphicsPath();
public DrawingGrid(Size gridSize) : this(gridSize, new Size(20, 20), Color.LightGray, true) { }
public DrawingGrid(Size gridSize, Size cellSize) : this(gridSize, cellSize, Color.LightGray, true) { }
public DrawingGrid(Size gridSize, Size cellSize, Color gridColor) : this(gridSize, cellSize, gridColor, true) { }
///
Creates an instance of a class for drawing a grid on an image
///
Total area of grid to draw
///
Size of each cell to draw
///
Color to draw the grid
///
Determins if 'GridPositionFromPoint()' snaps passed Point to the grid.
public DrawingGrid(Size gridSize, Size cellSize, Color gridColor, bool snapPointsToGrid) {
BeginUpdate();
GridSize = gridSize;
CellSize = cellSize;
GridColor = gridColor;
SnapPointsToGrid = snapPointsToGrid;
Visible = true;
EndUpdate();
}
///
'Snaps' the passed point to grid, returns as-is if snapping to grid is disabled.
public Point GridPositionFromPoint(Point point) {
if (!SnapPointsToGrid)
return point;
Point gridPoint = new Point();
gridPoint.X = (int)Math.Floor((decimal)(point.X / CellSize.Width)) * CellSize.Width;
gridPoint.Y = (int)Math.Floor((decimal)(point.Y / CellSize.Height)) * CellSize.Height;
if (point.X % CellSize.Width > CellSize.Width / 2)
gridPoint.X += CellSize.Width;
if (point.Y % CellSize.Height > CellSize.Height / 2)
gridPoint.Y += CellSize.Height;
return gridPoint;
}
///
Draws grid to Graphic 'g' if Visible, regenerates grid if 'size' is different
public void DrawToGraphic(Graphics g, Size size) {
if (Visible) {
if (size != GridSize)
GridSize = size;
g.DrawPath(new Pen(GridColor), Grid);
}
}
///
Draws grid to Graphic 'g' if Visible
public void DrawToGraphic(Graphics g) {
if (Visible)
g.DrawPath(new Pen(GridColor), Grid);
}
///
Prevents (costly) regeneration of grid during property changes.
public void BeginUpdate() { noRendering = true; }
///
Allows grid to be regenerated by property changes again, also regenerates grid.
public void EndUpdate() {
noRendering = false;
makeGrid();
}
///
(Re)render the grid to the 'path' variable.
private void makeGrid() {
/* Do not render if durring an 'update' */
if (noRendering)
return;
int cellX = CellSize.Width;
int cellY = CellSize.Height;
/* Clear old grid */
path.Reset();
/* Add vertical lines (columes) */
do {
path.StartFigure();
path.AddLine(cellX, 0, cellX, GridSize.Height);
} while ((cellX += CellSize.Width) < GridSize.Width);
/* Add horizontal lines (rows) */
do {
path.StartFigure();
path.AddLine(0, cellY, GridSize.Width, cellY);
} while ((cellY += CellSize.Height) < GridSize.Height);
/* Call all grid updated events */
if (GridUpdated != null)
GridUpdated();
}
}
}
DrawingTools class
A collection of drawing tools and an abstract class and event driven drawing tool system.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
namespace CrayonAutomaton {
///
A collection of DrawingTool
class DrawingTools {
///
Event for when an update is required.
public event Action PreviewUpdate;
///
Gets or Sets the currently in-use drawing tool.
public DrawingTool Tool { get; set; }
///
A collection of DrawingTools
public List Tools { get; set; }
///
Functions which are called on the mouse input before the mouse data is used.
public IEnumerable> MouseInputFilters {
get { return _mouseInputFilters; }
set {
performToAllTools(delegate(DrawingTool tool) { tool.MouseInputFilters = value; });
_mouseInputFilters = value;
}
}
public GraphicsPath Path {
get { return _path; }
set {
performToAllTools(delegate(DrawingTool tool) { tool.Path = value; });
_path = value;
}
}
private GraphicsPath _path;
private IEnumerable> _mouseInputFilters;
public DrawingTools(GraphicsPath path, Func mouseInputFilter/*, Control hookToSurface*/)
: this(path, new[] { mouseInputFilter }) { }
///
Instances a usable collection of DrawingTool's
///
Path for the tools to draw to
public DrawingTools(GraphicsPath path, IEnumerable> mouseInputFilters/*, Control hookToSurface*/) {
/* Instance all locally coded drawing tools */
Tools = new List(new DrawingTool[] {
new NullDrawingTool(),
new LineDrawingTool(),
new RectangleDrawingTool(),
new EllipseDrawingTool(),
new FreeDrawDrawingTool(),
new TextDrawingTool()
});
/* Set-up all required members */
performToAllTools(delegate(DrawingTool tool) { tool.ParentCollection = this; });
Path = path;
MouseInputFilters = mouseInputFilters;
SetTool("");
}
public void Preview() {
if (PreviewUpdate != null)
PreviewUpdate();
}
public void HookToolsToSurface(Control surface) {
}
public bool SetTool(DrawingTool tool) { return SetTool(tool.Name); }
///
Changes the in-use tool based upon 'name'
/// Returns 'true' if a tool is found and set, 'false' otherwise.
public bool SetTool(string name) {
foreach (DrawingTool curTool in Tools)
if (curTool.Name == name) {
Tool = curTool;
return true;
}
return false;
}
private void performToAllTools(Action delegateFunction) {
foreach (DrawingTool curTool in Tools)
delegateFunction(curTool);
}
}
abstract class DrawingTool : IEquatable {
///
Get the tools name
public string Name { get { return _name; } }
///
A value indicating if the mouse is presently inside the drawing area
public bool IsMouseInside { get; set; }
public GraphicsPath Path { get; set; }
public IEnumerable> MouseInputFilters { get; set; }
public MouseButtons MouseButtonState { get; set; }
public DrawingTools ParentCollection { get; set; }
private string _name;
protected Point mouseDownLocation;
///
Abstract class for drawing tools
///
Name of the drawing tool, must be unique
protected DrawingTool(string name) {
_name = name;
IsMouseInside = false;
}
///
Call to pass the mouse down event to the in-use tool.
public void MouseDown(Point point) {
point = filterMouseInput(point);
mouseDownLocation = point;
mouseDown(point);
}
///
Call to pass the mouse move event to the in-use tool.
public void MouseMove(Point point) {
point = filterMouseInput(point);
mouseMove(point);
}
///
Call to pass the mouse up event to the in-use tool.
public void MouseUp(Point point) {
point = filterMouseInput(point);
mouseUp(point);
}
public void MouseLeave() {
IsMouseInside = false;
mouseLeave();
}
public void MouseEnter() {
IsMouseInside = true;
mouseEnter();
}
public void Render(Point currentMouseLocation) { Render(Path, currentMouseLocation); }
public void Render(GraphicsPath path, Point currentMouseLocation) {
render(path, filterMouseInput(currentMouseLocation));
}
protected virtual void mouseMove(Point point) {}
protected virtual void mouseUp(Point point) { }
///
This function should be override if it's possible to render with mouseDownLocation and the currentMouseLocation.
/// If this function is not overloaded, drawing is still possible, but preview rendering is not.
protected virtual void render(GraphicsPath path, Point currentMouseLocation) { }
///
Override if mouse down detection is needed
protected virtual void mouseDown(Point point) { }
///
Override if mouse enter detection is needed
protected virtual void mouseEnter() { }
///
Override if mouse up detection is needed
protected virtual void mouseLeave() { }
///
Returns passed point as processed by the list of provided filters in MouseFilterList
protected Point filterMouseInput(Point point) {
foreach (Func curFilter in MouseInputFilters)
point = curFilter(point);
return point;
}
///
Reorders the passed points so that point1 is to the upper left of point2
/// Returns the distance between refactored point1 and point2
protected Size orderPoints(ref Point point1, ref Point point2) {
point1.X = Math.Min(point1.X, point2.X);
point1.Y = Math.Min(point1.Y, point2.Y);
point2.X = Math.Max(point1.X, point2.X);
point2.Y = Math.Max(point1.Y, point2.Y);
return new Size(point2.X - point1.X, point2.Y - point1.Y);
}
///
Returns a rectangle from where MouseDown and mouseUpPoint occured
protected Rectangle mouseDragRectangle(Point mouseUpPoint) {
return new Rectangle(mouseDownLocation, orderPoints(ref mouseDownLocation, ref mouseUpPoint));
}
public override string ToString() { return Name; }
public bool Equals(DrawingTool obj) { return obj.GetHashCode() == GetHashCode(); }
public override int GetHashCode() { return Name.GetHashCode(); }
}
///
A base level null drawing tool for default tool selection
class NullDrawingTool : DrawingTool {
public NullDrawingTool()
: base(string.Empty) { }
}
///
A DrawingTool for drawing single lines
class LineDrawingTool : DrawingTool {
public LineDrawingTool()
: base("Line") { }
protected override void render(GraphicsPath path, Point currentMouseLocation) {
path.AddLine(mouseDownLocation, currentMouseLocation);
}
protected override void mouseUp(Point point) {
Render(point);
}
}
///
A DrawingTool for drawing single rectangles
class RectangleDrawingTool : DrawingTool {
public RectangleDrawingTool()
: base("Rectangle") { }
protected override void render(GraphicsPath path, Point currentMouseLocation) {
path.AddRectangle(mouseDragRectangle(currentMouseLocation));
}
protected override void mouseUp(Point point) {
Render(point);
}
}
///
A DrawingTool for drawing single ellipses
class EllipseDrawingTool : DrawingTool {
public EllipseDrawingTool()
: base("Ellipse") { }
protected override void render(GraphicsPath path, Point currentMouseLocation) {
path.AddEllipse(mouseDragRectangle(currentMouseLocation));
}
protected override void mouseUp(Point point) {
Render(point);
}
}
///
A DrawingTool for 'free hand' drawing
class FreeDrawDrawingTool : DrawingTool {
Point lastPoint;
public FreeDrawDrawingTool()
: base("Free Draw") { }
protected override void mouseDown(Point point) {
lastPoint = point;
}
protected override void mouseMove(Point point) {
if (MouseButtonState == MouseButtons.Left) {
drawLine(point);
lastPoint = point;
}
}
protected override void mouseUp(Point point) {
drawLine(point);
}
private void drawLine(Point point) {
Path.AddLine(lastPoint, point);
}
}
class TextDrawingTool : DrawingTool {
public TextDrawingTool()
: base("Text") { }
enterTextDialog textDialog;
protected override void mouseUp(Point point) {
textDialog = new enterTextDialog(ParentCollection.Preview);
if (textDialog.ShowDialog() == DialogResult.OK)
render(Path, point);
}
void textDialog_PreviewUpdateEvent() {
}
protected override void render(GraphicsPath path, Point currentMouseLocation) {
path.AddString(textDialog.EnteredText,
textDialog.SelectedFont.FontFamily,
(int)textDialog.SelectedFont.Style,
textDialog.SelectedFont.Size,
mouseDownLocation,
StringFormat.GenericDefault);
}
}
}