Extending the GUI (C#) |
This article describes how to extend the default behaviour, functionality and graphical user interface (GUI) of Grasshopper document objects. We'll focus on components as you should be familiar with those from earlier topics, but the same logic also applies to Parameters and custom objects.
When you derive a class from GH_Component or GH_ParamT you get a lot of functionality and GUI for free. It is quite important that all the objects in Grasshopper behave in a consistent and predictable fashion so you typically don't need to override this default behaviour. However there can be cases where changing the default Grasshopper GUI is the best solution. Overriding the GUI is not exactly a trivial task, there are a lot of different facets to this and I'll discuss the most important ones in this topic.
There are three common ways in which the default GUI can be altered:
It is possibe to insert items into the default pop-up menus of objects, or even to completely alter the menu layout. If your component for example can run in two different modes, you can choose to expose an additional GUI option instead of an input parameter. These modes can then be toggled via the component pop-up menu.
At the lowest level, pop-up menus are generated by the canvas when a right mouse button click is detected over a component or parameter. The menu by default contains no items and it is the responsibility of said component or parameter to populate the menu. The top-level method which is in charge of this is AppendMenuItems which is defined inside IGH_DocumentObject and thus propagates to all objects on the canvas.
The GH_DocumentObject abstract class does not create any menu items, so unless this function is overridden, there will be no popup menu for a certain object. However, it is unlikely you derive directly from GH_DocumentObject so this should not be a problem. GH_ActiveObject, which is the base class for all objects on the canvas that actually do something (Sketches and Scribbles don't "do" anything, hence they derive directly from GH_DocumentObject), does provide a default implementation of AppendMenuItems(). The default layout of popup menus is:
NickName
Preview
Enabled
Bake
Warnings
Errors
Help
public override bool AppendMenuItems(ToolStripDropDown menu) { Menu_AppendGenericMenuItem(menu, "First item"); Menu_AppendGenericMenuItem(menu, "Second item"); Menu_AppendGenericMenuItem(menu, "Third item"); Menu_AppendSeparator(menu); Menu_AppendGenericMenuItem(menu, "Fourth item"); Menu_AppendGenericMenuItem(menu, "Fifth item"); Menu_AppendGenericMenuItem(menu, "Sixth item"); // Return true, otherwise the menu won't be shown. return true; }
If you want to insert additional items into the menu it would be very annoying if you had to recreate this default menu layout from scratch every single time. So eventhough you can override AppendMenuItems() it is recommended you instead override AppendAdditionalMenuItems() which allows you to insert custom menu items between Errors and Help without losing the standard functionality:
public override void AppendAdditionalMenuItems(ToolStripDropDown menu) { base.AppendAdditionalMenuItems(menu); Menu_AppendGenericMenuItem(menu, "First item"); Menu_AppendGenericMenuItem(menu, "Second item"); Menu_AppendGenericMenuItem(menu, "Third item"); Menu_AppendSeparator(menu); Menu_AppendGenericMenuItem(menu, "Fourth item"); Menu_AppendGenericMenuItem(menu, "Fifth item"); Menu_AppendGenericMenuItem(menu, "Sixth item"); }
GH_Param<T> for example derives from GH_ActiveObject and re-implements AppendAdditionalMenuItems() in order to supply the Wire Display, Disconnect, Reverse, Flatten and Graft menu items that are present in all parameters. GH_Component, likewise, derives from GH_ActiveObject and it re-implements AppendAdditionalMenuItems() in order to insert the Shortest List, Longest List, Cross Reference and the parameter submenus.
Long story short; if you wish to insert additional menu items then either re-implement AppendAdditionalMenuItems() if you derive from GH_Param<T> or re-implement AppendAdditionalComponentMenuItems() if you derive from GH_Component:
// If you implement IGH_Param, then override this method. If you implement IGH_Component, // then override AppendAdditionalComponentMenuItems instead. protected override void AppendAdditionalMenuItems(ToolstripDropDown menu) { // Place a call to the base class to ensure the default parameter menu // is still there and operational. base.AppendAdditinalMenuItems(menu); // Now insert your own custom menu items. Menu_AppendGenericMenuItem(menu, "My Custom Menu Item", Menu_MyCustomItemClicked); } private void Menu_MyCustomItemClicked(Object sender, EventArgs e) { Rhino.RhinoApp.WriteLine("Alcohol doesn't affect me..."); }
You can also choose to handle specific mouse and keyboard events. You could for example choose to respond to a mouse double-click event on your component. Complicated objects such as Gradients and Graph Mappers handle all sorts of mouse events to provide grip-dragging functionality directly within the Grasshopper canvas. todo: finish this section
Finally, it is possible to override the way an object displays itself on the canvas. These alterations can be minor, mere additions to the default display, or they can be radically different (as with the Gradient and Graph Mapper objects). For a detailed explanation regarding display overrides, see the Custom Attributes topic.