Change The Gumball Appearance Settings From Code?

Hello,

I see a lot of gumball posts on here but none that answer my question from what I can tell…

The gumball, as I understand, renders itself in its own DisplayConduit

How, then, after updating a Gumballs appearance settings do I actually get the gumball to show the updated settings?

    def SetupCustomGumball(self, use_custom):
        """Setup and show custom gumball from code"""
        print("UI.SetupCustomGumball Call")
        try:
            if use_custom == True:
                # Rhino.RhinoApp.RunScript("Gumball Off", True)  # Debug

                # Custom gumball for editor viewport
                gumball = Rhino.UI.Gumball()
                gb_attr = gumball.AppearanceSettings

                if UI.h_colors is not None:
                    gb_attr.ColorX = Utils.ParseHexColor(UI.h_colors.get('x'))
                    gb_attr.ColorY = Utils.ParseHexColor(UI.h_colors.get('y'))
                    gb_attr.ColorZ = Utils.ParseHexColor(UI.h_colors.get('z'))

                gb_attr.MenuEnabled = False
                
                gb_attr.ScaleXEnabled = False
                gb_attr.ScaleYEnabled = False
                gb_attr.ScaleZEnabled = False

                gb_attr.TranslateZXEnabled = False
                gb_attr.TranslateYZEnabled = False
                gb_attr.TranslateZEnabled = False
                
                # Optional: Set custom origin if needed
                # gumball.Origin = Rhino.Geometry.Point3d(0, 0, 0)
                
                return gumball
            else:
                # Rhino.RhinoApp.RunScript("Gumball On", True) # Debug

                # Use Rhino's default gumball settings
                return Rhino.DocObjects.Custom.CustomGumball.Default

        except Exception as ex:
            Rhino.RhinoApp.WriteLine(f"SetupCustomGumball Exception: {ex}")

Thank you!

Hey Michael,

does this help?

1 Like

Thanks @mrhe ,

I did come across this but couldn’t get it to run in R8.

I added it as a command, compiled the plugin, and when I run it it “loads” but nothing after that happens so I gave up on it.

Without testing it was a bit hard for me to decipher which parts are relevant.

I attempted to convert that sample to Python 3 with … some luck. I got the custom gumball to show up but the dragging and get functionality I haven’t got working yet.

Here’s as far as I got with that code… should be able to run in editor without compiling anything.

#! python3
import rhinoscriptsyntax as rs
import Rhino
import scriptcontext as sc


def create_cylinder(plane, radius, height):
    """Creates a cylinder and returns its GUID"""
    circle = rs.AddCircle(plane, radius)
    cylinder = rs.ExtrudeCurve(circle, rs.AddLine(Rhino.Geometry.Point3d(0, 0, 0), Rhino.Geometry.Vector3d(0, 0, height)))
    rs.DeleteObject(circle)
    return cylinder


def setup_radius_gumball(origin, direction):
    """Creates a gumball with a single X-axis control"""
    gumball = Rhino.UI.Gumball.GumballObject()
    gumball_frame = Rhino.Geometry.Plane(origin, direction)
    gumball.SetFromPlane(gumball_frame)

    # Configure appearance - only enable Z translation
    gas = Rhino.UI.Gumball.GumballAppearanceSettings()
    gas.RelocateEnabled = False
    gas.RotateXEnabled = False
    gas.RotateYEnabled = False
    gas.RotateZEnabled = False
    gas.ScaleXEnabled = False
    gas.ScaleYEnabled = False
    gas.ScaleZEnabled = False
    gas.TranslateXEnabled = True
    gas.TranslateXYEnabled = False
    gas.TranslateYEnabled = False
    gas.TranslateYZEnabled = False
    gas.TranslateZEnabled = False
    gas.TranslateZXEnabled = False
    gas.MenuEnabled = False

    return gumball, gas


