Python for Maya: Artist Friendly Programming | Dhruv Govil | Skillshare

Playback Speed

  • 0.5x
  • 1x (Normal)
  • 1.25x
  • 1.5x
  • 2x

Python for Maya: Artist Friendly Programming

teacher avatar Dhruv Govil

Watch this class and thousands more

Get unlimited access to every class
Taught by industry leaders & working professionals
Topics include illustration, design, photography, and more

Watch this class and thousands more

Get unlimited access to every class
Taught by industry leaders & working professionals
Topics include illustration, design, photography, and more

Lessons in This Class

67 Lessons (7h 24m)
    • 1. Introduction!

    • 2. Overview of the Course Materials

    • 3. Using the Script Editor

    • 4. Hello World

    • 5. Hello Cube: A Hello World in 3D

    • 6. Project 1: Creating a Cube Rig

    • 7. Variables and Types

    • 8. Overview of Maya's Programming Languages and Libraries

    • 9. Nodes in Maya

    • 10. Python 2 vs Python 3

    • 11. Saving Your Scripts

    • 12. Project 2: The Object Renamer

    • 13. Finding Help

    • 14. The List Command

    • 15. If Statements

    • 16. For Loops

    • 17. While Loops

    • 18. Finding Object Types

    • 19. If, Elif and Else Statements

    • 20. Setting Up PyCharm

    • 21. Functions

    • 22. Dictionaries: Keys and Values

    • 23. String Formatting

    • 24. Scopes in Python

    • 25. Project 3: The Gear Creator

    • 26. Making a Python Script

    • 27. Creating a Gear

    • 28. Modifying the Gear

    • 29. Classes: Custom Types and Interfaces in Python

    • 30. Converting our functions to classes

    • 31. Project 4: The Animation Tweener

    • 32. Overview of User Interface Libraries in Maya

    • 33. Getting Data for the Tween Function

    • 34. Setting Keys with the Tween Function

    • 35. Creating a User Interface

    • 36. Reusing our Interface for the Gear Creator

    • 37. Adding our Scripts to the Maya Shelf

    • 38. Project 5: The Controller Library

    • 39. Overview of the Qt Interface Library

    • 40. Qt vs Cmds

    • 41. Duck Typing

    • 42. Using Qt in Python

    • 43. Importing Qt Modules

    • 44. Creating the Library Directory

    • 45. Saving Files

    • 46. Finding Files

    • 47. Loading Controllers

    • 48. Our First Bug

    • 49. JSON: Reading and Writing Data

    • 50. Capturing Screenshots

    • 51. Qt Documentation

    • 52. Displaying a Qt Window

    • 53. Building the Qt Interface

    • 54. Making a Gallery for our Controllers

    • 55. Signals and Slots

    • 56. Making our Interface Work

    • 57. Project 6: The Light Manager

    • 58. PyMel: An Alternate API in Maya

    • 59. Starting the Interface and Partials

    • 60. Custom Widgets and Lambdas

    • 61. Adding Visibility and Intensity to our Widget

    • 62. Adding Color to our Widget

    • 63. Portable Code and Logging

    • 64. MQtUtil: Combing Qt with Maya Controls

    • 65. Try/Except: Handling Errors

    • 66. Exporting Our Lights

    • 67. Importing Our Lights

  • --
  • Beginner level
  • Intermediate level
  • Advanced level
  • All levels

Community Generated

The level is determined by a majority opinion of students who have reviewed this class. The teacher's recommendation is shown until at least 5 student responses are collected.





About This Class

In Python for Maya: Artist Friendly Programming, I aim to take you from no programming experience at all to creating advanced interfaces and tools you can use in production right away.

Whether you're an absolute beginner or an intermediate looking to hone their skills, this class will teach you many professional programming techniques to help you make your own tools.

Meet Your Teacher

Teacher Profile Image

Dhruv Govil


Class Ratings

Expectations Met?
  • 0%
  • Yes
  • 0%
  • Somewhat
  • 0%
  • Not really
  • 0%
Reviews Archive

In October 2018, we updated our review system to improve the way we collect feedback. Below are the reviews written before that update.

Why Join Skillshare?

Take award-winning Skillshare Original Classes

Each class has short lessons, hands-on projects

Your membership supports Skillshare teachers

Learn From Anywhere

Take classes on the go with the Skillshare app. Stream or download to watch on the plane, the subway, or wherever you learn best.


