Intelligent custom object handles in MultiCAD.NET



    Ease of editing drawings is one of the key characteristics of CAD systems. An important tool for working with drawing objects is grips - special markers at key points of the object that allow you to modify the object with the mouse, without using the menu or command line.

    The handle control mechanism in MultiCAD.NET allows you to work with both simple and intelligent pens. We wrote about simple pens in a previous article, here we will consider intelligent pens, which, in addition to the shape (round, triangular, diamond-shaped, etc.), differ from simple ones in that they can change individual parameters of an object, call a pop-up menu, or perform a set of actions defined in a handler. In addition to this smart pen API, you can also create simple pens, but using a new, unified approach.

    Under the cut, the code for creating several types of smart pens of the object and animated images demonstrating their use.

    McSmartGrip <T> Class


    The MultiCAD.NET API uses a class to describe smart pens McSmartGrip<T>. This class contains several constructor options with various lists of parameters, as well as event handlers that are generated depending on user actions:

    • MoveGrip - called when the handle is moved,
    • MouseMove - called when moving the pen interactive type,
    • GetContextMenu- called when you click on the handle with the type GripType.PopupMenu,
    • OnCommand- is called when you click on the handle with the type GripType.Buttonor on the context menu item obtained from GetContextMenu.

    For example, to create a simple pen that is responsible for moving the point of an object, the following constructor can be used:
    var simpleGrip = new McSmartGrip<ObjectRefEntity>(position, (obj, g, offset) => { obj.TryModify(); obj._pnt += offset; }
    

    This constructor provides for the implementation of the delegate MoveGrip, which we did using the lambda expression ( http://msdn.microsoft.com/ru-ru/library/bb397687.aspx ), namely, we moved the position of the object by an amount offset.

    Handle Registration


    Handles of a custom object are registered using the AppendGrip()class method GripPointsInfo:
    publicvoidAppendGrip(Multicad.CustomObjectBase.McBaseGrip grip);
    

    This class is used as an argument to a method GetGripPoints()that is called to get handles each time an object is displayed:
    publicvirtualboolGetGripPoints(Multicad.CustomObjectBase.GripPointsInfo info); 
    

    The following code snippet creates and adds the same simple pen:

    publicoverrideboolGetGripPoints(GripPointsInfo info)
    {
      info.AppendGrip(new McSmartGrip<ObjectRefEntity>(_pnt, (obj, g, offset) => { obj.TryModify(); obj._pnt += offset; }));
    }
    

    As you can see, the whole procedure is very compact and takes only one line of code. However, this concerned the most elementary case, namely, simple pens. Let's look at what other types of pens are supported in the MultiCAD.NET API, as well as the specifics of working with each of them.

    Types of pens


    Using MulitiCAD.NET, you can create the following types of pens:
    • Simple - a simple pen. Handle handling processing is implemented in MoveGrip.
    • PopupMenu - a pen that, when clicked, displays pop-up menus. Event handling is implemented in OnCommand.
    • Button - a pen-button, when pressed, the actions described in OnCommand.
    • Interactive - a type that is similar to Simple, but allows you to work with object snaps. Unlike a simple handle, event handling is implemented in MouseMove.


    The appearance of the pens


    One object may contain several pens of various types; in order to visually distinguish them, you can assign the appearance of each of them, determining its shape and color. The variety of shapes of pens is determined by enumeration McBaseGrip.GripAppearance. Here are some of them:



    You can also set the desired color of the pens from the set of colors defined in the class GripColors, or you can define the color in the standard way using System.Drawing.Color.
    Let's see how it works. As an example, we take the familiar primitive TextInBoxdescribed in this article and create several intelligent pens of various types for it.

    Simple pen

    We already mentioned this type of pens in the article, and, as the name suggests, it is used for simple actions, for example, for moving points of an object. Add one simple handle to move the corner point of our primitive:
    info.AppendGrip(new McSmartGrip<ObjectRefEntity>(_pnt, (obj, g, offset) => { obj.TryModify(); obj._pnt += offset; }));
    

    The result of the operation of such a pen is in the animated illustration:



    Knob

    Add a pen-button that will control the display of the frame around the text by clicking. To create such a pen, use the constructor with the type of pen McBaseGrip.GripType.Buttonand the base color. The button handler OnCommand changes the value of the frame drawing indicator _show_frameto the opposite. For the created button-handle, we define the appearance “on”, which will change to “off” when pressed, and vice versa.

    var OnOffGrip = new McSmartGrip<TextInBox>(McBaseGrip.GripType.Button, 1, _pnt +  stepVector, 
                                         McBaseGrip.GripAppearance.SwitchOn, 0, "Hide Frame", GripColors.Base);
    OnOffGrip.Tag = "OnOffGrip";
    if (_show_frame == false)
      OnOffGrip.SetAppearanceAndText(McBaseGrip.GripAppearance.SwitchOff, "Show frame");
    OnOffGrip.OnCommand = (obj, commandId, grip) => { obj.TryModify(); obj._show_frame = !obj._show_frame;};
    info.AppendGrip(OnOffGrip);
    


    Result:



    Also, by pressing the knob, the necessary registered command can be called up:

    var cmdGrip = new McSmartGrip<TextInBox>( McBaseGrip.GripType.Button, 1, _pnt + 2 * stepVector, 
                                       McBaseGrip.GripAppearance.Circle, 0, "button", GripColors.Base);
    cmdGrip.Tag="cmd";
    cmdGrip.OnCommand = (obj, commandId, grip) =>
    {
      McContext.ExecuteCommand(grip.Tag.ToString());
    };
    


    Menu handle

    Another type of pens that can be created in MultiCAD.NET is the handle for invoking the context menu. This type of handle is used when the user needs to select from the list the required value of an object parameter from the list.
    This type of pens is created using a constructor with an indication of the type McBaseGrip.GripType.PopupMenuand appearance defined by the value McBaseGrip.GripAppearance.PopupMenu. To work with the context menu, it is necessary to implement two delegates:
    GetContextMenu - call the menu when you click on the handle,
    OnCommand - call actions when selecting items

    var ctxGrip = new McSmartGrip<TextInBox>(McBaseGrip.GripType.PopupMenu, 2, _pnt + 2 * stepVector, 
                                    McBaseGrip.GripAppearance.PopupMenu, 0, "Select menu", System.Drawing.Color.Lime);
    ctxGrip.GetContextMenu = (obj, items) =>
    {
      items.Add(new ContextMenuItem("Command 1", "none", 1));
    };
    ctxGrip.OnCommand = (obj, commandId, grip) =>
    {
      if (grip.Id == 2)
      {
        switch (commandId)
        {
          case1:
          {
            MessageBox.Show("Command 1 is selected");
            break;
          }
        }
      }
    };
    info.AppendGrip(ctxGrip);
    


    Result:



    Interactive pen

    And finally, the last type of pens that we look at is interactive. The main difference between these handles is that they can use information about binding objects and, depending on this, determine their behavior.
    As an example, we add one of these pens, which allows us to change the text of our primitive to the name of the selected object (except for the parent object). Depending on the binding object, the pen will change color: in the initial state, the pen will have a color GripColors.Base, when you hover over the parent object, the color will change to Color.Red, to any other object that supports the binding, to Color.Green.
    An interactive pen is created by the constructor indicating the type McBaseGrip.GripType.Interactive, and the pen is implemented in the delegate MouseMove(unlike simple pens, where it is usedMoveGrip)

    var interactiveGrip = new McSmartGrip<TextInBox>(McBaseGrip.GripType.Interactive, 3, _pnt + 3 * stepVector, 
                                                 McBaseGrip.GripAppearance.Arrow, 0, "interactive", GripColors.Base);
    interactiveGrip.IsMovable = true;
    interactiveGrip.MouseMove = (obj, entInfo, grip, offset) =>
    {
      grip.Color = GripColors.Base;
      if (!entInfo.SnapedObjectId.IsNull)
      {
        if (ID == entInfo.SnapedObjectId)
        {
          grip.Color = Color.Red;
        }
        else
        {
          grip.Color = Color.Green;
          obj.TryModify();
          obj.Text = (entInfo.SnapedObjectId.GetObject().GetType().ToString());
        }
      }
    };
    info.AppendGrip(interactiveGrip);
    

    Result: the text “Text field” is replaced by “MultiCAD.Samples.TextInBox”.



    We have listed the main types of smart pens that allow you to create an effective interface for working with custom objects created on MultiCAD.NET. MultiCAD.NET documentation is part of the nanoCAD SDK, which can be accessed by registering with the nanoCAD Developer Club .

    Discussion of the article is also available on our forum: forum.nanocad.ru/index.php?showtopic=6518 .
    Article translation into English: Smart grips of custom object in MultiCAD.NET

    Also popular now: