jspanchu/vtkDearImGUIInjector

Unable to catch vtkCommand::LeftButtonReleaseEvent

Closed this issue · 5 comments

Clicking area A can capture vtkCommand::LeftButtonReleaseEvent, but clicking area B cannot capture it.
Snipaste_2023-11-21_14-48-50
code show as below:

class MyCallback : public vtkCommand
{
public:
    MyCallback() = default;
    ~MyCallback() = default;

    static MyCallback* New()
    {
        return new MyCallback;
    }

    void Execute(vtkObject* caller, unsigned long eventId,
        void* vtkNotUsed(callData)) override
    {
        if (vtkCommand::LeftButtonPressEvent == eventId)
        {
            std::cout << "LeftButtonPressEvent" << std::endl;
        }
        else if (vtkCommand::MouseMoveEvent == eventId)
        {
            std::cout << "MouseMoveEvent" << std::endl;

        }
        else if (vtkCommand::LeftButtonReleaseEvent == eventId)
        {
            std::cout << "LeftButtonReleaseEvent" << std::endl;
        }
    }
};

//------------------------------------------------------------------------------
// Main
//------------------------------------------------------------------------------

int main(int argc, char* argv[])
{
  // Create a renderer, render window, and interactor
  vtkNew<vtkRenderer> renderer;
  vtkNew<vtkRenderWindow> renderWindow;
  vtkNew<vtkRenderWindowInteractor> iren;
  renderWindow->SetMultiSamples(8);
  renderWindow->AddRenderer(renderer);
  iren->SetRenderWindow(renderWindow);

  // Create pipeline
  vtkNew<vtkConeSource> coneSource;
  coneSource->Update();

  vtkNew<vtkPolyDataMapper> mapper;
  mapper->SetInputConnection(coneSource->GetOutputPort());

  vtkNew<vtkActor> actor;
  actor->SetMapper(mapper);

  // Add the actors to the scene
  renderer->AddActor(actor);

  // Start rendering app
  renderer->SetBackground(0.2, 0.3, 0.4);
  renderWindow->Render();

  /// Change to your code begins here. ///
  // Initialize an overlay with DearImgui elements.
  vtkNew<vtkDearImGuiInjector> dearImGuiOverlay;
  // 💉 the overlay.
  dearImGuiOverlay->Inject(iren);
  // These functions add callbacks to ImGuiSetupEvent and ImGuiDrawEvents.
  SetupUI(dearImGuiOverlay);
  // You can draw custom user interface elements using ImGui:: namespace.
  DrawUI(dearImGuiOverlay);
  /// Change to your code ends here. ///

  vtkNew<vtkCameraOrientationWidget> camManipulator;
  camManipulator->SetParentRenderer(renderer);
  camManipulator->On();
  auto rep = vtkCameraOrientationRepresentation::SafeDownCast(camManipulator->GetRepresentation());
  rep->AnchorToLowerRight();

  // Start event loop
  renderWindow->SetSize(1920, 1000);
  vtkInteractorStyleSwitch::SafeDownCast(iren->GetInteractorStyle())->SetCurrentStyleToTrackballCamera();
  iren->EnableRenderOff();
  vtkNew<MyCallback> cb;
  iren->AddObserver(vtkCommand::LeftButtonPressEvent, cb);
  iren->AddObserver(vtkCommand::MouseMoveEvent, cb);
  iren->AddObserver(vtkCommand::LeftButtonReleaseEvent, cb);
  iren->Start();

  return 0;
}

Hi, This is not a bug in this project. It is a known behavior in VTK - see mailing list discussion for details.

The reason this happens is because VTK interactor style eats up left button release events. That is why your interactor's observer never sees it. The solution here is to create a custom interactor style to handle events and assign that interactor style to the render window interactor.

Thank you, I can capture the release of the left button by writing style. But I want to know: Why was it captureable in area A before, and why wasn’t it “eaten”?

Thank you, I can capture the release of the left button by writing style.

Glad it worked!

Why was it captureable in area A before, and why wasn’t it “eaten”?

Because in area A, the injector doesn't notify VTK about mouse button events. So the button press event never even went to VTK.

Sorry, I still can't understand: using vtkCommand, area A can get the vtkCommand::LeftButtonReleaseEvent, but area B can't

Let's try again.

In Area A, the left button press event is not sent to the interactor style, leading to the emission of a left button release event upon release. In Area B, the press event is passed down to the interactor style, which consumes the release event upon release.
Here's an illustration:

+-------------------+     +-------------------+
|      Area A       |     |      Area B       |
|                   |     |                   |
|  Left Button ---> |     |  Left Button ---> |
|  Press Event      |     |  Press Event      |
|       |           |     |       |           |
|  [Not Sent        |     |  [Sent to         |
|  to Interactor    |     |   Interactor      |
|  Style]           |     |   Style]          |
|       |           |     |       |           |
|  Emits Left       |     |  Eats Up          |
|  Button Release   |     |  Release Event    |
|  Event on Release |     |                   |
+-------------------+     +-------------------+

Refer to the code if that helps better - https://github.com/jspanchu/vtkDearImGUIInjector/blob/main/src/vtkDearImGuiInjector.cxx#L559