1. Introduction!: welcome to fight on for Maya. In this artist friendly introduction to programming, I'll be walking you through your very first line of bite on all the way to creating violence user interfaces. You learn skills to help you work, foster and add value to you on the job market. Under Global Elite, Pipeline Developer is work on movies like Guardians of the Galaxy, Spider Man and Cloudy with the chance of meatballs, too. I talked myself when I was an artist, and now my tools they used by hundreds of artists every single day. I'll be teaching you with the state methodology that I used to learn python creating really cool projects that I could make yourself immediately way. Learn to program the creation of geometry, create animation tools, greater control, a library and a lighting manager all while learning the fundamentals of my projects are split up complexity so you could jump in regardless of your experience level. Whether you're a beginner or an intermediate looking to hone their skills, score should offer value for everyone. Programming, especially with python, is an increasingly valuable skill, and I believe with my course, anyone can learn 2. Overview of the Course Materials: in this project, we learned to create a light manager to manage the lights and are seen. We'll learn how to combine it with my A you elements so that we can dock and undock it from the Maya you. I Additionally, we'll be able to control. Additionally, we'll learn how to enable and disable our lights from the U I. Solo them, delete them and we'll also hook it up to control the intensity of the light as well as the color off the lights. In this project, we learned to use Pi Mel as an object oriented alternative to the Maya Commands library. We learned some slightly more advanced python functionality, like anonymous functions, using Partial and Lambda, as well as using the logger library inside of Python. We'll also learn to use parts of the open Maya, a p I to interact between are cute you elements and our Maya commands you elements. This will be slightly more advanced than our previous projects, but I'll break it down at every step so that it's still easy to follow. Along with that, let's get started 3. Using the Script Editor: If you're taking this course, I assume you're somewhat familiar with Maya and its user and face. You, however, may not be familiar with the script editor. You can access it in three ways. You know Windows General Editors script editor, which will open it in a separate window. You can do the same by clicking on the shortcut button here. Additionally, if you have multiple a few ports, you can convert one of them to the script editor by going to Panels panel script editor, which will change the View port to a script editor. The script editor is broken down into two parts. Does the output window, which represents everything you do in Maya? For example, if I were to click on this model, you can see that it says Select human body. And if I were to click on the glasses, it would do the same for the glasses below. That is the input window there. Two towers by default, there's Mel and Python. These are the two languages. De Maya supports a scripting. You can create more tabs and choose a language by clicking on the little plus icon. Additionally, you can also input code down here in the input in the input line and choose a language by clicking on the word Mellor python to run any code. You cook the double arrow here, and if you're sick of seeing the output here, you can click on the erase button here, and it'll clear history. In the next video, I'll go over how to create your first very simple Python program inside Maya. 4. Hello World: I think it will be a very, very short video because we're gonna create our very first Python program in the Maya script Editor, choose the python tab and type print, followed by a space quotation marks. Hello. My name is and put in your own name. My name is through of someone put down through finally to run it. We're going to click on the double hours up here. When you click that, you'll see the Mayer reports back. Hello. My name is through. Congratulations. You've just written your very first by Tom program continuing on from here. We're, of course, going to make much more villains programs, but I figured I'd show you how simple python can actually be. 5. Hello Cube: A Hello World in 3D: getting my a print of my name isn't all that exciting. So let's create something with it instead for a stroll that's get rid of this text. Then we need to let Python know how to contract. Admire. So we have to get the Maya commands library. We do this by typing from Maya import C M. D. S C. MDs is short for commands. Next we want to create a cube. So we say commands dot Polly Cube and give it currencies. I'll explain. Were saying from the commands library, get the Poly Cube Command and execute it by giving parents sees were telling it to execute it. So now let's click on the double arrows and see what happens. Lo and behold, Maya creates a pollock you for us. Still no super exciting. So in our next video, I'm gonna show you how to take this and automatically profit for animation. 6. Project 1: Creating a Cube Rig: way have a cube. That's not all that exciting. What I want to do with this cube, it's I wanna parented underneath a circle controller so that I can use it as an animation prop. But we have a problem. We created this cube and my call a peaky one. But recall if we call this command again, it will create Peak. You too. So we don't actually know the name of the object of my is gonna create. This isn't actually true. What by a does is when we call this command, it gives us back the name off the Cuba created. And we can store this in something that python calls a variable. I'll show you an example now. So if I say cube is equal to command. So Polly Cube, let me get rid of these old cubes real quick. And when they run it now I'm running things by selecting them and hitting control. Enter, By the way, if I had run it now I'll get a cube. And if I see print Cube, you can see the cube is equal to something. Nowhere tells us is that the cube is equal to P Q one and Polly Cube one. That's kind of strange. The reason is peaky. One is the name of the Cube and Public Cube. One is a name off the Maya node that created the Cube. You can see that if I run this again, the NASCAR P keep to and Polly Cube, too. This means that every time you run it, Cuba will equal the actual name the object. But we don't actually want the constructor. We just want the actual cube itself. So let's say cube shape is equal to Cube zero. Let me explain what's going on here. Cube is equal to two strings. A string is a word or sentence. You can tell it's a string because it's inside quotation marks. Do you hear? Just means that it's a Unicode string, and it's something Maya does that we can ignore. So for all intents and purposes, he's a two strings inside square brackets. Square brackets means that it's a list list is an object that can contain other objects. In this case that contains two strings, we can access the list and get a specific item by using the square brackets. So we say cube and in the square brackets and then we give the number zero. And if we run that, you can see that it's equal to P Cube, too, which is the first item. Hold on. I said zero. I didn't say one. And this is because computers start counting a zero. So when I say zero, I'm actually saying, Give me the first object. If I was to say if I was just a one and I run this again, it now gives me the second object because in computers they start from zero. They don't start from one. So when I say one, I'm actually mean to it's kind of confusing, but you got to use to it. So what I'm saying is, give me the first object and let's assign it to cube shape. So now if I reprint cube shape and that could do this, it will say P cubed to which, if you recall, was the first object off the list. Call Cube. No, we can do the same with a circle. So let's say circle. It's equal to command. Start circle print circle so you can see we create the circle again. Recall the Circle Command from the commands library and we signed Whatever Meyer gives us back to the circle variable. And then we print the circle variable, which gives us a list of two other strings. The first is a circle node that you can see there. And the second is a construction object again. Circle is a list. I can show you this by saying type circle and you can see type is list. If I want to get the first object in circle, I do circle zero, which gives me nerve circle one. And if I do type of that, it gives me Unicode. Unicode is a type of string. So for all intents and purposes, we'll just call it a string. My amex all strings Unicode because that's how it handles it under the hood. But you don't need to worry about that. So now we'll get circle shape is equal to circle zero. So now we have the cube shaped in the circle shape. Well, we need to do is parent one under the other, so I'm gonna use the parent command. But if I use the parent command, it gives us an error. When I run it. It says not enough objects of values. So the parent, come on, actually expects to variables. The first is the child. In this case, I must say cube shape. The second is the parents. I'm gonna say circle shape. And we put this inside the parentheses because we're telling parents how to run. Were saying put this under this. So for run it. Oops. I actually never assigned circle shape. Let me run this again and then let me run this again and you can see that the cube is now under the circle. This is great because that means I can move the circle on the Cube moves with it. But there's a problem. If I move the cube, it can still move without the circle. And I don't want that. So what we're gonna do is we're gonna lock the cubes attributes so we'll go to the channel box and let me clear out the history here by clicking the solo racer icons. I can show you what I'm going to show you. So we'll right click on translate X and I'm going to say lock selected. Now, this told us exactly what it did, except it tells us in Mel, which isn't all that useful, but we can still use it of the starting point. So we know that it used the set at her command. So we said commands just said at her We know that it used P Cube too. The T X, which is short for translate X as you can see over there. And we know that it said lock is true. So we say lock equals true. See? So Maya told us how it runs in Mel, and it's really simple to convert it to Python. So if I run this But let's change TX to t why you can see that a locked the translate Why channel? But hold on. We went through all this work so we wouldn't have to ever actually call the Cube by its actual name. And you're right. So let's get rid of this we're going to say is we know the cubes name will be stored in cube shape. You can add strings together with the plus sign. So we're saying cube shape plus duck T y and what this will give us if I run this Well, give us p cubed to don t y exactly like up here This is because strings can be added together with the plus symbol. But I don't want to just do t Why I wantedto all the translates. So let's say translate. And then let's run this and I locked all three translates. No, let's copy this and changed this to rotate and this just scale and let's run these two lines that we just made. Now all the attributes are locked so I can move the cube. I can scale it an icon rotated, but I can rotate, move and scale circle. So now let's just run through this all together again. Let me create a new scene file you seen, and I'm gonna use the double arrows to run everything. And while that was really quick so we have the cube, we can move the cube become rotated, and we can't scale it in the outline. Er, the cube is under the circle, so we can who? The circle rotate the circle and scale it and the queue follows along. But you notice that when we did this, the Cuba selected wouldn't it be nice to just put the cherry on the top so that we can actually directly select the cube. Oh, sorry. I mean, directly select the circle. So we said commands trust. Select because we're calling the select command, and we tell it to select a circle shape. So now when we run it by clicking the double arrow, it's elects a circle shape, and I could move it, rotate it and scale it. So in a few minutes, we've gone and created a script. They'll create a cube, create a circle well, parent, the cube under the circle, and then we lock all the cubes translation values so that we can admit on it. And finally, real select a circle. Congratulations. You just made your first real python program in my, uh 7. Variables and Types: another beer bout into python a bit. I'd like to introduce some core concepts. First fall, you'll see the print keyword. They will print anything after it in this case, the string Hello World strings air denoted by their quotation marks. Anything in either single or double quotes of the string. So if I say print type hello world, you can see that the type of string. As I'm typing, you'll see pie charm giving me auto completion to help me type Foster. So if I say print type 22 you can see that the type of 22 integer integers the whole numbers. But if I say a 22.1 it's now afloat because floats anything with the decimal point. Other types are false, which is a boule and true, which is also boule boule. A short for bullion, they can either be true or false. Finally, the law simple type is none. None means nothing is assigned. It is a nun type. We've been introduced to variable so I can say food is equal to hello. If I say print, Foo will print hello because hello is being assigned to Fu and we're printing Fu, which prints out the value of hello following the simple types. We now have complex types so I can say my list is equal to hello 22 and false lists are denoted by the square brackets and they can basically contain any other object inside them , in this case, a string, an inter and a bullion. So if I would say print my list out, get a list containing the string the Inter during the Boolean that I gave it, I list and contain other variables I can say Fu is equal to true And if I add this to the end, if I can type properly, you can see that it now includes the value of Fu. I can change objects in a list by saying my list dot append and I can say goodbye. And if I print my list, you can t that it now includes the word goodbye. I can access objects in a list by giving square brackets off to the list and giving a number. So if I say the number two I know get false. If I think the number one I get 20 to know why is this the number one should be. Hello, right? Because it's the first object. No, in Python and other computer languages, they start counting from the number zero. So go 0123 So when we say the number one, we actually didn't mean the second object, which is 22. Similarly, we can reassign things inside a list so we can say my list number zero is equal to I don't know. Let's say spam enough. You print my list. You can see that in sort of. Hello. It's a spam. It's Let's clear this out. No, there are different types of lists. We have a simple list with square brackets. We have a more complex lists, which is the two people which has made with round brackets or parentheses, so we can do the same thing. Fu bam 22. False, True. Just like a smattering of values. So we say, print my to pull and type to pull a my to pull. You can see that we get the to pull back, and it is indeed of type to pull at what makes a to pull different than a list. Well, I can't do my to pull dot upend because two pools have no attribute. A pen and icon reassigned anything insider to pull because the to pull does not support item assignment. Similarly, we have an object called a set. It's also special in that it contact duplicates of the same valley. So let's say I have Fu. Let's change the spam too few as well. So if I were to print my to pull, you'll see that there, too, for there to foods 22 of False into. True. If I convert the stress set using the set function, you can see that a smell is set that's false. True food and 22 sets don't have an order, but they're also unique so that you contact multiple foods and you can't of multiple 20 twos, for example. Finally, we have one other collection type called the dictionary. A dictionary is sort of like what you would expect in English. You have a definition off python, for example, and you would say that it is ah, programming language except so you Basically you would have a key and a value. So let's define our first victory. We say my dicked is equal to, and you give it curly braces for dictionary you say name inside quotation marks and this will be the key colon and their brackets. We'll say drove. We'll give it a comma and you'll say, Roll and again colon and save pipeline TD again. You have the key, the value another key, another value. And like lists, dictionaries can contain variable types. So again we have an integer instead of just strings. And we can save print my addict So something you know, dictionaries like sets are not ordered like sets they cannot share. They cannot have more than the same Ah kee So like, a set could not have the same value multiple times. Addiction cannot have the same key multiple times. See, I can only have one name, one roll in one age to access the dictionary. They use it like a list. But instead of giving a number, I give the key that I want access. So when a access name. So I asked her name and I get name and the value of through. If I want to change that, I can say my name is Cartman. If I print my dicked No, my name is Cartman. So dictionaries of similar lists. But in sort of having numbers as their indexes, they have words. This completes a quick look at some basic python concepts that we'll need to continue down the road. 8. Overview of Maya's Programming Languages and Libraries: wear now going to go over all the programming languages and AP eyes inside of Maya, my has to a P i libraries. The first is a commands library or C M. D. S for short. It consists of bite size commands that artists can use to string together to make larger applications and tools. The other library inside of Maya is called the Open Maya a P I. This gives technical developers deep accessed Jeremiah's internal architecture, but it comes at the cost of complexity, and it isn't very suited for artists to quickly pick up. But the rest of this course will be mostly focusing on the Commands library. My has four programming languages. The first is Mel. Mel is a Maya specific language that's intended to be simple for artists to pick up, and it can only use the commands library melas, an interactive language being that weaken. Type it and see the results in real time. This is a poster Maya's other primary language, C plus plus that was used to create my itself. C plus plus is a more complex language, and it can only access you open my A p I. Additionally, C++ requires to be compiled ahead of time, meaning that it can only be distributed. It's plug ins and can't be developed in real time. Like C++, Maya has another language called C Sharp C. Sharp support in Maya is limited to Windows, and it has the same caveats. A C plus plus it has to be compiled and can only access the open my A P I. On the flip side, C Sharp is quite a bit easier to use than C plus plus, and it is quite popular in the gaming community. Finally, the lost programming language and Maya. And the focus of this course is Python. Python is in a unique position because it can access both the Open my A P I and the Commands library. It is the only language inside admire that is capable of doing this. Unlike Mel, Python is used by programmers outside of Maya as well. Similar to C plus plus and C Sharp Fight on is quite popular in the programming community. Google has chosen it for its machine learning technologies. Dropbox uses it extensively, and scientists use it for scientific research. What this means is that Python has a very Voss community with many libraries that we can leverage for use inside of Maya for tools. Additionally, this means that there are a lot of resource is for pie time. The reasons for pythons popularity is because it is an intuitive language, while providing many advanced features that both C plus plus and C sharp have. This comes at the cost of performance. Python is in the middle of the road. It is much easier to use and C plus plus and C sharp, but it can be much slower. Usually, this is a trade off worth making, because python code is quite easy to write, and often you don't need the speed that C plus plus a C sharp offer. Insider Maya. There are actually four AP I libraries that Python can make use off the first of the Commands library. This was originally designed for Mel, but we can use it from inside Python as well. The commands Lavery is quite performance, but due to its heritage as being created for Mel, some of the syntax and use can make it quite verbose to use in python. This isn't ideal, but it's also not a deal breaker. The other a PR that I mentioned already is the open Maya, a P I. There are actually two version of this open Maya one and open my A to open My A one was originally designed for C plus plus and again, like commands. It is not completely platonic. This means that you will often be typing things that don't make sense in Python, but would have made sense in a C plus plus world in reaction to this Autodesk made open Maya too open My A two is a little more platonic and simple to use inside a pie time. Unfortunately, it has not yet feature complete, so you'll still have to use open Maya one. In some cases, the Lost A p I the Python can use. Insider Maya is a hybrid AP I created by Loom. A pitcher's called Time L Primal was resigned from the ground up to provide a very python like interface inside of Python. It does this by wrapping the Commands library and the Open Maya AP I into one interface that we can use. Primal is a pleasure to use because it can cut down on the code we have to write and makes it much easier to interact with objects inside of Maya. This flexibility comes at a cost pi Millikan often be slower than both male and the open my i p I. Additionally, some studios do not allow primal because of the speed concerns and because of some stability concerns. Generally, if you're writing strips, pie mill is quite all right to use. But for this course I'll be focusing mostly on the commands library because it is more important to learn. We will have one project that will use both the open Maya FBI briefly as well a za pi metal , a p I for the entire project. With this covered, let's continue on to our next projects. 9. Nodes in Maya: when we need to affect objects inside, a Maya will primarily be affecting attributes on these objects. These attributes are often refer to by the object name, followed by a dot and then finally followed by the attribute name itself. Every object in Maya is actually a node. You can view this inside of the note editor, but I'm going to show you a simplified diagram. Every node has several attributes to reconnect it. We can access these attributes in our scripts by using the object name dot and the attributes name. But on the node, the appears objects called plugs. Plugs can have value set on them, and that's what we often do with script. We can also key them, but we can also create connections between one nodes, plugs and another's. This is how most, if not all, objects inside of Maya interact with each other. It's also how will primarily be interacting with objects inside a Maya. By changing these values, using our scripts 10. Python 2 vs Python 3: in this video, we'll be going over the two different Python versions in the Wild. The two current versions of Python, Our Fight on 2.7 and Python 3.5 Python 2.7 is the latest in the python to Siri's and Python 3.5 is the latest version in the Python three. Siri's Fight on two will see no more active development outside of simple security fixes and will receive an end of life in the next couple of years. The Python Foundation has decided that Python three is a way forward. No, why are there different versions of Python? Well, this is because python to and python three how many breaking changes between them. This means that python to code isn't guaranteed to run under Python three. Additionally, Python three has many new features that cannot be used by python to this means that even though the language is very similar between Python to and python three and in most instances you cannot even tell the difference, it does mean that python to and python three are not guaranteed to be compatible with each other. My originally launched with Python in my 8.5 with Python version 2.4 point three in My A 2000 and nine, the upgrade of the Python version 22.5, and Maya 2011. They upgraded again to 2.6. Finally, in my 2014 they've upgraded Python to fight on 2.7. This is the most recent version of Patan in the python to Siri's and will likely be the Lost. The visual effects industry has decided to stick with Python 2.7 as long as they can. This is because of significant investment in the python to ecosystem, which would be hard to port over to Python three. The VFX platform has decided that bite on 2.7 is a version of Python that all software should be using. Therefore, whenever we're developing for Maya, we'll be using Python 2.7 11. Saving Your Scripts: video. I'll go over how to save the script and then slow or sit back in so we'll go to file safe script. This brings up the document browser, the documents destroyed in different locations on different operating systems before Windows. It's under documents. Maya, you, my aversion and scripts. If you're using Mac OS or Lennix, I'll make sure have mentioned them in the video. I'm gonna save the script as object rename, er example dot pie and hit Save another. Save the script. I can get rid of this. Now that the script is gone, I can say file, vote script, Find it again and it loaded into the current tab. Alternatively, I can say file source script, and it's sort of loading it in. What I will do is they'll execute it immediately. This is an ideal because, as you can see, it's changed all the names of my objects. And it didn't want that In our next video, I'm going to go over how to compose our script into functions that won't run immediately but will be available for us to call easily. One last way to call a script is because it saved in a Scripts directory, you can say import object rename er example, and what it will do is will import that, just like reimported the Maya commands library, and now the script has been imported into Maya. But unfortunately, Importing also executes a script, causing it to run yet again again. In our next few videos, we'll go over how to compose it and functions that will only run when called. 12. Project 2: The Object Renamer: through this project will be learning how to create a controller library using cute. Our controller library will be flexible and will support thumbnails. We can import any of the objects that we save out, and we could also create any new objects we want. In this case, I will say this as the test, and when I hit save, you'll see that it shows up inside of for our window. We learned how to save data out as Jason and files as well as load them back into Are you? I We'll be using cute provided by pi side to inside of my 2017 and pie side. In previous versions of Maya, we'll go over the differences between cute four and cute five, as well as the differences between pie cute and pie side and pie, Cute five and pie side, too. I'll also be going over a popular cute library that's used by Disney, WETA, Sony Imageworks and more. There will help us write code that can be used the cute in both Maya 2017 and previous versions of Maya. In the next video, I'll do a brief introduction to cute on. The different versions are cute use inside the different versions of Maya 13. Finding Help: Before we continue any further, I'd like to show you how you can get information about each of Maya's commands. Inside of Maya, you can go to the help menu, go to my a scripting references and click on the Python Command reference. This will open the Autodesk documentation, and it will list every single command that Maya has to offer. I want to look at the parent command, and over here I can see that the parent command takes two objects the child and the parent and another series of parameters scrolling down. We can see each of the parameters with this long name and a short name as well as a type. It's rolling down even further. We confined documented examples of how to use it back in Maya. We can also find help inside of the script editor. For example, if I want help on the parent command, I can select it right click and go too quick. Help. This will list all of the flags with the short names and the long names. Traditionally, I can also enable auto completion. I can go to this menu and I can enable come on completion and show tool tip help. Now, when I type, we will try and auto complete for me. And when I'm inside of a command, it will list all the flags that it takes. Personally, I like to disable this because it can get quite busy inside of Maya, though I leave it enabled inside a pie charm. If you ever struck the documentation online can be a great help. My has helped. Features are limited to only the Maya libraries, but you'll often need to look up information about python itself. The python dot org website has great documentation on everything inside Python, for example, this is the page and all the variable types. You can also access help inside of my for example, if I run help and give it an object, it will print out all the information about that object type. In this case, I'm looking up the help documentation for a list. Sometimes you already have an object defined, and you want to look up what you can do with that object. In that case, you can use the de IR command. What the D I R command will do is they'll give you a list of all the objects and attributes that are associated with the object to give it. In this case, who can see that the list object assigned to the variable A has all these functions inside ? If it and we can see that we can append to it, we can count it, insert index, etcetera. Both these functions are very handy, as you can look up information on the fly while you're writing a script. 14. The List Command: to begin our course, we'll need to get a list of the items that will be operating on in my scene. I have to join chains. A Cuban, a group, but you could have anything you want. First of all, we need to get the Maya commands library again. Who will say, from Maya import communes inside of the commands library is a list function. If we run this and I'll print out the outfit, you can see that it gives us back a list ofall the objects in the scene. At the very end, you can see the objects that we're talking about, but we also get a bunch of objects that I don't actually care about. These are hidden objects inside of Meyer. So what we can do is fill the ls object to only use the selection that we want. So let's look up the documentation for the L s command. If you double click on it and then right click, you can select. Come on, Documentation. This will open up the browser for the L S command. Down here, you can see the selection parameter, and if I click, it will take us to the documentation for the selection parameter. You can see that the long name is selection and the short name is SL. It is of type Boolean, which means that it could be either true or false. And if it's true, it will list objects that are currently selected. So back in Maya now let's give the L s command the selection parameter. So we say selection is equal to true. And now you can see that it only list the object I have selected in this case Joint one. So let's store this inside of a variable. You'll say selection is equal to command. Zarrella selection is equal to true. But what if we don't have anything selected? If I now printout selection without anything selected, you can see we just get an empty list because nothing is selected. And if I redo it with something selected, we'll get back that object. If we don't have something selected, I want to do something different. So we'll be introduced to the s statement in the next video 15. If Statements: in this video, we'll be learning about the if statement, the if statement. Let's just say that if something is true, do something else and the syntax is pretty simple. We're saying is if the statement is true, only then will redo this and you can see that the things that we will do our indented in python this is called a scope. The scope of this logic is this. If statement, everything underneath the safe statement that is indented will only run. If this if statement is true and if it's not indented, then it will run regardless off. Whether this, if statement is true, So back in Mayer, let's write our if statement. So we say if the lent off the selection is equal to zero, we'll get a new selection. First of all, let's look at the double equal symbol that we used. The single equal symbol means that we're assigning something. The double equal symbol means that we're comparing something in value. So we're going to say if the length of the selection is zero, then let's get a new selection. So we'll say command sort ls I'm going to use two parameters that I'm going to introduce shortly. I'm gonna say Dag equals true and long equals. True. If you go back to the documentation and look at long, you can see that it takes a Boolean and you can see that if it's true, will return full pot names for Dag objects. No. Why am I doing this? Back in Maya, you concede that I have joint one and joined four. But underneath Joint One, I also have another joint four Sort of like a work when you have to John's. And if you say hey John, neither of them assure which one should respond in. Maya, If I was to say he joined four, both joint fours will try and respond, and it will cause an error. The long parameter means that we get the full pots to the object so we'll get joined four and know that is a child joint one. Where is this Joined? Four has no parent. Now let's look at the Dag parameter back in the documentation. We can scroll up to Dag and you can see that it's actually called Dag objects. But I've used a short form gag this list Dag objects, if any type what this means is that we'll only get objects that are listed in the outline er and none of the hidden objects inside of Maya. So if I now print the selection after this, if statement I noticed that my print statement is outside of the if statement, that means there whether or not if straight men runs this print will still run tonight. If I run this, you can see that it's only going to use the selection that I have because I have more than one object selected deferment. This statement is false. If I select nothing and now I run, you can see that it's listed every object in the outline. Er, this is because if statement is false and does not run, this is because the if statement is true. The left of the selection is zero. Therefore, we will get the new selection, which will list everything in the outline. Er but you can see that the order of the list isn't particularly useful to us. The problem is that if we renamed joined four, but it has the full part which has joined one joined four. That is all right. But if we rename joint one. The posture joined four. Now changes. This means that we can no longer find joint for. Therefore, we need to sort it with the Children first and the parents at the end. Back in Maya, what I'm gonna do is I'm going to sort the selection. So before this print statement, I'm going to say selection don't sort because selection is list and it has a sort method. If I now print selection, you can see that it's actually sorted the list, but that is sorted them alphabetically. That's the default behavior for sort. This isn't useful for us. Instead, we need to tell Sort to use the left of the objects. This is because the Children will have a longer full name than the parents because the deeper down, for example, Joint Four will include Joint One in its part, was Joint One will have nothing because it is the top most object, so we'll tell the selection not sort to use. The length is the key for sorting, so we'll say key is equal to lend. And now if you run this, you can see that objects assorted from shortest to longest again. That's not what we wanted. We wanted the opposite. We can also tell Sort to reverse it. So we say reverse equals true. And now if you run it, you can see that the longest objects are at the end and the shortest objects are at the other end. What this means is that the Children will be acted upon first and then the parents, thereby not affecting the parts to the Children. In the next video, we'll go over four loops and how we can go through all the items in the list and do something with them. 16. For Loops: in this video will be introduced to the four loop. The four loop says therefore, item in my list. Do something with this item again. You can see that the logic is indented. This means that it will only run in the scope of the four loop. Anything outside the loop is un indented because they will run outside of the four loop. The syntax of the four loop says four item where item is the name for temporary variable and item could be called anything you want inside my list where my list is a list that you want to look through We're going to do something with that item No, back in Maya we're going to do is we're just going to go through every item inside of our selection and find the short name for this item. So you're gonna say four will be J short for object in selection, which is the list that we have off. All are selected objects. We're going to save print O B J. Enough. I run this. You can see that it prints out our names. The names are kind of long at the top. They have this pipe symbol to show they have this pipe symbol to show the part of the object. What we want is to split up the string. Why the pipe symbol? Fortunately, O B J is a string object, so we can say print O. B. J not split, and the split operation by default works on spaces. But we need to tell it to work on the pipe symbol instead. So we give it the pipe symbol, insider quotation marks, and we run this. Now you can see that each object is now list off every word split up by the pipe symbol. But we don't want every single word. We just want the loss word. So since it's a list we already know how to access objects within it, we use the square brackets and give it a number. But the problem is that each of these lists is a variable length. Some of them are only one object long and some of four objects long. Fortunately, Python lets us iterated backwards through a list, a swell, so if you given minus one, it means that we will take the very lost object inside of the list. So now if you run this, you can see that we only have one word. And the word is the loss word inside of the list. We will take this and we'll assign it to the variable short name in the next video. We'll look about flushing out this four loop by renaming these objects according to their type. 17. While Loops: I'd like to take a pause here and talk about a different kind of loop with Wild Loop. The while loop is very similar to the if statement and the for loop combined. What it does is it says if this statement is true, keep doing this action until the statement is no longer true. Additionally, you can exit the while loop or even a four loop by thing break Break tells fight on to break out of the loop that is currently in. Why loops a powerful for when we don't know how long in action should run for. But we know when we wanted to stop, we'll be covering while loops later on in the course. But I thought it was useful to mention it now so that you're aware of them. If you see them in any of the documentation 18. Finding Object Types: in this video, we're going to try and get the object types of each of the items in our list. We'll start off by saying print commands object type of the object in this list. And when we run this with this cube selected, it will give us back transform. Now you may be asking, why is it a transform when it's clearly a mesh object? Well, in the outline er, if we right click in, say shapes, you can see that every shape is actually a transform and a shape. This is just a Maya represent its objects. So let's get rid of the shapes for now. And we have to actually find the Children off the transform and then get the object type off the Children. So let's clear this out and let's fetch the Children. We can do this with a command, coolest relatives, and let's store this inside of variable called Children inside of list relatives. Let's give it the object that we want to get the relatives for. Then let's tell it that we only want the Children. Let's also tell it that we want the full pot to each of the Children. If I run this now and let me print out Children so that we can see what we get. I run this. Now you can see that this shading group, which is selected, has no Children. But if I select P Q. One, you can see that really get the P Cube shape one instead. If I choose this empty group, you can see that instead of the list, we get the nun object. This is kind of annoying in Maya, because even though the command says list when it has nothing to give us back, it gives us none. This means all our code would need to check if it's none or a list, but we can do a simple trick. At the end of this command, you can just type or and to square brackets. What we're saying is that if list relatives is empty or none, then let's just make it an empty list, which is denoted by the two square brackets. So no matter what we do, we're always sure that Children will be off object type list. So let's get rid of the print Children and get the object type off the child. The problem is, you only want to get the object type of the child if it's the only child underneath the parent, so we'll use an if statement. We'll see if the lent off the Children list is equal to one again. Note that were used to equal symbols to compare instead of one equal symbol to assign, we'll get the child from the Children's list. I will get the first child, which will hopefully also only be the only child by saying zero again. Remember the list. Start counting from zero instead of one, and we'll say Theo BJ type variable is equal to commands. Object type off the child. Otherwise, we'll say that LBJ type is equal to commands an object type off the parent in this case, O B J. Over here, you can see the else statement. The else statement is run if the if statement is not true. So if the length of the Children is less or more than one, we'll run this statement here instead. But if the length of Children is one, we'll run this. This lets us set up conditions for how the code will run based on values at runtime. Now that we have the object type. We can print it out and see that if I select the Cube, I will get mesh. And if I select the joint, I will get joint. And if I select, the empty group will get transform because that's what it is. In the next video, we'll go where more complex if statements using the object type to determine what the objects should be renamed to. 19. If, Elif and Else Statements: way have the object type. Let's figure out what our Suffolk should be, so we can use a few if statements to figure this out. So we can say if OVI J Type is equal to mesh again, note the double equal symbol instead of the single one. Well say suffix is equal to geo. Otherwise, if the object type is equal to joint, well, say the suffix is equal to joint. This is the LF keyword like the else keyword. It will only run if the if statement is false. But unlike the else statement, it provides another statement to check. In this case, we're saying, if the object type is mesh, then the Suffolk's will be geo. If the object type is not MASH, we'll do the next check to check if the object type is joint. If it's not joint, then we'll continue on down the chain off. If and l statements. So following this we'll have another LF and you'll save object type is equal to camera. I don't actually want to do anything if it's a camera so I can say print skipping camera and I can see it continue on what we're doing with continue is we're telling the four loop to continue on to the next item and not perform any of the other logic in this four. Look for the current item. Next, we'll have the else statement, which will only run if all the other statements in this if LF and Elstree are falls, we'll say. If none of these other statements are true, the Suffolk's is equal to group. Finally, we say the new name is equal to the short name plus Underscore plus suffix because both short name and Suffolk's our strings, we can add them with the plus operator, and this will create a string combining them. If I say print your name and run it, we can see the P Cubed One will be renamed to peaky one g R P. Because it is a group. But if I use peaky, won the represents a Cuban here and then run this, we can see that it will be renamed to Geo. Now let's do the actual rename recon say command are rename and we give it the old name in this case will give you the full park, which is represented by O. B. J. And we will give it the new name which is retreat just constructed. So if I run this now, you can see the PQ one has been renamed to peaky one underscore Geo And if I d selected and let me undo it And now if I run it, you can see the peaky one has got the suffix Every joint also have the suffix at all The groups also have the correct Suffolk's But like we said, none of the cameras have been affected on this is exactly what we wanted. 20. Setting Up PyCharm: thing is gonna be a small video on how to install pie charm and get it set up correctly for your system. On the pipe charm Edie website. Click on Download and choose your platform. I'm on Windows and we're just going to download the Windows version. Once his stroller is open, click. Next, choose of directory you want it to be in. The default should be fine. The sex part is the important one. I'll ask you to choose your python version. Make sure installed Fight on 2.7 and not Python 3.5. My uses bite on 2.7, so it's important that we stay in sync with it. Once estan simply click next and then just continue with the rest of the installer will take a little while to install. And when it's done, you should have pie charm ready to go. In this video, I'm going to go over how to set up I charm et you for Maya. If you're using a different editor, I'll go over the common editors in another video and how to set them up with Maya. But for now, let's focus on pie chart. First of all, we'll need to set up the Python interpreter. If you go to configure and settings or if you already have some code open, you can go to file settings. We'll open up the default settings window. If you go to Project Interpreter on the left hand side, they will bring up this panel with a drop down where you can choose different python versions to use. Well, we want to do is use the Maya Python version instead. So we'll click on this little gear icon and say, Add local. We'll have to navigate to where Maya is installed on Windows. This will be on your C drive. Whatever you installed your windows on under program files. Autodesk, my 2017 been and there will be an object call Maya Pie on Mac OS and Linux Axis will be in different locations that will be shown on the video. If you scroll down, you will find the Maya pie and you can select it, and this will tell pie charm to use my a pious It's Python version. Instead, go back to the gear icon and click on Mawr. Click the Maya Pie that we just added and hit the pencil. Let's call this the Maya 2017 Eitan, so we know which one you're using. Finally, we need to set up auto complete inside a pie charm. If you're using my A 2015 and below the deck it with the auto complete ships with Meyer. If using My 2016 or Maya 2017 you'll have to download the auto complete library on my get up page. The Dev kits are listed, so let's use the Maya 2017 download. We'll click on the link and it'll take us through the Autodesk App store on the Autodesk App store. You can download it by going to the right and clicking on download. When this is done downloading, you'll be presented with a ZIP file for your OS. Inside the ZIP file will be the deaf kid base. You must find your Maya install directory again. This will be on Windows Undersea. It will be in your program files under Autodesk Maya 2017 and all you need to do is extract all of these into that directory just into the route to that directory, not into any subdirectory. If you're using Mac Os or Lennix again, the pot will be different, but I'll mention it in the video, one so so extracted. Open up your pie charm settings again clicked a little icon at the bottom right? You'll be presented with a bunch of pots for python to use. We're gonna add once or click on plus again, we'll go to see and we'll navigate to the directories we just extracted. So we'll go to Autodesk my 2017 and we'll go to the death kit inside the deaf kit. Go to other primal extras and completion, then click on pie, the P Y. And then just add this directory by clicking OK, finally, simply click OK, hit Okay again and hit. Apply now. Pie charm will know to use a Maya python instead of your system pie time, and we'll be able to auto complete as you type. So let's close down these settings and I'm gonna click background so it doesn't take up my time and we'll open a project. We'll go to your documents where your Maya scripts restored. This will be different on Mac OS or Lennox, but again I will make sure to mention it. We'll go to Maya. You're my aversion. 2017 and we'll open the scripts directory. I'm gonna click, OK, to open it up. I'm gonna expand my pie term. And for the rest of this course, I'll be using pi charm and presentation mode so you won't see most this you I But for now, if I expand this, you can see our object rename or example over there. If I double click it, it will open up and you can see all our code from Maya inside here. 21. Functions: as I showed in the previous example. Whenever I source a script by either clicking source script and choosing the script or importing it, it runs immediately renaming or seen again, which is not what I want. So let me undo this and shift back to pipe charm in pie. Tom, you can see all our code that we previously wrote. What's happening is whenever Maya imports or sources are script, every single line of code is going to run from top to bottom. This isn't what we want because you don't want it to run when we import. This means that we can never reuse our script easily. So what we're gonna do, it's put all for code inside of a function to create a function type death for define. And then the function name in this case, rename and we'll give. Apprentice E is to say that it is a function. Finally, we'll put a colon, and like everything else in Python, the scope is denoted by indentation. So we'll select everything that we previously written and hit Tab Tabal indented it underneath our definition off the function. That means that all of these things will only run when the function is run, our function is created by the word death for define. This is the name of the function rename The parentheses are what we used to show what parameters are functional take In this case, our function takes no parameters. So we'll just have the empty prince sees followed by the colon and then followed by all our code back in Maya. If we import this again, nothing happens this time. But we now know that our object rename er example is a library with the renamed Function inside it. So if we run it, it'll say model object has no attributes rename. That's because Python is trying to be efficient. It knows. Have you already imported object rename our example so won't try to import it again. Instead, what we need to do is tell it to reload it. We'll say reload, object rename er example. I don't I don't know about you, but that's a pretty long name to type and we've already typed at three times. So what I'm gonna do isn't one a nickname it Where's the import object? Rename our example as O. R. E shortfall object Rename er example. Then instead of saying Reload, object, rename our example. That's a mouthful. You can say Reload Ory. And over here you can see it for E nor rename anyone. Recall this. You can see that it runs, and it renames all our objects again. This is your first function, and this will be it for this video. In the next video, we'll go over how to make our function more robust. 22. Dictionaries: Keys and Values: back in pie term. Our first step will be to make sure that if the suffix is already on the end of the object that we don't rename it again and double add the suffix. This is simple because the object type of a string we can say if o b j dot ends with some fix, continue and you can see pie Charm is auto Completing as I type. High charm has really powerful auto completion, which is why I like teaching with it because it's really useful if you're a beginner as well as if you're in advance TD. Anyway, I'm saying, If object ends with Suffolk, Sui will continue and skip the rest of this logic, including the step where we rename the object. This means that if the object does end with it, it won't have to times of Suffolk's every time we run this. So if you go back to Maya and run this function again, you can see that it doesn't affect any of these objects. But if I create a new cube, let's move it out here, which doesn't have the Suffolk's, and now I run this. You can see that it's added just to that cube because the Cube didn't have it before. But if I run it again, it won't. Added again, This is our first advancement in the script. Our next advancement is that I want to add more Suffolk Stripes eventually. But this if statements already getting pretty long, and if we had a new one for every single object type, it's going to get kind of crazy. So what we're going to do is we're going to make a dictionary where weaken define all the suffixes that we want so we can type. Suffixes is equal to and to make a dictionary will make curly braces. The reason I'm making this capital letters is because it is outside of a function, and usually it is nice. They're not necessary to make variables that are outside of function or any of the scope to be capital letters. Inside of this stuff X dictionary, we're going to create a new key called Mesh. We'll sit colon and we'll make mesh equal to Geo. Next, we'll create a joint type and we'll say the joint will have a jmt suffix and you make a camera and you'll say the cameras will have none. I will explain this in a bit. Next, I'm going to make a default suffix and I'm going to call this default suffix group. They're down here. Problem is, I have to say Suffolk's equals this Suffolk Sequels that multiple times. What if I make a typo? I'm typing the same logic multiple times with small variations. Ideally, I would just type this once and just use that so I don't have to keep repeating myself, so it may get rid of all these if statements. Instead, we'll use the dictionary that we just define to look up the suffix. So we'll say Suffolk's is equal to Suffolk's is our dictionary and you'll say gapped because we're trying to get a value from the dictionary. Now get takes one value by default. As you can see, Pie Charm is telling us the key, and we'll use object type. The second key is the default. If the dictionary doesn't have the key, the Riaz for it'll give us a default back in this case, none. But what we actually want to do is get back the default. Suffolk's default Suffolk's is equal to group. What we're saying is, if the dictionary doesn't have the object type revolves for. Let's just assume it's a group and get the default. Suffolk's back. But you'll remember that I said, Camera is none and this is because I don't want to put a Suffolk. If it is a camera, so what? I'm gonna do it somewhere. Say, if Lot Suffolk's continue. And what we're saying is that if the Suffolk sex is not true, this a shorthand well, say to continue and skip the rest of this logic differ for the camera. The dictionary will give us back the value none, and none is not true. So we're going to say to continue if you go back to Maya and if I run this again, it will say invalid syntax online to off my code. And that is because I Mr Khama here and you can see the pie charm was highlighting. It began. If I remove that, you can see that it says it's red and fad the comma. It says it's fine. Now I'll go back to Maya. If I run this again, this time it works and you can see that everything works. All right here. If I create a new object type. Let's say create lights an ambient light. The ambient light is off type little. See, the ambient light is of type ambient light. If you go back to pie charm, I can add the ambient light type here ambient flight. And I can say that I wanted to be a G T. If I go back to Maya and I run my script, you can see that it's renamed my ambient Light with the new L G T Suffolk that I provided. And you can see the advantage of using this dictionary to maintain it, because I don't have to add another FL statement for each single suffix. It cuts down on two lines of code for every single suffix. That's a lot when you add a lot more object types, the next thing we want to do is make sure that our function can be told whether to use the selection or not. So we're gonna add a parameter to our function. We're going to say the parameters name is selection is equal to, and we're gonna say that it's false by default so that it doesn't use the selection by default. That's a bit annoying because selection is already used as a variable name here, and this parameter name will be passed down into the function. And you can see pie charm miss highlighting every use of this variable now and that's not what we want. So I'm gonna select this word in pie charm, right click re factor. And I'm going to rename it and we're rename it toe objects and you can see the pie Charm has found every instance of that variable and renamed it. But it's also grabbed this one. So I'm just going to rename this back to selection. And what we're going to do is say objects is equal to commands, right? Ls selection equals true. This is what we had before. But instead of using the hard coded value of true, we're going to use selection as their input by default. It's false. But if a user provided true, then selection here will be true and it will be true. Here is well again, we're only interested in dag objects at only in the long names. That means we can get rid of this. But what if the user has said selection equals true and there is no selection currently. Well, we need to do is air early so that we don't run the rest for our code because the rest of our code can take a lot of time to run if we have a lot of objects. So let's error out early. We'll say, if selection and not objects. And what we're saying is that if selection is true and objects are not true, I'm by that we mean that objects are empty. There are no objects. We will raise a run time error and real say that you I don't have anything selected. How dare you? And this is our first error that we're gonna throw. We're seeing raise because we're going to raise an error just like you raised a complaint against someone. Or work for having smelly feet were raising a runtime error thing. That we've encountered an error during our run time. And then we give more details about it. You don't have anything selected. How dare you? I'm going to save this and move back to Maya where if I now have nothing selected. But I say selection equals true and I run this, you can see that I get a runtime Error From what? Our script. It tells us which line the arrows on where the script is. And it helpfully tells us error that we gave it. You don't have anything selected. How dare you let me select something and running again? This time I don't get an error. Alternatively, if I say selection equals false, that's the default. I don't actually even need to say this. Let me remove it. And it will run with selection, equals false by default and will run across everything back in pie charm. The next thing that we need to do is change how this formatting happens. This is all right, but we have two plus symbols and multiple strings. This is kind of inefficient and python. A better way to do it and slightly more complex is with a percent s symbol. It kind of looks like a weird emoji, but what we're doing is doing a string substitution. So I'm gonna say new name is equal to percent s underscore percent s and they will give it a percent symbol and we will give it the short name and the Suffolk's. And the reason I'm showing you this is it doesn't make as much sense for a short string. But when you start doing it a lot and over many objects, the other way of doing it can get really heavy. But this is a really light way of doing it. So what's actually happening is this percent s is being replaced by short name, and this percent s is being replaced by Suffolk's. In the end, it creates the same string. But this is a little more efficient, and I'll be using it for most of my examples. So I think it's a good example to show right now. The other thing is, if the object ends with suffix, it might actually be a valid object name and needs a Self X added what we actually need to do. It's check if it ends with the underscore and the suffix. And this will mean that it doesn't actually have the proper suffix, just like the Maya commands give us back a list of objects that they ran on. It will be nice of our object can do the same at the under four function outside of for four loop, I'm gonna say return objects return objects is gonna tell our function that when it's done , it sure turned the objects list that it has. But the problem is the objects list doesn't represent the new names, so let's change that. Let's get the index off the current item from the objects list. We'll do this by saying index is equal to objects dot index offer current object. What this does is gives us back the index value off the object from the Are objects list. So if it's a first object, we'll get back. Zero. If it's our second object, we'll get back one and so on and so forth. We'll use this to know what object to replace inside of the list to real objects Index is equal to, and now we'll replace the object inside there. So we'll say object would replace. And now we'll replace a string so that it has a new name inside. So we'll say object toward replace short name new name. And what this will do is in the objects list. At that index point, it will replace it with the object name where the object name has had the old short name replaced with a new name. So that means our list will have all the objects that operated on any time that we've renamed an object. It will have been replaced in the list with this new name. So if you go back to Maya, that's a print or you don't rename. You can see that I get a list of all the objects back with their new names, as well as the objects it hasn't renamed with their old names. Finally, we need to make sure that our function is easy to use. People using our code library don't want to be looking at our code. Just, you know, hard function works. If I say print help on this function, it gives me nothing back because there's no help for this function. How do we provide help for a function? This is simple. We call it the Doc String. First of all, inside a pie charm. Let's change the doctoring format. Let's go to file settings, and inside of this, I'm gonna go tools, python, integrated tools and winter change it from restructure text to Google, Google is a lot easier to read than restructure text, click OK, and I'll go back to my function after our function. I'm gonna hit, enter and type in three double quotes 123 and then I'm gonna hit, enter and you'll see that pie charms automatically filled it out a bit. This is called a doctoring. The first comment after a function with triple quotes will be what's presented when you call help on a function. So I'm going to say this function will rename any objects to have the correct Suffolk's. We'll say for a selection argument whether or not we use the current selection and for returns, we'll say a list ofall the objects we operated on. If I go back to Maya and they re run the help command, you can see that I now get the doc's ring that we wrote. It says Dysfunction will rename any objects to have the correct Suffolk's and gives us information on how to use the function. This is a form of documenting your code, doc strings air really helpful when other people have to use your function, or even if you're using a function down the road and you forgot how you wrote it. This is a form of commenting. The other form of commenting in python is with hashtag this isn't like Instagram or Twitter . Instead, these hashtags represent the intent of the code. So by type of hash tag and then I can type anything. Offer it, and these will not run with the program there, simply there other programmers to look at. It's a mercy. Hashtag dysfunction cannot run if there is no selection and no objects. The point of comments is a later when you have to look at your code or someone else has to look at your code. They don't have to read every single line of code to understand what you were trying to do . It's really useful as well for yourself, because you're bound to forget higher code works. I recommend adding comments trio code so that it's easy to follow along. All my code in the get hub Repo for this project will be documented with comments on how to use it. What I'm doing and high runs, you know, have a function that can be reused in other projects as well. It's called on its own to organize your scene and said, Oh, Maya in our next project will be looking at how to create drama tree procedurally 23. String Formatting: a common tosser. Doing python is creating strings. For example, let me create a string that says Hello. My name is through and I am 26 but I want to change this Seiken. Use different user names and a different age. So let's create a variable for user and I'll call it through and a variable for age. I know set this for 26. Now what I can do is say hello. My name is plus user plus and I am plus age. And if I know run, This will tell us if you can't add a string in an in TOB checked so it requires us to convert this integer into a string and now it will work. But this could get very cumbersome because we both need to know the type of the variable and we need to keep adding strings together, which could be kind of expensive to do. Another option is string substitution. So we can say hello. My name is percent s and I am percent s. Then we close the string, we give another percent sign and then we in princes will give the values to use in this case unless a user comma age. And what this will do is replace the first percent test with the first value on the 2nd 1 with second value and so on and so forth. If I now run this, you can see that I didn't need to care about my variable type, and it's very succinct to define. We can also do this with name lookups using a dictionary instead of a to pull. For example, If I say name an age, I can give it a dictionary. Now, with name an age Sorry that should be named and user and you can see that are now works. This form of using string substitution is one that was very popular in pie time. Unfortunately, as you go, as you create longer strings, it can become quite unreadable. And it's quite often that you'll have string substitution like this, where it's not possible to figure out what goes where. An ultimate way to do this is using the format operator. So you can say hello. My name is, and then we give to curly braces and I am and we give to girl curly braces again. And then we say format. And inside a format for Givet User and the Age and it works exactly the same. But this isn't a huge improvement. It's it's the same number of characters as percent s and we still have the same problem that we dont know what goes where without having to read the whole sentence. Instead, we could also do something like this. We can tell it which value to use and we got the same outfit. But the cool thing is, I can now change my string and refer to them out of order. Hello, I am and my name is and this is really cool because I couldn't define exactly where my values will go and it makes it much easier to read and maintain. It also means that I can reuse any of these values. If I just say 00 I'll just use the first value multiple times whereas with string substitution grows with the percent s method, I'd have to redefine user multiple times each use. I can also do this with a dictionary. Look up as well since sort of saying hello. My name is something and I am something I can say Hello. My name is User and I am age, and then I can just give these as arguments to the format function. Enough. I run it. It works exactly the same if you are doing a lot of string construction and by time, in my opinion, using the curly braces is the best way to go using the format operator. It's efficient, and it gives you a lot more functionality than using the percent s symbol. That said, if you're only using a single value percent s can be very convenient, it is also common to see it used in many python libraries like the logging library. This is because it has been around much longer and these libraries make use of its legacy. Functionality, for our course will pretty much be using the percent s format. But I want you to know about the dot format option as well, because it is more useful 24. Scopes in Python: in this video, we'll be going over the logic and function scoping of python python follow simple rules for looking variables. It first looks on local variables. This is variables that are assigned inside of the function or the current scope. For example, this is the scope off the inner function, anything that is indented underneath the scope declaration. In this case, the function declaration is the scope declaration. So we're saying anything underneath this that is also indented will be inside the scope and therefore when you look up variables, it will first look up inside of this scope and then it will look up in the scope above it, which is this outer function scope. And then finally we look above that and they only look inside a python itself so you can see this described here. This is called the L E G B rule. So l is for local names aside and in any way within a function. Innermost variable is a local function inside of inter function in closing function. This means the functions that are outside of this scope can be accessed. So inter variable is a variable outside of this scope. But it is Indian closing scope G for global are module level variables. A python file. It's called the Python module, and this is outside of any function. Therefore, it is a module level variable. Finally, you can use built in python types, which are just Patan variables that come with python. So let's get rid of the documentation up here and below this, let's make sure to call our outer function. And now if I run this, you can see that the inter function can access innermost variable, inter variable, the outer variable and the python global. If I moved us out of the scope, you can see that I can no longer access the innermost variable by charm is smart enough to tell me this. If I try running this, it will error. It says it cannot find the innermost variable at any level higher than this. So if I take that out, it will run. Similarly, If I now take this out of the scope of the outer function, you can see it's now un indented relative to outer function. I could no longer access inner variable. If I run this, it will error, So let me get rid of that and NAFTA on this, you can see that it works perfectly again. This is because we go from local two enclosed to Global two built in. This is what we call the L E g b principal off lookups. 25. Project 3: The Gear Creator: through this project will be learning how to create a controller library using cute. Our controller library will be flexible and will support thumbnails. We can import any of the objects that we save out, and we could also create any new objects we want. In this case, I will say this as the test, and when I hit save, you'll see that it shows up inside of for our window. We learned how to save data out as Jason and files as well as load them back into Are you? I We'll be using cute provided by pi side to inside of my 2017 and pie side. In previous versions of Maya, we'll go over the differences between cute four and cute five, as well as the differences between pie cute and pie side and pie, Cute five and pie side, too. I'll also be going over a popular cute library that's used by Disney, WETA, Sony Imageworks and more. There will help us write code that can be used the cute in both Maya 2017 and previous versions of Maya. In the next video, I'll do a brief introduction to cute on. The different versions are cute use inside the different versions of Maya 26. Making a Python Script: in this video. Instead of creating the script insider Mayas own script editor, we'll instead be using Pi Charm to create the script. In a pre in a previous video, we set up I charm to point to our Maya Scripts directory. If you don't remember where this is, you can say file open and go toe. See your documents folder Maya 2017 on the Scripts directory underneath There. If you're on Mac Olympics, I'll make sure to mention where your directory Zara's well, in an overlay In the video, you can see our previous script that we wrote here, the object rename er, but let's create a new script. Well, say file new and we'll say, Python file. We'll call this gear creator and we'll say OK, and you'll see because we said it's a python file that pie terms already added the dot p y suffix. Next, we need to load the center Maya. So let's write a little Prince statement that we can use to test Maya loading our script. So let's just say print and in quotation marks at Hello, Maya and save it down now go back in to Maya and say, import gear creator and run it and you can see the Maya said Hello, Maya. Down here. If you run it again, you can see that it doesn't print. Hello, My again. This is because Maya will cash the import so it doesn't have to re import it. This means that as we're developing, Maya will not pick up our changes. So what we need to do is at the reload statement. So now if you run this, you can see that it's imported it again and run. Hello, Maya. If I go back to pie charm and change this to say by my eye instead and now on it, you can see that I will say by Meyer now. 27. Creating a Gear: let's go over how we actually create a gear. So first I'm gonna go to create, and then I'm gonna choose a polygon pipe. We can set how many subdivision axes that it has by changing it in the channel box. Right now it has 20. We select each alternating face to create the teeth. Then we extrude them and this creates our gear. Now, the problem with this is we can't really change how many teeth the gear has. If I change the subdivisions, you can see that the extrude is now getting confused because it's pointing to polygons and no longer exist where they should be. So when you create our script, we'll have to make sure that we can control how many teeth the gator has, as well as how long the extrusion czar and we have to give it the ability to change the number teeth later on. So let's get back into pie charm. I'm gonna expand my script editor a bit. I'm gonna collapse my channel box. Let's get rid of the script that we already have. We're going to import the Maya commands library, so we're gonna say from Maya import commands and again, you can see pie charm giving me auto complete as I type. We're going to create our temporary function well, fit death to define function. We'll give it the name, create gear. We'll give it the prince sees within which will give it the parameters are first parameter . If teeth and we will give it a default value of 10 our next parameter is lent and we'll give this a default value of 0.3 thes air defaults that I think are good for a use case inside of this will say print, creating gear. And then I'm gonna just give the two parameters that we already have Soon after I run the script, insider. Maya, you can see that nothing happens. This is because we're not actually calling this function just like we call functions inside of the C. M. D s library. We need to call the function inside of a gear creator library. So going to say, gear creator that create gear. And we're going to say teeth is equal to 20. And now for on this you can see what happens with default values. We're overriding the value of teeth because you told a 20 instead of 10. But we keep the default value length at 0.3 because we haven't specified it inside of Maya , and you can see the function is clearly running because it prints out the statement creating gear on the two parameters. The number of teeth is a subdivisions multiplied by two. So let's call the spans. Well, say spans is equal to teeth. Times two. Remember, this is an integer, and we can multiply integers without the integers. So now if we say Prince bans and run this inside of Maya, you can see that assess 40 because we're giving it the value of 20. I'm gonna get rid of this default. And if you run this again, will give us a value of 20 because the default is 10. Let's leave a comment so that someone editing our script later can remember what we intended. When you use the hashtag symbol and I'm going to say teeth, our every alternate face so spans times two, then we're going to create the pipe object. We do this, but using the commands, the poly pipe object and we give it a parameter called subdivisions access and we tell it the number of spans if you want. If I run this now and I delete my old gear, you can see that we've created a pipe. Let me delete this and you'll give it a new value for teeth and I'll say 30. So I run this. You can see that we have that many spans across it. If I open the channel box, you can see that the Poly pipe has 60 because we have two times the number teeth for us bands. Let me delete this. Next, we need to make sure that we hold on to the transform and the constructor of this. Next we get a selection of the faces that we want on the side of the pipe. So we say side faces. This will be the name of a variable, and we use the range function. The range function gives us numbers between the first number on the second number. In this case, we're going to say spans times two and spans times three. Let me go into why we're doing this. If I create another pipe, let me create one, and I select every face that we want for our tea and again. This is created with the default value of 20 divisions. So if I select these faces, if I type ls Russia Cell and run, it will give me the faces back. I can copy this into pie charm, so it's easier for us to see. And when a copy them into pie term, you can see that they started face 40. Go to 42 44 so on and so forth. Let me get rid of this line. That means if we're starting with 20 spans, our faces start that spans time stew, which will equal 40 and the end that spans fans three, which will equal 60 If I go back into my and now run this, you can see that I started 40 but I'm going up in increments of one. But I correctly end at 59 which is just before spans. Times three, which is what we want. The range value also takes 1/3 argument, which is the steps that should take, which means I'll give us every second number. If I now run this, let me save it. If I now on this, you can see that it gives us 40 42 44 46 so on and so forth, which will the correct values that we expect? No, let's elect these faces. So first, let's clear any selection that we have some basic commands or select clear equals True. And we say for face inside faces it commands dot select and we're going to give it a string . And what we're doing with the string is we're going to say percent s dot f and in square brackets inside the square brackets will save percent s, and we're going to use string substitution to create the string than Meyer needs to select the faces. So we're going to give it to transform and the faith. And over here you can see this will be substituted with that and that this will be substituted with the second value. And we're also gonna tell him Maya to do is to add the selection instead of replacing it. If you were to simply run it without the ad parameter, when my oh do is each time it goes for the loop, it would only select that specific face. But we're telling you to do is to add it each time So if I now run this, you can see that I've created a pipe and selected every other face on the side, just like we expected. Next, we're gonna extrude these faces. Let me delete this polygon here and back in pie charm extrude which will be a variable name toehold extrude else it commands dot Polly extrude face. This is a command to extrude polygon objects. I'm going to give it a parameter off local translate Z and we're tell it to use length as the value of this parameter and more say print extrude to see what this command actually gives us back. So if I now run this and we got an error because I'm not type this properly because it's not poli extrude face. But what is it? So in my, uh if I actually extrude the face, you can see that the commanded ran was Polly extrude facet not face. So let me copy that back and replace it inside a pie charm. Let me delete this object. And now, if you run it, we've created a gear and we get a list back that says Polly extrude face one. Since our list will only contain one object. Let's only get back the first object inside of it. We'll do this by putting the square brackets after calling it and will give the value zero again. What we're doing is we know this gives us back a list and we can access that using the same access for method review seen Phyllis, which is using the square brackets and using the zero to access the first element. We don't assign all of this into the extrude variable. If I delete this again and run the script, you can see that we now get the poly extrude face one, which was the first element off that list. Finally, for a function, let's return three important objects that will need to make use off later. We'll save return and we're gonna take the transform constructor and the extrude node. So if I delete this gear in the scene and I run it again, But this time I'm going to say print whatever this function gives us. If I run it, you can see that our function gives back a to pull off the transform node, the constructor and the poly extrude face. And there you go. We have a function that can create a gear and gives us back useful data that we can use to manipulate the gear in the next video Before I finish off the video, let's had some documentation to our function so that people can use it easily, offer the function definition, put down three double quotes and hit enter and pie Charm should automatically complete it for you. If not, just copy. Whatever my video says, we'll say this function will create a gear with the given parameters. We'll say that the arcs or the parameters are teeth, the number of teeth to create and the length the teeth. And we'll say it returns a to pull off the transform constructor and extrude node. So now anyone calling our function can simply call help on our function and see what it will give us back. And finally, it's important to note that he should not use. The prince sees inside of the help because what this does is it executes this and then you run the help. It actually gives you to help for the two people that is returned by this without the prince sees. You're not executing it, and you're just giving help. The actual function instead 28. Modifying the Gear: to recap our loss video, we've created a function that can generate a gear based on the parameters that we give it. If I'm to run this, you'll get a gear with a variable number of teeth. In this video, we'll show you how to modify the gear that he would just created. The function that we created returns back to transform the constructor and the extrude node . These will be useful because we need to modify them in the next function. So let's put these inside of variables inside of Meyer, we're going to say transform, constructor and extrude are equal to our function. And if I now run this and I say print, transform, print constructor and I must say transform constructor print extrude. If I now run this, you can see that it says the transform is P pipe to the constructor is Polly Pipe to and extrude is probably extrude face to. So let's delete these gears. Let's create a new gear. I'm gonna expand Maya. If you go to the channel box, you can see that the polity pipe one has the subdivisions access that we can change to change the number of Pete that the gear will have. But if you change it, you can see that the you can see that the poly extrude node doesn't know which faces to edit any more, and you get really funky shapes. So when you change this, we also need to change the poly extrude node back in. Pike Charm will create a new function to do this. So let's create a gear again. And now the restored these values. Let's put a hashtag to comment it so that we can re run this command accidentally on the next line. Let's call a function that we're about to make. We'll say gear creator Duck change and then we'll give it the constructor and the extrude who were also going to give it, is the number of teeth. So when are we going to say we want to make 40 of them? So we have the scene. Let's create a new function. Well, say death changed heat because that's the name of the function we created. It will take two parameters, will take the constructor and the extrude. It will take the number of teeth to create and the length we'll print out the constructor and we'll print out the extrude so that we can see that it's getting the right values. And this is a good time to introduce the two types of parameters inside a python if you don't give a default value but giving the equal symbol and a value Python makes them positional arguments, which makes a mandatory if you call the change teeth function. You have to give these values because they have no defaults. But Python needs to know what the equal to. However, you don't need to get these two because they already have a default value, which means the Python knows exactly what they're equal to. So if you run this now, you can see that we have the Poly Pipe one and the Poly extrude face one. If I remove the extrude and then I run it, it's going to give us an era, says Change. Heat takes it at least two arguments, and we haven't given the necessary number of arguments. What we're going to do now is change the number of faces on the poly pipe. So again we'll say spans equal Pete Times two We didn't get the commands. Dup holly pipe. I'm gonna give it the constructor when you say edit equals true and we're gonna say subdivisions access equal spans. So what we're seeing now is I will use the Poly Pipe Command again with the polity pipe that we have this time we give it the edit flag so that it knows and sort of creating a new one to edit the existing one. So if we now on this, you can see that it's changed the number of spans on this. But the Poli extrude face is all messed up because it doesn't know which faces to accurately extrude How do you see what it's actually using? Destroy these values? Well, if you say Polly extrude face and we're going to use the list at her command inside a python so in a new line, I'm gonna say commands. First of all, let me import the commands, Lavery. So we'll say from Maya Import Ramone's and notice that commands the list adder. And then I give it the poly extrude face one. We now run this. It gives us back nothing. That's because we need to print it as well. If we select this and then run, it gives us back a list of all the attributes they're too many to go through. So I'll tell you, the one who interested in it's called Component. It's called input components, which you confined right here we can use to get at her commune to see what it's equal to. We say Get at her polity extrude face one dot input components. And if I now run this, you can see that it's equal to the face values that we have so we can use just like we used to get at her command. We can use the set at our commitment to set it again, so we'll create a list, destroy all of faces. And just like before, we'll say side faces is equal to range spans times to you spans times three and to again. This will mean that we'll go through the first face, which will be the number of spans times to you. Then we'll step up every two values as given by this. Sorry, this should be spans Times three. This will be the faces that we want and we're gonna change this list to call be called face names so that we don't get confused. So now What we'll do is we'll say four face inside faces face, name is equal to and again Will you string substitution will say f and square brackets. And inside of that, we'll say percent s because I percent s will be substituted by this next value inside these prints sees which will be face if I say print face and I now run this, let me get rid this. First of all, let me just copied this out so that we can see the values that are expected. Can I have her on this? You can see that it's giving us back the names, the numbers of the faces, what actually wanted with the face name. Suffice print that out. Now you can see that it says f and then in square brackets the face name that we want. So what we're gonna do is we're gonna add this to the face names list. So we say face names dot upend and again, you can see pie charm giving us helpful completion, and we'll save face name. So now if I say print face names and I run this, you can see that it's very similar to the list we have here now What we're gonna do is like we did earlier. We're gonna now set the attributes were going to say, Come on. So set at her again, will you string substitution? Because we don't know what the name of the extrude note is. While they were running the function, I'm gonna put give it the extrude node and then the next argument it needs is how many items there are in the list of giving it. So we'll say Len, and I'm going to give it the face names list. And what this will do is they'll get the length of the face names list and give it to the set out of function. Next it needs a list of old faces that will be using so weakened do is expand the face names list. We do this, but giving the asterisk and we say face names. And what this does is, instead of giving it the list of face names, it expands it so that each of them will be a parameter. This is the same as saying f 1 60 here and then giving another parameter saying f 1 62 and so on. And so forth. What we're doing is and started giving them each individually. We're expanding it from the list so that we don't have to do it manually. And finally, the loss variable is type because we have to tell it what kind of type the attribute is. And we're going to say component list. I must say this. And if I clear out the history here and then run the script, you can see that our gear has been edited to have the correct number of teeth. We also want to be able to change the length, and this is again very similar. So we say commands Nepali extrude facet because it's a command we used to create the extreme we give it extrude node. And just like we did earlier with the Poly Pipe, we say edit is true because you want to edit it and we need to know, and we need to let my I know that we want to edit it. And next we're going to use a short form for the variable of used earlier. We're going to say lt Z is equal to lend. This is a short form off the local translate Z parameter you concede the short names inside of the Maya documentation. I'm just going to use it here to be lazy. So if I never run this again, it works like we expect. I can change the number of teeth 10 again and run it. And the changes that and it can change the length to 0.5. If I run it now, you can see that it's extended the length and it can change it down really small. And just like that, we have a function. We've created a gear, and now we can modify the same gear that we've created. 29. Classes: Custom Types and Interfaces in Python: I will not be learning about clauses. Clauses are away inside a python to generate custom types in this case will be generating a type called Animal. We create the animal claws by using the clause keyword giving it the name of it called giving it the name animal. And then we tell it what to inherit from. In this case, we're inheriting from the python object, which is the lowest level type inside a python. This means that animal will take all the traits that object has we learn more about this in a bit within a clause? Weaken define methods. These are similar to functions, but they have to live within a clause. And they all take self as the first argument. Other than that, they all behave exactly like functions. We create an instance off the animal object the same way we create instances off any other type inside a python. So if I wanted to create a list, I would say my list is equal to list. I give it the type I want to create and then parentheses and then I store it in a variable called my list. So if I want to create a new animal. I can say something like Tiger is equal to animal and give it currencies in the same way we creator list. We're creating a new animal instance by telling it the type giving parentheses to indicate we're creating a new instance and then storing it in a variable called tiger. If I say print the type of tiger, you can see that it is a clause of animal stored inside a main. This is a relevant right now, but we learn about it later. We've learned how to call functions with objects so earlier. If you wanted to tell something to speak, we would say speak and give it the object that we want and give it the object we want to perform this action on. For example, we've been doing things like think, commands that parent and then give it an object like tiger instead of doing this. Where we're passing where were passing are variables into a function. Python has some tinkle object oriented programming. Object oriented programming lets us perform actions with the tiger object instead of performing actions on the tiger object. So instead of saying speak and giving it the tiger variable we can instead say tiger dot speak. And if I now run this, it will say I don't know how to speak. This is because we defined this behavior right here. Another aspect of classes is the fact that you can create multiple instances of one. So instead of having speak, say, I don't know how to speak, let's say my name is and then let's. And then let's make it refer to a very biblical name and we'll say name is equal to none because we haven't defined the name yet. This is our introduction to the self keyword. What this lets us do is refer to an instance off Kloss. So right now, if I say Tiger don't speak, it will say my name is none because self taught name is none. If I create to animals and l say and I tell both of them to speak till again, both say that the name is none. But now I can do something special. I can see tiger dot name is equal to Tiger and Buffalo. Done. Name is equal to buffalo, and if I run this now, you can see that this instance of the animal object will print out. My name is Tiger because the speak method is refering to self taught name, which is getting set here on this specific instance. This means that we can reuse the behavior of a class while only changing certain aspects off it as we see fit. This gives us the ability to define lots of reusable behavior we've seen her animal inherits from object, but we can create other types that inherit from animal. For example, let's create a dog and instead of object, I'll tell it to inherit from animal. And I'm not going to define anything here. So let's create a new dog. I'm gonna call it. Fido is equal to dog again. We're creating a new dog instance and then storing it in the fighter variable. If I say Fido dot speak, it's going to say my name is none because it's using because it's using the method defined up here. Instead, I wanted to say Wolf, someone say so I'm going to now redefine, speak and I'll say print worth. And now for on this it's going to say wolf, and this is because we've redefined just the speak method from this class up here. But if I now say fighter dot breathe, even though we haven't defined the breed method for dog, it's going to inherit those traits from animal. In this case we defined Breathe up here and you can see that it says I don't know how to breathe down here just the same A says I don't know how to breathe Appear. This is because dog inherits every single trait from the animal object, and this is because we define animal as the base for dog. We can explore this further by saying print type a fighter, and I will say that it is off the claws dog. But we say print is instance Fido off animal. It will say true, because Fido is an instance of dog as well as of animal, because fighter inherits both the dog and the animal traits. If we define more methods on this to override, we can say walk and I'll say print. I walk on four legs and now if I run fighter don't walk. They will say I walk on four legs, but again, if I say fighter, don't breathe, it's gonna is going to get the method from the animal Kloss instead of from the dog class. Finally, we can also always add our own methods. Any sub close. In this case, let's say what is breed and we'll say print self star breed. And let's define a breed up here and we'll say, breed as none. So if I say Fido, so what is breed? You can see that it gives us back none, but if I'd now. But if I now set this value and emergence, and I'm going to tell it to be a Doberman, if I now run, it will tell me it's a Doberman. But if I change fighter from a dog into just a regular animal and then run it, you can see that it says animal object has no attributes. What is breed? This is because what is breed is only defined on the dog object and not on the animal. Kloss. So it'll only work if Fido is for dog and not just an animal. What this allows us to do is define common behavior in a base. Kloss, in this case, animal that all animals can share, and we can define more specialized behavior inside of a subclass like dog. Now if you create a new clause, for example, fish and we'll tell her to be an animal, and we could just redefined the breathe method, and I'm gonna tell it that I breathe underwater. If I create a new fish and I tell it to breathe, it's going to say I breathe underwater because it's inheriting from animal. And if I tell it to speak, I will say my name is none because it's inheriting from animal. What this has allowed us to do is to find two different types of sub animals dog and fish that boat inherit from animal. But they define their own behavior where suitable, but they both inherit common behavior as a recap to show several reasons. My classes are very useful one. It lets us define reusable behavior that we can customize using instances. An instance variables to it lets us group common behavior. Together There relates to a single object type in this case, off animal types and three. It lets us inherit and extend any of these classes. We can override any of the methods that were defined, or we can add our own new methods to add more functionality to a clause without having to affect every other type of subclass that there is 30. Converting our functions to classes: we're not going to convert our gear creation and gear modification functions into a cloth that we can interact with more easily in pie term, create a new file. They're going to file new and say python file. Well, say gear cloths, creator. Instead, we're right. Click on the tab and say, Split vertically. This will split our code vertically between the gear creator and the Gear Clause Creator that will be now creating for the majority of this video will stay inside a pie charm. Still, we have to go back to Maya because the functionality is quite simple. First, let's say from Maya Import. See MDS. We'll create a class and we'll name a gear and we'll inherit from the python object. Inside of this, let's create a new function or method, and we'll call it Create gear. As you can see, pie charm automatically adds a self keyword so that we know how to refer to ourselves inside of the class. We'll use the same parameters as we did before, and you can see the old code on the left. I will say spans is equal to teeth. Times two. I'll write the exact same code again transform and constructor is equal to commands. Duck, Polly Pipe and let me just see the flags that used. Just gonna copy that across and we're going to say Side faces is equal to range spans times two spans toe three and say to again Well, tell it to clear the selection and we'll say four face inside faces. And let me just copy this the rest of code from this function and make sure that it's indented so it's in line with the create gear function or in this case, it's a method. Next, let's create the change teeth method will copy it across, and I'll just make sure that everything is indented properly by selecting it and hitting Tab. I know manually add the self keyword in the beginning, so this isn't very useful. We've just taken the same code and put it inside a gear object. If you go back into my, uh, we can import this by saying gear cloths creator as gear creator, what we're doing is importing the new module, but as this modules name so that we don't have to change the rest of our code. And if I try and run this Now, let me just comment. Towed this line. If I try and run this now, it'll say that there's no create gear if method, this is because it's now inside of a clause. So let's create the Kloss. Well, say gear equals gear. And if we now run this Oh, sorry. We have to say that gear is inside of gear Creator and if I now run this, you can see it works. We still have to manage all of these outside of for cloths. That's not very useful to us. So back in pie charm, let's change this. First of all, we have the self. What does this mean? This means that when we're inside of here, gear refers to this instance of gear and our methods know how to access it. Another thing that close is let us do it store values inside of ourself. So let's try this now. So we're going to do is they're going to say, self duck transform and self dot constructor and down here you'll change it to self dot transform, and we wouldn't return anything this time. Additionally, let's change it to self dot extrude, and what we're doing here is we're saying it's sort of having this variable stored inside of justice function. Let's door this variable himself. This is a way destroyed variables outside of this function, and it's a good example of python. Scoping is an example of a variable that exists only inside of this function. We cannot access it outside of this function. The second dysfunction finishes side faces no longer exists. Instead we construe, or this variable on the cloths instance itself by using self. That means restoring this variable on self. So now, if you go back to Maya and I run this, let me delete this. First, you'll say none type is not in terrible because we're trying to expand to return values. And, as you can see, we remove the return value. Originally, we had this. We no longer return anything, so let me get rid of that sick. I simply say geared or create gear. But now here's the cool part. I can say print gear dot transform. And if I run this, you can see that it says P pipe one. That's because I've set that attributes on this instance off gear, and I can now access this attribute on this instance of gear a swell. Similarly, I can say print the extrude and again it cept on the gear. I, however, cannot access the side faces variable. See if I try that. It says Gear has no attributes. Side faces. That's because the side faces variable is limited to justice function, and that's how we want it for now. So now that we're not getting back the transform the constructor and extrude like we were earlier, it makes no sense to have this here. So let's get rid of these variables. And now, if you go back to pie chart, let's also get rid of these parameters, and we can simply refer to them using self again. So it's saying, self taught constructor, which gets this value and again down here we can say self doubt, extrude and self doubt extrude again, saying Look up the value of self on ourselves. This means we look outside of the function and instead we look on the class. So if you go back to here and now run this, let me first delete this and if I now run all of this, you can see that we have a gear over here. With these changes applied, I can now change the number of teeth and the length. If I run this line again, you can see that we're just modifying the same gear. And if I was to say print type of gear, you can see that is off type gear from the Gear cloths creator. Therefore, you can feel cloth of a really good ways to contain logic inside of itself. Instead of having to call her function like in our previous example and storing the values who got from it and then using those values to feed it back into another function. We can just hold on to the one gear object, and it knows how to interact with itself. If you go back into pie charm, you can see that these values are only set when a creative year. But they're not there by default before we run this method. So if I go into Maya and I create a new gear and I said gear got extrude, this was something we could have got earlier. But if I never on it, you can see the gear object has no attribute extrude. This is because by default we on creating the attributes till this function runs. So if you say gear, create gear and now run it well, get the value back instead, let's set these values by default. Inside a pipe charm will create a function called in it. So to create this recent death, like just like we create all the functions of methods. But this time we type double in the scores and in it and pipe charm will suggest it for you , followed by two more underscores. So double underscore i n I t. Followed by two more underscores. We give it the value of self. And then in here we just say self doctrines. Form is equal to none. Self dot extrude is equal to none, and self, that constructor is equal to none. No, I was saying, is when we first initialize a new gear and then we can query geared out extrude. Oh, sorry. After reload this first, let me reload it. And if I created new gear instance and then I run geared out extrude, you can see that nothing is printed out. In fact, I can say print gear dot extrude and they'll say none. This is because back in pie charm. We're setting self doubt. Extrude equals none. But if I was to say Geared, I create gear and run this line now geared out extrude has value. But what this means is that if we haven't run, create gear, we can still get the value of gear dot extrude and back in pie term. I can finally explain what the unit function does. Thean it method is run whenever a new instance of the object is created. So whenever we do this, we're actually running the innit method. I can show you this quite simply. If I say print running the innit method, Whenever I create a new gear object, you can see that it says, running the unit method. So let me create a new gear object. I can try printing geared out extreme, and I'll say none because it's still set to none. But when I said geared or create gear and now do print geared out extrude, it has value because I method create gear has changed the value of gear dot extreme. Therefore, you can see the value of thean it method in letting us set of default values and behaviour . When a close is created and before any of its methods or run finally to document the gear class, we create the documentation underneath the word Kloss, just like we do for a function. So let's add three double quotes, and we can say this is a gear object that lets us create and modify a gear over here. Let's leave a comment to say the innit method. Let's a set default values, and then, if you feel like adding documentation for these, you can do it the same way. And there you go. We've created a very first cloth by converting the functions that we learned in our first video and using them to compose this clause called Gear. We've learned about self and about the unit method and about how close is consent values on themselves and then access values on themselves so that we don't have to posture own variables outside of the functions 31. Project 4: The Animation Tweener: through this project will be learning how to create a controller library using cute. Our controller library will be flexible and will support thumbnails. We can import any of the objects that we save out, and we could also create any new objects we want. In this case, I will say this as the test, and when I hit save, you'll see that it shows up inside of for our window. We learned how to save data out as Jason and files as well as load them back into Are you? I We'll be using cute provided by pi side to inside of my 2017 and pie side. In previous versions of Maya, we'll go over the differences between cute four and cute five, as well as the differences between pie cute and pie side and pie, Cute five and pie side, too. I'll also be going over a popular cute library that's used by Disney, WETA, Sony Imageworks and more. There will help us write code that can be used the cute in both Maya 2017 and previous versions of Maya. In the next video, I'll do a brief introduction to cute on. The different versions are cute use inside the different versions of Maya 32. Overview of User Interface Libraries in Maya: before we start designing. Are you eyes? I like to go over the various You I libraries inside admire my has to you I libraries. Oneness, part of the commands library that were already familiar with the other is based on something called Cute. It's spell Q T. But the official pronunciation is cute, so bear with me as I will use that the entire my user interface is built on Cute. Cute is a C Plus plus library that lets application developers develop for one operating system and have a you I that can look native on any other operating system. If I developed something on Windows, I can reuse the same code on Mac OS or Lennox, and my application will look like it belongs on that operating system. Additionally, it provides many other functions to help us develop cross platform applications. Prior to my 2011 when my A switch to cute Maya had different you I libraries for every operating system. This meant as a U I developer, you're forced to use the Maya Commands library where the commands would use the respective library on each operating system, so you wouldn't have to know what it was using. This caused many visual discrepancies and behavioral discrepancies. Additionally, the Maya Commands library only offers a small subset of what cute offers. So you lose control at the expense of not having to understand the underlying details. When my A 2011 came around my I had a new dark you I using the cute library, this mental Maya shed the same you I code on every operating system, and it meant that we could finally use something called Pike UT or pie. Cute Pi cute is a python binding around the cute library. This means we can use everything the Q tests or offer within Python. Suddenly, this gave you. I designers lock more control and flexibility over there, you guys because they no longer had to use the Commands library, which was a wrapper around. Cute. Anyway, it meant you got much more control over every little thing that you created in this first project. I'll be showing you how to create you guys with the Maya Commands library and in the next two projects offer that we'll switch to using the pie cute competitors er, the ships with Maya called pie side, too 33. Getting Data for the Tween Function: we'll be starting off by creating our script that we can import into Maya. So I click on your scripts directory, seeing New and Python file, and we'll name this tweener you I doc pie. We'll start off by creating between function that we can use inside. Admire. So let's say from Maya Import C. M. D s. Then let's create the Tween function. So we say death between again. Death is short for define between is our function name and in the prince sees Let's give the parameters that we need. First of all, in between ng we need to know what percentage between two. Then we need to know which object between. But let's make this a default of none. We want to know which attributes between, but well again say this is none. Finally, we can say selection equals true, because by default we want the Tween function toe work on the current selection. But before we continue, I think it's important to show that we can have conflicting arguments here. If I say selection equals false and I don't specify object, I won't have anything to run on. So let's put an error in the beginning of for code, so we don't spend time executing everything just to find out we couldn't run in the first place. So I'm going to say if not over J and not selection, then we're going to say graze value error and we'll say no object given to Tween. So if I run this right now, you can see there takes at least one argument, So let's give it a percentage. And the only reason I'm able to run this within pie charm right now is because I'm not using any of the commands library. So let's say between what we say, selection equals false. And now when you run this, you can see that it says no object given to Tween. Now, how does this check work? Well, we're saying, if not object, which means if object is equal to false now, object isn't equal to falls, but none is false ish, which means that if I converted it to a bulleted, it would be false and similarly selection is false. So we're saying if not object is true, which means object is false and not selection is true, which means selection is false. Then we'll raise, evaluate error evaluate error is an error that will be immediately presented to anyone calling our function and will give us details about what went wrong. We'll say no object given between and raise means to raise this error immediately and stop execution off her code. Next. You want to say that if no object is given, so if not o b j, we'll say O b J is equal to commands got LS and selection equals one. Sorry, selection equals true. And then we'll get the first object in the selection. No, let's comment this as well as we go along. So is saying, if object If LBJ is not given and selection, it's set to false error early. If no if No O. B. J is specified, get it from the first selection. Next, we need to do the same thing for attributes so that we can find out which ADDers to use. So we'll say if not ADDers. ADDers is equal to commands. Got list adder because we want to list the attributes that are available on this object. So we'll say object and Keeble equals true. So we're gonna So we're going to query the object that we got from the selection and we took the first item in the selection because this is a list. So we're gonna list all the attributes on it that are capable. So now I'm just gonna print out the O. B. J and the ADDers just to make sure that we're getting the right things. So back in Meyer, I'm going to run import tweener you. I hear that is a name for module. I'm gonna say Reload, cleaner. You I and I must say, tweener you I doc Tween and I'll give it some imaginary percentage of 50. So if I never on it, we'll get all these attributes that can be animated on P Cube one. In this case, it's everything in the channel box. So now we have to figure out exactly what we need to do to create a Tween. And this could be some slightly advanced logic. So first of all, we need to find our current time. The current time depends on the slider here. If we're over here, well, between in between this key and this key. But if for over here, well, between ing between the other two keys, let me just get rid of keys on other channels so we can just focus on the X Channel back in pie charm. Let's get the current time from Maya's, Hui said. Current time is equal to commands dot carton time and you will see a query is equal to true because we don't want to change it. We won't a query it. So now let's make sure that we are getting in the correct time. So we say Print card in time and back in Maya. If we run this, you can see the current time is 28 because right frame 28. If I go to frame 80 and run it, it says Frame 80. Next we need to do is go through each attribute on Look for the previous and next key. 34. Setting Keys with the Tween Function: first, let's create a four loop just like we've created four Luke before we'll say four at ER in ADDers, where ADDers is a list. Now, before we do this, it's important to mention that if List Adder does not get back any Keeble attributes, it's not going to return their list. Maya annoyingly returns a nun type, which means that we can use a for loop and our code will error for now. This is all right because an error is expected, but we'll come back to this later. So first, let's create the full at her name. So we'll say Adder full and again I'm gonna string substitution and I'm gonna give it over J an adder. So we're going to replace this percent s with O. B. J and this percent s with the adder in our current loop. On the percent symbol is simply telling it to replace the things on the left with things on the right. And the reason I'm creating the full at her name is because many of the Maya commands require this format, and instead of creating it in each and every command call, it's better to just created here. So we can reuse it later. For now, let's get a list of all of the key frames on the attributes. So we say key frames is equal to commands. Ducky frames adder. Full query equals true, and what this will do is it will give us back a list of all the key frames in the shot for the specific attributes. So if we save print key frames and we go back to Maya and run this, it says, Model has the attributes, key frames. So we made a typo somewhere. Ah, very simple historical key frames. It's called Key Frame again. I confined this out by looking up the mire documentation. So let's go back to Maya and run this again, and you can see that all the other cable attributes give us back none instead of a list, whereas the one attribute that can be keyed gives us back the frame numbers for the keys. So doesn't make sense to continued the rest of our logic if we don't have any key frames to in between. So what I'm going to say is, if not key frames, in other words, if key frames is not true, then let's continue on to the next object. And what this tells the loop is that if this statement is not true, then continue on to the next object and skip everything below me. This can help us save time because we don't We won't be running logic on something that doesn't need it. So now we need to get our previous key frame. So let's collect all the previous key frames. So now we're going to look through all the keys in the key frames list, so we're going to say four K in key frames. If K is less than the current time, which means it's a previous key frame, we're going to say previous key frames dot upend que. Now, before we continue any further, let's just comment this I'm going to say, construct the full name off the attributes with its object. I'm going to say, get the key frames off the attributes on this object. If there are no key frames, then continue and so on and so forth. It's important to do this so that you can come back and reference your code and understand what's going on. Usually, I won't comment every single line but I'll comment a large chunk of code and you can see this in my get hub examples for this video. I'm going a little overzealous with my commenting so I can demonstrate what's going on. Okay, now I'll be introducing you to a concept Kalis comprehension. Over here, you can see we've created a list on empty list, and then we've gone through all the key frames in key frames for each key. If it's less than the current time, then we're gonna add it to the previous key frames list. But this is 1234 lines of code just to figure out which key frames are before the current time. So Python has a concept, the list comprehension. Simply We can use it like this later. Key frames is equal to frame four frame in key frames. Efraim is greater then current time, and this is exactly the same as what we did here just in one line of code. So we're saying for framing key frames the same way we did four K and key frames. In fact, let me rename this K two frames so you can to frame and you can see it's a similar wording . So we're saying for framing key frames, Efraim is greater than current time. Add frame to this empty list. It's a little bit of a confusing syntax, but it could be very useful if you just want to do simple if statements inside of a four loop and then construct a list from it. Additionally, list comprehension is like this are often foster than running a full list like this. Now we need to check if there are no key friends before or after. This is very rare, but it's still worth checking for. So we say, if not previous frames and not key frames continue. So we're saying, if there are no previous key frames and there no later key frames, then continue. The and keyword here means that both this and this must be true. So both previous key friends must be empty and later key friends must be empty before we continue on to the next item in the list and continue just means we're skipping all the logic that will follow this so that we can start again with the next object in the list. For example, this continue if it's triggered, we'll skip all of this and we'll just start again from here with the next item in the ADDers list. Next, we need to figure out whichever our closest previous frame is. So we say if previous key frame the so that is, if there are previous key frames than previous frame is equal to Max off the previous frames. Another type of here. So I'm just gonna fix it. And what this will do is will go through all the objects in the previous key frames list, and we will get the maximum value a fall of them. If we need to find the closest of the previous frames, we need to find the one that is highest, which is therefore the closest to US health's. If there are no previous key frames, then we'll say previous frame is equal to none, which means that it hasn't been set again. This is four lines for such a simple evaluation. We can condense us down into one line, so we say next frame is equal to men later. Key frames, if there are later key frames else, will be none. And this is the same logic. We're seeing that if there are later key frames, just like we said, If there are previous key frames, the next frame will be equal to the minimum off the later key frames that will give us the closest frame to our current time. Otherwise, again, like the else statement here, we'll say that next frame will be none. And this is a nice feature inside of Python, where we can condemn simple if else statements down to a single line. So let's print the previous free and the next frame and go back to Maya to make sure everything is working. So if I now run this, you can see there gives us 47 113. Indeed, if I select this frame, it was Frame 113. And if I select this frame, it is free and 47. But what happens when we're on a specific frame and then we run it? It gives us one, and her and 13 that's perfect, is giving us two previous frame and the next frame. What if there are no more previous frames? Let's go to the very first frame and run it. Now we get none and 47 and this is because were saying that if there are no more previous key frames, then said it to none And again, if we say there are no more frames after this and then run it, we're again saying the next key frames are none. We want to say that if there are no more values after or normal values before the real simply ignore between ng operation I not change the key because it is an extreme. So let's say if not previous, keep previous frame or not. Next frame. Continue again. This is similar to up here, where we're seeing if there are no previous key frames and there no later key frames continue. But now we're using the or keyword or or means is that if there are no previous frames or there no next frame, then continue. Either of these could be true to satisfy this if statement causing this continue to trigger next, we need to get the value at both the previous frame on the next frame. Well, say previous value is equal to commands. Get adder because we're going to get the attributes and will say at her full. And then we'll say time is equal to previous frame on what this will do is they'll query the attributes at the given time. Next value is gold to commands. But get at ER and then we'll say outer ful again because we want a query that and this time you'll say time is a culture next frame. So now let's just check that we're getting the correct values at each of these frames. So let's go back to Maya and let's run it here. If I run this, it gives us minus 29 something the other, which, as you can see, is the value up here as also saying the next value is 1.344 which it is. So we can confidently say that we're getting the correct values. So what we next need to do is figure out the difference between the next value and the previous value. So we say difference is equal to next value Linus previous value, and we'll say the weighted difference is equal to difference times. The percentage that we were given divided by 100 when zero, and this will give us the amount that we need to add on to the previous value to get our current value. So we'll say current value is equal to previous value plus waited difference. And then finally we said Commands does set key frame because you want to set a key frame. Obviously, with this new value, we'll say at her full because that's the attributes we want to change. We'll say time is equal to the current time. I will say value is equal to the current value. And now, if you go back into Maya, let's see if everything we've written works. So we have this year, let's bias it 20 which means they'll be 20% this way, where zero will mean that it's equal to this on 100 roominess equal to that. So let's run this And there you go. It's biased 20% of the way, and we run it again, as it was. Zero now is biased zero, and if we say 100 is bias it 100. But a nicer bias would probably beat 90 which would give us a nice little fall off towards it. And back here we can say 30 and if you run it, it's by a 30% of the way less your 10% instead and gives us a nice fall off. And already you can see how this can help us with our curves. So in this video we've gone over how to simplify our code using list comprehension and in line. If statements and we created our Tween function in the next video, we'll be going over how to create the you I. 35. Creating a User Interface: I think this video will be creating our tweener. You I first let's look at the documentation for the window command. We'll go to help. We'll go to my ass scripting reference Python Common reference. Now we'll go toe windows and over here you can see the window command If we scroll all the way down and there's a lot of parameters, you can see this example of here. Let's copy this and go back to Maya. I'm gonna pace this in here and we're increased my script size and then I'll run this. And what you see here is a little window that it created. Now let me walk you through the code for this window. We say we create a window using the commands, the window command. We give it a title, which is long name, As you can see here, we can give it a Nikon and some dimensions. Finally, we give it a column layout, which is just a vertical layout that says, as you add objects through the window, put them vertically downwards. We create a button that says Do nothing. Another button that says closed with a command to delete the you I finally we said its parent to the Maya window, which is denoted by dot dot This isn't important. And then we'll tell it to show the window there we created here. This seems pretty simple. Let's start creating our own window now. We'll close that out. I'll clear this and would say between window. So obviously, if I run this, it'll say the Tween window doesn't exist. So let's go back to pie charm and create Tween window. We'll create a clause called Tween Window and we'll inherit from object, and for now, we'll do nothing. And when you do nothing, you simply write the word pause. Pause means that you go to pause through and do nothing. I want to go back to my, uh, they're on this. It won't complain anymore, but it also wouldn't do anything. So let's actually show window First. Let's create the show method, and again we create a clause. But using the word cloths, we name it Tween window and we inherit from object. Then we, in Dent on you can create methods which are functions inside the cloth on the similar to all the functions accepted. Take the self keep, except they take the self argument first, which tells it how to refer to itself. So when you say show, I'm going to say, Come on, Snow window, just like we did is equal to tweener window and then I'm going to say commands the show window by default. This will show the previous window that we created. So if I go back to Maya and I say creature, you are between window dot show And if I run this it opens up on milder monitor this big blank window with the word Tween a window on there. If I run this again, it opens up yet another window. I don't want this. I want to make sure that only one window can exist at a time. So what we do is back in pie charm. I'm gonna create a variable at the closet level. This means it's a variable that won't change as the clauses running. So I'm gonna say between your window because this is a variable that a static That means it will not change no matter what I can refer to. It flies just saying self the window name. But now I'm gonna do something different. I'm going to say that if this window already exists, let's delete it. So we say, if commands the window again, If you created something with a command, you can often query it again with same command to resell. FTA window name query equals true and exists equal. True. So what we're saying is that if a window with this window name exists, then let's do something to it. And we're gonna say self sorry. We're going to say commands don't delete you. I self the window name, and also you cannot have a space in the window name. So let's get rid of that space. And when you go back to Maya and we run this, you can see it creates my Tween a window. And if I could and if I run this again, it deletes it and then recreates it again for me. So let's go back to Pie Charm. So now I want to actually put things inside my window before I show the window. Let's call a method that we'll just create gold build you I This is a method that real defying ourselves, and again it takes self as his first argument, so their nose to refer to itself first, just like in the example, Let's create a Colum Lee out again. A column layout just means that any objects you add to this window will be added vertically , one below the other. No, let's create a text label There will tell our user how to use, are you? I will say Use a slider to set between amount and you go back to Maya and then run this. You can see that we now have little text. This is use a slider to set between amount. Now what I want to do is I want to add to Children, too, are you? I I want ad the slider and truth right? I won't add the reset button. This means that the column layout wouldn't work very well because it would add them one below the other. So we need to do is create the rolling out the rolling out, Unlike the column layout, will lay them out horizontally. So we say Ro equals commands are rolling out, and we say number of columns equals two because we need to have two columns within it. Otherwise it won't know how wide to make itself, and then we create a slighter, and I'm going to store the slider on ourselves so that we can access it later. Somerset commands the floats lighter because this is a slider with float values again, floater numbers with decimal points. And I must say men is equal to zero because that's the minimum value. Max is equal to 100 and our default value. Let's put a square in the middle at 50. And for step, let's say one. That means it can go up and down by one step at a time and has changed command. Let's tell it to call between function. What this means is that we created a float slider and we were assigned it to self doubt. Slider. The float slider will have a minimum value zero a maximum 400 a value of 50. By default, it will step up and down by one at a time, and whenever has changed, it will call between command instead. Next, let's add a reset buttons real sick. Amman's don't button and we'll see. Label is equal to in quotation marks. Reset and you'll sit. Command is equal to self the reset, and this is a method that we haven't developed yet. So let's do this death and we'll say Reset. And then we'll say Pause because we don't want to do anything. Yet before I continue, I'd like to mention why, when I'm giving these functions to come on and change command, I'm not giving parentheses. If I were to give parentheses, it would actually execute dysfunction instead of giving the function without the prince sees were actually telling it to run this function rather than executed immediately. Let's take out this pause and say, Print resetting you. I Let's go back to Maya. Close my old you I and run the new one and you can see we have the reset button and let's click it to see if it works. So when I click it, it says, takes exactly one argument, but two were given. This is because Maya buttons also send an extra value to any function that they're calling . We don't actually care about this, so let's capture this inside an ARDS variable. What this means is any extra arguments that are given to our function will be stored inside of our eggs, and the star just means everything that's not specified in this function well just restored in the art eggs. So if I were so if I were to now say, Print our eggs when we get back is actually a list what it takes. So when I now click on Reset, it works on. What you can see is that the button is sending a value call false, and we don't care about that value. So I'm just gonna put it in our eggs. With the asterisk on. They'll tell it to just dump it into this variable, which we never need to use. Finally, let's tell a reset button to actually do something. So we want to reset the slider so we'll say, commands the floats lighter because we used afloat slider to create it and we will say self best slider, because that's a slider we want to edit. As you can see from appear, you'll say edit is equal to true, and we'll save value is equal to 50. So if you go back to Maya and run this, which will again close, are you I and reload it. When I change my slider, you can see that it's creating a key over here because it's calling our Tween function every time. So if I was to clear out all these keys, have you created already and I drag the slider it works. The sliders hooked up to our Tween function, and this is because we used the change command when of the value changes will call between . And if we had reset, we'll change the slider to the value 50 but it won't trigger the change command. This is really handy because it means I can put the slider back of 50 without actually setting a key. Next, we need to add the close button. Now. The problem with the close button is that it needs to be below the slider and the reset button. But anything we are now will be added to the rolling out that we created up here. And this is because the way Maya commands work is that a stores, the lost layout that he created and anything you make off to that gets added to that. Similarly, when you created the column layout, everything we everything we created after it got added to the column layout, including are rolling out. So what we need to do is tell Maya to set the current parent to the column, and then we can create our button just like we did above. We can sit commands to a button and you'll see a label equals close. And then we'll say Command is equal to self dot close again. It's a method we haven't created, so let's create it. So we say death close again. Self is the first argument, and they will say Commands that delete you. I just like we did above and we'll use the window name that we used. So if you've been falling closely, you'll know that this won't work. When we go back and you run this and hit the close button again, I'll stay close. Takes exactly one argument to given if you're pinging. And if you're falling closely, you remember that I put this here again. I need to put this year because the close button is sending the same arguments that we want to ignore. So now if I go back to Maya and I run this, we have a window with him. Text on how to use it. When we drag the slider, it changes the key or sets a new key. If we had reset, it will reset the slider. And if we had close ill, close the window. And if we execute it again and we create two instances if it will only end up with one window again. It was important for us to create the Tween function first, because it's easier to test code without a u I. And it also means that if you want to call just I function inside another library you don't need the U I along with it is always important to separate your you I and your logic code. In the next video, we'll go over how to reuse this window to create and set up our gears. 36. Reusing our Interface for the Gear Creator: Theo thin This next video we'll be going over how to create a base. You I that we can reuse for both our tweener and for our gear creation. You Why? First, let's create a new script which will call reusable you I in this real import between function from our tweener you I too will say from tweener you I import Tween and what this means is that from the tweener you why that we built here? We can import just between function and nothing else. This is the upside that we're importing, just what we need. But it has a downside that we no longer have the nice name space before it to organize our functions. Next, we're going to import the gear clause So we'll say from gear class Creator import gear. And now let's create our base window so we could actually copy a lot of for a window code from their tweener You. Why? So let's open up between are you I and copied the class? I'm gonna pace us in and a mirror rename this to base window. I'm were renamed the window name to base window again. You can't use bases in here is telling us that we don't have the commands library. So let's import that. So from Maya import commands and now it's happy again. I'm gonna keep all of this functionality with checks of the window exists. And if it doesn't, then it deletes itself. I'm going to keep the clothes method, but the reset and the build you I will be different between the two. So I'm gonna say pause for both of them. And what this will do is that if we go back in to Maya and you'll say import reusable you I reload. Reusable you I reusable you. I dot based window does show on a run that it will create our base where no better one really do much else. So now let's go back and re create our animation window. It's what we can do is go back to our tweener you I and just copy the build you and the reset and the reset function. So we're going to say, plus, screener, you I and we're gonna inherit from the base window again. What this is doing is saying that we're going to reuse all of the structure that the base window has and only redefine the parts that we need. Teoh, the parts that we need to do our redefined the window name between her window and then we'll just copy the build you I and the reset code from a previous example. So now if you go back to Maya an answer based window, I'm gonna import Tween a window and run it. Oops, I think I forgot a tweener. You I sorry. And if I run this, it creates the window. If I drag the slider, you can see the values changing here. If I reset a neck and close Perfect. Now, if I go back here, I know Want to create one for a gear. So what I'm gonna do is I'm going to create a new cloths. I mean, call and we're going to call this gear window or let's call the gear you I and we'll again inherit from the base window. You'll say that the window name is equal to, and we're gonna call it the gear window again. No space is allowed, just like we did for the gear A class. We want to hold on to some values. So I'm going to create my in it again. Again, This is double underscore in it. Double underscore, and I'm just going to create a placeholder variable called Self Dot gear that all set to none. So I want to redefine the build you I. So first, let's create another column layout, just like we did before, and we'll store this and invariable of color column. Then we need to create a label to tell our user how to use this. So we'll say components or text, and we'll say label is equal to use the slider to modify the gear. And now we're going to create the rolling out, because what I want to do is I wanna have four objects in this rolling out. I want to have a button that says Make your another says Reset. Finally, I want the slider, and then I want a little text object. There will tell us the value off the slider, so let's first create the text object back in pie turn. Let's say self. The label, because I'm gonna edit this command struck text label is equal to 10 and I'm keeping it as a self variable because I want to access it later on your say self to. A slider is equal to command sort in slighter because I don't want float values. I want integer values. This time I will say a minimum value of five so that our slider concrete less than five teeth and a max of 30 We're gonna say value is equal to 10 and step is equal to one. So default values 10 and I'll go up and down by one. But this time, instead of the change command, I want to use the drag command. That means that the slider will in tract of the update as we drag, which is kind of cool. And now we're going to create this function. So we're gonna say modified gear and what the insulator does is it actually sends us the value of the slider, which will store in a value call teeth. And simply for now, let's just print out this value and will come back later to this function. Next, let's create a button that says Make gear. So we say label is equal to make year, and we give the command to self. Don't make your let's create this function here and again. The button will send us useless values to the are eggs variable. So let's stored there and let's print making gear. Finally, let's create another button called Reset, and we'll still label is equal to reset. And for common. We'll say self go reset, and we need to redefine this year as well, because it's not defined because it doesn't do anything in our parent. Plus and again, we use star our eggs to make sure that any of the variables the bucking gives us Ari thrown away into the arts variable and you'll say, print resetting. Next. We need to We need to reset our parent to the column. So we said, commands a set parent call him and commands a button label equals close command equal self dark clothes. And we don't need to redefine this because salary defined in our base window up here. If you've been paying close attention to pie chart, you'll notice that it gives these little symbols around certain methods because it's telling us that these air overridden from the base window. If you go back to Maya and launch the gear, you I by saying reusable you. I started here you. I parentheses no show and if we run, it L acute will create the gear window, but you can see that something's wrong. The fields are still appearing vertically. Let's go back and see what happened. This is because I never created the road layout. And again, it's just added it over and over underneath the column. So what I need to do is before this label that says 10 Let's create the rolling out So we say, commands thoroughly out. At this time. We have four objects that we want below. It was a number of columns equals four, and now if you go back to Baia and we run it, you can see that they're now laid out horizontally instead of vertically. If I click make gear, it's a making year click reset, it says resetting. And as I slide this, you can see that it's printing out the values off the slider. So let's close this and go back here and we can start implementing this. So first we need to create the gear to real say first we need to get the value of the slider, so we're going to say commands in slider because we created the slider with an int slider, and we need to query it. So we say self. A slider query equals true because we're going to query it. I'm gonna say value equals True, because we're going to query the value. This will give us an integer value to use for our teeth. Next, let's create a gear instance. So we say self dug gear is equal to gear, and this is a gear we've imported appear from our previous gear. Example. Now that we've done this, we could say self drug gear, Doc, create gear and you will say teeth oops is equal to and we will give it the value that we got from the slider. So now if you go back to Maya and run this and let me just put pull up my ah, let me just pull up my perspective. You here, Nuffer, run this and I say make year. You can see that it's made of gear right there for us. But if I change, the slider doesn't do anything yet. And if I click reset, it also doesn't do anything, so let's go back next. We need to tell it how to modify the gears. We'll say that if there is a gear self dug here, well, say self gear that change teeth and we'll say teeth equals the value we got another. What we're doing is we're saying that if the gear exist by default, there is no gear because we said it to none. So if we don't have a gear yet, it won't do anything. But if we have a gear which was assigned up here, it's going to use the change teeth method on the gear that we created. You can see this method over here in the Gear class creator and then So if you go back to Maya and let's close this you and running again, if I just drag the slider, nothing happens. Let me just delete this gear. If I create a new gear and then I dragged a slider, you can see that it's real time updating our gear with a number of teeth. This is really cool, but it's still not updating the still a text field here. Let's go back to Pie charm and fix that so outside of this, if statement we want to always so we want to always change the text field regardless if if there is a gear or not. So we put it outside of the S statement and we say commands doc text and we give it the label that we create earlier Self Bell label appear and we say edit equals true and we say label is equal to teeth. Well, let's go back and try this. So if I go back to Maya and now I drag the slider, you can see the values changing. If I say make gear, we'll create another year. Let me just delete both of these. I'll say make here and you can see that both gears Peter changing and the u I. Finally, we need to make the reset button work. So let's go back to Petra. And all we have to say is self care gears. None, because we want to not hold onto the gear anymore so that the Make Gear button will create a new gear. We want to reset Thean Slider so we give itself a slider. Edit equals true, and we give it back the value of 10 and we sick amounts or text self. The label at it equals true label equals 10 because what we're doing here is we're seeing We're resetting it so that we're not holding onto a gear, says the slider is no longer hooked up to a gear. We're changing the default value of the slider back, and we're changing the default text off the label back so that it matches slider. No, when you go back to Ah, Maya and run it, let me delete this. And now I run it. If I make a gear and they used a slider, it interactive lead changes that gear. If I had reset the slider no longer works until I make another gear. Let me move this out of the way. This is our new Year. And if I said this is our new Year and if I drag the slider will operate on the new gear, and if I create a new gear, it will only operate on the gear itself. 37. Adding our Scripts to the Maya Shelf: instead of always having to run your strip from the script editor, you can also add them to your shelf. There two ways to add your script to the shelf of here. I'll be adding it to the custom shelf, and if I select my script and middle click, drag it into my shelf and let go. We'll add a button over there, and I can right click on this button and hit Edit. This brings up the shelf editor. We concede the command that we saved. You can see that the languages python, and if you go to the shells tab, you can see on the left. Here it has our custom shelf selected, and our command here shows up is one option. We can change the name of this command by clicking on the rename and call it tweener you. I and create enter will rename it to something more sensible. This doesn't change our command here, just what is referred to inside the shelf down here, we can choose the icon that we want. I can either choose my own image by clicking on the folder here or use one of Maya's default images by clicking on this icon. The psych on may not exist in earlier versions of Maya, but it should be there from my 2016 and above. It opens up this other. You, I reckon, select when the icon said I want you can also search for it. So if I search for the word curve and hit enter, let me find one that I like. I like the cyclone, so I'm just gonna hit select. I can also add an icon label. In this case, I'm going to say tweener, and you can see that it adds it as a label to our icon up here and changes the icon as well . So let me say, Save all shelves and it closes the you I. The other way to add it is if you click on the little gear icon in your shelf and click on Shelf editor, select the shelf that you want added to or at a new shelf. But clicking on the plus icon here I'm just going to add it to the custom shelf and when I click, plus, it adds a new user script to change what the script does. I'll click on the command tab and I'll change it to Python, and I'll simply say, Print Hello World. I can also set what it does when I double click in this case off a print double clicking, I'll change, languish bite on, and you can also add options that show up when you right click on it. So I'm just gonna say, Save all shelves and you can see that it's added and you icon there for me. And when I click on this new icon, you can see that it runs print Hello World, which prints out Hello World. And if I double click on it, it says double clicking instead. I generally don't use the shelf while I'm developing, but if you're gonna be running the same code over and over again, it's often useful to just add it to your shelf up here. 38. Project 5: The Controller Library: through this project will be learning how to create a controller library using cute. Our controller library will be flexible and will support thumbnails. We can import any of the objects that we save out, and we could also create any new objects we want. In this case, I will say this as the test, and when I hit save, you'll see that it shows up inside of for our window. We learned how to save data out as Jason and files as well as load them back into Are you? I We'll be using cute provided by pi side to inside of my 2017 and pie side. In previous versions of Maya, we'll go over the differences between cute four and cute five, as well as the differences between pie cute and pie side and pie, Cute five and pie side, too. I'll also be going over a popular cute library that's used by Disney, WETA, Sony Imageworks and more. There will help us write code that can be used the cute in both Maya 2017 and previous versions of Maya. In the next video, I'll do a brief introduction to cute on. The different versions are cute use inside the different versions of Maya 39. Overview of the Qt Interface Library: this video will serve as a brief overview of cute as well as the different versions acute in the different versions of Maya. What is cute, cute written Q t but pronounce cute was created as an answer to a common problem back in the early nineties. If you wanted to write an application that ran on, multiple operating systems could have a really hard time because each operating system had its own. You I libraries as well as different ways to interact with the operating system. Cute, originally developed by Troll Tech, then bought by Nokia and finally sold to de Gea, is the library that lets developers create one application and the you I will look native no matter what operating system runs on and cute will handle. Abstracting all the functions that need to interact with the operating system does greatly ease development for multi platform developers. Up until my 2011 my owes using different you I libraries and OS code for each OS, this meant that Autodesk had more code to manage as well as many bugs that would be OS specific, starting with my A 2011 Autodesk switched acute cute means that Autodesk doesn't need to maintain different you like code for each operating system, and it means that they can focus on my itself. This is greatly reduced. The number of Os specific bugs in Meyer Maya, 2011 used cute four, and this has been the standard up till my 2016. My 2017 will use Cute five. Cute five comes in many advancements. It is better performing. It has a new library called Cute Quick, which helps you write really nice you wise very quickly that you can deploy to more operating systems than cute four Did. You can finally deploy on application to Android and IOS, and it includes new you I styled to mimic Google's material design and Microsoft. Universal designed cute is predominantly a C plus plus a P I. Fortunately, a company called Riverbank made a software called Pie Cute. This lets us use cute inside of python in a really nice and simple way. It acts and behaves like a completely native python library. Unfortunately, Pike, you test some licensing issues. This is where pie side comes in. Pi Side is a project officially backed by the cute foundation, and it comes with no licensing issues, and again it is similar to pie cute in the lets you use cute within python. In fact, for all intents and purposes, other than the name and the licensing their entirely the same. I like to change between cute four from my A 2011 to 2016 and the new cute five in my 2017 there are accompanying changes to pie cute and pie side. If you're using cute in my 2016 and below, my oh will ship with pie side. But you can also use pi cute for with my A 2017 and above. Meyer ships with pie site, too. Or you can also use pi Cute five. Since their significant changes between cute four and cute five, it is hard to write python code that runs with boat. This is where we can use a very popular abstraction library called cute Duck pie. Cute Top I is used by many large studios, including Sony Pictures, Imageworks, WETA and Disney. What it does is provide a simple layer above both cute four AP eyes and cute five AP eyes so you can just use keep dot pie and it will redirect any of your calls to the relevant a p I. I'll be using cute dot by for the rest of our videos, and I recommend that you do as well because it is quite useful to know and is what you will most likely be using inside of a studio. If you don't want to use cute dot by please make note off. Import statement changes here because that is a majority of the changes that we'll need to worry about. If you're using pi Cute four or pi side, you'll need to import the Q T gooey and the Q T core libraries. If you're using pi site to or pike you to five, you'll need to be importing the Q T widgets the Q T core on the Q t gooey library. This is a significant import change between the two. Any time there is a bigger change, I will cover it and you can see more documentation both on the cute doc pie get hub, which will be linked to from my get up, as well as all the code on my get hub for this project. Finally, I want to cover an aspect of cute that we will not be covering in this course, but it's quite common to run into this is called acute Designer. Cute designer is a dragon drop interface for designing you Eyes within Cute. It's quite easy to use and quick to get really nice You guys going? I would have been showing you cute designer, but I feel like it would be introducing just one more tool to an already long video. Siri's. We'll be focusing on python and designing cute you guys using the python AP I instead of the designer. Still, I wanted to make sure that you knew about the designer so that if you want to use it, you know that it exists. If you do decide to use a keep designer in the future. I also know that each of the cute libraries for Python comes with the conversion app. There will convert the cute you I code into python code. This is not always necessary because you can load the you I file directly and hook it up to a close inside. A python, additionally, will not be covering cute quick because cute quick is not a python library and instead uses javascript, which is not the focus of this course. 40. Qt vs Cmds: I recommend using the Q two I library wherever possible instead of the Maya command to my library. I have several reasons for this. First, the Maya Commands library was originally designed for Mel, and it's you I functions. Wrap a subset off all the cute functionality. Well, this may be easier for beginners to learn. It means that you lose access to all the powerful features and customization that Q test offer. Secondly, the Maya commands you I library is limited to just Meyer. If you wanted to write a U. Y outside of Maya, you would have to use cute anyway, so it makes more sense to focus your time learning cute instead of the Maya commands library. Lastly, cute uses a design paradigm called duck typing. We have experienced duck typing before, but will be most useful to us when we're developing you eyes. In our previous U example, you saw that we had to use the same functions to edit the you I element as we used to create it. That means that if we had an integer slider or afloat slider, we had to use the respect to function to modify it. This means that if we ever decided to change our you element, we potentially have to change all the editing functions in a lot of different places within our code. This becomes really problematic when developing larger user and faces. By contrast, because cute uses on object oriented design, every you element has methods on it that we can call. So regardless of the type of slider or you element we create, the often will have the exact same methods. So we could simply use the set value method on either of first sliders in cute, without having to worry about what kind of slider they are. 41. Duck Typing: I will not be going over a concept in Python called duck typing. Duck typing isn't unique to Python. In fact, it's quite common in many object oriented programming languages. Duck typing is a calo kilter that comes from the phrase if it sounds like a duck and walks like a duck, that it must be a duck. This refers to a design choice where many different types have the same interfaces that is , different types that have the same methods on their classes. For example, if I create a new string and I'll call it name and I will say, Dave, if I say name will print Oh, Dave and I can say the type of name is equal to string, but I can use this just like I would use a list. So if I say name and try and get the index of zero, I get D. Similarly, if I use, too, I'll get V. This is the same as if I just created a list of characters. So if I said list, name is equal to D. Okay, the e and I said, Let's name to again, I get V what this allows us to do is create functions that don't actually care what the type of four parameters are. My function could take a string. It could take a list, A to pull a set or a dictionary. It doesn't really matter as long as whatever object I'm getting has the same interface. So, for example, if my function takes a variable and it needs to get the index, it doesn't matter if I give it the list name, because I could do list, name one or if I give it a string, because as long as my function is accessing these variables in the same way, it doesn't actually care what type they are, and this will be useful when we're defining cute you eyes instead of the Maya commands way off, editing you elements where we have to know what type the U element is before recall a function to edit it in cute. Most you elements have the same methods on them. This means that if we had a slider and cute because, say, slider asset value 22 it doesn't actually matter what type the slider is, we could have many different types of sliders, and they'd all interact the same the same way. If I had a text box or a label, it doesn't matter, because I can just use the text method to get their value. This allows us to really simplify our code and be a little more free form in how we develop . 42. Using Qt in Python: before we start designing, are you? I Let's download markets says Cute pie abstraction Layer If you go to get hub dot com motto So cute pie you can find the code for this. You can see that is a cute binding. The wraps pie side by side to pike, you'd foreign pie Cute five. This means that instead of importing any of these python bindings directly, we can just use cute pie and we'll import the best binding for us. I'll be using the cute pile. I agree so that any a few watching this video who, using my A 2016 or earlier can still follow along with the code. And if using my A 2017 or above, it should be fairly simple. If you do decide to skip using this layer, I'll go over how to import your modules correctly in the next video. But for now, let me go over how to download this module. If you go up to the top, you can click the clone or download button and click download zip. I'll say save and then I'll open my zip Inside. My file is acute pie monster Go down inside here and they'll be acute pie dot file. I'll open up my Maya Documents folder on Windows. This will be inside your documents folder under Mayer, but our Mac Olynyk This will be in a different directory, and I'll make sure to have an overlay telling you where to find them inside. Amaya Directory. Go into the my aversion that you're using. I'm using 2017 and then go into the scripts directory. Simply drag the cute pie file inside here. Once it's in there, you can close this. Now you can go to Maya and open up the script editor Inside the script editor, you can say import cute, and if you run this, there should be no errors and it'll import the cute library. You can do this by thing print. Cute. Let me zoom in when you can see that it's already imported the pie side to module for me. This is because cute will automatically pick the best python Cute library for you. Now, if you want to create a new window, we'll say win is equal to cute. Cute widgets Que dialogue and L. A s a win dot show. And if I run this, you'll see that it creates an empty dialog window In our next video, I'm going to go over how to import the modules that we'll need if you don't want to use a cute layer. 43. Importing Qt Modules: will now be going over. Have to import specific modules, and we'll be using from the cute libraries. If you aren't using it, I'll go over how to import from the various python bindings for cute directly. Instead, the first let's start with cute pie. So to start, we'll say from cute import. Cute. Brigid's cute widgets are where all the U elements that you see will live. There's also cute core, which includes a lot of the core functionality for cute. Finally, that's cute. Gooey, acute, gooey includes many useful classes and functions. The real used to build are you wise, but it doesn't include any actual widgets or you elements itself. If you plan to use cute by, this will be our common import statement. If you're not using cute by and a using my 2017 and above, you have two other cute options. Instead, you can say frump eyesight, too, and the rest of the module stay the same. You're just defining a different parent library instead of cute. You're not saying hi site to buy sight to comes bundled with Maya, so you're guaranteed that it will always exist. Your studio yourself may, however, decide to use pi cute five instead, Pie cute is an alternative, binding for cute as often slightly more mature, but it does not come shipped with Maya. Do do licensing issues. This means that many people prefer to use by cute, but it's not always guaranteed to exist on another user system. But if you want to, you spike, you'd five. We simply change this import statement to pick you five. So regardless of watcher using, you still import the same sub modules and you're just changing the parent module. If, however, you using my 2016 and below, which uses cute for you, can do either of three things you can say from Cute and keep Your module is the same because we're using the cute abstraction layer. If instead you want to use pi side, which comes shipped with Maya, so it's always guaranteed to exist for my 2016 and below. You can use the same import statement, but just remove cute widgets. This is because in cute four cute widgets was combined inside, acute, gooey and acute five ever split out. So any time in the code that you see cute widgets, you can replace a acute gooey. If you're using my A training 16 and below and you're deciding not to use the cute abstraction layer similarly instead of pie side, you can also use pi cute for and you import the same libraries again. Similar to Pike, you'd five pi Cute four can be more mature than pie side, but it doesn't come shipped with Maya, so you or your studio may prefer to use pi cute. Just be warned that if you distribute your code, it is not guaranteed to be on every user system. For all my videos, I'll be using the cute library, and I'll be using it as a fem using cute five. I recommend that you do the same because they'll make it easier to follow along. Better will also mean that your code is portable between different Maya versions. Now that we're done with a rather lengthy introduction to cute and cute inside a Maya, let's start actually creating the logic for a controller library 44. Creating the Library Directory: will now be creating the logic for our controller library. Just like we've seen with our animation tweener and our gear creation tool. It is always in our best interest to create the logic separate from, Are you I The simplifies our development, and it also means that we can reuse or code without having to call. Are you I in pie charm? Let's create the package for our controller to live within right click on the scripts project and say New and Python Package and Real Man This con library packages are away in python to contain code together as a packaged library. You can see that the package contains of a directory with the name that we gave it, as well as an innit dot pie thean. It got pies empty. It simply exist to tell Python that this directory is actually a package and not just the directory. We'll right click on the con library, and now we'll create a python file. We'll call this controller Lavery and inside of this, let's say print. I am the controller library. I'm doing this so that when we import in Maya, you can see that it's importing from the con library package and importing the controller library module back in Maya, let's say from Con Library, which is the name of her package import controller library. And if I run this, you can see that a princess I am the control of library. But if I run it again, it won't print out anything again. This is because we haven't put the reload in. So if I say this, if I say reload control of library and I now run this, you can see that it prints it out again. And this me and this means that it will always be picking up the latest changes to our code . So back in pie charm, let's get rid of this print statement. First, let's import some of the module said we'll be using first fall. We'll, of course, be using the Maya module so we'll say from Maya import commands. We'll be using the OS module to interact with our operating system, and we'll be using the Jason module to write our data. We'll also be using a module called P Print. This will let us pretty print a lot of our data so that so that it's easier for us to read . So now that we have the imports out of the way, what is our first call affection? Well, first, we need to create a directory where we can save all our controllers and their related data . So let's figure out first where the mire directory is now. This will be different on every user's machine, and it will definitely be different on every operating system, so we can't guess as to where it will be. Fortunately, my, of course, knows where this is, and we can query it for Maya. So I'm gonna do user after and this will be the name of a variable and else it commands. Got internal var. I'm going to query the user after variable from Maya. So if I say print user after and I go back to Maya and I now run this, you can see that it's printed out the user App directory, which is under my user name, document and Maya. And this will, of course, worked regardless of which operating system you're using. Next, we need to construct the name of the directory before we create the actual directory. So let's door a variable directory and we'll say is equal to, and now we need to join this user after with the name of Far Directory. So we'll say the West right pot got joined, and we will give it the variables user after and the name of our directory controller library. Know what Westra Parts tojoin does? Is will use your OS specific separator, which is different between Windows, Lennox and Mac. On Windows, it is a backward slash and our Mac and Linux. It is a forward slash, and this will tell Python. Use your OS specific separator to join these two directory names together. So if I now say print directory, when I go back to Maya and I run this, you can see that it's now created the directory as appropriate to our operating system. It may be confusing because it's using the forward slash here, but this is because the directory that my against us back is using forward slashes. If it wasn't using that Hi Tom would do the correct behavior and give the backward slash. We can create a function called Create Directory so we'll say death to define a function and we'll call it create directory, and I'm going to give it a variable called directory and I'm gonna Kestel it to use This is the default value. This means that if no one gives my function any value, it will just use this next time you say if not Oh, esta pot dot exists directory, then you'll say, Oh s dot m. Kader, we think if this directory does not exist, then make this directory. But here you can see a problem. We're using directory multiple times and could be confusing whether this directory means the argument that our function is getting or this variable up here some python. It is quite common to have variables that are at the top like this be all capitals. So now I'm going to right click on it. I'm gonna go to re factor and rename and in winter need And I'm going to rename it all Capitals and I'll her and I'll hit three factor and you can see that pie charm is smart enough to rename it both here and here. But he knows that I didn't mean to use this over here, so it hasn't changed these similarly, I'll do the same for user after I'm going to use a shortcut. Shift F six, and I'll call it you user AP dir and you can see that it's renamed it both here and here. Finally, before we continue, let's out, Doc Strings to our function. I'm gonna put three quotes and hit enter and you can see that pie term automatically fills in our arguments. I'm going to remove their documentation for returns because it doesn't return anything. I'm gonna say that directory is a spring and it's the directory to create. And we're to say that the function creates the given directory if it doesn't exist already . So let's go back to Meyer. I must say, Controller, library, dark, create directory. And if I run this and I opened up my file Explorer, you can see that has created the control of library directory For me that didn't exist earlier. If I call it again, it won't create it again because it's checking, but it exists first. If I delete this and then run it again, you can see that it's created the directory again. 45. Saving Files: will now be creating a class to manage our controllers. This includes both finding existing safe controllers as well a saving new ones. Let's start by creating our cloth and we're sick loss controller library because our claws will be called Controller Library. And I wanted to inherit from dicked dicta short for dictionary. And the reason I'm doing this is because the dictionary is a really good way to store relationships between the name of something and any information pertaining to it, including this file pot and any screen shots for other information that we create. Now, let's create the same method. So we say death save and you can see that pie chart automatically adds a self keyword because it knows it's necessary. Now we need to consider the two parameters that will be necessary to saving down our file the first his name, because we always need her name to know what to save it to. On the second will be directory so that we know where to save it to. I don't want to always specify this. So let's make directory default to the directory that we defined appear now inside this function, we don't know If this directory exists already, we've already made the create directory function. So let's call it again and we'll tell it to use this directory. Notice that I'm not giving the actual keyword name here. If you don't give the keyword name, Python will do it in order. So since directory is the first key word by giving the directory value here it is automatically being given to the directory keyword. Next, we need to create the part that will be saving this. Do so we say path is equal to and again, we use oestrogen. Parts are joined to make this so we say, Oh, Esther path to join And we will say the directory. I'm running a string substitution again. So it's a percent s dot m a and I'm gonna say percent name and then next I'm going to try and save it. But first, let's go over some of the parameters of the safe command. Let's open the documentation off the file command and scroll down to the very bottom where we get help for it. You can see what we have to do to save it. We first need to rename it to the location that we want to save it and then we need to tell it to save, and we need to give it the type. My asking, Let's copy this and go back to Pie Charm. Let's pay system to pie charm. So we're seeing Command Start file and we're telling it to rename it to fred dot m A. This isn't what we want. So let's tell it to rename it to this path that we've constructed and then we're gonna tell it to save. And we were telling to save a Zumaya, ask you type. We also need to say force equals true. This is because it the file already exists. We want to force that we save over it. So we have constructed this path. That's the directory and the Maya file name. We rename it to that path, and then we save it. So back in Maya, I'm going to create a new instance off our library. It's a little bit long, so please bear with me. So we say lib is equal to Controller Library, which is a module name dot control of library, which is our claws. Name and re Esperance sees to create a new instance off it to finance a lived out save and run it. It's going to say that Safe takes the least two arguments, of which only one was given. It's expecting the name. So let's say test, Let's run this. And if I look back in my Meyer directory, you can see that there's a control of library directory that we created inside. It is a test autonomy, and I can import it. But it's empty. Let's try this with some dummy data. So let's run this again. And if I open up this file, you can see that it's opened up the Cube exactly as we expected. But let's say I have multiple objects, but I only want to save one of them. So if I create a sphere, for example, and I only want to save this fear, if I run this and let's create a new file and then opened this existing test Emmy, you can see that it saved both the sphere and the Cube. But I only wanted to save this fear. So let's add some functionality to save on Lee. Just our selection. See back in pie charm, let's say, instead of just saving we say, If commands don't ls selection equals true. And if you remember previously, what we're doing is we're seeing if there is a selection, let's get the list of the selections and instead we'll sit commands dot file and you'll get very similar arguments. We'll say force equals true type equals Maya asking because you want to save it as a my asking. But instead of save, let's say export selected equals true. And if nothing is selected else, well, tell it to just save so back in my Iife. We now run this, and if I open up the test file that we saved out, you can see there save just a cube. But if I create a cube as well, clear my selection and then run this and then let's open up the file again, you can see that it saved both of them 46. Finding Files: will now be going over how to find any of the files that we saved. So back in Maya, let's save a couple of files down. So let's select this fear and let's save it down using the save sphere. And then let's do the same for the Cube and call it Cube this way inside of her controller library. We have the Cube, this fear and the test start Emmy that we've already created Vacuum Pie Charm. Let's add a fine method so we say Death find. Give it parentheses again. Pie charm automatically as a self keyword, we'll say Directory to look in and real making use the default directory that we've created and inside here. First, let's check if the directory exists, because if it doesn't exist, that means that there are no controllers saved. So we'll say if not you. Ester Park that exists directory. They were thing. If the directory puss doesn't exist, just simply return that way. We don't need to continue on now. Let's list all the files in this directory so we'll say files is equal to Oeste. A list dura, and we will give it the directory. We're going to list the directory. So I'm gonna say print files. I'm going to go back to Maya and instead of lib dot save, I'm going to say lib dot find and run this and you can see that my of will print out a list of three objects. There's a cube, the sphere and the test. These are exactly the same files that we have in that directory. But here's the problem. Let's say I create a new text file. I'm going to call this the dummy text. If I now run this, you can see that I get the Cube, the dummy Texas Fear and the test any I don't want to dummy text setback in pie charm. Let's filter out anything that isn't a Maya file. So we're gonna say Meyer files is equal to and just like we did earlier, we're going to use list comprehension. So we're going to say f for F in files if f dot ends with DOT Emmy. And this is the same as if I said Maya files is equal to an empty list. I'm gonna say for F and files and it is important that we don't call this variable file because file is actually an important key word inside a python. He will say four f in files if f that ends with dot m a. My files dot upend F. Now this is 1234 lines of code. Where is this is a single line and it's about a simple to read. So let's get rid of this because this was just a example to explain what's happening here. So now if I print Maya files and I go back to Maya and I run this, you can see that they're no longer includes the dummy dot txt. Now that we found these Myer files, let's loop through them and add them to our dictionary. Who will say four m A in my files. Now we need to just get the name without the extension for the Maya file. So we'll say name. Comma extension is equal to OS Start pop that split E X D, and we'll give em a and what this does. It will split the extension from the file and will give us back the name and the extension . So if I now print the name and they go back to Maya and run this, you can see that it's printed out just the names of the files without their extension. So now that we know the name of the file, we need to store this in our dictionary, linking to the path to the file. But the problem is, if we print out M A and go back here and run this, it's only giving us the names of the actual file and not the full directory. So we need to do is say path is equal to us. That path don't join, and we'll give it the directory in the m A. So when we're reconstructing the full path name by using US Pasta joint and the directory researched N on the Maya file so we can say self on inside, square brackets will say name is equal to path. This could be a little confusing, but remember there were actually a dictionary that means that we can access ourselves as if were a dictionary. So it was saying in the square brackets that assigned the key name to this pot. So now if I go back to Maya and I run this, there won't print out anything anymore, but if I say print lib. You can see that it prints it out like a dictionary. You have the key and the value where the key is the name of the controller, and the value is a full path to the controller. While we're developing, I don't want have to print out every time in Maya. So let's make the fine method print out. Everything is found at the end. Another problem is that just printing out the dictionary printed out flat like this, which makes it kind of hard to read so back in pie charm outside the four loop. But inside the fine method USPI print P print and say self. What this will let us do is use the pretty print module to pretty print the contents off our dictionary, which is self. So if I now run this, you can see that it's printed it out on each separate line in easy to read manner. So we got the key, and the value in our next video will be going over how to load the files back in 47. Loading Controllers: This will be a quick video on how to load the file back inside of Maya. So now let's create a load method inside of the controller library. We'll create a new method called Load Again by charm as the self keyword, and we'll give it the name to load and we'll say part school self. And because we're a dictionary, we can look up our contents using the same dictionary methods in this case, the square brackets. So we're going to look up to see if we have the same name, insider file instance. And then when you say it commands don't file, we're going to give it the parts to import. We're going to tell it to import. But the problem is the Python one let you use the import keyword, so we have to use a short fun, which is I. So we say I is equal to true, and I don't want to use the name space. It's also using names basis false. This means that it won't import our controller into a secondary name space, which can be kind of confusing and know what we want. So back in Mayer, let's reload everything. Let's create the instance. If a library let's find all the controllers and you can see that it's found these and then I can just say lib, don't load test. Let's delete these. And when I run this, you can see that it imported the test file. If I delete keys again and say sphere instead, you can see that it's imported this fear file, and then we have our code saving, loading and finding our controllers. We're not going to go into saving extra data along with our controllers. That could be useful down the road. In the next video, we learned how to use the Jason module to do exactly that. 48. Our First Bug: back in control of library save method. First, I want to bring our attention to an issue. When we save something our library doesn't actually update. With this, I can show this by doing live dot save and I'll say this as error. If I do this and then I print out live, you can see that it has. It has the test controller, the sphere controller and the Cube controller. But it doesn't have the error controller that we just saved. And I can look this up specifically. And I will say that there's a key error because the key does not exist. But if I do lib dot find before that and then run, it will work just fine. I don't want to always have to run lib dot find every time I save a controller. So let's just update ourselves every time we save real, say self and in square brackets, name is equal to pat the way we're always updating every time we save 49. JSON: Reading and Writing Data: Now that we've solved our first bug, let's create a dictionary to save data for our controller. First, we need to know where to save this data to. So I'm gonna create another part. This time I'm gonna call it in. Full file is equal to I'm were created the same way that I created the path to save. Originally, I'm going use us star path for a joint. I'm going to give it the directory. I'll you string substitution again, just like a did above. But this time I'm going to use the Jason Extension. Now, we need to know what data to save to this. But I don't wanna have to specify every possible data that we might want to save. I want to give the ability for users to save any data that they want. We can do this by allowing our save method to taken arbitrary amount off information. Just like we use star ARDS to store any excess variables inside of the arg variable. We can do double star info, destroy any extra arguments inside of the info variable. Let's try this out right after the safe command. I'm here Say print info. I'm going to return immediately so the rest of our command doesn't run. Let's go back to Maya to try this out. So if I just run lib, save again, you can see that just prints out an empty dictionary. This is what info is equal to. If I now add any arbitrary parameters, let's say spam is equal to true eggs equal to green, and I now run this. You can see that the dictionary is equal to eggs equals green, and spam equals true. This is because any arguments that aren't defined as part of our method will automatically get stored inside of the info key work inside of the info variable. Oh, and as we've seen, info will be a dictionary by default so we can save this dictionary down with our file whenever we want. So let's try doing this at the end of four Save method before we say before we add the path to ourself, say, with open info file and then hit comma and in quotation marks, put W as f and then on the next line Jason Dodd dump. Remember that this has to be indented and we will tell it to dump the info because this is a dictionary will tell it to dump it into F with an indentation off. Four. Let's go over this we're seeing with unopened file and this is a part name to that file. We'll open it in write mode. Would W. And we'll store this open file in a temporary variable called F. And with this variable ical f, we're gonna use Jason to dump the in four dictionary that we have from here into F, which is the file stream that we just opened. And we're gonna indented everything by four spaces. What do you see here with open is called a python context. We won't be using them much in our course other than opening a file, but essentially what they do is they will run code inside it, and before and after this code runs, they will do something. In this case, they'll open the file before the code runs and they'll close the file offer. The code is done running. This is regardless off if the code fails or not, and it's a very convenient and safe way to open files. So now let's go back into Maya and try this out again. I have my arbitrary arguments to my safe function. So I'm saying lived out safe. I'm going to call this the info test and even give it to arbitrary values. Chemicals true and eggs equal green. So let's run this. If I open up my directory again, you can see that there's a new file in here. Call info test on Jason. I can open this in my sublime text editor, which is another editor that I like, and you can see that it saved it as a dictionary. Eggs equals green, and spam equals true. This means that we can save any data that we want alongside our controller. See, back in pie charm. Let's add more information to this info file so we always have it to depend on because we know info is a dictionary we're gonna say in folk, and we're gonna add a new key to it. Call name. We're tell it that the name is the name. We're also gonna have to know the key called path, and we're going to give it the path that we created appear back in Maya. Let's try running this again. So I'm gonna run this and I'm going to open up my sublime text and you can see that it now saves the name as a value as well as the path with the full path to the file I just saved back in pie charm. Let's make another adjustment or save method. Currently, we're only saving the path name in our controller library. Instead, I want to save all the information that's also being stored in our Jason. So instead of saying self and in square brackets, name is equal to path, let's make it equal to the info dictionary instead. Similarly, in the fine method, Realtor now need to find the Jason Dictionary that we created. So in the fine method, go back down to the four loop that we had inside the four loop. Let's create a new variable, and we'll call it in. Full file is equal to and really you string substitution again, and it will be called the same name as their Maya file. Just with a Jason extension, we're going to check if this info file was found to real say if info file in files because we've already listed old files in the directory up here, so it doesn't make sense to check for that file again. To real say, if this info file is in the files relisted, then let's construct a full part. So we'll say info file again because you goto os drop path, right? Join. And just like we did up here, well, we'll create the part again with the directory and the info file, and now we need to read the file back in. So just like we did in the save method with the open file here, we can copy that. But instead of using W, I want to say our So we're opening this file with the read flag and started the right flag , and we don't want to dump the data. So we say, Jason the load. I want to load it from F where f is the file stream that we just opened. So that is only running in that if statement. And once we load this Jason Data we want to store, we want to store it in a variable called info. Otherwise, let's say let's print no info found. And also, let's p print our info so that we can see what we've loaded in back in Meyer. It's sort of lived out. Save. Let's say Lib got fined and let's run this again and you can see that it's saying knowing, full, found, knowing, full found. And then suddenly it's red in this dictionary that we saved out and it continues on. And then finally, it prints out all the objects that have found, so we can therefore see that it is finding and reading in our Jason dictionary. This is successful, so we know info is a dictionary and Jason is loading the dictionary into it. So let's get rid of this p print. And in the else statement say, info is equal to an empty dictionary. Again. The empty dictionary is signified by curly braces, and what we're thing is, if we don't find the Jase on file, let's just say that Info variable is an empty dictionary. That way, we know info is always on empty dictionary. Next, let's populate this dictionary, just in case the information isn't there. So we'll say Info. Name is equal to name, and we'll say info hat is equal to path the way we know that the name and the path are always given, and just like we did in the same method. Let's store the actual information dictionary instead of just the path. So instead of saying self name equals path, well, say self name is equal to info. And now, if you go back to Maya, let me clear my history and run this. You can see that our library consists off the names of the controllers as the keys, and then each of the keys has a dictionary as its value, with more information, and by default, each one will at least have the name on the path value. But if we specified mawr and if it's found the Jase on file, we'll load back those values as well. Finally, because we've changed what our library consists off, we need to also change what are load Method does so instead of getting the path from self name because this now equals the dictionary and not the path we have to say self name. And because that is giving us back a dictionary, we can query it like a dictionary. So another square brackets inside this let's say path and let's just this out. Let's reload all of this and thence, let's say live dull load and let's say I want to load the Cube. And if I run this, well, uh, it's got the Cube back in. 50. Capturing Screenshots: We now want to add the ability for a library to save a screenshot off the controllers. It's a back in pie charm. Let's go back to our save method for a controller library and let's add a new keyword parameter to a save method. I'm gonna call this screenshot on by default. I wanted to save a screenshot that I want to give the ability to disable it. Now I want to save the screenshot after we saved the actual controller. But before we write out the Jason file, so what I'm going to do is it went out a new line that says, If screen shocked as an if screenshot is set to True self does save screen shocked, which is a method that we haven't created yet. I don't want to save it with the name and to the directory that we've been given. I also imagine that this method will give us back the location of the screenshot, which I want to save into our info dictionary. So I'm going to say info and in square brackets, I'll say a screenshot is equal to the operator of the method. Nope, I charms correctly saying that this method does not exist. So if you click on that and go to the lightbulb icon, you can say add method, say screenshot, and it will create a method with the arguments that we just specified. Alternatively. Or if you're using your own editor, you can just create this yourself. But I'm going to let Pike Charm do the dirty work for me. I need to change it a bit. So that directory has a default value off the directory. Recreate earlier, and I'm going to create the pot that we're going to save it to. I think OS Dark Path not join. And again, we'll just get with the directory on the name and we'll automatically just returned this path so that it's saved inside so that it saved inside the info file. Next, I want to make sure that the Maya view fits exactly around our controller. My has a command for this called view fit. I'm gonna call it the men each tell Maya how to save out the image. Do I wondered a JPEG PNG, a tiff or some other image format For this exercise? We will be using JPEG, so we're going to set the default Render value to J. Peg. This is one of Maya's many quirky corner cases and therefore is pretty ill documented. So you so you'll just have to follow along. So Music Commons does set adder and in quotation marks, said default, render Global's docked image format and then just go until it decided to eight. No, why is this? So if you go back into Maya and we open up the default render settings, I'm gonna clear my history in the script editor so you can see what I'm doing. If I change the image format to J. Peg, you can see that it's doing a set at her. He followed. Render Global's Image format eight. If I change this surge, if it's zero and for changes to my I i f. F at seven. Notice something. Jif comes before J. Peg, which comes of for my i i f F. But that's not the order of thes numbers. This is because Autodesk decided to save these in a different order toe how it adds them to the menu. That's why the easiest way to set it to J. Peg is just to blindly believe that eight is the value for J. Peg. So let's send it back to J. Peg and let's go back to Pie Charm. Lastly, the way to render this out is using the plate glass command. So we say, Come on, struck, play, blast and then we need to give it various parameters. So first, let's say complete file name is equal to path because that's a complete file name that we want to save, too. You wanted to tell it to force over, right? Who will say force overwrite is true. We'll say that the format is an image. I will say that the width is 200 and the height it's 200 does a flag for show ornaments. I will say this is false ornaments of parts of the view port that aren't actually in your scene but are just a few port overlays, so want to disable them. I only want to write our one image, so I'm going to say start time is equal to one. An end time is also equal to one. Lastly, I don't want to actually open this in any viewer. Someone to save ur equals false so that we don't get so that we don't get Maya's image viewer or any other viewer opening up. So if you go back to Maya and let's Skipper to follow this and let me clear my selection and I'll say live dot save, I'll say screen test. Let's save it out and you can see that it resize may view port to fit the controllers, and it also flashed it. Now if I opened my directories, I can see that there's a file ical screen test, and that's kind of useless to me. And this is because I forgot to put an extension on there. Let me delete this because I don't really need it right now. Let's go back to Pie Charm. And the reason is, over here, I just have name and the name doesn't have an extension. So let's use a string substitution again. So safe percent s Dajae PG percent a name. So if I go back to Maya and I run this again and I opened up May directory, you can see that there is a screen test, RJ Peg and it's an itty bitty ton nail that includes the controllers that we just saved out . So now that we have the saving working. Let's also make sure that our fine confined the street peg after we have read in the Jason . Let's see if the screenshot also exists to We'll say screen shocked is equal to percent sa J. Peck the same way we did for the info file percent name. And we'll say that if the screenshot is in is in the files that we found above, then it must exist, right? Who will say info Screen shot is equal to. And then we'll just construct the full part to the screenshot using arrester parts or join . We'll give it the directory on the name. And now, if you go back to Maya and I say lib dot find and I run this, you can see that screen test has a screenshot value and none of the other ones do, because it's the only one that actually has a screenshot 51. Qt Documentation: way before we get into actually building, are you? I It's important to let you know where you can find documentation about pie cute and the actual c++ cute library, even if you choose to use pi side instead of pie. Cute the pike. Your documentation is much more in depth than that. If the pie side documentation, you can find the pike you documentation by searching for pie Cute Reference guide. This can be found in pie, cute or source. Forge dot net slash docks flash by cute five and if you go down, you can see all the various clauses that are available inside a pie. Cute. The most common will be the Q Dialogue as this will create a dialogue. Notice that all pie cute and indeed all acute classes start with the letter Q to signify that they come from the cute library. If you click on cue dialogue, it will actually just give you a link to the C plus, plus documentation instead, and clicking that will take you to the actual acute documentation. On the actual cute documentation, you can learn information about the Q dialogue class. You can see that it is inherited from the Q widget and that all these other you elements inherit from it. That means that cute dialogue is a subtype of Q widget. But all these Q file dialogues que font dialogue, etcetera our Children off the Q dialogue. You can see functions that are enabled on this object at Dallas functions that it over rides. They're all the slots and signals. But there are also more methods that actually defined by the original que widget. I'm going down. You can see many, many more functions. This can make cute a little confusing to look up documentation for it first, because all the documentation may not live directly where you expect it to. But over time you'll learn to appreciate the cute documentation because it divides up the contents into easy to digest parts. Finally, another website that I find useful for looking up how to use pi cute is knowledge. Your knowledge dot com. You can search for any of the clauses that you want, and I'll give you sample codes on how to use them. On this page, you can see that I've searched for the pike. You'd five cute widgets que dialogue and gives me examples of code that are using it. This is really useful because sometimes the documentation can be a little confusing, and actually seeing it in use is a better reference than reading the documentation. Finally, if you ever struck with cute, it is a very common library, and therefore you can always find help for it. Using Google or Stack Overflow, they'll be links to all these documentation websites in my guitar Grippo if you ever get lost. 52. Displaying a Qt Window: Now that we've finished writing all the logic for control of library, let's start by creating the you I on your con library package. Right Click and seeing new python file. And let's call it library. You I and hit enter. This will create a new module inside of Farrakhan Library package called Library. You I in here? Let's import our control of library cloths. We'll say from controller Library, Import controller Library. So we're saying from the control of library module import the control of library class. Next, we need to import the cute modules that will be using. So, like we covered in the previous video, I'm gonna say from cute import, cute widgets, cute core and keep gooey. If you aren't using the cute library, you can replace this with whichever pie cute library you're using. And if you're using my 2016 or earlier replace any usage is off. Cute widgets simply with cute gooey because cute widgets didn't used to exist. Let's create a clause that would represent our library. You I and we'll call it controller library. You, I we'll need to inherit from acute dialogue because we want our control A library to be a dialogue. So let's say cute widgets, Doc. You dialogue another cola and hit. Enter, then add thean it method. So this is deaf. Underscore. Underscore in it. Underscore underscore. Inside this, we'll call the super method so right Super. And if you hit enter, you can see the pie charm automatically completes this. Let's explain what you've just written. The double underscore innit? Method is a method that all python classes have. Whether you implement it or not, it's called whenever you create a new instance of the clause inside of this we using the super function. What super does is, it says, Let's find the super close off this cloths. In this case, the super of the control of library you. I is the closets. Inheriting from this is cute widgets or Q dialogue. This is so that our code never actually needs to know what we're inheriting from, and it can figure it out while it's running. This means that if I wanted to change what this inherits from and change it to a Q main window instead, I don't have to change all my code occurrences that are calling the super. So let's change this back to Q dialogue and let's continue explained the super the next argument to super itself. Now that we found the cost that our controller library you I inherits from, we need to tell it how to refer to the specific instance. This won't be necessary in Python three and above. But since we're using Python to this is still an annoyance that we'll have to live with. And having phoned the control of library you I and telling it to use this instance, we then call it's innit method. This is the same as having done this now. This may look more simple to use now, but like I said, if you were ever to change what you inherit from then you'd have to change every instance of this. Instead of doing that, Using Super makes a code much from a flexible and scalable. Additionally, bite on lets you inherit from multiple clauses. So even though I'm using Cute, which its stark you dialogue I could inherit from any other cloths that I want as well and Mike Loss will be a child of both of them. So if I added a clause and in this case let's add the str close our control library would be both acute dialogue and a string I'm calling. This ignores the fact that our class can inherit from both of them. So it's always better to use super where possible because it takes care off all these little details within Python without us having to worry about it. And like I said, pie charm automatically fills in this in tax for you, so you don't actually need to remember it now on to why we're calling in it. We're calling the in it because the queue dialogue actually does some logic inside its own innit function. But because we're redefining our own innit method here, it means that we aren't actually calling the Q dialogues innit method, as we've seen in our introduction to classes before. But because we need to run the Q dialogues in it, we use the Super to find the Q dialogue and then run. It's in it. This means that we get to use all of the logic inside of the Q dialogue without having to rewrite it ourselves. Next, let's create a function to show. Are you I outside of for cloths? Let's create a standalone function cold, show you I and inside of this we'll say you. I, which is a new variable, is equal to control of library You I and let's use Prince sees to create a new instance off it. And then we'll say, you, I don't show with currencies to tell. Are you I to display? And finally, let's return. Are you I to Maya now back in Maya, let's say from Con Library, because this is the name of for a package. We'll say import library You, I and I'm going to say reload library you I because I want to reload any changes that I make. And finally, I want to say library you, I that show you I to call our you show you. I function now. If I run this, you might have seen a little window pop up and disappear immediately. Let me run this again and pay close attention. This is because even though we're creating the you, I variable here as soon as our function ends, Python is deleting this variable from existence because it sees that nothing is actually using it. This is called the garbage Collector, and basically it's Python's way of cleaning up unused variables because you wise only used inside our function python correctly but annoyingly assumes that we won't need this variable and cleans up any data related to it. But pythons assumption is incorrect. In our case, we actually want to use the u I so simply creative variable inside a Maya, we can call it to you I and safe equal to the return value Off our show you I function and because I show you I function returns the you i variable. It means that this year I variable will equal to that. So now if you run this, you can see that the window stays alive because Python sees it, we're still using this. You i variable and it isn't deleting it now. This dialog box isn't very exciting. It's just a plain gray box with no real title. So let's close it down and customize it back in pie term. We're going to edit the innit method that we defined. First, let's set a window title so we simply say, self doubt, set window title And in here I'm just going to tell it to set the window. Title two controller library. You I next, let's store on instance off our library inside the u I. So I'm going to say self done library is equal to control a library, and I'll create a new instance off our control of library. After that, I'm gonna call to methods that I haven't defined yet. But let's call them anyway. So we'll say itself. Don't build you. I, which is a method that I haven't defined yet and self, don't populate again. Another method of having to find yet you may notice the pie charm is unable to tell us if these methods drone exist. This is because pie charm is confused by acute abstraction library because it doesn't know where it's importing from. Therefore, it can't understand it. This is a small price to pay, because cute allows us to use our code anywhere. But if you want to switch back to just using pi side to or pie side, please feel free as well. Make pie charm much easier to use. I'm gonna switch back just so that it's easier for me to demonstrate, So if I say from by sight to and I keep the and they keep, the module is the same you can see that we now get better. Completion by charm will take a little while to think about it. And in the meantime, let's create these methods by saying Pause and saying Let's not put anything inside there yet we just want to run them as soon as a new instances created And in fact, instead of saying pass, I'm gonna say, print building you I and I must say, print populating so that you can see that they're running. If I go back to Maya and run this, you can see that it said building you I and populating as soon as that created a new instance and you can see that our dialogue now has a window title that we set. 53. Building the Qt Interface: before we continue. Let's take a look at the you I will be designing. So we have this dialogue with the text control alive for you. I we can see that it's mainly vertical, but we have elements air laid out horizontally. You have a text field up here. The stakes field will be for people to enter the name of the controller. We can see controllers that have been saved out. And from our previous video, you can see that we have many with no actual thumbnails except for screen tests where we did save a screenshot. So we need to support both instances. If I grow or shrink my you, I you can see that the elements resize within it. Below that, you can see a refresh button on import button and a close button laid out horizontally. Additionally, if I hover over any of these elements, you can see a tool tip with the information that we read back from the Jason on file. Let me close this down and let's start creating this First. We need to create a vertical layout as our master layout. So let's say layout is equal to cute Widgets. Q. V Boxley at and you can see now that we've changed from using the cute abstraction layer to price I to directly by charm is able to auto complete for us again. We lose the benefit if using the cute abstraction layer. But we also get certain benefits while developing, and I can always change us back to just cute. Whenever I release this, of course, I would have to test to make sure that everything still works. But for the most part, everything should work. So now we have a V box layout and the V Boxley Out is short for vertical box layout, which is another name for the column Lee out the Maya uses. This means that any widgets we add to this layout will be added vertically. We also need to tell this layout what to apply to in this case. We'll tell it to apply to ourselves, which is this que dialogue inside that we need to add horizontal line for a text field and a bucking for saving down our controller using that name. So let's create a layout. There will be horizontal instead. First we create a widget, and I'm gonna call this safe which it and we say equals too cute widgets, Doc, You widget. Next, I'm gonna create a layout for this called Save Lee. Out is equal to cute widgets Que each box layout, which similar to the V box layout, is short for horizontal Boxley out which will lay out any of its Children horizontally from left to right again. We need to tell it which widget to apply to. In this case, it will be the save widget. And then let's add our new save widget to the original Q V box layout. Surreal sale layout that ad rigid. And I'm going to say save rigid. Next, let's create the items that will be inside the safely out. First, we'll have a name field. Some will say Save name. Field is equal to cute widgets, Doc. You line at it. We need to access this save name feel later. So I'm going to add self before it self dot like we've seen before. This means that this variable will be accessible inside of the cloth. Later on, we'll add it to the horizontal layout that we just created, and you can already see a big difference between using cute on the Maya commands library. The Mayacamas Lavery automatically adds everything to the lost layout created. Where is cute requires you to explicitly define this. This may seem or inconvenient now, but as your developed larger you wise, the explicitness of defining your own hierarchy is really useful and keeps your code very clean and easy to maintain. Next, we'll create the save button by saying Save and then be tiene, which I use for short form for buttons. Then I'm gonna say Cute widgets, Doc. You push button and inside the prince sees. I'll tell us the texture have for the button and I'll say, Save. Let's add this again door save Leah will say, Save Lee Upton. Add widget. That's save buttons. If I go back to Maya and I run my code, you can see that my you I now shows and we have a text field that we created on the save button that we just created. They won't do anything yet, but we will define the behavior later. Next, we need to add the thumbnail view to browse For all of our controllers, it's a back in pie charm. Let's create a new widget. I'm going to call this the list widget Because the thumbnail view is really just a list off everything that we want. I'm again. I'll need to access this later. So I'm gonna use self dot list widget, which will be the name of a variable. And we're gonna sign this acute widgets, Doc, you list widget. And now we need to add this list rigid to are you I If I say layout that add widget and they'll say itself a list widget, you can see that we now have an area for all fired controllers to live going back to pie charm. Now, let's add all the buttons that we want at the bottom of the u I. We want these buttons to be laid out horizontally. So let's create a new widget like we did appear to hold our buttons somewhere. Say, button widget is equal to and like we did before, I'm just going to create a new widget using cute widgets, Doc, you widget. I'm gonna add a layout to this. Someone say button layout is equal to cute widgets, Doc, You each Boxley up and then I'm gonna sign this to the button widget. That we just created. And before we forget, let's add this to the monster Leah. So we're seeing Lee out. Add widget button widget Inside this button widget. Lets add three buttons. I'm gonna create the import bucking, and I'm going to call on him or create a new push button for it. And I say, Import button, Is it go too cute. Widgets, Doc. You push button and inside parentheses. We'll give it the text we want to display. I'm going to import with a little exclamation mark for some flair. We're going to add this to the button layout, and we're now going to create the other two buttons in a similar way. So we're so I'm going to create a refresh button. Refresh button is equal to cute widgets, Doc. You push button on in princes and we'll put Refresh. We'll add this to the button. We act no the same way we did before and lastly relied a close button, you know, and we'll say close button is equal to cute widgets. A que push button and currencies will say close. We'll add this for the button layer by saying button layout, not add widget. Close bucking if you go back to Maya and run, are you? I you can see that we have the you I created really quickly. You have a tax field here with the save button. We have a new area for all the controllers to be listed as well as three buttons. I don't really do anything right now. Import, refresh and clothes laid out exactly as we want. 54. Making a Gallery for our Controllers: Lau go over how to use our control. The library to find and display all of the controllers. Have you previously saved act? If you haven't saved out any controllers already, I recommend going back and saving down a few so that we can use them as examples for this You I in pie charm. We had defined this populate method. If I go down to it, you can see that currently it just says populating and it runs whenever we create a new instance A for you, I The first thing we need to do is call our library self done library. I mean to tell it to find all the existing controllers. Then we need to go through all the controllers that it finds and add them to the u I. So let's say for name, comma info in self delivery that items real print the name and info. So if I run it now, you can see that it's printing out all of this information, the name and the valve and the info. This is because self turn library two items returns to objects for every four loop. The key on the value in this case, the name and info. So with this, let's create a new list widget item to add to our list widget. So I'm going to say Item is equal to cute widgets, Doc. You list widget item an imprint sees. I'm gonna give it the text that it should have in this case. I'm gonna write name because the name variable is a string for the name that should be displayed. I'm gonna add this to the list widget, and I'm going to say Self doubt list widget or that item item. If you go back to Maya and now run, are you? I You can see that it's just listing them vertically. Where's my you? I listed them as Tom Nails and they would flow around like a little gallery view. We'll fix this up right now, but first, let's had a screenshot to each of these elements. We'll say Screen shot is equal to info dot Get and from the information dictionary, you'll get the screenshot variable. We'll say, if screen shocked, let's create a new let's create a new icons will say icon is equal to cute gooey because the icon cloths lives in cute, gooey and you'll say dot que icon and we'll tell it to use the pot to the screenshot that we just got next. We'll tell our list rigid item that we just created to use this icon missing item to set icon and used the icon Variable. Now, if you go back to my and run this, you can see this. There are itty bitty little icons next, each of for next to each of her items. So far, so good. But I still want to display them as the thumbnail view. This involves modifying the list rigid that we just created. Fortunately, this is really easy and cute. So let's go and find where we defined our list. Widget. It's over here. Self done list. Rigid insider. The build you I method I'm gonna hit enter and right after creating the list widget, I'm going to say Self done list widget dot set view mode. I am Go tell it to be cute Widgets que list widget duck Icahn mode and basically, from this list rigid. We're getting this icon mood variable And what this tells our list widget to do is that it should displayed the view mood in icon mode instead So if you go back to Maya and now run this, you can see there's displaying them as little icons, and that's exactly what we wanted. But there are a little bit hard to see, and we want them to be much bigger. Sebek in Pie Charm Let's define size that we want these icons to be. I'm going to create a new, very biblical size, and I'm gonna tell it to be 64 because we wanted to be 64 pixels wide. We're not going to tell the list rigid to set its icon size. So we'll say self. The list widget dot set icon size and this method will take a cue size object. So let's create that. So we'll say Cute core, Doc you size. And this takes an X and a y parameter, for which we'll just give size and size because our because there Tom nails are square. So now if you go back to Maya and run this, you can see that we now get larger thumbnails exactly like we wanted, but they don't re flow and grow to the size of to you. I plus closest and go back to Pie Charm. and again this is another parameter that we can set. So we say self done list widget dot set resize mode And we're going to say again, cute widgets, Doc, you list rigid and we're going to get the adjust variable on it. So we go back and now run this again. You can see that as I grow and shrink my you i that the controllers move along with it. So finally I'm gonna add one more parameter. I mean, it's yourself a list widget that set cred size and I'm gonna add another que sais so cute core Doc, you size on this time I want to add a little bit of foot buffer space so created small creative variable up here called Buffer and we're set it to 12 because I want the buffer size to be 12 pixels. Come back here again where we set the grid size in the queue size parameters, I'm gonna say size plus buffer and size plus buffer. If I know if I now go back to Maya and run this, you can see that there's a little bit of gap which helps our, which helps our objects be a little more readable. 55. Signals and Slots: I think this video will be covering signals and slots. And cute, he accuses will recall event driven programming widgets, another name for a U. I. Element inside of cute emit signals. These are events that happen. For example, when a button is clicked, it emits a clicked signal. When a check boxes toggled, it emits a toggled signal. This is so the widgets and cute comptel other objects that something has happened. What we do is reconnect slots to these signals. We told a signal that when it admits to call this other function So, for example, we can say that when a button is clicked, it will call this other function. We can say that when a slider is dragged, it will update this label. So the event that is emitted is called a signal because it is signalling a change or in action happening. The function, a method that receives a signal. It's called slot and we register slots to a signal. Most cute widgets come with their own signals, but you can also define your own signals on any cute class that you want. Signals and slots are key concept and cute, and one the reasons why it's so nice to develop with. Well, now be using signals and slots with their U I to hook up you, I elements and you I events to functions that will carry out the logic that are you wise and charge off. 56. Making our Interface Work: will now be setting up for you. I so that the buttons and widgets actually do something. We'll be connecting signals from each of for widgets to a slot on Are you I? Let's start with the close button at the end of our build. You I met ID. So let's go to our build You. I met it scroll all the way down to our close button, and after we define it, we'll say close b TN dot clicked and you'll notice that when used by Charms, Auto complete will often add these parentheses. Signals don't need signals. Don't need these parentheses. So we'll say close but not clicked, docked without any Princz. And then we'll say connect and now we'll use parentheses. So what we're saying is when the close button is clicked, connect the clip signal to this function that we're going to give it a new gunner. Tell it to run the self dark clothes method. The self dark clothes method is defined in our Q dialogue. In fact, it's defined in the queue widget that Q dialogue inherits from fig. So if you go to Maya and runner you I and now if I click the close button, you can see that it closes, are you? I Similarly let's hook up a refresh button to re populate. Are you? I so that if any changes happen on disk, are you? I will stay up to date, So let's find what we defined a refresh button. After that, let's create a new line. Refresh DTN Doc clicked and again removed the parentheses dot connect, and this time they're going to use the same populate method that we created earlier. Again, it's important not to have parentheses after the populate. This is so that we don't actually run the populate method and instead richest, telling it to connect to the populate method directly. So if you go back to Maya, this will expose a bug. So we're now you are first loads. You conceal the controllers. But if I had refresh, you can see that it's indeed refreshed. I you I. But it's adding the same controllers again, and every time I add and every time I click the refresh button, it just grows our list with duplicates off the same controllers. This is actually a good test to see if our grid view works well. If you don't have enough controllers, but let's fix this. The problem is they were always calling the populate method that just keeps adding these items to the list widget. It never removes them or checks if they already exist. I also don't want to go through and check if all of the controllers in Are You. I still exist on disk Instead, let's trust that our populate method works properly. And when it runs, let's tell it to clear out the list. Widget first said the head of the populate method will say self done list reject, not clear. And all this does is it tells a list widget to clear all if its contents. So now if we run, are you I and I hit refresh again. You can see the nothing changes. What's actually happening is our refresh is clearing out all the elements in our list rigid and then adding them back in. If I open up my file explorer, you can see that we have all these files on disk. Let me delete this fear files. I only need to delete the sphere dot m A and I must say delete. And if I go back to my controller and now clicking the refresh button, you can see that it's actually not doing what I said. Where deletes the sphere? Even though that's fierce file doesn't exist on disk. This is because of a bug in our library code. So let's go back to our library code. So in our controller library, let's go down and find the fine method. And just like we cleared the list widget in our Q t y, we can clear our dictionary so we'll say self duck clear. I also want to remove the P print at the end if it because it's getting distracting slips, removed the P print. And if you go back to Maya and close this and run it, you can see that it's working. But if I opened my file Explorer again and this time, let's delete the ball, let me find the ball. Let me delete the J Peg and the Jason. And if I hit delete and the head refresh, you can see that the thumbnail has disappeared. But the ball still exists, and this is because when you go back to our code, we've changed the control of library but were never reloading it and and our library you I is holding onto the instance. So all we need to do is instead of importing the controller library directly, we'll import just the control of library package. Well, say, import controller Library to import the control of library module and we'll say, reload. Controller library. Another group changes import. We need to change our self to a library. Variable insider in it, all we need to do is had the controller library prefix to our controller library variable. And that means any of the code that we change in our controller library module will automatically be picked up by Are you I So now if I go back into this and hit and close this down and run it, of course our ball is gone because we've created a new instance. If are you I But let me clone one of these files and rename it just fear dot m a and my you is still open. And if I had refresh, you can see that it's correctly loaded this fear back in. And this is because it's reloading all off the logic changes that we made in our original controller library module. This is a very common problem that many developers phase when they're updating code in one model and they find the python is in reloading and properly. We shouldn't distribute our code with the reload intact, but, like I said before is very useful while developing. So now that we have the refresh button working, let's set up the import button. So in Are you I Let's go back to the build you I method and find our import button. After recreate the import button, let's say import button dark clicked and again remove the prince sees, and we'll connect it to a method we haven't created yet. And this will be self God. Load Millette, scroll down to the bottom of for cloths and add a new method, and we'll call this load with this method will be loading all of the controllers that we have selected. First, we need to get the current selection from our list. Who will say current item is equal to self. The list widget dot current item. This will give us the current selected item in our list rigid. Of course, it's also possible that nothing is selected, so we need to safeguard against that. So we'll say, if not current item return, because we don't need to do anything. At that point from this item, we can get the text so we'll say name is equal to current item doc text. And because you've already defined the load method in our library, we can say self the library load and give it the name to load If you go back to Maya and let me close my you I and split my view if I now open my you, I and I hit the import, but nothing happens. But if I select any of these objects, let's choose the tourists and hit import. You can see that it's imported, are tourists and of a hit platonic, and your examples will obviously be different depending on what you saved and hit import will import platonic. Let's close this you I and continue on to defining the functionality of to save button. So let's go back to pie charm, and we need to hook up the save button to save. So just like we've hooked up the clicked signal to these slots, which are just methods, we can do the same for the save button. So in the build you I let's find the save button well connected to a method that we have to create. First, let's connected so well. Say save bucking dot click dot Connect and we'll say self dot save and we'll go down and we'll at the very bottom. We'll create a new method called Save so we'll say deaf save. And now we need to get the name to save it as from our text field. So just like we did for the card item, you can get the text from the text field. It's a real say name is equal to itself. Don't save name Field because we designed it to ourselves as a variable doc text. And now I'm just gonna print out the name every time this runs. So I'm gonna say print, name, comma and then the name variable. So if I go back to Maya and I runner you, I every time I hit save, you can see that it's printing out the word name and then an empty string. And if I enter something in this text field, let's say hello world and I hit Save. You can see that it's saying the name is Hello world. We want to make sure that someone always enters the name. But the problem is in python. While an empty string is false, a string that has multiple spaces is true. So what we need to do is strip the string off any of his white space. We're just means any empty spaces, so we're going to say, if not name, Death Strip. That means that if, after stripping the name, the name doesn't exist, real issue a warning. So I'm going to say Camiones no warning and I'll say you must give a name and you can see the pie. Charm is complaining that there is no commands module. If you click on commands and you'll see the squiggly lines and hit all to enter, it will give you the option to import Meyer dot commands. So you say import meyer dot commands. If you go back all the way up, you can see that pie terms added our import for us, and it says from Maya import commands. If you're not using pi time, you could just do this manually, and it's exactly the same. So back down in our save method We've issued this warning and we'll return. But if we do have a name, we now need to save it down. We can use a save method in our library. So we'll say Self done library, Doc Save and we'll give it the name that we just got after that. We need to refresh our view instead of doing anything fancy. We can just call this populate method that we already defined so mercy itself duck populate and then lost. Lee, I want to make sure that we reset the text to nothing. So I must say itself dot save name, field dot set text. And I'm just gonna put an empty string in there by putting two quotation marks if you go back to my and try this act. So let's delete this open, Are you? I and I'm gonna put a bunch of spaces first to test that it can catch when we have just empty spaces. So if I put a bunch of spaces and hit safe, you can see it gives us a warning. You must give a name so we know that's working properly. If I now create a primitive were created tourists and they were named this big Taurus. And after doing that, it's added the big tourists into Are you I? If I delete this and now select the big tourists and hit import, you can see that it works just as expected. We're missing a couple things that my demo you I had. When I hover over any of these, I expect to see some information about each of them. But we're not getting that. So let's add that on. Let's also a documentation so we know what we did when you come back to it. So let's go back to our populate method down here. We need to have a tool tip to each item that we add So in here, after creating the screen shopped, let's say item dot set tool tip. And remember to do this in the for loop because we have to do it for each single item that we create. And in the set tool tip. Just write p print that p format, and we're just going to give it the entire information that we have again. You'll see that we haven't imported people. So if I click it and hit all enter, I can tell Papa Charm to install. I can tell pie charm to import p print. Or if you don't want to do that, you can import people into yourself and then recalling the P format, which is a pretty format function and just like P printing, will pretty print out everything peform at just four maths a text in a pretty way. So if we now go back to Maya and run, are you I Whenever I hover over any of these, you can see that it will display any of the info that's been saved in our Jason files. That's pretty much it for you, I. But we still need to add some documentation so that when we come back to are you I it's easy to pick up where we left off. First, let's add some documentation to our class. Let's that the triple quotes and say the controller library You I is a dialogue. The lets us save an import Controllers, you know, or in it method is fairly simple, but I'm gonna just add a little comment here. The library variable points to an instance off our controller library, and then I'm gonna add another comment before rebuilt. saying, Every time we create a new instance, we will automatically build. Are you I and populated our build you I met It is pretty simple. So we'll just had a simple doctoring again that says, this method bills out the you I. And then let's just add some comments that you go through above Lee out. I'm going to say this is the monster Lay up above save widget. I'll say, This is the child horizontal widget. The next two widgets, the name field in the save button are pretty self explanatory before a list rigid does a lot of things were doing. So let's say these are the parameters for our thumbnail size. And before we create the list rigid, let's add another comment saying this will create ah grid list widget to display our controller come nails and finally, before the button widget, add one more comment. That's Ah, this is our child, which it that holes all the buttons for populate. Let's add to Doc's Ring and we'll say this clears the list widget and then re populates it with contents off our library and for a load and save, we lead a few more docks rings. We'll say this loads the currently selected the currently selected controller and for Save you'll say the Save the controller with the given file name finally for show you I I'm just gonna say the shows and returns a handle to the u I. And under returns, I'm just going to say que dialogue so that everyone knows that we're returning acute dialogue. And with that we created an easily maintainable and extensible you I that could be used to interact with a controller library logic. Our controller library can be used independently or for you, I So if other code wants to use it, it's free to do so. But we also provide a you I so that our artists so that either you or any other artists can easily load and save any of these controllers. 57. Project 6: The Light Manager: in this project, we learned to create a light manager to manage the lights and are seen. We'll learn how to combine it with my A you elements so that we can dock and undock it from the Maya you. I Additionally, we'll be able to control. Additionally, we'll learn how to enable and disable our lights from the U I. Solo them, delete them and we'll also hook it up to control the intensity of the light as well as the color off the lights. In this project, we learned to use Pi Mel as an object oriented alternative to the Maya Commands library. We learned some slightly more advanced python functionality, like anonymous functions, using Partial and Lambda, as well as using the logger library inside of Python. We'll also learn to use parts of the open Maya, a p I to interact between are cute you elements and our Maya commands you elements. This will be slightly more advanced than our previous projects, but I'll break it down at every step so that it's still easy to follow. Along with that, let's get started 58. PyMel: An Alternate API in Maya: this project will serve as an introduction to pie mail. Pi Mill is an alternate AP I inside of Maya, originally designed by Loom a pitcher's rather than using the commands a P I, which was designed for Mel or the Open Maya, A P I, which was designed for C plus plus pi. Mel was designed as a library for Python. Specifically, it does this by wrapping both the commands a P I and the Open Meyer FBI under the hood to give us a new A p I that says, easy to use as a commands library. But with all the power off the open, my p I. So in Maya, I'm going to import the primal a p I. I'll be creating cube, the same as we would in the commands a p I, and I'll sign it to acute variable. But now, if I check with the cute variable is equal to you can see that it gives us the transform node and the Poly Cube node. But instead of being a string, it's actually giving us a pie node. This is an object type within primal. So in the commands, Lavery, if I wanted to rename something I would do. Commands are rename, and I would give it the transform. In this case, I would say Cube zero, because Cuba is a list off both the transform and the shape and I would give it the other name that I want and this is all right, but it means that we're losing a link toe Water Cube object has now called unless restore it ourselves. Instead, what primal lets us do is simply called the rename method on the object directly so we can say Cube zero our rename and I'll call it Fu. And now when I run this, you can see that my object is directly renamed Fu. This is because primal, unlike the commands, Lavery does not give us back just strings as names for the objects. It gives us back a python object, which has a link to the actual object in the Miocene. This is similar to how the open Meyer FBI does it, and indeed, primal is using open my under the hood. But instead of having to use several calls like we would in C plus plus, we can use a simplified call like we would using the commands library. Therefore, we get the best of both worlds the power off the open, my FBI but the ease of use of the commands. Lavery. So why haven't we been using Pi Mel from the beginning? Well, there are several reasons. The first is that many Maya tools are written with the commands a p I. If we're very likely to run into tools written directly with the commands a p I instead and it's in your best interest to know it. The second reason is a pie Melis, significantly slower in some cases, then both the commands library and the open my a p I creating and passing around these pine owed objects instead of using strings is much heavier. So when you're iterating over large data sets, scripts will run much slower. Primal is also not directly supported by Autodesk. As it is, 1/3 party library there does come shipped with all my aversions. Lastly, because pie millis so complex under the hood, it can actually introduce instability. Jeremiah, this is rare, but certain studios will not allow you to use pi mail. This is why I focus from teaching you the commands. A p I first, but it is also very useful and important to know primal. It can cut down your code significantly and make it much easier to read. And as a result of using actual python objects instead of strings, it can also cut down on bugs in your code. Significantly, there's documentation for pie mail online hosted on the Autodesk website. We'll give you an introduction off why Pie Mill was created. Some examples where pie mill is better than the commands a p I, as well as giving you documentation on every single object and function inside of the pie Male library. I'll have a link to this documentation in my get hungry pope so that it's easy for you to find does it for this introduction to Pie Mill. Now let's get a hands dirty by diving into actual code. 59. Starting the Interface and Partials: in pie charm. Let's create our python file right click or new scripts rectory saying New and say Python file and we'll call this the lighting manager. We know we're going to create a cute groupie, so let's import the cute libraries. So we'll say from cute import. Cute widgets, cute core and cute. Gooey. If you're not using the cute abstraction layer, you should watch the previous video teaching us how to import directly from your other libraries. Next, we know that we'll be using Primal so we'll say Import Pie Mill Dark core as PM time. Eldad core, like its name suggests, includes all the Pie Mela core functions. Now we can start by creating a lighting manager. You I So I'm gonna say Kloss like manager. And just like we did earlier, it's going to be a queue dialogue. We'll create the innit method again. This is deaf. Underscore. Underscore in it. Underscore underscore. When you hit the brackets, ill add self automatically. And just like we did in the previous video, we'll call it a super function. Give it the light manager, as as the clause to find the super off give itself and then called in it. This will call the innit method on the super close. Off the like manager in this case is Q dialogue without our the way. Let's create a show. You I function outside of the class so deaf show you I and over here we will see you as you call to like manager with currencies to indicate recreating a new instance. You I ducked show and Richard Unreal returned the You I now back in Maya. Let's import a light manager so we'll say Import lighting manager, because that is our module name. Well, reload this so that we're always picking up the latest changes to the code. And then we'll say you I because we need to store it in a variable is equal to lighting. Manager does show you I and if we run this, you can see that it's created. Are you I for us now back in Pike Charm. Let's set up. Are you I So I'm now going to set the window title someone say self not set window title. I'm going to call this the lighting manager. I'm going to create a new method called Build You. I and I'm going to call this inside of the unit by saying self not build you I inside here , I'm going to create a new layout type I missed. A lay up is equal to cute widgets, Doc, You Gridley A. I'm going to tell it to apply it to self, which is the which is the dialog we're just creating. Now you've been introduced for the view box layout and H box layout which had the vertical and horizontal layouts respectively. So far, we've been creating horizontal and vertical layouts and nesting them inside each other. So far, we've been creating horizontal and vertical layouts within the within each other to lay out . Are you elements as we want? The Q Gridley out is a slightly more advanced layout that lets us specify the X and Y position off the elements. Everyone, a place. This means that we don't have to create several layouts and can have one lay out the positions. Everything. Next. Let's create a combo box where we can put in the light types who want to create. So we'll say self done. Light type CB, where CB is short for combo box is just a shorthand. I like to use, and I'm gonna say cute widgets, doc. You combo box. Next, we'll add it to the layout. The same we redid earlier on missile layout that add widget. I'm gonna say self dot light type CB, but this time we have to give to other arguments. We have to give the X and Y position where we want this to be put in. So since this is the first widget, it can simply be at 00 Next, let's create a button to create our light somewhere. Say, create button, which is the name of her button is equal to cute widgets, Doc, you push button. And in the princes, I'm gonna put a string that says Create again allowed it to the layup. I'll see Leo that add widget, create button. But this time I'm gonna add it at 01 This says that we're gonna add it as rose zero and call him one. Now, back in Maya, if you run our code, you can see that we get a window. Where we have the window title is lighting manager, a drop down and a create button back in pie charm. Let's populate this combo box. So that has light options that we can select from. But since these light options won't change every time we run this close, let's store it up here as a cloth variable. I'm gonna call this light types, and it's going to be the dictionary. The keys will be a name that will appear in the drop down. So first I'll have the point light, and the value will be the function that we use to create the light. This is because each light has a different function, and we need to store it according to the light name. So for this, I'm going to say, PM dot point light we're not gonna execute it with the prince sees. Instead, we'll just give it the direct function. To call in this case will be the pie malfunction called Point Light. Our next light. It's a spotlight, and the function for this one a spotlight again, no prince sees. We just need to give it the actual function. Next, we'll have the directional light, and we're going to call the directional light function from Primal. Let's have two more light types. I'm gonna call it the area light, but here's something interesting if you go back to Maya and let's in Mel called the Area light function, you can see that there is no function for area light. This is because if I go into Maya and I say create light area light, you can see that it calls the function default area light. We don't actually want to call that function. We want to figure out how to create an area light. This is the function in Mel to find where it is in my Mel tab. I can type what is and I'll give a default area light. I'm gonna run this. Well, tell me what the function lives. If I source this code into here by going to file load script and I give it the script I want you can see that it loads this giant code in here. Ideally, I'd opened this in a text editor. That's easier for me to show you here and right away we can see the default area light function with a bunch of values. But this is a part we're interested in. String. Light name is equal to shading node as light area light. We need to execute this shading node as light area light. So let me delete all the code here and just write that out. So for now, run this. You can see that it's created an area light. Unfortunately, re conscious give the function inside of my dictionary because we also need to give it these arguments. This is where we use a library called Partial So back in pie charm. Add a new import so we'll say from funk tools. Import partial another. We've imported partial for area light. Let's have the key partial and give parentheses and inside here let's say we want to call the shading node function again. No parentheses. We just need to give it the function and then we can give it the arguments that we want so we can say, Well, we can say area light. This is the type of life we want to create, and then you want to say, as light equals True. Now what does partial do? Partial lets us create an object that will tell us which function to call later, as well as what arguments to give it because we can't just give the function name since we need these two arguments will be using partial to let a store. Both the arguments and the function name together to be called later. Similarly, if you want to create a volume light, we have to create another partial. So we say partial Well, say PM does shading note, because it's the same call again. No parentheses. This time the argument will be a volume light, and the keyword argument as light will be true again. Next, go back down to where we created the light type CB and on the next line, say four. And then we're going to go through each of the light types we just defined. We'll say light type in self dot light types. Self delight type CB dot add item light type. This is similar to how we added items to the list. Widget were simply adding items based on the name of the light into our light type CB. If you go back to my A and then run this in my python tab, you can see that we now have all the light types, but you can also see something interesting. The light types aren't ordered like we'd expect. Point light is followed by volume light, and they're on complete opposite ends off our dictionary. This is because dictionaries aren't ordered. We could use an order dictionary type, but instead let's just sort it alphabetically. So in our loop, instead of saying for light, type in self down like types will say four light type in sorted. And then let's open the prince sees. And then on the other side of self done light types, let's close. The prince sees so what we're doing. It's where sorting all the keys off like types and then iterating through it. So if you go back to Maya and run this, you should see Ariel itis first, followed by directional, and will continue on alphabetically. Next, let's hook up the create button so that they actually called these functions. I'm going to create a new function called Create Light, and inside this, we first need to get the light type that's currently selected. Who will say life type is equal to self. The light type CB, and we'll get the current text from the drop down. This will be the light type that we need next. I need to get the function from our dictionary. Remember that the functions are the values and the light type is our key. So I'm going to say funk short for function is equal to self. Don't like types and then all your square brackets, and they'll give it the light type the green trusted in Next. We'll run this funk by using currencies, and we will store this in a variable collect and we'll say light is equal to funk. Now that we created this function, let's hook up the create button to call it so back up here where you define the create button, let's say create button got clicked dot connect and well connected to self create light without any prince sees, because we don't want executed right away on Lee when clicked happens. So let's go back to Maya and run our code. And now, when I create the now and I hit the create button, you can see that it's added a new area light. If I create a new directional light, you can see that is calling the right function 60. Custom Widgets and Lambdas: I will not create a custom widget to interact with our lights. Let's create a new clause above to show you. I met it and we'll call this the light widget and, like its name, suggests, we're gonna inherit from the cute widgets key widget Again, let's define the underscoring to score in it method and inside the innit method. Let's call super to the light widget you'll give itself, and we'll call the super's innit method as well. Now we also need to be able to accept a light so that we know which light to create this widget for so in the unit, we can add other arguments. I'm gonna add light as an argument, but I don't always know if the light I get will be in the name of the light or the actual light object from Primal. So let's have a check over here just to be sure. I'm going to say, if is instance the like variable that we received off type based ring, which means it could be of any string type real, then convert the light to a pie. Male notes will say light is equal to PM docked. Pine owed. Sorry PM Dark pine owed off the light. Then let's store. This is variable. So it's a self total light is equal to light. And then let's called a build you I method I'm going to define the build you I method just like we've just done. I'm going to create a grid layout again. So I'm gonna say layout is equal to cute widgets, doc. You Gridley at when applied to self. Well, now create a check box so that we can toggle on and off the lights. I'm gonna call itself. Dot Name is equal to cute widgets. Doc, you check box with a capital C and a Capital B inside here. I need to give it the name. Now, if I just give it the light that regard it won't automatically convert to a name. Instead, we need to call the string function on it and give itself down light. Self done light might actually equal the shape, but not the transform. And we want to actually get the transform node So we'll say self did light don't get transform. And already you can see how useful pie Mel is. Whereas in the commands a p i you would have to use the list relatives function, give it our light and then traverse the results with primal weaken. Simply disk all the get transform method on it to get the transform node. I don't want to set the default state of this check box. Someone say Self got name dot set checked and we're going to set it based on the current visibility status of the light. So let's say self dot light visibility. We want to get the visibility attributes and then we simply call dot Get. This is the same as using commands. Don't get at er Self Bud Light done visibility, but it's much simpler to use and much shorter. Next, let's add it to our you I So we'll say layout that add widget name. Sorry, self got name and we'll add it at Rose zero column zero. So if you go back to Maya and run this again, you'll see that nothing has happened. This is because we aren't actually drawing, are you? I yet, So let's go back to our lighting manager and let's create an area for Are you elements to exist? I want to create a central area where we can add all the light widgets that we need I wanted so that we can scroll through it if there are too many to fit on the screen. So that means we'll be creating a new scroll widget. So let's go back up to our like manager close and under build you I Let's create a new widget. We're going to call this a scroll widget. So we'll say scroll widget is equal to cute. Rigid. The key widget. We're not going to create its layout. We're going to say software Skrill layout is equal to cute widgets, Doc, you ve box because we want to lay them out vertically scroll, and we're gonna sign it to the scroll widget. Now, I've already said we wouldn't be nesting layout, but sometimes it's the best option. So we're going to nest this Q V Boxley out inside of a scroll area and then at that school area to our Gridley out. So now let's create the school area. So we're going to say scroll area is equal to cute widgets dot que scroll area. I want the scroll area to be re sizable. So if you re add more items or should remove them ill size accordingly. So we'll say scroll area that set rigid, re sizable, and we'll set it to true. Next, we need to tell the scroll area what Richard to use will say scroll area that set widget and it will tell it to use the scroll widget. Finally, let's add this to our layer to will. Still, they act dot add widget scroll area and then we'll add it at Row one column zero and then we can give to extra parameters. We can tell it how many rows to take. So we wanted to take exactly one row, but you can see that we've already added two items up here on two separate columns. So I want this to be the same width as both of them. So adding it to Row one, which is the second row at column zero, which is the first column. We're telling it to take one row, and we're telling it to take two columns. Finally, in the create light method, let's add a light rigid to represent our light to the scroll area. So we'll say widget is equal to, and we're going to create a new light widget to the light widget real pasta light that we just created. And then we'll say self, not scroll layout that add widget, and we'll add the widget we just created. So if you go back to Maya and now run this and if I now create a directional late, you can see that we added a check box. It wouldn't do anything. But as we add more items, you can see that a school area expands to fit all the lights that we create. If we add more lights than are sterile, area can fit. We get in a light, nice little scroll bar, but as you can see, the check boxes don't actually do anything. So let's go back and hook up our check boxes. So let's go back to Pie Charm and go down to our light widget. Let's hook up ourself done name check box so that it toggles on and off the light accordingly. So after we've set the default value of Self dot name, using the subject method, add a new lying. So say self name Doc Toggled so that whenever it's toggled, it will emit a city aerial, emit a signal and will connect this. But instead of creating a new function to connect us to, let's borrow the concept of partial. We know we just need to change one single value, and I feel like we don't need to create a function just for that. But partial only takes pre defined values to set over here. We want to get the value of the check box and set it as a value off our visibility. So, like I just said, partial only lets us that pre defined values so it won't update on the fly. But that's the behavior we need. So instead of partial, we can use something called Lambda. So let's say Lambda and Lamb does can take inputs. So we're going to save Al for short for value and we'll say self dot light stop visibility dot set fell and this could be a little confusing, but let's go over. What a Lambda is so similar to partial Lambda is let us call functions at a later time. Additionally, Lambda Iskan take inputs when they're called, and they can run logic as well. In this case, every time self dot name. Our check boxes toggled when it emits a signal. It also tells it what value it's been set to either true or false. So our Lambda can accept that value. It didn't take the value and then can use it as a variable inside itself. This is the same as if I defined a new function call set, light, visibility and it took a value. And then I said, Self, don't light visibility dot set now. But instead of having to define a full function, we can just use lambda, which is way of creating anonymous function. I eat a function that we won't be using more than just this one time, and therefore it doesn't either name because we won't be calling it more than this once. So let me just get rid of this demo. So now back in Maya, let me create a new directional light. Someone said, Create, let's scale it up. And I want to show you something. When I talk all this check box on and off, you can see that the light disappears here, but the visibility in the channel box doesn't change right away. So let's go back to pay trim and I'll explain. This is because self floodlight on Lee refers to the actual shape node, so our shape note is having its visibility toggled. But our transform isn't and that's what we actually need to toggle. So just like we did above here, we'll use to get transform method So we'll say self done like Don't get transform and we'll change the visibility off to transform. So back in Mayer if I now run my you I and I created directional light. Let me scale it up. And if I now toggle it on and off, you can now see that in the channel box the light is turning on and off its well, as well as in the View port before we continue on to our next video. I also want to highlight one of the change that we can make. So let's say I create a Let's say I create 100 lights, you can see there are scroll area works properly and everything is hunky Doory. But if I only have a couple lights, our school area works. When are you? I a small But when are you wise? Large? Everything is stretching. I don't want all this empty space between our lights. It kind of looks ugly to me. So let's go back into pie charm and fix this up. You need to affect our scroll widget. Segovia, like manager, close on, goto it down to the build you I method and find where you define scroll widget after you creates girl widget. We need to tell it how to behave when it's resized. So we're going to say scroll widget docked set size policy and in parentheses. We're going to give it to parameters both foots vertical and horizontal. And we're going to tell it that it should only take the maximum size that is required if it and nothing more to will say cute widgets, Doc. You size policy lips que sais policy dot maximum. Now, when I create many lights, you can see that the stroll still works. But now when I drag a bigger, they all stay just the maximum size that is required of them. And don't stretch down all the way to the bottom. In my opinion, this looks much better in the next video. We'll continue it flushing out this light widget 61. Adding Visibility and Intensity to our Widget: I will now continue flushing out the light widget that we just created. So let's go back down to light, which it and Goto's build you. I met ID. We've just created the check box, but now we need to create some other buttons. We now need to create a button that will let us solo the light so that we can disable all of their lights and just leave ours active. So I'm going to create a button. I'll say Solo button is equal to cute widgets dot que push button and in Prince sees, I'll tell it to have solo as its text. We want this button to have a state. That means that the button could be pressed and depressed. A swell. So we will say solo button dot set checkable. It's true. Next, just like we did with the check box. We'll tell it to emit a signal. So just like we did with our check box, any time a button is pressed, I want to do something. What I want to do is I want to go and check what other light widgets exist. And for each of the light Brigid's, I want to disable all the other light except for this one. Unfortunately, our light widget cloths doesn't know anything about the other light widgets. It's self contained, but what we can dio is that a signal to our light widget that would tell our like manager to do what we want Cute lets you define your own signals. Cute lets you define your own signals, so you're not just limited to the ones that come out of the box. First, we need to import the signal. Kloss. So let's create our new signal. If you go up here, weaken type under the Kloss and before the unit, we just type solo. We'll create a new signal call on solo, and it'll just be a new instance of Q t core, not signal. That's important to mention that if you're using pi cute, it won't be called signal. It will actually be call pie. Cute signal. But since our course will most likely be using PI, side will use cute core that signal. If you look at the code on the guitar repo, you can actually see how import from either pie cute and pie side and use them interchangeably. So now that we defined the on solar signal. And remember that has to be defined outside of any methods. But within the cloths, let's go down and told Solo button to admit this. Whenever it's clicked, the solo button will behave very similarly to the name check box. So we'll say Solo button, doc, toggled dot connect. And again, I'll just use the Lambda. So I'll say Lambda and a Lambda will take the value off whether the bucking is checked or not. And real type of colon and you'll say self not on solo, not emit. But if we emit just on solo, all we know is that this has been soloed. We don't know what stated it then. So if you go up to where we define the on solo signal, we have to tell it, water will emit. We need to tell it there will emit a bullion. So where you've defined on solo just but bull within the prince sees when you define the signal. Now back down here for solo button will say self taught on solo dot emit and inside that will tell it to just repeat Val. So any time the soul about Miss toggled aerial trigger Lambda that will emit the on solar signal using the value that the Lambda got. Next. Let's add destroy layout will say layout got add widget. We'll say a solo button, and we want to add it to the same row, which is row zero. Well, I added to the, But we want to add it to the next column, which is one so back in Maya. Let's run this and you'll see when you create a new light, you'll see this in New York. Solo button and l stay clicked whenever re click it. No, let's hook this up inside a far like manager. So let's go up to the create like method where we add the light widget. Well, we need to do is hook up the light widget on solo signal to trigger a solo function. First, let's move this to a new function so that we can call it without having to call a create light. So I'm simply just gonna hit enter twice and then create a new function will add light and it'll take two parameters self and light. And in the create light method, I'm going to say self dot add light and pasta like down. So in create light, we're now it is calling the ad light method, which then creates a widget and adds it to the scroll layout, just like we were doing earlier. Let's had another line here we can say so we can say widget dot on solo dot connect, just like we connected every other signal and we'll connect it to self dot on solo, which will be a new method that will need to create. So we'll create a new method now called Death on Solo and I'll take a value. So inside this, our logic needs to be the following. We need to find all the light widgets that we have, and then we need to check if the light widget is the one that needs to be so load. But if it isn't, then we need to disable it. So first, let's get all the light widgets. So in pie charm, inside the on solar method create new variable light widgets is equal to, and then we'll call acute function called self docked. Find Children and we will tell it to find Children off type light widget. So let's print like widgets and go back to my A and run this. Do we run this? You can and let's create a light And let's create a couple. Actually, when I hit solo and we'll print out all the light widgets and you can see that the three of them that are part of the lighting manager so we can see there are Solo Button is admitting our custom on solo signal, and we can see that we've hooked it up to the on solo method Insider for lighting manager. This is how we make widgets within cute talk to each other, including widgets that we define. So next let's go through all of the light. Bridget's, who will say for widget in light widgets and cute lets us do something nice. It lets us know who is emitting the signal. We can check this by saying, if rigid is not equal and this is done by using the exclamation mark, followed by the equal sign to equal to self dot sender. And we're saying that if this widget in this loop isn't equal to the sender, then we will turn it off. So I will say widget, don't disable, liked and we'll give it the value that we received. Now, if you were to run this right now, we can see that the widget doesn't have a disabled light method. So let's add it. So down here, let's create a new method, and we'll call it disabled light. This will be inside our light, rigid and all we need to do in here. It's a self. The name, which is our check box that set checked is equal to value, and obviously, disabled light needs to take a value, but this will be backwards when we tell it to disable light and give it a value. We want to make sure that it's doing the opposite of what the value says. So instead of saying self done named Offset checked value and said, we can say not value, this means that it will be the opposite off whatever value is. Now, let's go back to Maya and run, are you? I I'm going to create a few lights, and when I hit solo on any one of them, you can see that all the other lights turn off, and if I hit solo again, they'll turn on. Therefore, we can see how easy it is to contract in many cute objects from our single light widget. Let's continue on and define mawr parameters for a light widget. So now back in pie charm, let's go to your light widget and to its build you I method and add the delete button. So we'll create a new thing called Delete Button and we'll create a new widget, Cute widgets, Doc. You push button and we're just gonna put an X to represent elite because delete is kind of a long word. So we're going to say, Delete button, not clicked that and we're going to connect it to a new method goal. Self delete Light Well defined this in a bit, but let's just add our button first, we'll say delete dot set maximum with to 10. And this is because I want her button to be as small as possible. And I only wanted to be 10 units wide. Finally, let's add it to our you are So we'll see Layout. Don't add widget, and we're gonna add the delete button. Oh yeah, and we're going to add it to rose zero. But call him, too. So it's right after our solo button Oops. I forgot to add button to this delete usage here and next. Let's just define the delete light method. So let's create a new method. Delete light sell and it just takes selfies. This only parameter, and we need to tell it to first remove this widget from the U I so that if the light is deleted than it has no place in the U I. This takes a couple steps. First, we need to remove it from the parents. So you say Self dosek parent is none. Then we need to tell it to hide itself. So we say itself does set visible false. This is because you enough to remove it from the parent. It may just hang around for a while. This is still python or cute. Decide that it's no longer necessary, but that could be a little while later. Finally, we'll tell cute to delete it later. So we'll say self delete later, which tells cute that we no longer need this and to delete it as soon as I can. But again, that might be later, as a function name suggests. Finally, once we've hit in the u I, we need to actually delete the light, so we'll say p m dot delete and we'll give itself done light. Don't get transform because again, we need to delete the transform and not the shape. So if you go back to Maya and run this and I'll create an area light, you can see recreate area like five. And if I had X, you can see that it gets deleted from the scene. And from Are you I? So just to recap, this method first would remove it from the like manager by setting our parent to none. It couldn't still hang around for a bit. So we set its visibility to false and finally rid elite later to tell a q T to delete it later when possible. Theoretically, you could just run the single call, and both of these should happen. But sometimes python and cute can conflict and will keep it around, so I find it's best to run all three of these together. Next, let's add a little slider to control the intensity off our light. So I'm gonna say in our build you I method after the delete button, I'll say intensity is equal to cute widgets, Doc you slider, and if we create this right now, it'll be vertical. But I wanted to be horizontal. So let's tell it to be horizontal. She will say Cute core doc. Cute horizontal. And this is just basically telling the Q slider that it needs to go left to right instead of top to bottom. We need to set its minimums, will say intensity dot set minimum and we'll set the minimum toe one. And then we'll set its maximum intensity. Not said maximum, and I'll set it to something like 1000. You can go higher if you like. Then let's set its value based on what the lights current intensity is. So we'll say intensity dot set value, self done light got intensity. No, don't get on this way. If we created from an existing light, it will automatically get the right value. Next. Let's hook it up so that it affects the intensity of the light as well. We'll say intensity value changed. This is a signal that is emitted whenever the value changes and we'll connect it to another lambda again. Our Lambda will take the value and will say self. Don't light dot intensity don't set and we'll give it the value. Now let's add it to the layouts. Will say layout. Add widget intensity. I wanted to be on the next row, which is Row one at column zero I want to take. I wanted to take one rule space, but two columns worth of space. If you go back to Maya and now run the U I. And let's create a new light and look at the intensity slider here. As I drag my slider up and down, it will automatically update the intensity of the light. 62. Adding Color to our Widget: Okay. Now let's add a color button to affect the color of our light to reel in the same method that we've been editing will say self, not color button, because we'll need to query this later is equal to cute widgets, Doc. You push button and it's not gonna have any text because it's just going to be a color. Next, we'll adjust the width and the height of this button by saying self dark color button that set maximum with, and I'll set it to 20 and I'll also affect the height by things that maximum height to 20. Next. Let's hook up this button to a method that will set the color of her light. So we'll say Self dot color button not clicked dot Connect self does set color. Then we need to add it to the layer. Will sell layout, got add widget, self dot, color button one, and to this is because I want added to row one that call him, too. Let's define the set color methods will say deaf set color, and I'll take no parameters. But before we do that, we want to set the buttons color itself. So right before we connect the color button to the secular method. Let's call another method, so we'll say itself dot set button color. And let's define this as well. So we'll say death set button color, and this is so we can change the button color first before we hook it up. It's not that important to do it in this order, but it's just something I like to make sure. So in our set button color method, we'll add a parameter for a color. We will stay color, but we don't need it to be a necessary color. So well said color is equal to none. Inside, it will say that if no color is given, so, if not color, then color is equal to self doubt. Light, dark color dot get so we'll be getting the color from the light itself instead of setting it to whatever value we want. Next, we need to make sure that we actually get a list of three values if it's more or less an that we won't be able to continue. So we need to assert this. So I'm going to write, assert Len Color is equal to three. Oh, and if it's not. I'll give an error that says you must provide a list off three colors. Now what's happening here, CERT, is a python keyword. They will see if this statement is true. If this statement is not true, then it will given error that we have defined. This is a good way to validate the inputs to your functions before you continue, the colors we get will be between zero and 1.0. This is because Maya reports colors as floats. Instead, we needed as integers from 0 to 255 because these are the color is acute expects. So I'm going to say our G B to get the colors that we want is equal to, and we're going to revisit list comprehension. So in these brackets, well, say see times 2 55 for C in color. So what we're doing is for each value and color, we'll be multiplying it by 255. And since there are three values and color weaken, just extract it into R G and B know that we have these values. Let's set the color on the button, so we're going to say self. What color button not set style sheet with two capital s is inside. Here. We'll be using something called Q SS, which is similar to something called CSS, which are style sheets used for the Web. For the most part, Q. SS and CSS are exactly the same, so you can use most Web design references to style your cute you guys so back in pie charm , said Self Start Call button dot set style sheet. In quote, we'll say background color background. Dash color colon is equal to R G V A. And put to print sees inside it will save percent deaths. Comma percent s comma percent s 1.0 and this is because we're going to use string substitution for it. So, outside our quotations put another percent and inside Prince sees put our kamajii com a B so that real replaces percent S is with R G and B. Next, let's define ah set color method, which is triggered whenever a button is clicked. Since I said color, we'll say light color look is equal to self got light, not color. Don't get again. We're just getting the color from the light. Next, let's open up the Maya color editor. So I'm gonna say color is equal to High Mill P m dot color editor, and we'll give it the current color values. So we'll say RGB value is equal to light color, which we just got. So what this will do is they'll open up a color editor and what our values we choose in there will be assigned to this variable color. So I'm gonna show you something really annoying in my and we'll learn how to work around it . So just after this, say, print color, let's go back in to Maya. Let's open. Are you I and create a light. And when I click on the color button, you'll see that the color editor opens up just gonna choose red and I'll had done, and you can see some values here. 1001 That's a value for red. But here's the annoying part. It's not a list of Al used Maya, for whatever reason, actually gives us back a string where each value is separated by a space. This is completely useless to us again. I can prove this by saying print color on the type of color. If I go back and run, are you? I again that had done. You can see that it's just a unique code string, and I don't know why am I a does this, but it's easy to work around. So let's Ah, remove our print statement and let's convert our color into RGB and a values solicit our kamajii comma B comma A is equal to, and we're going to use list comprehension again. So we'll say C for C in color dot split, and what this will do is it will split the string at every space so that we only get so we only get back the RGB and A values. And since there are four values, weaken just cost it straight into the RGB and a because you want to throw away A. Unfortunately, it will still be a string, so let's convert it to afloat somewhere safe float. So now this line should read our G B A is equal to in square rockets float, see, foresee and color dot split. Next, let's redefine the color variable to a list that re like so we'll sit. Color is equal to in parentheses. Our comma g comma be because we won't be using the A value you'll say self got light, dark color dot set and we'll give it the color that we just defined and we'll process to the button itself. Will say self does set button color and we will give it the color. So now if you go back into Maya and run this, let me open up the attribute editor so you can see the color change. Let's create a new light. When I click the button, you'll see we get the color wheel. Let me just pick something random and I'll hit done and you can see that the button has had his color set and you can the Maya you. I has also updated. There is a slight difference between the color here and the color in Maya's You I. It's due to Hamas you. I is color correcting the colors and cute you is not. We're not gonna worry about it for right now, but it's an easy fix to make later. If you're so inclined, if you click the button again, we can change it to any color. You can see their updates there, So now we have a fully functioning widget for each of her lights. We can affect the intensity. Weaken solo, just the one light weaken. Delete our lights and we can change the color off any of the lights that we want. But if we rerun, are you? I none. The lights show up, so let's fix that. Let's go back into pie chart. So let's go up to our like manager and inside our life managers in it find where you called build you. I, after that, called a new method called Self Dot populate, just like we did for our previous project. Let's define the populate method, and first we need to go ahead and clear out. Are you I So we need to go through every single child of refined and remove it. I'm going to use a wild do pure to show you some of cuties, other functionality. But it's not how I would recommend doing it. I would recommend using the mechanism used in the solo method to find all the light widgets and then remove them, but instead I'll show you how to do it inside A for wild group. So let's say while while self does krylia don't count, widget is equal to self. That's girl layout. Don't take at zero widget, and what was saying is a while. Self trust, girly Out can count its Children. Get the child at position zero to get us widget. And then we'll say, if rigid, because sometimes it can return none. If there is no widget, we'll say widget dot set visible, false and widget Delete. Later, you might be wondering why we're not doing set parent None. That's because the take at actually does the same thing. Next, let's go through and add the lights of refined to will say four light in PM dot LS and we'll say type and for type you can actually give a list of strings will say area like comma spotlight, comma point light, comma, directional light comma and volume light. And what this P m dot ls Will do is give us an object for each of these. If it can find it and will cost it to the light variable and you will say self, don't add light light. Now if you go back into Maya and run, are you? I you can see that it's automatically populated. Are you? I with each of the existing light. And if I delete them, you can see that they get deleted and I can interact with them. This is area light shape 10 which is this one right here. I can affect its intensity and this color. Finally, let's add a refresh button to our light manager so we can refresh. Are you I if we create lights without using the U I? So in our like manager, go down to the build you I method. And at the very end, if it after the school areas defined, create a new refresh button, so we'll take. Refresh button is equal to cute widgets, Doc. You push button and we'll give it the text. Refresh. We'll say Refresh button not clicked dot Connect and well connected to the populate method . Remove the prince sees because we don't want to call it right away. Only when it's triggered to know, let's add it to the layout will say layout that add widget refresh button. I want to add it to the next row, which is Roe, too, but I don't want to add it to the first column. Instead, I want to add it to the 2nd 1 so I'll say one. If I now go back to Maya and I run this, you can see that we have a refresh button, and when I click it, nothing really happens. Let me delete a few of the lights. So now we only have one light left, and when I hit refresh here you can see that it's removed all the widgets and then just added the one that's the and then just left, the one that's important for us. 63. Portable Code and Logging: well now look into how to make a like manager a doctoral widget inside of Maya. We'll have to import a few more libraries to be able to do this. Unfortunately, one of the functions we need to use lives in a different library, depending on which pie, cute pie side or pie side to binding were using. So let's go over how to make import statements that can work regardless of which Python library you're using for cute back in pie charm at the very top of her file. Let's add a few more imports. Let's import the cute library that we've been using. This is because acute library has a variable that lets me know which binding it's using under the hood. So we'll say if cute dot underscore Underscore binding underscore. Underscore is equal to pi side. Then we'll say from she broken import wrap. Instance she broken is a library for pie side that could works cute elements into pie side elements. Next, we'll say l if q t dot underscoring the score. Binding dot starts with pie cute. That is, if we're using either Piket for or Piket five, we'll say from sip import wrap instance, and Sip has rap instance as fully lower case as rap instance. So what we're doing is from sip, which Sylar to share broken. Let's pi cute in tracked with cute, we'll import rap instance, but as the same name as we would use from Pie Side, which is wrap instance with a capital I else well say from ship broken too Import wrap instance. And this is the case if we're using pi site to which is the default with Maya, 2017. Additionally, like I mentioned before, the cute core signal is different between pie cute and pie side. So let's imported up here to a common name so we can use it. Portable e we'll say, If cute, binding his by side. We'll say from cute core import signal if I can spell and in the lost one for pie site to will say from cute core import signal. But for a pie Cute, real safe from cute core import pie. Cute signal as signal. I'm just like we alias. Drop instance as the same one that we get from the two pi site. AP eyes. We're alias ing pie. Cute signal a signal so that it's the same for both the other libraries. Let's go down and replace our use of the cute core signal with this. So down here in your light widget close, we redefine on solo. Let's get rid of the word cute core and dot So they were just using the signal. Kloss. Additionally, I want to know which of these bindings amusing, and I wanted to log this. So let's import a logger. So at our in our import statements say, import logging, logging is a python library that lets us define many different outfits and many different levels. So in our code, we can have logging dot debug logging, not info. Logging not critical on these air, different levels of loggers by default. If we enable all these levels, they will simply print out whatever message we give them. But we can configure each level to behave differently and weaken, enable and disable each level as well. So, while we're developing weaken, set all the levels to be on, so we get all the information we need. But when we released our code for other people to use, we can disabled some of the lower logging levels so they only get the relevant information they need and aren't bothered by any of our developer information. Additionally, we can set up loggers to write errors to a file, so it's easy for us to access or even email it to us. Basically, it's like a print statement on steroids that we have full control over. So we've imported the logging module Lester a basic configuration off it by saying logging that basic config, the basic and fig sets it up so that any logging errors go to the standard error output and any other loggers just go to the standard output. This way we can monitor them separately. Next, let's go toe lager specifically for a lighting manager, so we'll say lager is equal to logging. Get lager and we'll give it a name in this case to say, Lighting manager. This is another very useful part of logging. We can control all the loggers in our python session from one place, but each of for libraries is free to have its own logger. That means I can enable Mawr logging levels for certain libraries that I'm using without affecting all of them. Now that we have our lager, let's set its default logging level. We'll set it to the lowest logging level so that everything we do is logged out. So we'll say lager dot set level and we'll give it logging debug. So we'll say that every kind of logar down till the debug lager will be logged out next, inside of for if statements. Let's say what we're using. So I'm going to say Lager, Doc debug and I'll say using pi side, she broken and I'll do the same for a pike. UT, I'll say logger debug, I'll say, using high cute with sip and then finally else a logger, the debug using hi side to which she broken. If we go back to my A and run this, I get an error. This is because I forgot to put an equal sign up here to make it a double equals. This is a very common error for people to make, but fortunately, pie charm warns us about it. And if I go back to my and I run this, we get another error, which says, No module name. Cute core. This is another common error. We've imported cute core in here, but cute core isn't a top level package. Cute is so instead, everywhere we mentioned cute core. Just put cute docked before it. So it's cute. Doctor. Cute core. All of us. Copy that and replace it for each of these. And now if you go back to Maya, it all runs and you can see a little message here it says Lighting Manager, which is the name of Far Longer. And it says you were using Pi side, too, with shit broken if I was using this in my A 2016 or using Pi cute five instead, it would give me one of these other two messages. Whenever I have released this code for other people to use, I can change the lager level to logging dot info. And now, if I go back to Maya and I run this, you can see that it doesn't print out any of those logging statements. I didn't have to change any of my code down here, and I just had to change it in one spot. For now, let's send it back to logging. No debug, but I hope that illustrates some of the usefulness of the logging module 64. MQtUtil: Combing Qt with Maya Controls: logging out of the way. Let's learn to convert Maya you elements into something that are python Cute libraries can understand. First, we need to import one of the open Maya AP eyes so that we can get access to Maya's. You I elements at the very top at another import statement and say from Maya import open. Maya, you I s o m u I So we don't have to type out open Maya, you I every time and weaken issues a short form next. After all these if statements, let's create a new function and we'll call it get Maya Main window will say death. Get Maya main window. It doesn't need any parameters. And we'll say win is equal to, um you i dot m cute util underscore main window. And this will give us back the memory address off the main window. We need to convert this to something R python libraries will understand. I will say PTR shortfall pointer is equal to wrap instance, and we'll use a function called Long, and we'll put wind inside it. This is so that we can convert the memory address into a long integer. Next, we'll tell it what we want to wrap it. As in this case, I want to rapid as cute widgets, Doc. You main window. Finally I'll return the pointer. But why do I actually need the Myo main window? Well, a simple. Instead of using this show you I mattered for everything. I can simply show inside of my claws directly. I don't need to manage this variable and hold onto it inside a Maya to keep my u Y alive with my you. I parented to Maya. Maya will maintain my you i for me. So let's get rid of the show. You I function and let's go up to our light manager. Let's add something will say Parent is equal to get Maya main window. Then for the super function will recall the in it inside the parentheses Put Parent is equal to parent back in Maya. Let's change our logic a bit. Let's get rid of this line Instead, we'll just a lighting manager light manager, really use the prince sees to create it and we'll say dot show notice. We don't need to store it in a variable, and when I run it, it will automatically just display and better yet, while I'm working with Maya, it's no longer disappearing under Mayer. This is because Maya itself can manage the C y for me, and it sees it as one of its own Children. Let's go back to Pie Charm now. I also want to make this DACA ble. Right now it's only a dialogue, but I want to attach it to a dock so that we can drag it in and out of tabs. So after a new function called Get My a Main Window, let's add a new function. We'll call it Death. Get Doc on the name and we'll give it a parameter for the name by default notice. Call it lighting manager Doc inside. Here. Let's create a new dock control. Well, say control is equal to PM now. Workspace control if you're using my A 2016 and below. This used to recall the Dock Control Jeremiah 2017 and above. It's been renamed to the workspace control, but the parameters are roughly the same. We'll say Name for the name of Fire Doc. Well, say Doc, two main window, because we want to dock it to the main window and we'll tell it to dock to the right on the perimeter. One. You can learn more about these parameters by looking up the documentation online, but for now, let's out a new LaBella's. Well, this will be the tab name, and we'll call it lighting manager. So let's go back to my A and call dysfunction. I'm gonna comment this out by adding a hash tag. Instead, I will say, Lighting manager, Don't get Doc. And when I run it, you can see that it's added a lighting manager, Doc there for me. I can drag this around and I can dock it back in. But if I run this again, you'll see that I get an error and it says there's already a lighting manager, Doc. Therefore, the name is not unique, so let's adjust our code for this. First, let's add a function called Delete Doc and call it before we call anything else. So we'll create a function called dilly Doc. So death delete Doc again. We'll take a name but will default to the lighting manager Doc inside. It will say, if pm our workspace control name and then we want to query this where equals true and exists equal True Well, said PM delete you I and we will tell it to delete this you I with this name. So now in our get doc before we do anything else, let's call the delete Doc function and give it the name Back in my Iife, we now run our code again. You can see that it's created the lighting manager, and if I run it once more, it deletes it and then recreates it. Let me close this and let's get rid for code in the script editor and uncommon where I'm showing the light manager. Let's go back to Maya and let's convert this to something that we can use for a light manager, just like we did with the getting my a main window, we can convert this control into a pointer. Synnex, Let's get the control So we'll say cute Control is equal to Om Yui the Open My are you? I well say m cute you till underscore find control and then we just give it the name. So we just say control and what this will give us back is the memory address off this control the same way this did and just like we did up here. We need to convert it to an instance. So we'll say Pointer is equal to wrap instance long because we need to convert it to a long give it the cute control. And then we just want to convert it to a regular widget to execute widgets que widget and we'll say Return, pointer. So now what I want to do instead of same that the parent is the Maya main window. I want to make this optional. So let's had a parameter tore like managers in it. Method. We'll add a parameter that says Doc equals True because he wanted to be docked by default instead of saying the parent is to get my A main window will create a new dialogue. So let's get rid of this line and instead say, If Doc, as in if we've been told to dark will say Parent is equal to get Doc else. If we've been told not to dock, let's first delete the doc this way. If her doc already exists, we won't have, are you? Why in two places next we'll create the dialog window that are lighting Manager will be inside, so we'll say Parent is equal to cute widgets. Que dialogue, and I'm gonna tell it that its parent needs to be the myo main window. So I'll say, Get Maya main window. So now when this dialog is created, it will be parented under the Miami and Window, and our lighting manager will be parented under this dialogue. We'll give it a name. We'll say Parent, not set object name is lighting manager. The object name that we give a widget is the same thing that Maya does when we tell it to name any of his controls. This means that Maya can always look up any of the controls we create because it knows its name. So we'll do the same because I'll make use of this later. Next, we'll set its window title so we'll say, Parent, a set window title and we'll call it lighting Manager finally relied a layout to it. So we'll say layout is equal to cute widgets, Doc. UV Boxley out because I want everything to be laid out vertically and I'll apply it to the parent. And next, we need to do a couple more changes First. If this window already exists, lighting manager. I want to delete it. So let's just use Maya to do that for us. Before we create the window. Let's put a little function call. Well, say PM. Don't delete you. I and we'll tell it to delete the lighting manager. This is the same way we deleted au I up here and we'll be deleting it down here because, like I said, when we name an object, all of Maya's commands can interact with it. They may not in tracked with it properly, but nevertheless they confined it. But we have a problem. If this doesn't exist, this will error. This line could only run if the lighting manager already exists. So this simple well put a try up here and after it will put an except. And if nothing happens, we'll say, logger debug no. Previous you I exist. Now what does this try? Except we're seeing Try to do this. And if there is an exception, which is another name for an error, then do this. So I think, try to delete it. If it doesn't there to delete or if you know, or if you encounter an error deleting it, then just let us know that no previous you I exists and continue on with the rest of us. Another thing we need to change is that are, like Manager is no longer dialogue since it will be a child off a dialogue or for Doc Stop top. Let's change the light manager from acute dialogue to a simple que widget. That means we can get rid of this call to self doubt set window title. But it also means we need to add it to whichever parent we created. So at the end of her in it, let's add it to Our parents will say self dot parent and we can query the parent by using the parent method on ourself and using The Prince sees to get it well, say softer parent currencies, and we can get our parents lay up by saying self taught parent or layout dot add widget and then we'll add ourselves to it. Next. We need to tell a parent to show the Maya doc automatically shows, but the Q dialogue will not automatically show, so we'll say if not Doc, parent not show. And now if you go back to Maya, let's get rid of the dot show because it's automatically being done. Now we run this. You can see that are lighting Manager is docked automatically. I can pull it out. I can drag it into any of these and they will behave properly or in my code. If I say Doc equals faults and now run it, it closes my doc and opens it up A simple dialogue. If I run this again, it closes my dialogue and reopens it again. 65. Try/Except: Handling Errors: for now going to talk about cashing exceptions in Python. We've seen that we can raise an error by saying Raise, exception and give it a message. And if I run this, you can see that we get an error that says This is an error With the exception we created, I can change this to a runtime exception, and similarly, it's now run time error so we can use us within our functions to raise appropriate errors. When we raise an error, our script stops immediately. So if I say print hello, raised exception and print goodbye and now run this the second it hits the Rays exception will stop. So it's printed. Hello, but it hasn't reached the print goodbye. And Pie Charm is smart enough to say that this code is unreachable because the exception is raised before it. Instead, what we can do is we can say, try to do something, and if a exception happens, then we'll say print. There was an error, and over here let me define a function called Do Something and all our function will do is raise an error, and before the try, let's say print hello and after the except blood. Say print goodbye and never run this. You can see that it says hello. And even though do something, error it out. It just prints that there was an error because our except is catching this error and it doesn't stop our code on. We can go on to say print goodbye. You can also catch different kinds of exceptions separately. It's like if I create a new try and I'm just going raise a run time error, I can say, except runtime error has e friend. We had a run time error except Sprint. We had another error, so none for on this you can see that it prints up. We had a run time error. But if I change the runtime error over here to, let's say an Iot error, it now says we had another ever since. Similar to an if statement was saying that if our exception is a runtime error, do this. But if it's not that kind of error, then just do this and we can add as many of these as we want. Let's get rid of this essay pry. I'll just raise a simple exception if we encounter an exception I'll say print. There was an exception, but we can also add another key word we can say else credit. There was no error, and it correctly says there was an exception. But if I get rid of this exception and I simply save print running my code, it will run. Whatever happens in the else statement, we're basically say, Try this. If there is an exception, then do this. Otherwise, do this and there's one loss keyword, weaken, say finally, and I can say we are done and you can see that we'd say We're running my code. There's no exception. So we print There was no error and then finally, it says We are done finally will run regardless of whether there is an error or not. So if I change this back to saying Raise, exception can now run it, you can see that it says there was an exception and we're done. This is a way to make sure that some code always runs. Regardless of what happens, it's important not to abuse the try an except statement. Some developers like to put all the code within a try and accept what this does is hide all the errors in our code, and it can make it so that we have bugs for years before anyone notices. It's important to be responsible when using the try and accept statements and to limit the amount of code that we run inside. It, they accept, also gives us back the exception. So if I change this now to accept exception as E. And if I print E, it won't give us back anything right now. But if I had a message to marry, exception and say this is an error when we print out E is printing up message off the exception, we can also raise this e and it will raise our error. No, Why would you want to do this? We've just tried to do this and we're trying to catch the failure. Well, sometimes we still want to let the error go up, but do something before that happens. In this case, I'm just going to say print loops and you can see that it prints are groups before it raises our error. This is the best behaviour because it lets us do something before our script stopped. But it's still reports all if I errors. We'll be making limited use of the try and accept statements, but it is still important to know because it is a common pattern inside a python. 66. Exporting Our Lights: I will now go over how saver liked down into a Jace on file on disk at the top of for a script. Let's import the Jason Library to real, say, import Jason. Next, let's go down to our like manager and let's create a new button. So go down to the build you I method. And before the refresh button, let's had a couple of new buttons. We'll add the save button and you'll say It's ah que push button so we'll say cute. Which it's dark. You push button. I'll use the word save. Let's add it to the layout, stealthily out to add widget. Save button. I want to add it to the second row, where a refresh button lives. I want to add it in the first position. Let's do the same for an import button, so I'll say import Button recalled. Cute widgets, Doc. You push button and I'll say, import until they are that Add widget import button and I'll add it to Row two and position one. But that's where a refresh button live, so let's move our refresh button over to call them to, but this is going to upset our layout I'll show you in a sec. Let's go back to Maya and see what happens. You can see that a refresh button lives in a column all by itself, and that's no what I want. I want. I want this to spend whole with. So let's go back and change that. Let's find where we added the school area and changed the lost 2 to 3 because we wanted to span three columns and I want our combo box to also spend two elements. So when we add ourself don't like type CB to the layout. Let's change it to take of one row and two columns, which means we'll have to move or create button to the second column. So now if you go back to Maya and run it, you can see that. Are you eyes back to looking good? Let's hook up the save button and the import button to functions. Let's create to function. Let's create two methods. Well, say, save lights and we'll put pause for now and then we'll add another method and we'll call it import lights and again I'll put pass because we will define it in a bit. Let's hook up to them to our bookings. So after redefined the save button, you'll say Save button, not clicked that connect self, not save lights again with no prince sees and for import button, I'll do the same. Also import button dot clicked. Start connect self dot Import lights again no prince sees. So now let's define our save lights method. Let's create a new dictionary and you'll call it properties and I'll just being and it'll just be an empty dictionary. Then we'll say four light widget in self. Don't find Children off type light widget. This is the same thing we did on on solo. We can say light is equal to light, which it because that is an accessible parameter on the light widget. And we can say transform is a culture like don't get transform. So now we'll add this to the property is dictionary will save properties str transform because we want to convert it to a string is equal to, and then we'll create another dictionary, and in this dictionary we'll just have a bunch of parameters to look up. So now we can add the properties that we want, so I'm gonna say translate and we look up to translate on the transforms will say Transform , translate, start, get and we'll do the same for the rotation will say a rotation and we will say transform. Got rotation so I don rotate, got, get let's print out our properties just to see if it's working and let's go back to Maya. Now if we run this and I hit save, we get a dictionary with rotation and the translation values back in pie charm. Let's get rid of the print statement and let's write out these properties somewhere. Let's figure out where to write these out to first before we add any more parameters. So we'll say directory is equal to Westra. Part. Don't join. I'm inside here. We'll give it to parameters. Will do pm dot internal var and we'll look up the user after and we will say true. Next, we'll give it the directory. Want to write it out, too? So we'll say, like manager, we can print out this directory and you can see the pie. Charm says the OS module is not imported, so let's go to the top and import us. Let's go back down to the save method and you can see that we're printing out the directory . Let's go back to Maya and run this to see if we're getting the right directory and you can see that it's in the like manager, just like earlier. We need to check if it exists, and if it doesn't, then we'll create it. We'll say, if not US stock policy that exists. Directory Oh, Esther M. Kader and we'll tell it the directory to create. Next. We'll need to know what file to save. Two. I'm gonna call this file the light file, and it's gonna be a Westrup pasta join directory, and I'm going to call it like file Jason. But this means that every time we write it out, we'll be rewriting over the same file. So let's give it a unique identifier. So let's say underscore and let's say percent s So now I'm going to say percent and I'm going to get the time, and I'm going to get the current time somewhere safe time dot str f time and put parentheses and you can see pie charms complaining because the time module is not imported . So if I click on it, go to this little red light bulb. I can say import this name and hit Enter until import time for me and inside the str f time I'm gonna put some parameters and what I'm gonna put in here It's percent m lower case followed by percent de lower case. And what this will do is give us the month as the integer and current day of the month as an integer We can see what this equals. If I say print light file can go back to my and run this and I hit Save, you can see that it's equal to light file 10 21 Jason because it is the 10th because it is the 21st of October. So let's write this out now. So I'll say with Open And then I'll tell her to open the light file w as f because we need to open in write mode and I'll say, Jason, Doug, dump properties into F and I'll tell it to in Dent by four spaces. So now if I open this and save this out, you can see that it's gonna error because the vectors we get back from Primal aren't directly convertible into something that Jason can understand. We'll put the queries inside of a list. And now when we run this and hit save, you can see that there are no errors. But we also don't know where it saved, too. So let's log that out for us again after we save it out. Let's just say logger dot info saving file, too, and I'll put Percent s again. Percent, and then I'll tell it the location. So now let's go back and run this and we got a logging message saying Saving file, too. This location. If I open this with my other text editor sublime, you can see that we get the rotation values and the translate values as well as the name of the light. So obviously we want to store a few more values because this alone isn't that useful. So we'll say light type, and we can simply use PM object type and give it the light. We also need to know the intensity so we'll say intensity and we'll say, liked dot intensity don't get finally we need to know the color so well, Sick color and again we'll just say light, dark color dog, Get so we If you go back to Maya and write this out, let me reload my you, I and hit Save it will save to the same location because we're only saving one file per day . You can change this if you like, but it makes it easy from you to just open up the same file. And no, you can see that we get the light type and the intensity and the color off the light. 67. Importing Our Lights: way. Next, we need to know how to open up these lights again. So we need to know which directory to look in for import lights. So let's extract this into its own function. Pie chart makes us easy. If we right click on it and go to re factor, we can say extract and we can say method. And I'm just gonna call this get directory and hit OK and you can see that it's made a get directory method for us and it assigns it to a variable, and all our code should just work, as is so for import lights I missed. A directory is equal to get. Directory is equal to self. Don't get directory. Next, we need to open a file dialog cell say file So it's a final name is equal to cute widget. Doc, you file dialog, Doc, get open file names dot Get open file name inside here Really need to tell it are its parent. So we'll say self. The next parameter is a window title, so we'll say ah, like browser. And after that we just tell it the directory. If you go back to Maya and now run this and I say Import, you can see that it opens up to the directory. They're expects Flood. And when I selected, it closes down. If I print out the file name Celtic Print file name and run this again and hit import and open, you can see it gives us a list of all the file names, in which case we just need the 1st 1 That's correct. So we can say with Open with open file name zero because we only need the first item in read only mode with our as F properties is equal to Jason Load. If and now if I print of properties, let's go back to my and try this out. Run my you I hit import and load this back in You can see we get a dictionary off all these values. I know what kind of light tohave the intensity, and I can now re create it. So let's go through all the lights that we just right back in. And I can say four liked info in properties dot items because we want to look through all the key value pairs. I can try and figure out what the like type is, but this is a little bit complicated because our light types don't automatically associate with the types in our dictionary. I'm gonna put a continue here for now so that nothing happens. So now I need to go through each of the dictionary items to see if they match the current light type. So we'll see for light type himself dot light types. And then we need to see which, like, types match up. So really a string substitution to check for this. So we'll say light type is equal to percent s light, and all we need is the first word off the like type in lower case. So real say light type, and I'll split it by the space. You'll take the first object using square brackets, and we'll convert it to lower case. And then we need to compare this to the light type off the light we're getting. So let's actually change your logic a bit. I'm gonna say, like type is equal to info. Don't get light type, but you see, we have this variable and it's getting redefined here and that's not good. So let's just rename these lt instead. So I'm gonna call these lt I copied this over and next we'll say If lt is equal to life type, then break because if we found it, there's no point going through all of them. So let's break out. Otherwise, let's continue. And then we can say else after the four loop, not inside it. And we'll say else if you haven't broken out of the four loop yet, we can say we can discontinue because we don't understand how to create this light. But let's also put a message. We'll say logger dot info cannot find a corresponding light type 4% s percent light. So this way, if it can't find a corresponding type, it will just skip it altogether. But if it can, the Newell said it for every one of the light types. You'll check of the light type matches, and if it does, it'll break out off the light. It'll break out of the loop before loops. Also have an else statement that says, If you do not break, then run this logic