Profile Picture

How to change standard port shape ?

Posted By michal bandrowski 15 Years Ago
Author
Message
Ivo Milanov
Posted 15 Years Ago
View Quick Profile
Forum Member

Forum Member (35 reputation)Forum Member (35 reputation)Forum Member (35 reputation)Forum Member (35 reputation)Forum Member (35 reputation)Forum Member (35 reputation)Forum Member (35 reputation)Forum Member (35 reputation)Forum Member (35 reputation)

Group: Forum Members
Last Active: 2 Months Ago
Posts: 35, Visits: 15
Hi Michal,

Following is the new source code of the NCreateConnectorTool, which will enter the next release it has two properties - SnapStartPlugToShape and SnapEndPlugToShape which control whether to additionally try to snap to the default shape port below the mouse pointer:

using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Diagnostics;
using System.Windows.Forms;

using Nevron.GraphicsCore;
using Nevron.Dom;
using Nevron.Diagram.Filters;
using Nevron.Diagram.Batches;

namespace Nevron.Diagram.WinForm
{
///
/// The NCreateConnectorTool creates new connectors
///

[Serializable]
public class NCreateConnectorTool : NCreateElementTool
{
#region Constructors

///
/// Default constructor
///

public NCreateConnectorTool()
: base(NDWFR.ToolCreateConnector)
{
m_ConnectorType = ConnectorType.Line;
m_bAllowCreateDisconnected = true;
m_bAllowCreateReflexive = true;
}


#endregion

#region Interface implementations

#region INMouseEventProcessor

///
/// Processes the mouse move event
///

/// mouse event arguments
public override bool ProcessMouseMove(MouseEventArgs e)
{
base.ProcessMouseMove(e);

// if not active - highlight the potential FROM port and request ready to activate cursor
if (m_bIsActive == false)
{
NSnapPointResult res = SnapStartPlug(m_Controller.m_MouseInfo);
NPort port = res.GetValidInwardPort(null);
HighlightPorts(port, null);
RequestReadyToActivateCursor(NDWFR.CursorCreateConnector);
return false;
}

try
{
// snap end point
m_EndSnapRes = SnapEndPlug(m_Controller.m_MouseInfo);

// try to leave the FROM shape
if (m_bHasLeftFromShape == false)
{
m_bHasLeftFromShape = IsMouseInFromShape();
}

// if connector can be created -> highlight the FROM and potential TO ports
// else -> remove highlights and request NO cursor
if (CanCreateConnector())
{
// redefine preview
NShape connector = (m_Preview as NShape);
RedefineConnector(connector, m_StartSnapRes.SnappedPoint, m_EndSnapRes.SnappedPoint);
connector.Visible = true;

// highligth ports, request cursor and valid drag bounds
HighlightPorts(m_StartSnapRes.GetValidInwardPort(null), m_EndSnapRes.GetValidInwardPort(null));
m_View.m_InteractivityManager.RequestCursor(NDWFR.CursorCreateConnector);
m_View.OnDragging(connector.Bounds);
}
else
{
// hide preview
(m_Preview as NShape).Visible = false;

// hide ports, request no cursor and no valid drag bounds
m_View.HighlightedPoints = null;
m_View.m_InteractivityManager.RequestCursor(Cursors.No);
m_View.OnDragging(NRectangleF.Empty);
}
}
catch (Exception ex)
{
Trace.WriteLine("Failed to update connector preview. Exception was: " + ex.Message);
}

return true;
}

#endregion

#endregion

#region Properties

///
/// Specifies the type of connector, which must be created
///

///
/// By default set to Line
///

[Category("Behavior")]
[Description("Specifies the type of connector, which must be created")]
[DefaultValue(ConnectorType.Line)]
public ConnectorType ConnectorType
{
get
{
return m_ConnectorType;
}
set
{
m_ConnectorType = value;
}
}
///
/// Gets/sets whether partially disconnected connectors can be created
///

///
/// By default set to true
///

[Category("Behavior")]
[Description("Gets/sets whether partially disconnected connectors can be created")]
[DefaultValue(true)]
public bool AllowCreateDisconnected
{
get
{
return m_bAllowCreateDisconnected;
}
set
{
m_bAllowCreateDisconnected = value;
}
}
///
/// Gets/sets whether reflexive connectors can be created
///

///
/// By default set to true
///

[Category("Behavior")]
[Description("Gets/sets whether reflexive connectors can be created")]
[DefaultValue(true)]
public bool AllowCreateReflexive
{
get
{
return m_bAllowCreateReflexive;
}
set
{
m_bAllowCreateReflexive = value;
}
}
///
/// Specifies whether to attempt shape snapping if by default the start plug was not snapped to port
///

[Category("Behavior")]
[Description("Specifies whether to attempt shape snapping if by default the start plug was not snapped to port")]
[DefaultValue(false)]
public bool SnapStartPlugToShape
{
get
{
return m_bSnapStartPlugToShape;
}
set
{
m_bSnapStartPlugToShape = value;
}
}
///
/// Specifies whether to attempt shape snapping if by default the end plug was not snapped to port
///

[Category("Behavior")]
[Description("Specifies whether to attempt shape snapping if by default the end plug was not snapped to port")]
[DefaultValue(false)]
public bool SnapEndPlugToShape
{
get
{
return m_bSnapEndPlugToShape;
}
set
{
m_bSnapEndPlugToShape = value;
}
}

#endregion

#region Overrides

///
/// Activates the tool
///

///
/// Overriden to store the FromPort and FromShape parameters as well as to create a connector preview
///

public override void Activate()
{
base.Activate();

// init start and end snap results
m_StartSnapRes = SnapStartPlug(m_StartMouseInfo);
m_EndSnapRes = new NSnapPointResult(m_StartSnapRes.SnappedPoint);

// init the has left from shape
m_bHasLeftFromShape = false;

// create the preview and add it to the preview layer
m_Preview = CreateElement(true);
m_View.m_PreviewLayer.AddChild(m_Preview);
(m_Preview as INVisible).Visible = false;
}
///
/// Deactivates the tool
///

///
/// Overriden to create a new connector
///

public override void Deactivate()
{
// remove port highlights
m_View.HighlightedPoints = null;

// destroy preview
m_View.m_PreviewLayer.RemoveChild(m_Preview);
m_Preview = null;

// do nothing if connector must not be created
if (CanCreateConnector() == false)
{
base.Deactivate();
return;
}

// get the target layer
NLayer layer = TargetLayer;
Debug.Assert(layer != null, "Must not activate if there is no target layer");
if (layer == null)
{
base.Deactivate();
return;
}

m_Document.StartTransaction(NDR.TransactionCreateConnector);

try
{
// create connector
m_Element = CreateElement(false);

// redefine connector
NShape connector = (m_Element as NShape);
RedefineConnector(connector, m_StartSnapRes.SnappedPoint, m_EndSnapRes.SnappedPoint);

// append to layer
NBatchInsert batch = new NBatchInsert(m_Document, m_Element);
NTransactionResult res = batch.Append(layer, false);

if (res.Succeeded)
{
// connect
NPort fromPort = m_StartSnapRes.GetValidInwardPort(null);
if (fromPort != null)
{
connector.StartPlug.Connect(fromPort);
}

NPort toPort = m_EndSnapRes.GetValidInwardPort(null);
if (toPort != null)
{
connector.EndPlug.Connect(toPort);
}

// reflex or reroute
INReflexiveShape reflexive = (connector as INReflexiveShape);
if (reflexive != null && reflexive.CanReflex())
{
reflexive.Reflex();
}
else
{
INRoutableShape routable = (connector as INRoutableShape);
if (routable != null && routable.CanReroute())
{
routable.Reroute();
}
}

// select
if (m_bSelectNewElement)
{
m_View.m_Selection.SingleSelect(m_Element);
}
}
}
catch (Exception ex)
{
Trace.WriteLine("Failed to create connector. Exception was: " + ex.Message);
m_Document.Rollback();
base.Deactivate();
return;
}

m_Document.Commit();
base.Deactivate();
}
///
/// Aborts the tool if it is active
///

///
/// Overriden to destroy the preview
///

public override void Abort()
{
// remove port highlights
m_View.HighlightedPoints = null;

// destroy preview
m_View.m_PreviewLayer.RemoveChild(m_Preview);
m_Preview = null;

base.Abort();
}

#endregion

#region Protected overrides

///
/// Overriden to create a connector from the specified type and with the specified style
///

/// whether the node is for preview
/// new connector
protected override INDiagramElement CreateElement(bool preview)
{
NDiagramElementFactory factory = m_View.ElementFactory;

switch (m_ConnectorType)
{
case ConnectorType.Line:
return factory.CreateLineConnector(preview);

case ConnectorType.Bezier:
return factory.CreateBezierConnector(preview);

case ConnectorType.SingleArrow:
return factory.CreateArrowConnector(preview, ArrowType.SingleArrow);

case ConnectorType.DoubleArrow:
return factory.CreateArrowConnector(preview, ArrowType.DoubleArrow);

case ConnectorType.SideToTopBottom:
return factory.CreateStep2Connector(preview, false);

case ConnectorType.TopBottomToSide:
return factory.CreateStep2Connector(preview, true);

case ConnectorType.SideToSide:
return factory.CreateStep3Connector(preview, false);

case ConnectorType.TopToBottom:
return factory.CreateStep3Connector(preview, true);

case ConnectorType.DynamicHV:
return factory.CreateRoutableConnector(preview, RoutableConnectorType.DynamicHV);

case ConnectorType.DynamicPolyline:
return factory.CreateRoutableConnector(preview, RoutableConnectorType.DynamicPolyline);

case ConnectorType.DynamicCurve:
return factory.CreateRoutableConnector(preview, RoutableConnectorType.DynamicCurve);

default:
Debug.Assert(false, "New connector type?");
break;
}

return null;
}


#endregion

#region Protected overridables

///
/// Redefines the specified connector geometry to connect the specified start and end points
///

///
///
///
protected virtual void RedefineConnector(NShape connector, NPointF start, NPointF end)
{
switch (m_ConnectorType)
{
case ConnectorType.Bezier:
{
NBezierCurveShape bezier = (connector as NBezierCurveShape);

float dx = end.X - start.X;
float dy = end.Y - start.Y;

bezier.Points = new NPointF[]{
start,
new NPointF(start.X + (dx / 2), start.Y),
new NPointF(end.X - (dx / 2), end.Y),
end};
}
break;

case ConnectorType.SingleArrow:
case ConnectorType.DoubleArrow:
{
NArrowShape arrow = (connector as NArrowShape);
float mm = m_Document.MeasurementUnitConverter.ConvertX(NGraphicsUnit.Millimeter, m_Document.WorldMeasurementUnit, 1);
mm = mm / m_Document.SceneScaleToWorldX;
(arrow.Primitive as NArrowPath).DefineModel(arrow.ArrowType, start, end, 5 * mm, 45, 15 * mm);
}
break;

case ConnectorType.Line:
case ConnectorType.SideToTopBottom:
case ConnectorType.TopBottomToSide:
case ConnectorType.SideToSide:
case ConnectorType.TopToBottom:
case ConnectorType.DynamicHV:
case ConnectorType.DynamicPolyline:
case ConnectorType.DynamicCurve:
{
connector.StartPoint = start;
connector.EndPoint = end;
}
break;

default:
Debug.Assert(false, "New connector type?");
break;
}
}
///
/// Highlights the specified ports
///

/// port 1
/// port 2
protected virtual void HighlightPorts(NPort port1, NPort port2)
{
ArrayList points = new ArrayList();

if (port1 != null)
points.Add(port1.Location);

if (port2 != null)
points.Add(port2.Location);

m_View.HighlightedPoints = points;
}

///
/// Determines whether a connector can currently be created
///

///
protected virtual bool CanCreateConnector()
{
NPort fromPort = m_StartSnapRes.GetValidInwardPort(null);
NPort toPort = m_EndSnapRes.GetValidInwardPort(null);

// cannot create a connector with zero length unless at least
// one of its plugs is going to be connected
if (m_StartSnapRes.SnappedPoint == m_EndSnapRes.SnappedPoint && fromPort == null && toPort == null)
return false;

NShape fromShape = GetFromShape();
NShape toShape = GetToShape();

// self loop checks
if (fromShape != null && fromShape == toShape)
{
// cannot create a self loop, if the mouse has not left the from shape
if (m_bHasLeftFromShape == false)
return false;

// cannot create a self loop, if explicitly specified
if (m_bAllowCreateReflexive == false)
return false;
}

// cannot create if either port is not valid and disconnected connectors are not allowed
if (m_bAllowCreateDisconnected == false)
{
if (fromPort == null || toPort == null)
return false;
}

// return true if user allows both ports
return ValidateFromPort(fromPort) && ValidateToPort(toPort);
}

///
/// Gets the from shape
///

///
protected virtual NShape GetFromShape()
{
NPort port = m_StartSnapRes.GetValidInwardPort(null);
if (port == null)
return null;

return port.Shape;
}
///
/// Gets the to shape
///

///
protected virtual NShape GetToShape()
{
NPort port = m_EndSnapRes.GetValidInwardPort(null);
if (port == null)
return null;

return port.Shape;
}
///
/// Determines whether the mouse is in the from shape
///

/// true if the mouse is in the from shape or the from shape does not exist, otherwise false
protected virtual bool IsMouseInFromShape()
{
NShape shape = GetFromShape();
if (shape == null)
return true;

return (shape.HitTest(m_View.GetMousePositionInDevice(), m_View.ProvideDocumentHitTestContext()) == false);
}

///
/// Called to snap the start plug.
/// The default implementation simply calls SnapShapePlug method of the snap manager.
/// Override this method to support custom start plug snapping.
///

///
///
protected virtual NSnapPointResult SnapStartPlug(NMouseInfo mouseInfo)
{
NSnapPointResult res = m_View.SnapManager.SnapShapePlug(mouseInfo.ScenePoint, null);
if (m_bSnapStartPlugToShape == false)
return res;

// successfully snapped to port
if (res.GetValidInwardPort(null) != null)
return res;

// attemp shape snapping
NShape shape = View.LastDocumentHit(mouseInfo.DevicePoint, NFilters.TypeNShape) as NShape;
if (shape == null || shape.Ports == null || shape.Ports.DefaultInwardPort == null)
return res;

NPort port = shape.Ports.DefaultInwardPort;
res.SnappedPoint = port.Location;
res.XSnappedTo.Object = port;
res.XSnappedTo.Type = SnapTargetsMask.Ports;
res.YSnappedTo.Object = port;
res.YSnappedTo.Type = SnapTargetsMask.Ports;

return res;
}
///
/// Called to snap the end plug.
/// The default implementation simply calls SnapShapePlug method of the snap manager.
/// Override this method to support custom end plug snapping.
///

///
///
protected virtual NSnapPointResult SnapEndPlug(NMouseInfo mouseInfo)
{
NSnapPointResult res = m_View.SnapManager.SnapShapePlug(mouseInfo.ScenePoint, null);
if (m_bSnapEndPlugToShape == false)
return res;

// successfully snapped to port
if (res.GetValidInwardPort(null) != null)
return res;

// attemp shape snapping
NShape shape = View.LastDocumentHit(mouseInfo.DevicePoint, NFilters.TypeNShape) as NShape;
if (shape == null || shape.Ports == null || shape.Ports.DefaultInwardPort == null)
return res;

NPort port = shape.Ports.DefaultInwardPort;
res.SnappedPoint = port.Location;
res.XSnappedTo.Object = port;
res.XSnappedTo.Type = SnapTargetsMask.Ports;
res.YSnappedTo.Object = port;
res.YSnappedTo.Type = SnapTargetsMask.Ports;

return res;
}

///
/// Validates the port to which the connector start plug is going to be connected
///

///
///
protected virtual bool ValidateFromPort(NPort port)
{
return true;
}
///
/// Validates the port to which the connector end plug is going to be connected
///

///
///
protected virtual bool ValidateToPort(NPort port)
{
return true;
}

#endregion

#region Protected properties

///
/// Determines whether the mouse has left the from shape (if there was a from shape)
///

protected bool HasLeftFromShape
{
get
{
return m_bHasLeftFromShape;
}
}
///
/// Gets/sets the current snap result for the start connector plug
///

protected NSnapPointResult StartSnapRes
{
get
{
return m_StartSnapRes;
}
set
{
m_StartSnapRes = value;
}
}
///
/// Gets/sets the current snap result for the end connector plug
///

protected NSnapPointResult EndSnapRes
{
get
{
return m_EndSnapRes;
}
set
{
m_EndSnapRes = value;
}
}

#endregion

#region Fields

// properties
internal ConnectorType m_ConnectorType;
internal bool m_bAllowCreateDisconnected;
internal bool m_bAllowCreateReflexive;
internal bool m_bSnapStartPlugToShape;
internal bool m_bSnapEndPlugToShape;

// start and end snap
[NonSerialized] internal NSnapPointResult m_StartSnapRes;
[NonSerialized] internal NSnapPointResult m_EndSnapRes;

// has left start shape
[NonSerialized] internal bool m_bHasLeftFromShape;

#endregion
}
}

