I want to create a tool (DgnElementSetTool) that will require 2 element "picks" before computing the final result. The tool will not support Selection Sets or Fence. Based on some of the delivered examples, this is what I have so far:
bool _WantDynamics() override { return false; } StatusInt _OnElementModify(EditElementHandleR el) override { return ERROR; } size_t _GetAdditionalLocateNumRequired() override { return 2; } bool _SetupForModify(DgnButtonEventCR ev, bool isDynamics) override { // Called before each dynamics frame and once for final accept. if (GetElementAgenda().GetCount() < _GetAdditionalLocateNumRequired()) return false; // false if not enough input to process elements... return true; // compute the result } bool _WantAdditionalLocate(DgnButtonEventCP ev) override { return WantAdditionalLocateHelper(ev); } virtual bool _OnModifierKeyTransition(bool wentDown, int key) override { return OnModifierKeyTransitionHelper(wentDown, key); }
which (so far) operates like I want it to (select two elements with datapoints and a third datapoint to "process" the result). I'm trying to figure out how to display my "result". I want to create an element (the "result") as a transient element that should be displayed after the second datapoint (i.e. two elements have been selected). Since I've turned "off" dynamics, where do I make the calls to get the transient to display? _SetupForModify() seems to be called AFTER the third ("acceptance") datapoint is issued.
Bruce
Your tool should implement IViewTransients:
struct MyTool : DgnElementSetTool, IViewTransients
struct MyTool : DgnElementSetTool, IViewTransients virtual void _OnPostInstall() override { IViewManager::GetManager().AddViewTransientHandler(this); __super::_OnPostInstall(); } virtual void _OnCleanup() override { IViewManager::GetManager().DropViewTransientHandler(this); __super::_OnCleanup(); } virtual void _DrawTransients(ViewContextR context, bool isPreUpdate) override { if (isPreUpdate || !m_haveResult) return; // Draw your result geometry... }
Then _LocateOneElement is probably a good place to create/update the transient geometry to preview the tool result.
virtual void _LocateOneElement(DgnButtonEventCR ev, bool newSearch) override { // Be aware that after picking an element, before accepting, the user can use reset to cycle between overlapping elements so you'll want to update your result assuming you haven't // overriden the default MicroStation tool behavior. When called from reset, "newSearch" will be false. __super::_LocateOneElement(ev, newSearch); // Erase/free existing transient geometry. // Use RedrawElems method with "this" for the IViewTransient and "false" for isPreUpdate to erase an old transient and show the new transient outside of doing a full update. // DGNVIEW_EXPORT void DoRedraw(IViewTransientsR, bool isPreUpdate); //!< Call the _DrawTransients method of the supplied IViewTransients for incremental display of created/removed transients. if (m_haveResult) { // Call RedrawElems with DRAW_MODE_Erase to clear an existing result... m_haveResult = false; } if (GetElementAgenda().GetCount() != _GetAdditionalLocateNumRequired()) return; // Create new transient geometry from current agenda... m_haveResult = true; // Call RedrawElems with DRAW_MODE_Normal to show new result... }
NOTE: If your tool wants 2 elements and only 2 elements, you DO NOT want to call WantAdditionalLocateHelper and should not override _OnModifierKeyTransition. Those methods are to help tools that want to do something like require a minimum of 2 elements before you can accept, but allow additional elements to be selected using ctrl + data.
bool DgnElementSetTool::WantAdditionalLocateHelper(DgnButtonEventCP ev) { if (SOURCE_Pick != _GetElemSource()) return false; if (NULL == ev) return true; // Helper method should only be called by multi-locate tools... // Require a minumum of a nRequired elements, if control is down select additional elements... return (m_agenda.GetCount() < _GetAdditionalLocateNumRequired() || ev->IsControlKey()); }
Instead your tool can simply do this:
virtual bool _WantAdditionalLocate(DgnButtonEventCP ev) override { return (nullptr == ev || GetElementAgenda().GetCount() < _GetAdditionalLocateNumRequired()); }
Answer Verified By: Bruce Reeves SRNS