How to switch Capture/Release of a component in GH_ComponentAttributes?

It seems that by returning “GH_ObjectResponse.Capture” as the return value of the RespondToMouse method of GH_ComponentAttributes, the component enters the “Capture” state. Is it possible to intentionally switch the Capture/Release state of a component other than returning “Capture” as the return value of the RespondTo~ method?


The specific situation I would like to use is to expand and switch component drop-down menus, as shown in the figure below. We would like to make the component in “Capture” state so that mouse events of the currently expanded component will take precedence even if other components or menus overlap. However, it is necessary to “Release” at the timing when the component switches to unselected state.

The process of closing the menu when switching to the unselected state is implemented by overriding the Selected property of GH_ComponentAttributes as shown below.

private bool m_selected;
public override bool Selected
{
    get { return m_selected; }
    set { 
        if (m_selected != value && m_selected) OnDeselected();
        m_selected = value; 
    }
}

public void OnDeselected()
{
		// 1. Close Menu !
		// 2. Release Component !
}

Any advice would be appreciated.

I am having the exact same issue and would like to know if you have found any workaround.

I may not have done enough research, as I did not end up using the questions I asked in my implementation, but it seems that the state in which a component is Captured is actually related to whether the component is registered in the corresponding GH_Canvas.ActiveObject property or not. This property is normally null and can be assigned to, so it is possible to check the Captured state and change it freely.

As an example, the following implementation allows switching the Capture/Release state from the context menu of the component, instead of using the RespondTo~ method. (The RespondToMouseDown() method is implemented to check the Capture state by checking whether a click outside the Component’s region is picked up.)

// implimented in GH_ComponentAttributes
public override GH_ObjectResponse RespondToMouseDown(GH_Canvas sender, GH_CanvasMouseEvent e)
{
    if (e.Button == MouseButtons.Left)
    {
        bool isactive = object.ReferenceEquals(
            Grasshopper.Instances.ActiveCanvas.ActiveObject, this);
        string id_text = Owner.InstanceGuid.ToString().Substring(0, 6);
        string state = isactive ? "Capturing" : "Released";
        RhinoApp.WriteLine($"Component {id_text}... {state} X: {e.CanvasX}, Y:{e.CanvasY}");
        return GH_ObjectResponse.Handled;
    }
    else {
        return GH_ObjectResponse.Release;
    }
}

// .......

// implimented in GH_Component
protected override void AppendAdditionalComponentMenuItems(ToolStripDropDown menu)
{
    base.AppendAdditionalComponentMenuItems(menu);
    Menu_AppendItem(menu, "Capture", Menu_CaptureClicked, true);
    Menu_AppendItem(menu, "Release", Menu_ReleaseClicked, true);
}

private void Menu_CaptureClicked(object sender, EventArgs e)
{
    Grasshopper.Instances.ActiveCanvas.ActiveObject = this;
}

private void Menu_ReleaseClicked(object sender, EventArgs e)
{
    Grasshopper.Instances.ActiveCanvas.ActiveObject = null;
}

I hope you find this helpful !

1 Like

I implemented that and it seems to work. Thanks a lot!