Ivo Milanov
Posted 15 Years Ago
View Quick Profile
Forum Member

Forum Member (35 reputation)Forum Member (35 reputation)Forum Member (35 reputation)Forum Member (35 reputation)Forum Member (35 reputation)Forum Member (35 reputation)Forum Member (35 reputation)Forum Member (35 reputation)Forum Member (35 reputation)

Group: Forum Members
Last Active: 2 Months Ago
Posts: 35, Visits: 15

Hi Michal,

1. Regarding highlighted points appearance:

You can override the PaintHighlightedPoints method of the NDrawingView. Following is the default implementation:

protected virtual void PaintHighlightedPoints(NPaintContext context)

{

    if (m_HighlightedPoints == null)

        return;

   

    if (m_HighlightedPointsStroke == null)

    {

        m_HighlightedPointsStroke = new NStrokeStyle(new NLength(2, NGraphicsUnit.Pixel), Color.Red);

    }

   

    float width = m_HighlightedPointsSize.Width;

    float height = m_HighlightedPointsSize.Height;

    int count = m_HighlightedPoints.Count;

   

    context.Device.ActivateStyles(null, m_HighlightedPointsStroke, null);

    IN2DPainter painter = context.Device.Painter;

   

    for (int i = 0; i < count; i++)

    {

        NPointF point = m_SceneToDevice.TransformPoint((NPointF)m_HighlightedPoints[i]);

        painter.PaintRectangle(new NRectangleF(point.X - width / 2, point.Y - height / 2, width, height));

    }

}

