[CONNECT C++] DgnElementSetTool and dynamics when picking multiple elements

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