RobotLocomotion / drake

Model-based design and verification for robotics.
https://drake.mit.edu
Other
3.17k stars 1.24k forks source link

ImGui style API for Meshcat Buttons #21377

Open axbycc-mark opened 2 months ago

axbycc-mark commented 2 months ago

Is your feature request related to a problem? Please describe. It is kind of tedious to use the Meshcat buttons because it requires the user to track the number of clicks since the button has been spawned. I believe the following is idiomatic.

meshcat.GetButtonClicks(button_name) > num_button_clicks:
    num_button_clicks = meshcat.GetButtonClicks(button_name) 
    # do some stuff

Describe the solution you'd like The popular Dear ImGui library has a friendly API which I miss when using Drake's interface to Meshcat. I believe many in the robotics space will be familiar with this style.

if (ImGui::Button(button_name)) {
    // do some stuff
}

I believe something close can be achieved with Meshcat, even though it does not follow an immediate-mode paradigm. I'm thinking something like the following.

meshcat.AddButton(button_name)
...
if meshcat.WasButtonPressed(button_name):
    # do some stuff

In the above, the call to WasButtonPressed checks if the current number of button clicks matches the number of clicks since the last time WasButtonPressed was called.

Describe alternatives you've considered Here is a little snippet that implements the desired feature that one can readily copy paste.

from collections import defaultdict

_BUTTON_TRACKER_ = defaultdict(lambda: 0)
def was_button_pressed(meshcat, button_name):
    global _BUTTON_TRACKER_
    current_button_clicks = meshcat.GetButtonClicks(button_name)
    if current_button_clicks > _BUTTON_TRACKER_[button_name]:
        _BUTTON_TRACKER_[button_name] = current_button_clicks
        return True
    return False

Then in user code, one calls was_button_pressed(meshcat, button_name).

Additional context I'm not familiar with the C++ side, but perhaps a similar situation hold there as well.

jwnimmer-tri commented 2 months ago

What would you think about an option to meshcat.GetButtonClicks(button_name, reset=True) that clears the count back to zero while also returning the count prior to the reset?

meshcat.AddButton(name)
...
if meshcat.GetButtonClicks(name, reset=True):
    # do some stuff
axbycc-mark commented 2 months ago

@jwnimmer-tri It's more ergonomic for me to have just one parameter eg meshcat.GetButtonClicksAndReset(name) because it can be more easily autocompleted. Even better for autocomplete if the function name does not share a prefix, eg meshcat.ResetButtonClicks(name) although it would be slightly confusing to read:

if meshcat.ResetButtonClicks(name):
   # do some stuff

But I imagine you are making your suggestion because it's easier to implement, in which case it's still a good improvement.