Author Topic: Working with EntityJigs - cancelling on spacebar/enter  (Read 2136 times)

0 Members and 1 Guest are viewing this topic.

Atook

  • Swamp Rat
  • Posts: 1027
  • AKA Tim
Working with EntityJigs - cancelling on spacebar/enter
« on: May 07, 2015, 03:35:08 AM »
I'm just getting started with blockjigs, and they're working OK, but the user needs to hit Esc to exit out of the while loop. I'd like to cancel out of the command when the user hits space(enter), similar to most autocad commands.  Ideally it will react differently to a space/enter: if I'm in the rotating jig, it'll keep the block at the original rotation, if inserting a block, it'll cancel out of the command. Once I trap the space/enter, I can work that logic out though.

Basically I have a do/while loop executing a jig drag while the promptStatus is OK.

I'm not sure if I need to change the do/while loop where I call the jigs, or maybe it's in the UserInputControls in the SamplerStatus override? Also, if my execution is silly/inefficient I'm open to other comments, I'm still really new to this.

The call to the jigs with the do/while loop:
Code: [Select]
public static void InsertRotatorBlockTest(ObjectId blockId, Scale3d scale, string layerName = "0", ResultBuffer optionalXData = null)
{
   Database db = Active.Database;
   Transaction tr = Active.Document.TransactionManager.StartTransaction();
   using (tr)
   {
      //Open block table to be sure it exists
      BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
      PromptResult pr;
      double rotation = 0;
      do
      {
         // now the jig
         // create the blockref
         Point3d pt = new Point3d(0, 0, 0);
         BlockReference br = new BlockReference(pt, blockId)
         {
            ScaleFactors = scale,
            Layer = layerName,
            Rotation = rotation
         };
         if (optionalXData != null)
         {
            br.XData = optionalXData;
         }
         InsertBlockJig insertJig = new InsertBlockJig(br);
         // insert the blockref into modelspace
         pr = Active.Editor.Drag(insertJig);
         if (pr.Status==PromptStatus.OK)
         {
            // rotate it
            RotatingBlockJig rotateJig = new RotatingBlockJig(br);
            pr = Active.Editor.Drag(rotateJig);
           
            BlockTableRecord curSpace = (BlockTableRecord)tr.GetObject(Active.Database.CurrentSpaceId,
               OpenMode.ForWrite);
            curSpace.AppendEntity(br);
            tr.AddNewlyCreatedDBObject(br, true);
            // Call a function to make the graphics display (otherwise it only shows after commit)
            Active.Document.TransactionManager.QueueForGraphicsFlush();
            rotation = br.Rotation;
         }
      } while (pr.Status != PromptStatus.Cancel &&
            pr.Status != PromptStatus.Error &&
            pr.Status != PromptStatus.Keyword);
      tr.Commit();
   }
}

The two EntityJig classes:
Code: [Select]
class InsertBlockJig : EntityJig
{
   Point3d _mCenterPt, _mActualPoint;

   public InsertBlockJig(Entity ent)
      : base(ent)
   {
      _mCenterPt = ((BlockReference) ent).Position;
   }

   protected override SamplerStatus Sampler(JigPrompts prompts)
   {
      JigPromptPointOptions jigOpts =
        new JigPromptPointOptions();
      jigOpts.UserInputControls =
        (UserInputControls.Accept3dCoordinates
        | UserInputControls.NullResponseAccepted
        | UserInputControls.NoNegativeResponseAccepted);

      jigOpts.Message =
        "\nEnter insert point: ";

      PromptPointResult dres =
        prompts.AcquirePoint(jigOpts);

      if (_mActualPoint == dres.Value)
      {
         return SamplerStatus.NoChange;
      }
      else
      {
         _mActualPoint = dres.Value;
      }
      return SamplerStatus.OK;
   }

   protected override bool Update()
   {
      _mCenterPt = _mActualPoint;
      try
      {
         ((BlockReference)Entity).Position = _mCenterPt;
      }
      catch (Exception)
      {
         return false;
      }
      return true;
   }

}

class RotatingBlockJig : EntityJig
{
   // Fields
   private double _mRotation;
   private BlockReference _br;

   // Constructor
   public RotatingBlockJig(BlockReference br)
      : base(br)
   {
      _mRotation = br.Rotation;
      _br = br;
   }

   // Overrides
   protected override bool Update()
   {
      (Entity as BlockReference).Rotation = _mRotation;
      return true;
   }

