// (C) Copyright 2019 by
//
using System;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.EditorInput;
#pragma warning disable 0618
// This line is not mandatory, but improves loading performances
[assembly: CommandClass(typeof(CreateMLeader.MyCommands))]
namespace CreateMLeader
{
// This class is instantiated by AutoCAD for each document when
// a command is called by the user the first time in the context
// of a given document. In other words, non static data in this class
// is implicitly per-document!
public class MyCommands
{
[CommandMethod("00MTextToMleader")]
public static void MTextToLeader()
{
// Queue<Entity> entities = SelectionUtilities.SelectObjectsOnScreen2Queue();
// (ObjectId, Point3d, string, double) itemsTuple = entities.Peek().TextPropertyExtractor();
Document doc = Application.DocumentManager.CurrentDocument;
if (doc == null) return;
Editor ed = doc.Editor;
PromptPointResult rsPnt = ed.GetPoint("\nGet start point");
if (rsPnt.Status != PromptStatus.OK)
return;
DirectionalLeader("ABCDEFGH", rsPnt.Value, 100.0);
}
public class DirectionalLeaderJig : EntityJig
{
private Point3d _start, _end;
private string _contents;
private int _index;
private int _lineIndex;
private bool _started;
private ObjectId mlStyleId;
private ObjectId mTextStyleId;
private double width;
public DirectionalLeaderJig(string txt, Point3d start, MLeader ld, double width) : base(ld)
{
// Store info that's passed in, but don't init the MLeader
_contents = txt;
_start = start;
_end = start;
_started = false;
mlStyleId = GetMleaderStyleObjectId();
mTextStyleId = GetMTextStyleObjectId();
this.width = width;
}
// A fairly standard Sampler function
protected override SamplerStatus Sampler(JigPrompts prompts)
{
var po = new JigPromptPointOptions();
po.UserInputControls = (UserInputControls.Accept3dCoordinates | UserInputControls.NoNegativeResponseAccepted);
po.Message = "\nEnd point";
var res = prompts.AcquirePoint(po);
if (_end == res.Value)
{
return SamplerStatus.NoChange;
}
else
if (res.Status == PromptStatus.OK)
{
_end = res.Value;
return SamplerStatus.OK;
}
return SamplerStatus.Cancel;
}
protected override bool Update()
{
var ml = (MLeader)Entity;
if (!_started)
{
if (_start.DistanceTo(_end) > Tolerance.Global.EqualPoint)
{
// When the jig actually starts - and we have mouse movement -
// we create the MText and init the MLeader
ml.ContentType = ContentType.MTextContent;
ml.MLeaderStyle = mlStyleId;
var mt = new MText();
mt.SetDatabaseDefaults();
mt.TextStyleId = mTextStyleId;
mt.Width = width;
using (TextStyleTableRecord txtTblRec =
mTextStyleId.Open(OpenMode.ForRead) as TextStyleTableRecord)
{
mt.TextHeight = txtTblRec.TextSize;
}
mt.Contents = _contents;
ml.MText = mt;
// Create the MLeader cluster and add a line to it
_index = ml.AddLeader();
_lineIndex = ml.AddLeaderLine(_index);
// Set the vertices on the line
ml.AddFirstVertex(_lineIndex, _start);
ml.AddLastVertex(_lineIndex, _end);
// Make sure we don't do this again
_started = true;
}
}
else
{
// We only make the MLeader visible on the second time through
// (this also helps avoid some strange geometry flicker)
ml.Visible = true;
// We already have a line, so just set its last vertex
ml.SetLastVertex(_lineIndex, _end);
}
if (_started)
{
// Set the direction of the text to depend on the X of the end-point
// (i.e. is if to the left or right of the start-point?)
var dl = new Vector3d((_end.X >= _start.X ? 1 : -1), 0, 0);
ml.SetDogleg(_index, dl);
}
return true;
}
public static ObjectId GetMleaderStyleObjectId()
{
var doc = Application.DocumentManager.MdiActiveDocument;
var ed = doc.Editor;
var db = doc.Database;
var tr = db.TransactionManager.StartTransaction();
ObjectId mlStyleId = ObjectId.Null;
using (tr)
{
DBDictionary mlStyles = (DBDictionary)tr.GetObject(db.MLeaderStyleDictionaryId, OpenMode.ForRead);
if (mlStyles.Contains("Multileader"))
{
mlStyleId = mlStyles.GetAt("Multileader");
}
tr.Commit();
}
return mlStyleId;
}
public static ObjectId GetMTextStyleObjectId()
{
var doc = Application.DocumentManager.MdiActiveDocument;
var ed = doc.Editor;
var db = doc.Database;
var tr = db.TransactionManager.StartTransaction();
ObjectId mlStyleId = ObjectId.Null;
using (tr)
{
TextStyleTable mlStyles = (TextStyleTable)tr.GetObject(db.TextStyleTableId, OpenMode.ForRead);
if (mlStyles.Has("Standard"))
{
mlStyleId = mlStyles["Standard"];
}
tr.Commit();
}
return mlStyleId;
}
}
public static void DirectionalLeader(string content, Point3d start, double width)
{
var doc = Application.DocumentManager.MdiActiveDocument;
var ed = doc.Editor;
var db = doc.Database;
// Start a transaction, as we'll be jigging a db-resident object
using (var tr = db.TransactionManager.StartTransaction())
{
var bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead, false);
var btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite, false);
// Create and pass in an invisible MLeader
// This helps avoid flickering when we start the jig
var ml = new MLeader();
ml.Visible = false;
// Create jig
var jig = new DirectionalLeaderJig(content, start, ml, width);
// Add the MLeader to the drawing: this allows it to be displayed
btr.AppendEntity(ml);
tr.AddNewlyCreatedDBObject(ml, true);
// Set end point in the jig
var res = ed.Drag(jig);
// If all is well, commit
if (res.Status == PromptStatus.OK)
{
tr.Commit();
}
}
}
}
}