How to create a custom Gumball?

Hi all!

I’m trying to build a custom gumball for grips. ( related ) In Rhino 7.
I’ve found some examples spreaded around the forum and github, but nothing to actually go deep near what I need.

I want to make a gumball with more than 3 arrow/handles and that are not perpendicular each-other.

I’m expecting to have some sort of geometry (one for each draggable arrow/handle of the gumball), that is “clickable+draggable” which trigger an event(?) which then would interactively deform a rhino geometry.

My questions are:

  • What is the best approach in rhino environment to create a gumball handle/arrow anchored to a grip/point: an actual geometry (like a mesh) renderend in front of everything? A System.Drawing shape drawn in front of everything in screen space? Something else?
  • How to get the “click+drag” input event of an “handle”?
  • How to interactively update the global shape of a geometry while the dragging is still happening?

If possible I’d like to be pointed to some examples… but even a rough global direction is very appreciated.

Thanks in advance!

maybe this topic hides some startingpoints:

I need to make this for Rhino 7. (I’ve edited main post)
Is Eto accessible from Rhino 7? …
Also, not much relevant stuff in that thread… nothing remotely similar to a gumball or that interactively deform a shape.

Also, not much relevant stuff in that thread… nothing remotely similar to a gumball or that interactively deform a shape

How about this?

You don’t need Eto for this kind of interaction. It’s mostly drawing shapes in the foreground and working with mouse events.

3 Likes

Cool!

Nice! That’s what I’m asking.
In the video the cursor change from Z axis to XY plane for the drag constraint. Is that toggled with some key?
As a gumball works, I need many different arrows and the user click-n-drag the one he needs.


Any example code?

Yeah, we’re listening to keyboard events and changing functionality based on user input.

As for the code example:

EDIT: You might also want to check this one out:

Hi,
Complex and uncapped customization:

Summary

Personally I think that a much easier approach would be to make a custom overlay in d3/OpenGL.
it would allow you to easily and extensively customize your overlay.

An example would be this animated overlay (60fps), in Rhino you would be gutting your performance, by running a separate overlay you do not lose performance, It’s not computationally expensive and It’s not too hard to implement.

Personally I think that by going with the ETO path you will be having a harder time than just going straight for your own overlay in ogl/d3 when you will intend to further customize your UI.
Screen capture - b2830eb2edf9e214309e38e41d03ef14 - Gyazo


Simple and efficient

Summary

You could use otp to use PyQt5 if you’re going to be using Rhino8+
Here’s an example of overlay you can easily pull off inside of rhino and to interact with rhino, with a much better event handling and customization capabilities

There you have a sample script demostrating how to implement it :

from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton, QWidget
from PyQt5.QtCore import Qt, QPoint
from PyQt5.QtGui import QPainter, QRegion, QCursor
import rhinoscriptsyntax as rs  # Import Rhino's Python library

class CircularOverlay(QMainWindow):
    def __init__(self):
        super().__init__()

        # Get mouse position
        mouse_pos = QCursor.pos()

        # Set window properties
        self.setWindowTitle("Circular Overlay")
        self.setGeometry(mouse_pos.x(), mouse_pos.y(), 200, 200)  # Smaller dimensions and positioned at mouse
        self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint)
        self.setAttribute(Qt.WA_TranslucentBackground)

        # Create a QWidget for the central widget
        central_widget = QWidget(self)
        self.setCentralWidget(central_widget)

        # Create buttons and connect them to Rhino commands
        self.button1 = self.create_button("SuperMoveEdge", central_widget, 0, 0, 100, 100)
        self.button2 = self.create_button("SuperCut", central_widget, 100, 0, 100, 100)
        self.button3 = self.create_button("Isolate", central_widget, 0, 100, 100, 100)
        self.button4 = self.create_button("View", central_widget, 100, 100, 100, 100)

    def create_button(self, command, parent, x, y, w, h):
        button = QPushButton(command, parent)
        button.setGeometry(x, y, w, h)
        button.clicked.connect(lambda: self.run_rhino_command(command))
        return button

    def run_rhino_command(self, command):
        rs.Command(command)  # Execute the Rhino command

    def paintEvent(self, event):
        # Create QPainter object
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)

        # Draw circle
        painter.setBrush(Qt.white)
        painter.drawEllipse(0, 0, 200, 200)  # Smaller circle

        # Create a circular region and set it as a mask
        region = QRegion(self.rect(), QRegion.Ellipse)
        self.setMask(region)

if __name__ == "__main__":
    app = QApplication([])
    window = CircularOverlay()
    window.show()
    app.exec_()

Hope this sparks some inspiration,
Farouk

2 Likes

This first example seems interesting

Can I ask you how you made that?
Are those Rhino Geometries or System Geometries in conduit?


That is very interesting, thanks, but I’m doing this for Rhino 7. (I’ll be using it in 8 also, but need backward compatibility).
Also, this is an overlayed UI. I need something different.
I need a custom gumball (more than 3 arrows, non-orthogonal each-other).
Aligned in 3d space, clickable and draggable, and that updates when the viewport camera rotate.