The view will display all highlight points with the same appearance.

2. Regarding connector tool:

The connector tool will by default will perform shape plug snapping (via the SnapShapePlug method of the snap manager). Unfortunately we have not wrapped these calls in separate overridable methods that you can simply override in the connector tool (we will do this for the next release however). Later today I will send you a code preview of the new connector tool implementation, and also explain how extend the FROM/TO Shape/Port logic that the connector tool uses.

Best regards,
Ivo



michal bandrowski
questionmark Posted 15 Years Ago
View Quick Profile
Junior Member

Junior Member (10 reputation)Junior Member (10 reputation)Junior Member (10 reputation)Junior Member (10 reputation)Junior Member (10 reputation)Junior Member (10 reputation)Junior Member (10 reputation)Junior Member (10 reputation)Junior Member (10 reputation)

Group: Forum Members
Last Active: 15 Years Ago
Posts: 10, Visits: 1
Hi,

How can I change standard port shape ?

e.g.
--
I'm adding port to group (NGroup)

group.CreateShapeElements(ShapeElementsMask.Ports);
NDynamicPort port = new NDynamicPort(group.UniqueId,
ContentAlignment.MiddleLeft,
DynamicPortGlueMode.GlueToContour);
port.DirectionMode = BoundsPortDirectionMode.AutoSide;
group.Ports.AddChild(port);

then I use NCreateConnectorTool to connect some shape with group.
When mouse cursor is close enough to port, 'port tip' is being shown, but always with the same red square shape (take a look at the attached screenshot - inside blue circle).

I would like to change this 'port tip' to something else, for example change its colors and bounds.
If not, could you please give me a clue, how to made NCreateConnectorTool to recognize whole group (NGroup) area as possible line drop zone, so it will be attached to port ?

Thanks in advance,
Michal

Attachments
ex.PNG (144 views, 52.00 KB)


Similar Topics


Reading This Topic