   protected override SamplerStatus Sampler(JigPrompts prompts)
   {
      JigPromptAngleOptions prAngleOpts = new JigPromptAngleOptions("\n Rotation: ");
      prAngleOpts.BasePoint = _br.Position;
      prAngleOpts.UseBasePoint = true;
      prAngleOpts.Cursor=CursorType.RubberBand;
      PromptDoubleResult prRotResult = prompts.AcquireAngle(prAngleOpts);
      if (prRotResult.Status == PromptStatus.Cancel) return SamplerStatus.Cancel;
      // Return no change if no rotation, to prevent flashing
      if (prRotResult.Value.Equals(_mRotation))
      {
         return SamplerStatus.NoChange;
      }
      else
      {
         _mRotation = prRotResult.Value;
         return SamplerStatus.OK;
      }
      return SamplerStatus.OK;
   }
}


MexicanCustard

  • Swamp Rat
  • Posts: 705
Re: Working with EntityJigs - cancelling on spacebar/enter
« Reply #1 on: May 07, 2015, 07:48:52 AM »
In your JigPromptOptions you can set JigPromptOptions.UserInputControls with the UserInputControls.InitialBlankTerminatesInput flag.
Revit 2019, AMEP 2019 64bit Win 10

Atook

  • Swamp Rat
  • Posts: 1027
  • AKA Tim
Re: Working with EntityJigs - cancelling on spacebar/enter
« Reply #2 on: May 07, 2015, 02:03:12 PM »
Thanks M.C. I was hoping for something simple like that.

Do I need to set something else to go along with it? I've implemented
 
Code: [Select]
prAngleOpts.UserInputControls = UserInputControls.InitialBlankTerminatesInput; and
Code: [Select]
jigOpts.UserInputControls =
(UserInputControls.Accept3dCoordinates
         | UserInputControls.NullResponseAccepted
| UserInputControls.NoNegativeResponseAccepted
                 | UserInputControls.InitialBlankTerminatesInput);

And the behaviour doesn't change.

In trying to read up on UserInputControls, I came on this post indicating that maybe a message filter is the way to go. A message filter seems like a clunky solution for something so basic.

On a more meta level, where can I go to read up on this stuff? I installed the help files into VS2013, but from what I've read so far, it isn't too helpful.  Even the objectbrowser for the autocad stuff is sparse. Searching the Developers guide rarely gives up anything useful. I remember finding all kinds of helpful usage examples in the COM help file back in the day.

n.yuan

  • Bull Frog
  • Posts: 348
Re: Working with EntityJigs - cancelling on spacebar/enter
« Reply #3 on: May 07, 2015, 05:00:25 PM »
You may want to look into JigPromptOptions.Keywords. In your case, you can only add 1 keyword, like "Cancel", and set it as default. Then test the PromptResult.Status not only for PromptStatus.Cancel, and/or PromptStatus.Keyword.

Atook

  • Swamp Rat
  • Posts: 1027
  • AKA Tim
Re: Working with EntityJigs - cancelling on spacebar/enter
« Reply #4 on: May 19, 2015, 12:35:34 AM »
The solution I ended up with was applying an IMessageFilter like so:

Filter:

Code: [Select]
        public class SpaceRightClickFilter : WinForms.IMessageFilter
        {

            public bool canceled = false;
            public bool PreFilterMessage(ref WinForms.Message m)
            {
                int WM_RIGHTCLICK = 0x0205;
                int WM_KEYDOWN = 0x0100;
                Keys kc = (Keys) (int) m.WParam & Keys.KeyCode;
                // check for space press or right click
                if ((m.Msg == WM_KEYDOWN && (kc==Keys.Space)) || m.Msg==WM_RIGHTCLICK)
                {
                    canceled = true;
                }
                // never falter
                return false;
            }
        }

Usage:

Code: [Select]
                    InsertBlockJig insertJig = new InsertBlockJig(br);
                    // insert the blockref into modelspace
                    insertPrompt = Active.Editor.Drag(insertJig);
                    // Add a message filter to the window
                    SpaceRightClickFilter cancelInsertFilter = new SpaceRightClickFilter();
                    System.Windows.Forms.Application.AddMessageFilter(cancelInsertFilter);
                    if (insertPrompt.Status == PromptStatus.OK && !cancelInsertFilter.canceled)
                    {
                        // get rid of insert filter
                        System.Windows.Forms.Application.RemoveMessageFilter(cancelInsertFilter);
                        // Do some cool stuff where space/rightclick doesn't cancel
                        // ...
                    else
                    {
                        canceled = true;
                    }
                    // Clean up; remove the filter
                    System.Windows.Forms.Application.RemoveMessageFilter(cancelInsertFilter);


cincir

  • Guest
Re: Working with EntityJigs - cancelling on spacebar/enter
« Reply #5 on: May 22, 2015, 11:47:22 AM »
You also need to or UserInputControls.AcceptOtherInputString. otherwise you can not enter blank and cancel will not occur.