====== Differences ====== This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision | ||
doc_opener [2015/08/19 14:33] swann |
doc_opener [2015/08/20 12:07] (current) swann [c. custompath operator] |
||
---|---|---|---|
Line 32: | Line 32: | ||
Dans cette partie, nous allons éclaircir le fonctionnement de certaines fonctions clef de l'addon. | Dans cette partie, nous allons éclaircir le fonctionnement de certaines fonctions clef de l'addon. | ||
- | === a. initSceneProperties === | + | ==== a. initSceneProperties ==== |
C'est ici que ce déroule l'enregistrement des variables de scènes, nécessaires à toutes sortes de choses. On retrouve par exemple tous les champs, que ce soit la séquence, l'asset ou autre sous forme de variable de scène ici. | C'est ici que ce déroule l'enregistrement des variables de scènes, nécessaires à toutes sortes de choses. On retrouve par exemple tous les champs, que ce soit la séquence, l'asset ou autre sous forme de variable de scène ici. | ||
Cette fonction de divise en deux parties, l'instentiations de variables déstinées à être **dynamiques** ou **statiques**.\\ | Cette fonction de divise en deux parties, l'instentiations de variables déstinées à être **dynamiques** ou **statiques**.\\ | ||
Ici nous suivrons le code séquentiellement, et donc commencerons par la partie dynamique.\\ | Ici nous suivrons le code séquentiellement, et donc commencerons par la partie dynamique.\\ | ||
- | Dans Blender, l'actualisation des propriétés de scènes EnumProperty pose toujours problème: il est impossible de les mettres à jour sans les supprimer et les recréer. Ainsi, pour mettre en place les Enum dynamique, j'ai simplement crée une fonction(UpdateEnum) donc l'unique utilité est de supprimer et de recréer les Enum passé en paramètre.\\ | + | Dans Blender, l'actualisation des propriétés de scènes EnumProperty pose toujours problème: il est impossible de les mettres à jour sans les supprimer et les recréer. Ainsi, pour mettre en place les Enum dynamique, j'ai simplement crée une fonction(UpdateEnum) donc l'unique utilité est de supprimer et de recréer les Enums passés en paramètre.\\ |
Dans le cas de l'Opener, les propriétés dynamique servent à mémoriser les assets,séquences,shots,stores,... ajoutés par l'utilisateur. \\ | Dans le cas de l'Opener, les propriétés dynamique servent à mémoriser les assets,séquences,shots,stores,... ajoutés par l'utilisateur. \\ | ||
L'exemple qui suit est juste une partie succinte du code de la fonction initSceneProperties concernant la création de la propriété stockant le(s) répertoires choisi par l'utilisateur.\\ | L'exemple qui suit est juste une partie succinte du code de la fonction initSceneProperties concernant la création de la propriété stockant le(s) répertoires choisi par l'utilisateur.\\ | ||
Line 68: | Line 68: | ||
interface.UpdateEnum(bpy.types.Scene,ressources.Items,properties[i][0][0],properties[i][0][1],ressources.Items[0][0]) | interface.UpdateEnum(bpy.types.Scene,ressources.Items,properties[i][0][0],properties[i][0][1],ressources.Items[0][0]) | ||
</code> | </code> | ||
+ | |||
+ | Ci-dessous, un exemple de déclaration de propriété de scène statique, pour la propriété root. | ||
<code python> | <code python> | ||
#STATICS ATTIBS-------------------------------------------------> | #STATICS ATTIBS-------------------------------------------------> | ||
- | |||
#ROOT-----------------------------> | #ROOT-----------------------------> | ||
bpy.types.Scene.roots = EnumProperty( | bpy.types.Scene.roots = EnumProperty( | ||
Line 84: | Line 85: | ||
</code> | </code> | ||
+ | La partie intéressante est la ligne suivante: | ||
+ | <code python> | ||
+ | update = interface.update_naming | ||
+ | </code> | ||
+ | Cette dernière consiste à appeler la fonction **update_naming(self,context)** __à chaque modification de la propriété__. Ce qui nous amène à cette fonction. | ||
+ | |||
+ | ==== b. update_naming ==== | ||
+ | Comme précédement expliqué, Opener utilise la librairie de Naming. Cette dernière est mise en place dans le module interface.py, la fonction update_naming est chargé de préparer le dictionnaire avec tous les champs avant de le charger avec la librairie. | ||
+ | <code python> | ||
+ | #Copie du dictionnaire pour des vérifications | ||
+ | temp = ressources.path.copy() | ||
+ | | ||
+ | #Nettoyage du dictionnaire path | ||
+ | ressources.path.clear() | ||
+ | | ||
+ | #Séparation des éléments en fonction de l'OS | ||
+ | if sys.platform == 'win32': | ||
+ | dest = bpy.context.scene.drives.split('\\') | ||
+ | else: | ||
+ | dest = bpy.context.scene.drives.split('/') | ||
+ | #Mise à jour du dictionnaire | ||
+ | if bpy.context.scene.roots == 'LIB': | ||
+ | ressources.path['Lib'] = 'LIB' | ||
+ | ressources.path['Family']=bpy.context.scene.famille | ||
+ | #Si jamais l'asset sélectinné dans la liste est Other lors de la MAJ, on l'ajoute aux assets | ||
+ | if bpy.context.scene.asset == 'other': | ||
+ | #Construction du tuple temporaire pour vérifier son unicité dans la liste des asset | ||
+ | tempAsset = (str(bpy.context.scene.newA),str(bpy.context.scene.newA),'') | ||
+ | #Si il n'existe pas alors on l'ajoute | ||
+ | if tempAsset not in ressources.Items_asset: | ||
+ | #On récupère le nouvel asset à ajouter dans le dictionnaire | ||
+ | ressources.path['Asset']=bpy.context.scene.newA | ||
+ | #On ajoute cet asset à la liste | ||
+ | ressources.Items_asset.append((str(bpy.context.scene.newA),str(bpy.context.scene.newA),'')) | ||
+ | UpdateEnum('',ressources.Items_asset,'asset','','') | ||
+ | bpy.context.scene.asset = bpy.context.scene.newA | ||
+ | | ||
+ | else: | ||
+ | bpy.context.scene.newA = "" | ||
+ | | ||
+ | else: | ||
+ | ressources.path['Asset']=bpy.context.scene.asset | ||
+ | </code> | ||
+ | |||
+ | Dans les lignes suivantes, les champs dynamique sont mis à jour, si modification il y a eu. | ||
+ | <code python> | ||
+ | #................Quelques lignes plus tard.............. | ||
+ | #Si jamais lors de l'execution de la fonction, on se trouve dans la fenêtre MOVIE alors: | ||
+ | elif (bpy.context.scene.roots == 'MOVIE') and (bpy.context.scene.drives != 'none') and (temp['Dept'] == ressources.path['Dept']) and ('Shot' in temp) and ('Sequence' in temp): | ||
+ | temps = persistence.load_seq() | ||
+ | for i in range(len(temps)): | ||
+ | y = (str(temps[i]),str(temps[i]),'') | ||
+ | if y not in ressources.Items_seq: | ||
+ | ressources.Items_seq.append((str(temps[i]),str(temps[i]),'')) | ||
+ | change = True | ||
+ | #Si il y a de nouvelles séquences, on les ajoutes | ||
+ | if change: | ||
+ | UpdateEnum('',ressources.Items_seq,'seq','','none') | ||
+ | bpy.context.scene.shot = ressources.Items_shot[0][0] | ||
+ | #Si jamais le shot n'a pas changé | ||
+ | elif temp['Shot'] == bpy.context.scene.shot: | ||
+ | #On va scanner les dossier pour vérifier la présence de nouveaux shots | ||
+ | temps = persistence.load_shots() | ||
+ | ressources.Items_shot.clear() | ||
+ | ressources.Items_shot.append(('none','none','')) | ||
+ | for i in range(len(temps)): | ||
+ | y = (str(temps[i]),str(temps[i]),'') | ||
+ | #Si jamais il y en a des nouveaux, on les ajoutes | ||
+ | if y not in ressources.Items_shot: | ||
+ | ressources.Items_shot.append((str(temps[i]),str(temps[i]),'')) | ||
+ | #On met à jour la liste des shots | ||
+ | UpdateEnum('',ressources.Items_shot,'shot','','none') | ||
+ | </code> | ||
+ | |||
+ | Ces dernières lignes sont également très importantes, c'est ici que l'on va appeler la fonction qui, à l'aide de la librairie Naming et du dictionnaire ressource.path va génerer et vérifier l'authenticité du chemin et des nom par rapport à une syntax précise. | ||
+ | |||
+ | <code python> | ||
+ | #................Quelques lignes plus tard.............. | ||
+ | try: | ||
+ | bpy.context.scene.newF = create_naming(self,context,'',ressources.path,ressources.command) | ||
+ | files.Update_ListFile(bpy.context.scene.newF) | ||
+ | except: | ||
+ | print('naming no setup, clearing list') | ||
+ | #Nettoyage de la liste des fichier | ||
+ | bpy.context.scene.custom.clear() | ||
+ | ressources.command.append("! missing field !") | ||
+ | |||
+ | </code> | ||
+ | |||
+ | Nous allons maintenant parcourir un des opérateurs crée pour l'addon. Il faut savoir que dans Blender, les Operateurs représentent un des outils les plus pratiques pour le développement pour de nombreuses raisons( ils sont facilement accessible pour l'utilisateur, ils peuvent prendre des arguments,etc,...).\\ | ||
+ | Dans l'Opener, j'utilise aussi les opérateurs à des fins ergonomiques pour mettre en place des boutons. En fin de compte, chaque boutons est un opérateur auquel on a assigné une icône lors de son appel dans l'interface. | ||
+ | |||
+ | |||
+ | ==== c. custompath operator==== | ||
+ | |||
+ | Pour apprendre à faire un opérateur de base, suivez le lien suivant:[[http://www.blender.org/api/blender_python_api_2_57_release/bpy.types.Operator.html|Blender Operator Guide]]\\ | ||
+ | |||
+ | La première partie de l'opérateur consiste naturellement à déclarer les différents champs est variables nécessaire: | ||
+ | <code python> | ||
+ | #Entête avec héritage de l'object Operator de blender, nécessaire à chaque fois que l'on créer un opérateur | ||
+ | class OBJECT_OT_custompath(bpy.types.Operator): | ||
+ | bl_idname = "object.custom_path" | ||
+ | bl_label = "open" | ||
+ | __doc__ = "" | ||
+ | | ||
+ | filename_ext = "" | ||
+ | filter_glob = StringProperty(default="", options={'HIDDEN'},subtype='DIR_PATH') | ||
+ | | ||
+ | |||
+ | #Variable stockant le chemin choisi | ||
+ | filepath = StringProperty(name="File Path", description="Filepath importing store dir", maxlen= 1024) | ||
+ | #optionnel, récupère les fichiers séléctionnés | ||
+ | files = CollectionProperty( | ||
+ | name="File Path", | ||
+ | type=bpy.types.OperatorFileListElement) | ||
+ | </code> | ||
+ | |||
+ | Ici il s'agit du corps de l'opérateur, la fonction execute va s'éxecuter à chaque appel de l'opérateur. Il en est de même ,pour les fonctions draw et invoke. | ||
+ | <code python> | ||
+ | def execute(self, context): | ||
+ | #ajout du chemin sélectionné | ||
+ | ressources.Items.append((str(self.properties.filepath),str(self.properties.filepath),"")) | ||
+ | #Création du tuple temporaire | ||
+ | t=(str(self.properties.filepath),str(self.properties.filepath))) | ||
+ | #Mise à jour de la liste des dossier racine | ||
+ | interface.UpdateEnum(bpy.types.Scene,ressources.Items,'Store',t) | ||
+ | | ||
+ | #Sauvegarde du dossier sélectionné de manière persistante | ||
+ | persistence.write_config() | ||
+ | #Find de fonction | ||
+ | return {'FINISHED'} | ||
+ | | ||
+ | #Fonction d'affichage de l'explorateur de fichier | ||
+ | def draw(self, context): | ||
+ | self.layout.operator('file.select_all_toggle') | ||
+ | def invoke(self, context, event): | ||
+ | wm = context.window_manager | ||
+ | wm.fileselect_add(self) | ||
+ | return {'RUNNING_MODAL'} | ||
+ | </code> | ||
---- | ---- | ||
<WRAP center round important 60%> | <WRAP center round important 60%> |