mirror of
				https://github.com/KevinMidboe/linguist.git
				synced 2025-10-29 17:50:22 +00:00 
			
		
		
		
	added .pyp suffix and an example source file. closes issue #1
This commit is contained in:
		
							
								
								
									
										241
									
								
								samples/Python/Cinema4DPythonPlugin.pyp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										241
									
								
								samples/Python/Cinema4DPythonPlugin.pyp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,241 @@ | ||||
| # | ||||
| # Cinema 4D Python Plugin Source file | ||||
| # https://github.com/nr-plugins/nr-xpresso-alignment-tools | ||||
| # | ||||
|  | ||||
| # coding: utf-8 | ||||
| # | ||||
| # Copyright (C) 2012, Niklas Rosenstein | ||||
| # Licensed under the GNU General Public License | ||||
| # | ||||
| # XPAT - XPresso Alignment Tools | ||||
| # ============================== | ||||
| # | ||||
| # The XPAT plugin provides tools for aligning nodes in the Cinema 4D | ||||
| # XPresso Editor, improving readability of complex XPresso set-ups | ||||
| # immensively. | ||||
| # | ||||
| # Requirements: | ||||
| # - MAXON Cinema 4D R13+ | ||||
| # - Python `c4dtools` library. Get it from | ||||
| #   http://github.com/NiklasRosenstein/c4dtools | ||||
| # | ||||
| # Author:  Niklas Rosenstein <rosensteinniklas@gmail.com> | ||||
| # Version: 1.1 (01/06/2012) | ||||
|  | ||||
| import os | ||||
| import sys | ||||
| import json | ||||
| import c4d | ||||
| import c4dtools | ||||
| import itertools | ||||
|  | ||||
| from c4d.modules import graphview as gv | ||||
| from c4dtools.misc import graphnode | ||||
|  | ||||
| res, importer = c4dtools.prepare(__file__, __res__) | ||||
| settings = c4dtools.helpers.Attributor({ | ||||
|     'options_filename': res.file('config.json'), | ||||
| }) | ||||
|  | ||||
| def align_nodes(nodes, mode, spacing): | ||||
|     r""" | ||||
|     Aligns the passed nodes horizontally and apply the minimum spacing | ||||
|     between them. | ||||
|     """ | ||||
|  | ||||
|     modes = ['horizontal', 'vertical'] | ||||
|     if not nodes: | ||||
|         return | ||||
|     if mode not in modes: | ||||
|         raise ValueError('invalid mode, choices are: ' + ', '.join(modes)) | ||||
|  | ||||
|     get_0 = lambda x: x.x | ||||
|     get_1 = lambda x: x.y | ||||
|     set_0 = lambda x, v: setattr(x, 'x', v) | ||||
|     set_1 = lambda x, v: setattr(x, 'y', v) | ||||
|  | ||||
|     if mode == 'vertical': | ||||
|         get_0, get_1 = get_1, get_0 | ||||
|         set_0, set_1 = set_1, set_0 | ||||
|  | ||||
|     nodes = [graphnode.GraphNode(n) for n in nodes] | ||||
|     nodes.sort(key=lambda n: get_0(n.position)) | ||||
|     midpoint = graphnode.find_nodes_mid(nodes) | ||||
|  | ||||
|     # Apply the spacing between the nodes relative to the coordinate-systems | ||||
|     # origin. We can offset them later because we now the nodes' midpoint | ||||
|     # already. | ||||
|     first_position = nodes[0].position | ||||
|     new_positions = [] | ||||
|     prev_offset = 0 | ||||
|     for node in nodes: | ||||
|         # Compute the relative position of the node. | ||||
|         position = node.position | ||||
|         set_0(position, get_0(position) - get_0(first_position)) | ||||
|  | ||||
|         # Obtain it's size and check if the node needs to be re-placed. | ||||
|         size = node.size | ||||
|         if get_0(position) < prev_offset: | ||||
|             set_0(position, prev_offset) | ||||
|             prev_offset += spacing + get_0(size) | ||||
|         else: | ||||
|             prev_offset = get_0(position) + get_0(size) + spacing | ||||
|  | ||||
|         set_1(position, get_1(midpoint)) | ||||
|         new_positions.append(position) | ||||
|  | ||||
|     # Center the nodes again. | ||||
|     bbox_size = prev_offset - spacing | ||||
|     bbox_size_2 = bbox_size * 0.5 | ||||
|     for node, position in itertools.izip(nodes, new_positions): | ||||
|         # TODO: Here is some issue with offsetting the nodes. Some value | ||||
|         # dependent on the spacing must be added here to not make the nodes | ||||
|         # move horizontally/vertically although they have already been | ||||
|         # aligned. | ||||
|         set_0(position, get_0(midpoint) + get_0(position) - bbox_size_2 + spacing) | ||||
|         node.position = position | ||||
|  | ||||
| def align_nodes_shortcut(mode, spacing): | ||||
|     master = gv.GetMaster(0) | ||||
|     if not master: | ||||
|         return | ||||
|  | ||||
|     root = master.GetRoot() | ||||
|     if not root: | ||||
|         return | ||||
|  | ||||
|     nodes = graphnode.find_selected_nodes(root) | ||||
|     if nodes: | ||||
|         master.AddUndo() | ||||
|         align_nodes(nodes, mode, spacing) | ||||
|         c4d.EventAdd() | ||||
|  | ||||
|     return True | ||||
|  | ||||
| class XPAT_Options(c4dtools.helpers.Attributor): | ||||
|     r""" | ||||
|     This class organizes the options for the XPAT plugin, i.e. | ||||
|     validating, loading and saving. | ||||
|     """ | ||||
|  | ||||
|     defaults = { | ||||
|         'hspace': 50, | ||||
|         'vspace': 20, | ||||
|     } | ||||
|  | ||||
|     def __init__(self, filename=None): | ||||
|         super(XPAT_Options, self).__init__() | ||||
|         self.load(filename) | ||||
|  | ||||
|     def load(self, filename=None): | ||||
|         r""" | ||||
|         Load the options from file pointed to by filename. If filename | ||||
|         is None, it defaults to the filename defined in options in the | ||||
|         global scope. | ||||
|         """ | ||||
|  | ||||
|         if filename is None: | ||||
|             filename = settings.options_filename | ||||
|  | ||||
|         if os.path.isfile(filename): | ||||
|             self.dict_ = self.defaults.copy() | ||||
|             with open(filename, 'rb') as fp: | ||||
|                 self.dict_.update(json.load(fp)) | ||||
|         else: | ||||
|             self.dict_ = self.defaults.copy() | ||||
|             self.save() | ||||
|  | ||||
|     def save(self, filename=None): | ||||
|         r""" | ||||
|         Save the options defined in XPAT_Options instance to HD. | ||||
|         """ | ||||
|  | ||||
|         if filename is None: | ||||
|             filename = settings.options_filename | ||||
|  | ||||
|         values = dict((k, v) for k, v in self.dict_.iteritems() | ||||
|                       if k in self.defaults) | ||||
|         with open(filename, 'wb') as fp: | ||||
|             json.dump(values, fp) | ||||
|  | ||||
| class XPAT_OptionsDialog(c4d.gui.GeDialog): | ||||
|     r""" | ||||
|     This class implements the behavior of the XPAT options dialog, | ||||
|     taking care of storing the options on the HD and loading them | ||||
|     again on startup. | ||||
|     """ | ||||
|  | ||||
|     # c4d.gui.GeDialog | ||||
|  | ||||
|     def CreateLayout(self): | ||||
|         return self.LoadDialogResource(res.DLG_OPTIONS) | ||||
|  | ||||
|     def InitValues(self): | ||||
|         self.SetLong(res.EDT_HSPACE, options.hspace) | ||||
|         self.SetLong(res.EDT_VSPACE, options.vspace) | ||||
|         return True | ||||
|  | ||||
|     def Command(self, id, msg): | ||||
|         if id == res.BTN_SAVE: | ||||
|             options.hspace = self.GetLong(res.EDT_HSPACE) | ||||
|             options.vspace = self.GetLong(res.EDT_VSPACE) | ||||
|             options.save() | ||||
|             self.Close() | ||||
|         return True | ||||
|  | ||||
| class XPAT_Command_OpenOptionsDialog(c4dtools.plugins.Command): | ||||
|     r""" | ||||
|     This Cinema 4D CommandData plugin opens the XPAT options dialog | ||||
|     when being executed. | ||||
|     """ | ||||
|  | ||||
|     def __init__(self): | ||||
|         super(XPAT_Command_OpenOptionsDialog, self).__init__() | ||||
|         self._dialog = None | ||||
|  | ||||
|     @property | ||||
|     def dialog(self): | ||||
|         if not self._dialog: | ||||
|             self._dialog = XPAT_OptionsDialog() | ||||
|         return self._dialog | ||||
|  | ||||
|     # c4dtools.plugins.Command | ||||
|  | ||||
|     PLUGIN_ID = 1029621 | ||||
|     PLUGIN_NAME = res.string.XPAT_COMMAND_OPENOPTIONSDIALOG() | ||||
|     PLUGIN_HELP = res.string.XPAT_COMMAND_OPENOPTIONSDIALOG_HELP() | ||||
|  | ||||
|     # c4d.gui.CommandData | ||||
|  | ||||
|     def Execute(self, doc): | ||||
|         return self.dialog.Open(c4d.DLG_TYPE_MODAL) | ||||
|  | ||||
| class XPAT_Command_AlignHorizontal(c4dtools.plugins.Command): | ||||
|  | ||||
|     PLUGIN_ID = 1029538 | ||||
|     PLUGIN_NAME = res.string.XPAT_COMMAND_ALIGNHORIZONTAL() | ||||
|     PLUGIN_ICON = res.file('xpresso-align-h.png') | ||||
|     PLUGIN_HELP = res.string.XPAT_COMMAND_ALIGNHORIZONTAL_HELP() | ||||
|  | ||||
|     def Execute(self, doc): | ||||
|         align_nodes_shortcut('horizontal', options.hspace) | ||||
|         return True | ||||
|  | ||||
| class XPAT_Command_AlignVertical(c4dtools.plugins.Command): | ||||
|  | ||||
|     PLUGIN_ID = 1029539 | ||||
|     PLUGIN_NAME = res.string.XPAT_COMMAND_ALIGNVERTICAL() | ||||
|     PLUGIN_ICON = res.file('xpresso-align-v.png') | ||||
|     PLUGIN_HELP = res.string.XPAT_COMMAND_ALIGNVERTICAL_HELP() | ||||
|  | ||||
|     def Execute(self, doc): | ||||
|         align_nodes_shortcut('vertical', options.vspace) | ||||
|         return True | ||||
|  | ||||
| options = XPAT_Options() | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|     c4dtools.plugins.main() | ||||
|  | ||||
|  | ||||
		Reference in New Issue
	
	Block a user