|
| 1 | +"""Demonstrates the most basic command/dialog plugin possible. |
| 2 | +
|
| 3 | +Note: |
| 4 | + This is not only a command hello world example, but generally a plugin hello world example. See |
| 5 | + the py-cmd_gui_simple example for a slightly more complex case that is also commented more |
| 6 | + verbosely. |
| 7 | +
|
| 8 | +Open this dialog example by running the command "Py - Hello World Gui" in the Commander (Shift + C). |
| 9 | +This is a very simple dialog example, which demonstrates how to create a dialog with three buttons |
| 10 | +that display a message when clicked. |
| 11 | +
|
| 12 | +Subjects: |
| 13 | + - GeDialog.CreateLayout() and its most basic usage to build a GUI. |
| 14 | + - GeDialog.Command() to handle user input. |
| 15 | + - CommandData.Execute() to open the dialog. |
| 16 | + - Registering a command plugin that manages a dialog. |
| 17 | +""" |
| 18 | +__copyright__ = "Copyright 2025, MAXON Computer" |
| 19 | +__author__ = "Ferdinand Hoppe" |
| 20 | +__date__ = "06/06/2025" |
| 21 | +__license__ = "Apache-2.0 license" |
| 22 | + |
| 23 | +import c4d |
| 24 | +import typing |
| 25 | + |
| 26 | + |
| 27 | +class HelloWorldGuiDialog(c4d.gui.GeDialog): |
| 28 | + """Realizes the most basic dialog possible. |
| 29 | + """ |
| 30 | + # Define the button IDs. |
| 31 | + ID_BTN_RED: int = 1000 |
| 32 | + ID_BTN_GREEN: int = 1001 |
| 33 | + ID_BTN_BLUE: int = 1002 |
| 34 | + |
| 35 | + def CreateLayout(self) -> bool: |
| 36 | + """Called by Cinema 4D when the GUI of the dialog is being built. |
| 37 | + """ |
| 38 | + # Define the title of the dialog. |
| 39 | + self.SetTitle("Py - Hello World Gui") |
| 40 | + |
| 41 | + # Set the spacing of the implicit outermost group of the dialog. |
| 42 | + self.GroupBorderSpace(5, 5, 5, 5) # A 5px border around the dialog. |
| 43 | + self.GroupSpace(5, 5) # A 5px space between the elements in the dialog. |
| 44 | + |
| 45 | + # Add the three buttons. Gadgets are identified by their ID, which is an integer. We make |
| 46 | + # all buttons consume the full width of the dialog (BFH = horizontal, SCALEFIT = consume |
| 47 | + # all space on that axis). BFV_SCALEFIT would make the buttons consume all vertical space. |
| 48 | + self.AddButton(self.ID_BTN_RED, c4d.BFH_SCALEFIT, name="Red") |
| 49 | + self.AddButton(self.ID_BTN_GREEN, c4d.BFH_SCALEFIT, name="Green") |
| 50 | + self.AddButton(self.ID_BTN_BLUE, c4d.BFH_SCALEFIT, name="Blue") |
| 51 | + |
| 52 | + # All the elements we add in this most simple manner will be stacked vertically. See |
| 53 | + # py-cmd_gui_simple for a more complex example of how to build a dialog with a more complex |
| 54 | + # layout. |
| 55 | + |
| 56 | + return True |
| 57 | + |
| 58 | + def Command(self, mid: int, data: c4d.BaseContainer) -> bool: |
| 59 | + """Called by Cinema 4D when the user clicks a gadget in the dialog. |
| 60 | + """ |
| 61 | + # Here we react to our buttons being clicked. |
| 62 | + if mid == self.ID_BTN_RED: |
| 63 | + c4d.gui.MessageDialog("You clicked the Red button!") |
| 64 | + elif mid == self.ID_BTN_GREEN: |
| 65 | + c4d.gui.MessageDialog("You clicked the Green button!") |
| 66 | + elif mid == self.ID_BTN_BLUE: |
| 67 | + c4d.gui.MessageDialog("You clicked the Blue button!") |
| 68 | + |
| 69 | + return True |
| 70 | + |
| 71 | + |
| 72 | +class HelloWorldGuiCommand(c4d.plugins.CommandData): |
| 73 | + """Realizes the common implementation for a command that opens a foldable dialog. |
| 74 | +
|
| 75 | + This example also reduces the CommandData implementation to its bare minimum, but it is |
| 76 | + strongly recommended to follow the more complete pattern shown in other examples, such as |
| 77 | + py-cmd_gui_simple. |
| 78 | + """ |
| 79 | + # The dialog hosted by the plugin. |
| 80 | + REF_DIALOG: HelloWorldGuiDialog | None = None |
| 81 | + |
| 82 | + def Execute(self, doc: c4d.documents.BaseDocument) -> bool: |
| 83 | + """Opens the dialog when the command is executed. |
| 84 | + """ |
| 85 | + # Instantiate the dialog if it does not exist yet. |
| 86 | + if HelloWorldGuiCommand.REF_DIALOG is None: |
| 87 | + HelloWorldGuiCommand.REF_DIALOG = HelloWorldGuiDialog() |
| 88 | + |
| 89 | + # Open the dialog when it is not yet open. We could also implement closing the dialog; see |
| 90 | + # one of the more complex examples for this, such as py-cmd_gui_simple. We open the dialog |
| 91 | + # asynchronously, i.e., the user can continue working in Cinema 4D while the dialog is open. |
| 92 | + if not HelloWorldGuiCommand.REF_DIALOG.IsOpen(): |
| 93 | + HelloWorldGuiCommand.REF_DIALOG.Open( |
| 94 | + c4d.DLG_TYPE_ASYNC, self.ID_PLUGIN, defaultw=300, defaulth=0) |
| 95 | + |
| 96 | + return True |
| 97 | + |
| 98 | + # The unique ID of the plugin, it must be obtained from developers.maxon.net. |
| 99 | + ID_PLUGIN: int = 1065651 |
| 100 | + |
| 101 | + # The name and help text of the plugin. |
| 102 | + STR_NAME: str = "Py - Hello World Gui" |
| 103 | + STR_HELP: str = "Opens a bare-bones dialog with three buttons that display a message when clicked." |
| 104 | + |
| 105 | + @classmethod |
| 106 | + def Register(cls: typing.Type, iconId: int) -> None: |
| 107 | + """Registers the command plugin. |
| 108 | +
|
| 109 | + This is a custom method and not part of the CommandData interface. |
| 110 | + """ |
| 111 | + # Load one of the built-in icons of Cinema 4D as the icon of the plugin. Then instantiate the |
| 112 | + # command plugin that will be registered. And finally register the command plugin with that |
| 113 | + # command instance and icon. |
| 114 | + bitmap: c4d.bitmaps.BaseBitmap = c4d.bitmaps.InitResourceBitmap(iconId) |
| 115 | + command: object = cls() |
| 116 | + c4d.plugins.RegisterCommandPlugin( |
| 117 | + id=cls.ID_PLUGIN, str=cls.STR_NAME, info=0, icon=bitmap, help=cls.STR_HELP, dat=command) |
| 118 | + |
| 119 | + |
| 120 | +# Called by Cinema 4D when this plugin module is loaded. |
| 121 | +if __name__ == '__main__': |
| 122 | + HelloWorldGuiCommand.Register(iconId=465001193) |
0 commit comments