def setup_height_gumball(origin, direction):
    """Creates a gumball with a single Z-axis control"""
    gumball = Rhino.UI.Gumball.GumballObject()
    gumball_frame = Rhino.Geometry.Plane(origin, direction)
    gumball.SetFromPlane(gumball_frame)

    # Configure appearance - only enable Z translation
    gas = Rhino.UI.Gumball.GumballAppearanceSettings()
    gas.RelocateEnabled = False
    gas.RotateXEnabled = False
    gas.RotateYEnabled = False
    gas.RotateZEnabled = False
    gas.ScaleXEnabled = False
    gas.ScaleYEnabled = False
    gas.ScaleZEnabled = False
    gas.TranslateXEnabled = False
    gas.TranslateXYEnabled = False
    gas.TranslateYEnabled = False
    gas.TranslateYZEnabled = False
    gas.TranslateZEnabled = True
    gas.TranslateZXEnabled = False
    gas.MenuEnabled = False

    return gumball, gas


def setup_display_conduit(gumball, appearance):
    """Creates and configures a gumball display conduit"""
    conduit = Rhino.UI.Gumball.GumballDisplayConduit()
    conduit.SetBaseGumball(gumball, appearance)
    conduit.Enabled = True
    return conduit


def main():
    # Get base point for cylinder
    base_point = rs.GetPoint("Select base point for cylinder")
    if not base_point:
        return

    # Initial cylinder properties
    radius = 5.0
    height = 10.0
    base_plane = rs.PlaneFromNormal(base_point, Rhino.Geometry.Vector3d(0, 0, 1))

    # Create initial cylinder
    cylinder_id = create_cylinder(base_plane, radius, height)

    # Setup radius gumball at cylinder edge
    radius_origin = rs.PointAdd(base_point, [radius, 0, 0])
    radius_gumball, radius_appearance = setup_radius_gumball(radius_origin, Rhino.Geometry.Vector3d(0, 0, 1))
    radius_conduit = setup_display_conduit(radius_gumball, radius_appearance)

    # Setup height gumball at cylinder top
    height_origin = rs.PointAdd(base_point, [0, 0, height])
    height_gumball, height_appearance = setup_height_gumball(height_origin, Rhino.Geometry.Vector3d(0, 0, 1))
    height_conduit = setup_display_conduit(height_gumball, height_appearance)

    # Main interaction loop
    while True:
        # Get point with gumball
        gp = rs.GetPoint("Drag gumball. Press Enter when done", True)

        if gp is None:  # User pressed Enter
            break

        # Check which gumball was picked
        if radius_conduit.PickResult.Mode != Rhino.UI.Gumball.GumballMode.NONE:
            # Update radius
            new_radius = radius + (gp[2] - radius_origin[2])
            if new_radius > 0:
                rs.DeleteObject(cylinder_id)
                radius = new_radius
                cylinder_id = create_cylinder(base_plane, radius, height)

                # Update radius gumball position
                radius_origin = rs.PointAdd(base_point, [radius, 0, 0])
                radius_gumball.SetFromPlane(Rhino.Geometry.Plane(radius_origin, Rhino.Geometry.Vector3d(0, 0, 1)))

        elif height_conduit.PickResult.Mode != Rhino.UI.Gumball.GumballMode.NONE:
            # Update height
            new_height = height + (gp[2] - height_origin[2])
            if new_height > 0:
                rs.DeleteObject(cylinder_id)
                height = new_height
                cylinder_id = create_cylinder(base_plane, radius, height)

                # Update height gumball position
                height_origin = rs.PointAdd(base_point, [0, 0, height])
                height_gumball.SetFromPlane(Rhino.Geometry.Plane(height_origin, Rhino.Geometry.Vector3d(0, 0, 1)))

        sc.doc.Views.Redraw()

    # Cleanup
    radius_conduit.Enabled = False
    height_conduit.Enabled = False

    sc.doc.Views.Redraw()


if __name__ == "__main__":
    main()

Hi @michaelvollrath,

I don’t believe there is a way of setting the properties Rhino’s internal gumball.

You can change these via command line scripting.

What you’re setting are the properties of some custom gumball you’ll be using, no Rhino’s internal gumball.

– Dale

1 Like

Thanks for clarifying @dale !

Can I create a custom gumball class that inherits from the default gumballs class?

Much like how one can override a GetPoint class to then have their own CustomGet.

I would like to make my own gumball that I can conditionally enable without effecting Rhino’s default gumballs settings.

Alternatively the ability to change the gumball settings to custom settings and then restore to the defaults could work as well.

I basically want a gumball that I can visually style but maintain the grip functionality for scale rotate etc. but turn off parts of it such as the menu, scale handles, change the colors and so forth