Manipulating Polygons Tutorial |
The Telogis.GeoBase.ShapeUI namespace includes the PolygonEntity and ShapeLayer classes. These are used to create and manipulate polygon shapes on a canvas.
In this tutorial we will create an application that demonstrates:
creation of a ShapeUI layer using the ShapeLayer class
creation of a polygon shape using the PolygonEntity class
the manipulation of a polygon's geometry by adding, moving and deleting polygon vertices (the junctures at which two line segments meet)
deleting a polygon shape
moving shapes up and down in rendering priority (that is, the z-index order in which shapes are rendered on a canvas)
The application we create will draw polygon shapes on the map, and allow the geometry of these shapes to be edited in real-time using a mouse. It will also allow the layer priority of shapes to be adjusted (moving the shape up or down the z-order: useful when shapes overlap), and individual shapes on a layer to be deleted, or an entire layer cleared.
The application will also include a status text field containing details of each action being performed on the selected shape.
Note |
---|
The complete code for the project example created in this tutorial is included at the bottom of this page. |
Create a new Visual Studio Project (a Windows Forms Application) called 'PolygonEditor'.
Add a reference to geobase.net.dll then switch to the Visual Studio 'Code' view (F7). To make the code simpler and more readable, add the following using directives to the top of the project form (Form1.cs).
using Telogis.GeoBase; using Telogis.GeoBase.Routing; using Telogis.GeoBase.ShapeUI; using Telogis.GeoBase.ShapeUI.State; using Telogis.GeoBase.Geometry;
Return to the 'Design' view (Shift+F7) and add the following controls to the form:
a GeoBase MapCtrl control named mapMain
a text box named statusBox
a button named deleteButton with the label text 'Delete'
a button named editButton with the label text 'Edit'
a button named zoomButtonIn with the label text 'Zoom In'
a button named zoomButtonOut with the label text 'Zoom Out'
a button named priorityButtonUp with the label text 'Move Shape Up'
a button named priorityButtonDown with the label text 'Move Shape Down'
a button named deleteAllButton with the label text 'Delete All Shapes'
Re-size and move your new controls such that they appear similar to the screenshot below:
Now add click events to all seven buttons, and a load event to the Form itself (Form1_Load). We will return to these and update them as we progress through this tutorial.
Note |
---|
The statusBox text box should be set to MultiLine. To do so, click the small arrow in the upper right corner of the text field when viewed in Visual Studio's 'Design' view and select the 'MultiLine' check box option. |
Next, return to 'Code' view (F7) and add the following code to the top of the project such that it is global (immediately above the Form1 constructor).
This code will:
declare a ShapeLayer instance named myLayer
set an initial integer value of 0 to be used as a counter when setting the priority of any new PolygonEntity we create on the ShapeLayer
create an inherited MyShapeLayer class containing a #ctor constructor, and retrieve the created ShapeLayer's state using the ShapeLayer class GetDefaultState method and the SelectState constructor
public ShapeLayer myLayer; public int priority = 0; public class MyShapeLayer : ShapeLayer { public MyShapeLayer(IMap map) : base(map) { } public override IState GetDefaultState() { return new SelectState(this, null); } }
Add the following code to the Form1_Load method. This will create a new ShapeLayer using the #ctor constructor (using the IMap object mapMain). We then add events that will be triggered by any changes to the created layer (the ModeChanged, SelectionChanged, ShapeAdded, ShapeRemoved events).
It will also:
create a number of mouse events on mapMain to track mouse movements across the map
set up the map, including disabling ClickToCenter (we will be using mouse clicks to trigger our own actions, so need to turn off the default GeoBase actions)
set the visibility and state of five of our seven UI buttons using a call to UpdateButtons
add some initial text to the statusBox as a guide to users when the application is first launched.
// create new shapelayer myLayer = new MyShapeLayer(mapMain); // add an event for when the layer needs to redraw myLayer.RedrawRequired += OnRedrawRequired; // enter selection mode myLayer.EnterSelectMode(); // create events when the layer mode changes myLayer.ModeChanged += new EventHandler<EventArgs>(myLayer_ModeChanged); myLayer.SelectionChanged += new EventHandler<EventArgs>(myLayer_SelectionChanged); myLayer.ShapeAdded += new EventHandler<ShapeEntityEventArgs>(myLayer_ShapeAdded); myLayer.ShapeRemoved += new EventHandler<ShapeEntityEventArgs>(myLayer_ShapeRemoved); // set the renderer for the layer mapMain.Renderer = myLayer; // create events for mouse movements mapMain.MouseMove += OnMouseMove; mapMain.MouseUp += OnMouseUp; mapMain.MouseDown += OnMouseDown; mapMain.MouseClick += OnMouseClick; mapMain.MouseLeave += OnMouseLeave; // set up the map mapMain.ClickToCenter = false; mapMain.AllowEdgePan = false; mapMain.Zoom = 40; mapMain.Anchor = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Right; // set up the visibility of the edit and delete buttons UpdateButtons(); // hide the buttons in the upper-left corner of the map priorityButtonUp.Visible = false; priorityButtonDown.Visible = false; deleteAllButton.Visible = false; // show a hint to users in the text box statusBox.Text = "Right-click the map to add a new shape.";
Below the Form1_Load method, add the following methods. These will be called by the events we added above whenever the content of the myLayer ShapeLayer is changed.
These methods contain new text content for the statusBox which will provide users with information about the state of the myLayer ShapeLayer. The myLayer_ModeChanged method also calls UpdateButtons, which determines whether to show or hide some of our buttons (those that should only be visible when myLayer has an active Selection).
void myLayer_ShapeRemoved(object sender, ShapeEntityEventArgs e) { // update the text box when a shape is removed statusBox.Text = "A shape has been deleted."; } void myLayer_ShapeAdded(object sender, ShapeEntityEventArgs e) { // update the text box when a shape is added statusBox.Text = "A shape has been added."; } // update the text box when the shape selection changes void myLayer_SelectionChanged(object sender, EventArgs e) { // if there is a selection if (myLayer.Selection != null) { // advise that a polygon is selected statusBox.Text = "A shape has been selected."; } else { // or if not, advise that there is no selection statusBox.Text = "No shapes on the canvas are currently selected."; } } void myLayer_ModeChanged(object sender, EventArgs e) { // update the text box when the selection mode changes statusBox.Text = "Mode has changed to " + myLayer.CurrentMode.ToString() + " \r\n"; UpdateButtons(); }
Directly below the myLayer_ModeChanged method, add the following UpdateButtons method. This code determines what text will be displayed on the editButton by checking the ShapeLayer's CurrentMode.
It will then check the myLayer ShapeLayer's Selection property and either enable or disable editButton, and deleteButton in the lower left corner of the window, and show or hide the priorityButtonUp, priorityButtonDown, and deleteAllButton buttons located in the upper left corner of the map.
void UpdateButtons() { // change the edit button text depending on the selection mode if (myLayer.CurrentMode == ShapeLayer.Mode.Edit) { editButton.Text = "Done"; } else { editButton.Text = "Edit"; } // change the edit and deleted button state depending on the // selection state if (myLayer.Selection != null) { editButton.Enabled = true; deleteButton.Enabled = true; priorityButtonUp.Visible = true; priorityButtonDown.Visible = true; deleteAllButton.Visible = true; } else { editButton.Enabled = false; deleteButton.Enabled = false; priorityButtonUp.Visible = false; priorityButtonDown.Visible = false; deleteAllButton.Visible = false; } }
Next, add the following three methods below the UpdateButtons method. These will be called by mouse events placed in the Form1_Load method to track mouse activity on the map.
// gather information when the mouse is used void OnMouseMove(object sender, MouseEventArgs e) { myLayer.OnMouseMove(sender, e); } void OnMouseUp(object sender, MouseEventArgs e) { myLayer.OnMouseUp(sender, e); } void OnMouseDown(object sender, MouseEventArgs e) { myLayer.OnMouseDown(sender, e); }
Our shape will be created, and its state edited, using mouse actions. The following code creates a BoundingBox at the current mouse location, listing every shape found within it in an entities list.
If the left mouse button is clicked, and no shape is found below the mouse cursor (that is, the entities list is empty), the layer's Selection property it set to null.
If the right mouse button is clicked, and the entities list is not empty (that is, there is a shape below the mouse cursor) then the first shape in the entities list array will enter Edit mode, allowing its geometry to be edited.
If the right mouse button is clicked, and entities list is empty, then a new polygon (myPol) is created at the mouse location, and a PolygonEntity named myEntity created using the polygon, given a blue color fill, then added to the myLayer ShapeLayer using the AddShape method. The map is then invalidated, causing the shape to be rendered immediately.
Note |
---|
Each new myEntity object created will be given a higher priority than its immediate predecessor using the priority counter. Doing so ensures that newer objects are rendered on the canvas later than older objects, keeping in their correct relative order. |
This snippet also adds several events (IsHighlightedChanged, GeometryChanged, and IsSelectedChanged) and OnEntityChanged that will call our own OnEntityChanged method.
Paste the following code directly below the OnMouseDown method.
// when the mouse is clicked void OnMouseClick(object sender, MouseEventArgs e) { if (!myLayer.OnMouseClick(sender, e)) { // get the location of the mouse click LatLon loc = mapMain.XYtoLatLon(e.X, e.Y); // list all shapes within a boundingbox // created using the current location List<ShapeEntity> entities = myLayer.QueryShapes(new BoundingBox(loc)); entities.RemoveAll(shape => !shape.HitTest(loc)); // if the left mouse button was clicked if (e.Button == System.Windows.Forms.MouseButtons.Left) { // and there was no shape beneath if (entities.Count == 0) { // there is no selection myLayer.Selection = null; } } // if the right mouse button was clicked if (e.Button == System.Windows.Forms.MouseButtons.Right) { // and there is one or more shapes if (entities.Count > 0) { // edit the shape myLayer.Edit(entities[0]); } else { // otherwise create a polygon based on the map zoom int size = 50; Telogis.GeoBase.Geometry.Polygon myPol = new Telogis.GeoBase.Geometry.Polygon( new Telogis.GeoBase.Geometry.LineString[] { new Telogis.GeoBase.Geometry.LineString( mapMain.XYtoLatLon(e.X - size, e.Y - size), mapMain.XYtoLatLon(e.X - size, e.Y + size), mapMain.XYtoLatLon(e.X + size, e.Y + size), mapMain.XYtoLatLon(e.X + size, e.Y - size), mapMain.XYtoLatLon(e.X - size, e.Y - size) ) } ); // then create a polygon shape entity on the layer PolygonEntity myEntity = new PolygonEntity(myLayer, myPol); myEntity.Priority = priority; priority++; // give it a blue fill myEntity.Fill = new SolidBrush(Color.DeepSkyBlue); // create some events triggered when the shape's // properties are changed myEntity.IsHighlightedChanged += OnEntityChanged; myEntity.GeometryChanged += OnGeometryChanged; myEntity.IsSelectedChanged += OnEntityChanged; OnEntityChanged(myEntity, EventArgs.Empty); // add the shape to the layer myLayer.AddShape(myEntity); // and invalidate the map to show the shape mapMain.Invalidate(); } } } }
Copy the following method below the OnMouseClick method. The OnEntityChanged method specifies the entity shape's appearance when in its selected or unselected states (as determined by the IsSelected property).
When not selected, the shape will have a thin black border; when selected, a thick black border.
// when the shape is selected give it a thick // black border. When it isn't, a thin one void OnEntityChanged(object sender, EventArgs e) { PolygonEntity entity = (PolygonEntity)sender; if (entity.IsSelected) { entity.Outline = new Pen(Color.Black, 5.0f); } else { entity.Outline = new Pen(Color.Black, 1.0f); } }
Copy the following methods below the OnEntityChanged method. These are invoked by the ShapeEntity events in the OnMouseClick method, and the RedrawRequired event in Form1_Load. These will update the editButton text, monitor mouse movements, and invalidate the map when needed.
// if the shape's geometry is changed - a vertice added, // deleted or moved - notify in the text field void OnGeometryChanged(object sender, EventArgs e) { statusBox.Text = "The shape's geometry has been changed."; } void OnMouseLeave(object sender, EventArgs e) { myLayer.OnMouseLeave(sender, e); } // if a redraw is needed, invalidate the map void OnRedrawRequired(object sender, EventArgs e) { mapMain.Invalidate(); }
Now we will configure the click methods for the zoom buttons zoomButtonOut and zoomButtonIn and the delete and edit buttons deleteButton and editButton. Update these methods in your project to match to code below.
Note |
---|
The order of these methods may differ in your project to those shown below. Their order is unimportant and determined by the order of their initial creation. Update the methods individually. |
The zoom in and out buttons simply adjust the map zoom using the Zoom property.
The deleteButton method checks that there is an active Selection on myLayer, then deletes the shape selection using RemoveShape if one is found.
The editButton checks the status of the shape using the CurrentMode property. If the layer is already in Edit mode, the layer's mode is changed to Select using the FinishEditing method. If the layer is not already in Edit mode (as described by ShapeLayerMode enumeration), the ShapeLayer enters Edit mode allowing the shape's geometry to be manually manipulated.
// zoom out when the zoom out button is clicked private void zoomButtonOut_Click(object sender, EventArgs e) { mapMain.Zoom = mapMain.Zoom + 2; }
// zoom in when the zoom in button is clicked private void zoomButtonIn_Click(object sender, EventArgs e) { mapMain.Zoom = mapMain.Zoom - 2; }
// if the delete button is clicked private void deleteButton_Click(object sender, EventArgs e) { // check that there is an active selection if (myLayer.Selection != null) { // if there is, remove the entity myLayer.RemoveShape(myLayer.Selection); } }
// if the edit button is clicked private void editButton_Click(object sender, EventArgs e) { // and the layer is in edit mode if (myLayer.CurrentMode == ShapeLayer.Mode.Edit) { // finish editing myLayer.FinishEditing(); // if it isn't in edit mode } else if (myLayer.Selection != null) { // begin editing the selection myLayer.Edit(myLayer.Selection); } }
We will also configure the methods needed for the two layer priority buttons priorityButtonUp and priorityButtonDown. Update these methods to match to code below.
These methods increase or lower the numeric priority of the selected shape using the Selection property. Increasing a shape's priority renders it higher in the z-index order, eventually bringing shapes placed below other shapes to the top. Reducing its priority will push the shape back, causing it to be rendered below other shapes sharing the same canvas area.
// increase the priority of the shape. If several shapes overlap, // use this to adjust their rendering order private void priorityButtonUp_Click(object sender, EventArgs e) { myLayer.Selection.Priority++; mapMain.Invalidate(); statusBox.Text = "The shape's priority has been increased."; }
// lower the priority of the shape. If several shapes overlap, // use this to adjust their rendering order private void priorityButtonDown_Click(object sender, EventArgs e) { myLayer.Selection.Priority--; mapMain.Invalidate(); statusBox.Text = "The shape's priority has been reduced."; }
Update the deleteAllButton_Click method to match the code below. This simply:
deletes everything on the myLayer ShapeLayer using the Clear method
updates the statusBox text to advise that the layer's content has been deleted
hides to map buttons displayed in the upper left corner of the map
// delete all shapes on the layer private void deleteAllButton_Click(object sender, EventArgs e) { myLayer.Clear(); mapMain.Invalidate(); statusBox.Text = "All shapes have been deleted from the canvas."; priorityButtonUp.Visible = false; priorityButtonDown.Visible = false; deleteAllButton.Visible = false; }
To add some convenience to users, we will change the cursor to the drag hand, using the DragBehavior property, when the shift key is held down. Paste the following Form1_KeyDown method into the project. Like our other methods, the location of this method is unimportant, but for this example we place it below all other methods.
// show the drag hand when holding down the keyboard shift key private void Form1_KeyDown(object sender, KeyEventArgs e) { if ((e.Modifiers & Keys.Shift) == Keys.Shift && mapMain.DragBehavior == DragBehavior.Box) { mapMain.DragBehavior = DragBehavior.Hand; } }
And finally, add the following line to the Form1 method (directly below the InitializeComponent constructor). This will call the Form1_KeyDown method using the standards Windows KeyDown event.
this.KeyDown += new KeyEventHandler(Form1_KeyDown);
Run the application. Add new polygon shapes by right-clicking the map and delete them by clicking with your mouse, then clicking Delete.
Note the text displayed in the statusBox text field. It will be updated with details of your actions as they are carried out.
To edit a shape, click the shape then click Edit (or simply right-click a shape: this is an automatic function). Edit the polygon's shape by dragging the border of the shape (doing so will add a new vertex) or by dragging existing vertices (identified as red circles, as in the image below). To delete an existing vertex, simply right-click it.
Place several polygon shapes close to one another such that they overlap, then select a shape and click the Move Shape Up or Move Shape Down buttons to show the effect of changing priority. If a polygon is selected and the layer is changed to Edit mode (by clicking the Edit button or right-clicking the shape), the priority of the selected shape will be increased to ensure that the entire shape is visible above any other shapes sharing the same space on the canvas (temporarily raising it above any overlapping shapes if needed). When editing has been completed, the shape's priority will return to its previous value.
Click Delete All Shapes to clear all shapes from the canvas (note that a shape must be selected on the map to view this button).
Note |
---|
The Edit and Delete buttons will only be active, and the Move Shape Up, Move Shape Down and Delete All Shapes buttons only visible, when a shape has been selected. |
Click any area outside the polygon to exit select mode, and right-click a polygon or click the Done button to exit edit mode.
The complete code for this example project is included below:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using Telogis.GeoBase; using Telogis.GeoBase.ShapeUI; using Telogis.GeoBase.ShapeUI.State; using Telogis.GeoBase.Geometry; namespace PolygonEditor { public partial class Form1 : Form { public ShapeLayer myLayer; public int priority = 0; public class MyShapeLayer : ShapeLayer { public MyShapeLayer(IMap map) : base(map) { } public override IState GetDefaultState() { return new SelectState(this, null); } } public Form1() { InitializeComponent(); this.KeyDown += new KeyEventHandler(Form1_KeyDown); } private void Form1_Load(object sender, EventArgs e) { // create new shapelayer myLayer = new MyShapeLayer(mapMain); // add an event for when the layer needs to redraw myLayer.RedrawRequired += OnRedrawRequired; // enter selection mode myLayer.EnterSelectMode(); // create events when the layer mode changes myLayer.ModeChanged += new EventHandler<EventArgs>(myLayer_ModeChanged); myLayer.SelectionChanged += new EventHandler<EventArgs>(myLayer_SelectionChanged); myLayer.ShapeAdded += new EventHandler<ShapeEntityEventArgs>(myLayer_ShapeAdded); myLayer.ShapeRemoved += new EventHandler<ShapeEntityEventArgs>(myLayer_ShapeRemoved); // set the renderer for the layer mapMain.Renderer = myLayer; // create events for mouse movements mapMain.MouseMove += OnMouseMove; mapMain.MouseUp += OnMouseUp; mapMain.MouseDown += OnMouseDown; mapMain.MouseClick += OnMouseClick; mapMain.MouseLeave += OnMouseLeave; // set up the map mapMain.ClickToCenter = false; mapMain.AllowEdgePan = false; mapMain.Zoom = 40; mapMain.Anchor = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Right; // set up the visibility of the edit and delete buttons UpdateButtons(); // hide the buttons in the upper-left corner of the map priorityButtonUp.Visible = false; priorityButtonDown.Visible = false; deleteAllButton.Visible = false; // show a hint to users in the text box statusBox.Text = "Right-click the map to add a new shape."; } void myLayer_ShapeRemoved(object sender, ShapeEntityEventArgs e) { // update the text box when a shape is removed statusBox.Text = "A shape has been deleted."; } void myLayer_ShapeAdded(object sender, ShapeEntityEventArgs e) { // update the text box when a shape is added statusBox.Text = "A shape has been added."; } // update the text box when the shape selection changes void myLayer_SelectionChanged(object sender, EventArgs e) { // if there is a selection if (myLayer.Selection != null) { // advise that a polygon is selected statusBox.Text = "A shape has been selected."; } else { // or if not, advise that there is no selection statusBox.Text = "No shapes on the canvas are currently selected."; } } void myLayer_ModeChanged(object sender, EventArgs e) { // update the text box when the selection mode changes statusBox.Text = "Mode has changed to " + myLayer.CurrentMode.ToString() + " \r\n"; UpdateButtons(); } void UpdateButtons() { // change the edit button text depending on the selection mode if (myLayer.CurrentMode == ShapeLayer.Mode.Edit) { editButton.Text = "Done"; } else { editButton.Text = "Edit"; } // change the edit and deleted button state depending on the // selection state if (myLayer.Selection != null) { editButton.Enabled = true; deleteButton.Enabled = true; priorityButtonUp.Visible = true; priorityButtonDown.Visible = true; deleteAllButton.Visible = true; } else { editButton.Enabled = false; deleteButton.Enabled = false; priorityButtonUp.Visible = false; priorityButtonDown.Visible = false; deleteAllButton.Visible = false; } } // gather information when the mouse is used void OnMouseMove(object sender, MouseEventArgs e) { myLayer.OnMouseMove(sender, e); } void OnMouseUp(object sender, MouseEventArgs e) { myLayer.OnMouseUp(sender, e); } void OnMouseDown(object sender, MouseEventArgs e) { myLayer.OnMouseDown(sender, e); } // when the mouse is clicked void OnMouseClick(object sender, MouseEventArgs e) { if (!myLayer.OnMouseClick(sender, e)) { // get the location of the mouse click LatLon loc = mapMain.XYtoLatLon(e.X, e.Y); // list all shapes within a boundingbox // created using the current location List<ShapeEntity> entities = myLayer.QueryShapes(new BoundingBox(loc)); entities.RemoveAll(shape => !shape.HitTest(loc)); // if the left mouse button was clicked if (e.Button == System.Windows.Forms.MouseButtons.Left) { // and there was no shape beneath if (entities.Count == 0) { // there is no selection myLayer.Selection = null; } } // if the right mouse button was clicked if (e.Button == System.Windows.Forms.MouseButtons.Right) { // and there is one or more shapes if (entities.Count > 0) { // edit the shape myLayer.Edit(entities[0]); } else { // otherwise create a polygon based on the map zoom int size = 50; Telogis.GeoBase.Geometry.Polygon myPol = new Telogis.GeoBase.Geometry.Polygon( new Telogis.GeoBase.Geometry.LineString[] { new Telogis.GeoBase.Geometry.LineString( mapMain.XYtoLatLon(e.X - size, e.Y - size), mapMain.XYtoLatLon(e.X - size, e.Y + size), mapMain.XYtoLatLon(e.X + size, e.Y + size), mapMain.XYtoLatLon(e.X + size, e.Y - size), mapMain.XYtoLatLon(e.X - size, e.Y - size) ) } ); // then create a polygon shape entity on the layer PolygonEntity myEntity = new PolygonEntity(myLayer, myPol); myEntity.Priority = priority; priority++; // give it a blue fill myEntity.Fill = new SolidBrush(Color.DeepSkyBlue); // create some events triggered when the shape's // properties are changed myEntity.IsHighlightedChanged += OnEntityChanged; myEntity.GeometryChanged += OnGeometryChanged; myEntity.IsSelectedChanged += OnEntityChanged; OnEntityChanged(myEntity, EventArgs.Empty); // add the shape to the layer myLayer.AddShape(myEntity); // and invalidate the map to show the shape mapMain.Invalidate(); } } } } // when the shape is selected give it a thick // black border. When it isn't, a thin one void OnEntityChanged(object sender, EventArgs e) { PolygonEntity entity = (PolygonEntity)sender; if (entity.IsSelected) { entity.Outline = new Pen(Color.Black, 5.0f); } else { entity.Outline = new Pen(Color.Black, 1.0f); } } // if the shape's geometry is changed - a vertice added, // deleted or moved - notify in the text field void OnGeometryChanged(object sender, EventArgs e) { statusBox.Text = "The shape's geometry has been changed."; } void OnMouseLeave(object sender, EventArgs e) { myLayer.OnMouseLeave(sender, e); } // if a redraw is needed, invalidate the map void OnRedrawRequired(object sender, EventArgs e) { mapMain.Invalidate(); } // zoom out when the zoom out button is clicked private void zoomButtonOut_Click(object sender, EventArgs e) { mapMain.Zoom = mapMain.Zoom + 2; } // zoom in when the zoom in button is clicked private void zoomButtonIn_Click(object sender, EventArgs e) { mapMain.Zoom = mapMain.Zoom - 2; } // if the delete button is clicked private void deleteButton_Click(object sender, EventArgs e) { // check that there is an active selection if (myLayer.Selection != null) { // if there is, remove the entity myLayer.RemoveShape(myLayer.Selection); } } // if the edit button is clicked private void editButton_Click(object sender, EventArgs e) { // and the layer is in edit mode if (myLayer.CurrentMode == ShapeLayer.Mode.Edit) { // finish editing myLayer.FinishEditing(); // if it isn't in edit mode } else if (myLayer.Selection != null) { // begin editing the selection myLayer.Edit(myLayer.Selection); } } // increase the priority of the shape. If several shapes overlap, // use this to adjust their rendering order private void priorityButtonUp_Click(object sender, EventArgs e) { myLayer.Selection.Priority++; mapMain.Invalidate(); statusBox.Text = "The shape's priority has been increased."; } // lower the priority of the shape. If several shapes overlap, // use this to adjust their rendering order private void priorityButtonDown_Click(object sender, EventArgs e) { myLayer.Selection.Priority--; mapMain.Invalidate(); statusBox.Text = "The shape's priority has been reduced."; } // delete all shapes on the layer private void deleteAllButton_Click(object sender, EventArgs e) { myLayer.Clear(); mapMain.Invalidate(); statusBox.Text = "All shapes have been deleted from the canvas."; priorityButtonUp.Visible = false; priorityButtonDown.Visible = false; deleteAllButton.Visible = false; } // show the drag hand when holding down the keyboard shift key private void Form1_KeyDown(object sender, KeyEventArgs e) { if ((e.Modifiers & Keys.Shift) == Keys.Shift && mapMain.DragBehavior == DragBehavior.Box) { mapMain.DragBehavior = DragBehavior.Hand; } } } }