﻿WEBVTT

00:00:00.120 --> 00:00:02.360
Hello and welcome to Scripting for Artists. My name is Sybren.

00:00:02.360 --> 00:00:05.080
 And in this episode, I will show you how to create

00:00:05.080 --> 00:00:06.080
your own operator.

00:00:07.000 --> 00:00:09.960
So far, we only created snippets of code, you can use them,

00:00:09.960 --> 00:00:12.720
but they're not the most user friendly.

00:00:12.720 --> 00:00:16.600
Many people have asked ways to create menus
and buttons and custom panels and stuff.

00:00:16.600 --> 00:00:20.240
In this episode, we will not look at that yet.

00:00:20.240 --> 00:00:22.840
But we will look at a necessary first Step, which is,

00:00:22.840 --> 00:00:23.960
creating your first operator.

00:00:26.240 --> 00:00:29.120
We will look at what an operator is exactly, then,

00:00:29.120 --> 00:00:31.720
we will see how to create your own operator
and how to make it

00:00:31.720 --> 00:00:34.960
more flexible by passing parameters to it. And then,

00:00:34.960 --> 00:00:38.720
we conclude by limiting the operator to specific context.

00:00:38.720 --> 00:00:42.080
An operator is the glue between menus, buttons, and hotkeys,

00:00:42.080 --> 00:00:44.480
and the code that should be executed by them. In the first episode,

00:00:44.480 --> 00:00:47.480
we already worked with operators by copy pasting them

00:00:47.480 --> 00:00:51.600
from menus and buttons into our own script.
Operators can be implemented

00:00:51.600 --> 00:00:54.840
in Blender itself in the C programming language.

00:00:54.840 --> 00:00:57.960
Or, they can, of course, be written in Python.

00:00:57.960 --> 00:01:01.720
No matter how they're made, they all have the same ingredients.

00:01:01.720 --> 00:01:05.000
First is an identifier. So this is what you would put after the "bpy.ops",

00:01:05.000 --> 00:01:09.600
so in this Operator, for example, it's far from complete,

00:01:09.600 --> 00:01:13.480
but we're building it up. So in this example, it would be

00:01:13.480 --> 00:01:17.840
"bpy.ops.sfa.example". These are always in the form

00:01:17.840 --> 00:01:21.600
"some category.a name". Best pick a category

00:01:21.600 --> 00:01:25.480
that already exist, like object or mesh or sculpt

00:01:25.480 --> 00:01:29.080
or whatever is suitable for your operator. But as you can see,

00:01:29.080 --> 00:01:32.000
you can also create your own. Then, we have a label.

00:01:32.000 --> 00:01:35.080
This is what appears on the menu items and buttons,

00:01:35.080 --> 00:01:39.360
and a description that is shown as Tool Tip. Then, everything is combined

00:01:39.360 --> 00:01:42.480
into a class. And this is something that we'll look at in a minute.

00:01:42.480 --> 00:01:46.360
For now, just think of it as some pot in which

00:01:46.360 --> 00:01:49.840
we gather all the ingredients of our operator. You can see that

00:01:49.840 --> 00:01:52.080
the class is named after the operator. So we have the category

00:01:52.080 --> 00:01:55.960
in capitals, then OT for the operator type, and then

00:01:55.960 --> 00:01:59.960
the rest of the identifier. So far, we've seen description,

00:01:59.960 --> 00:02:02.720
but not actual code yet. And this can be added in different ways

00:02:02.720 --> 00:02:05.960
for different purposes. So here are the possibilities

00:02:05.960 --> 00:02:09.840
from simple to complex. You have "Execute", this is where you put

00:02:09.840 --> 00:02:13.360
the main functionality of the code. If you want to create 600 monkeys,

00:02:13.360 --> 00:02:17.000
then this is the place to do it. The Execute function is also

00:02:17.000 --> 00:02:20.000
what gets called from Python directly. So if you call an operator,

00:02:20.000 --> 00:02:23.240
like "bpy.something.something"

00:02:23.240 --> 00:02:26.480
that's the function that gets called. Then we have "Invoke",

00:02:26.480 --> 00:02:29.240
this function is called when the operator is called for a menu

00:02:29.240 --> 00:02:32.600
or a button. If you want to do something extra, in that case,

00:02:32.600 --> 00:02:34.960
you want to have slightly different behavior, then you

00:02:34.960 --> 00:02:38.240
can do that in Invoke and you then call your Execute function from there.

00:02:38.240 --> 00:02:43.120
And now, we get to the most complex, the Modal one.

00:02:43.120 --> 00:02:45.840
The Modal function is for special operators that need to run

00:02:45.840 --> 00:02:48.720
for a longer period of time. This receives all kinds of events

00:02:48.720 --> 00:02:51.360
from Blender, from when you move your mouse,

00:02:51.360 --> 00:02:54.840
you click on buttons, you use the keyboard, that kind of stuff.

00:02:54.840 --> 00:02:57.840
Things like the Blender Cloud, texture browser, or CG cougars,

00:02:57.840 --> 00:03:01.000
Retopo, Float, Implemented, like this. If after all of these,

00:03:01.000 --> 00:03:03.720
you are in doubt about which function to use, keep it simple,

00:03:03.720 --> 00:03:07.120
just use the Execute function. If that turns out not to to be able to do

00:03:07.120 --> 00:03:09.960
what you want to do, then you have a concrete reason

00:03:09.960 --> 00:03:13.120
to look at something more complex. But before that,

00:03:13.120 --> 00:03:14.000
just keep things simple.

00:03:15.000 --> 00:03:17.360
Now, let's turn this into an actual operator that we can use.

00:03:17.360 --> 00:03:19.240
Let's create some more monkeys.

00:03:20.480 --> 00:03:23.600
Let's start by removing what we don't need. Let's keep it simple,

00:03:23.600 --> 00:03:30.360
just an Execute function. If you look at the Mesh Operators,

00:03:30.360 --> 00:03:33.360
you can see that, they start with "bpy.ops mesh primitive monkey add",

00:03:33.360 --> 00:03:38.080
or "bpy.ops mesh primitive ico sphere add"

00:03:38.080 --> 00:03:40.600
So all the Operators that create a new mesh object,

00:03:40.600 --> 00:03:44.360
they start with "mesh". So let's keep doing that.

00:03:45.840 --> 00:03:49.120
So the ID name becomes "mesh" and
we're going to create a monkey grid.

00:03:52.080 --> 00:03:58.240
Monkey Grid, label "monkey grid", the Tool Tip will be

00:03:58.240 --> 00:04:00.960
"let's spread some joy"

00:04:02.240 --> 00:04:05.360
and then the class name, we have to change, that becomes the category

00:04:05.360 --> 00:04:08.240
"mesh_ot_monkey_grid".

00:04:09.960 --> 00:04:14.080
The Execute function has to do something,

00:04:14.080 --> 00:04:17.720
but it also has to tell Blender whether everything succeeded or not.

00:04:17.720 --> 00:04:23.120
So everything was alright, you return "finished"

00:04:23.120 --> 00:04:26.600
and that tells Blender that the code actually performed well,

00:04:26.600 --> 00:04:30.000
but maybe your Operator cannot work, maybe it is for extruding a mesh

00:04:30.000 --> 00:04:32.720
and the mesh doesn't have any vertices.

00:04:33.720 --> 00:04:37.480
So in that case, you return "cancelled". There are a few other options

00:04:37.480 --> 00:04:41.600
and they are all described in the menu. To go there,

00:04:41.600 --> 00:04:45.240
you go to Help and then Python API Reference, and then

00:04:45.240 --> 00:04:49.120
to the section about "bpy.ops". So let's assume that

00:04:49.120 --> 00:04:50.600
everything will work correctly,

00:04:52.240 --> 00:04:56.080
we will return "finished". And now, all we have to do is

00:04:56.080 --> 00:04:58.240
put the code here that creates our monkey grid.

00:04:59.240 --> 00:05:01.720
So let's copy the code from Chapter 3 of Scripting for Artists

00:05:01.720 --> 00:05:07.120
and put it here. So this creates our 600 monkeys in rows of 25,

00:05:07.120 --> 00:05:12.840
having one Blender Unit between them.

00:05:12.840 --> 00:05:16.120
The Operators almost done already. So we have all the ingredients here.

00:05:16.120 --> 00:05:19.120
The only thing that we need to do now is

00:05:19.120 --> 00:05:22.600
tell Blender that this operator exists and this is called Registration.

00:05:24.840 --> 00:05:27.600
Fortunately, this is ather simple, we just call

00:05:27.600 --> 00:05:30.960
"bpy.utils.register_class" and then the name of the class,

00:05:30.960 --> 00:05:35.960
in our case, "mesh OT monkey grid". For symmetry, there should also be

00:05:35.960 --> 00:05:39.960
a Unregister function. So that looks like this.

00:05:39.960 --> 00:05:43.240
Instead of calling "register class", it's called "unregister class".

00:05:43.240 --> 00:05:46.840
Basically it undoes what the register function was doing, and then,

00:05:46.840 --> 00:05:50.720
we're almost there. It's just that, as you know, when you have

00:05:50.720 --> 00:05:53.480
a function like this, it's not automatically called when you run the script.

00:05:53.480 --> 00:05:57.720
There's a little trick for this.

00:05:57.720 --> 00:06:01.600
If you add some magic like this in here, and it looks a bit weird.

00:06:01.600 --> 00:06:06.000
But basically what this means is that, if this script is run,

00:06:06.000 --> 00:06:09.480
then it should call the Register function.

00:06:09.480 --> 00:06:13.120
There's multiple ways in which Blender can access your script,

00:06:13.120 --> 00:06:17.480
it can execute it, but it can also be imported from something else,

00:06:17.480 --> 00:06:21.720
just like we import BPY, other code can import this file as well.

00:06:21.720 --> 00:06:25.080
So there's a distinction between being imported from somewhere else,

00:06:25.080 --> 00:06:28.840
and being run. And only when it's being run,

00:06:28.840 --> 00:06:31.720
should it called the Register function, and that is what this code does.

00:06:31.720 --> 00:06:37.000
So now, what we can do, let's just name this "monkey_grid.py",

00:06:40.120 --> 00:06:41.480
and then let's click play.

00:06:43.120 --> 00:06:47.600
And nothing happened, which is kind of a good thing.

00:06:47.600 --> 00:06:51.600
We didn't see any error message, our code doesn't show any message.

00:06:51.600 --> 00:06:53.080
So silence is kind of good here.

00:06:54.120 --> 00:06:59.000
So, let's see what happens now,

00:07:00.600 --> 00:07:01.120
"bpy.ops.mesh.monkey_grid",

00:07:03.600 --> 00:07:06.600
there we go, we can create a monkey grid.

00:07:06.600 --> 00:07:09.600
The operator is there. Let's spread some joy. Let's not call it here.

00:07:09.720 --> 00:07:13.600
Let's see if we can find our new operator here in the F3 menu

00:07:15.000 --> 00:07:17.960
with a monkey and there's your monkey grid. So that's really cool.

00:07:17.960 --> 00:07:21.720
Press "enter" to execute it. And as you can see,

00:07:21.720 --> 00:07:24.960
Blender now freezes one is creating the 600 monkeys.

00:07:24.960 --> 00:07:27.240
And this is what happens when you do something that takes time

00:07:27.360 --> 00:07:31.120
in the Execute function, and that is okay. The code is part of

00:07:31.120 --> 00:07:34.840
this Blend file. So, let's see what happens when we create a new Blend file.

00:07:38.240 --> 00:07:40.120
As you can see, the operator is still there.

00:07:40.120 --> 00:07:43.120
Has been loaded into memory of Blender. It's been registered

00:07:43.120 --> 00:07:46.480
and it just keeps taking around. Now, let's see what happens

00:07:46.480 --> 00:07:47.600
if we restart Blender.

00:07:52.120 --> 00:07:55.080
And now, the monkey grid operator is no longer there.

00:07:55.080 --> 00:07:58.000
This is because, Blender doesn't just execute all the scripts

00:07:58.000 --> 00:08:00.960
that it can find in a Blend file, you have to tell it to do that first.

00:08:00.960 --> 00:08:04.120
You have to make sure that the name of the text file

00:08:04.120 --> 00:08:08.480
ends in ".py", and then here in the Text menu,

00:08:08.480 --> 00:08:10.000
you can check the Registered checkbox.

00:08:11.000 --> 00:08:13.120
Now, let's save, restart Blender,

00:08:16.720 --> 00:08:20.080
and now it's there. So let's have some fun and add some parameters.

00:08:20.080 --> 00:08:23.960
When you add a cube,  what you see here on the left

00:08:23.960 --> 00:08:27.360
is called the Redo panel. When you open it, you see different parameters

00:08:27.360 --> 00:08:30.000
which you can set. So what happens is that,

00:08:30.000 --> 00:08:33.360
when you change the parameters value, Blender pushes the Undo button

00:08:33.360 --> 00:08:37.360
automatically, and then re-execute the operator.

00:08:37.360 --> 00:08:39.840
That is why it's called the Redo panel, because it redoing things

00:08:39.840 --> 00:08:43.000
all the time. So let's add support for the Redo panel to our operator.

00:08:43.000 --> 00:08:46.360
We start by declaring the properties we want to have.

00:08:46.360 --> 00:08:49.600
This will be the number of monkeys in the X direction,

00:08:49.600 --> 00:08:52.600
number of monkeys in the Y direction, and monkey size.

00:08:52.600 --> 00:08:55.960
Just like operators live in "bpy.ops",

00:08:55.960 --> 00:09:00.000
the properties live in "bpy.props". So again, if you want

00:09:00.000 --> 00:09:03.120
to have more information, just go to Help, Python, API Reference,

00:09:03.120 --> 00:09:06.840
and then click on the "bpy.props" section. I will show you

00:09:06.840 --> 00:09:12.080
what it looks like. Let's call it "count x: bpy.props.IntProperty".

00:09:17.720 --> 00:09:20.960
IN stands for integer, which means a whole number,

00:09:20.960 --> 00:09:25.000
because we cannot have half monkey. So count X
has to be either one or two or three,

00:09:25.000 --> 00:09:29.240
but can never be like 2.5 or something. So it's whole numbers only,

00:09:29.240 --> 00:09:33.960
and this declares that we want to have that property.

00:09:33.960 --> 00:09:36.840
There is a big difference between the ":" we have here,

00:09:36.840 --> 00:09:40.240
and the "=" sign we have there.

00:09:41.360 --> 00:09:44.960
This sets a name to a value, and this is for things

00:09:44.960 --> 00:09:48.000
that just have to be set. We have to set "BL ID name" to match

00:09:48.000 --> 00:09:52.080
"monkey grid" to make it work. But here we don't really set anything.

00:09:52.080 --> 00:09:55.840
We just declare to Blender, this is an IN property,

00:09:55.840 --> 00:09:59.080
please act accordingly.

00:09:59.080 --> 00:10:02.480
You can add some parameters here to change behavior.

00:10:02.480 --> 00:10:03.360
First of all, we should set a name.

00:10:04.600 --> 00:10:07.120
We can call it X. It may be a bit cryptic,

00:10:07.120 --> 00:10:07.600
but for now, will do.

00:10:08.960 --> 00:10:10.480
And we can add a description,

00:10:11.480 --> 00:10:17.000
"number of monkeys in the X direction".

00:10:18.480 --> 00:10:20.080
So let's copy this to the Y.

00:10:22.080 --> 00:10:27.360
name this Y and "number of monkeys in the Y direction", and whatever size,

00:10:27.360 --> 00:10:30.720
which is another "bpy.props.FloatProperty".

00:10:32.480 --> 00:10:36.120
Float stands for floating point,

00:10:36.120 --> 00:10:38.720
is a technical term for just decimal numbers.

00:10:40.360 --> 00:10:48.120
"Name = size", and "Description = size of each monkey",

00:10:48.120 --> 00:10:51.600
this gives us our properties, but they're not used yet. So let's take a look

00:10:51.600 --> 00:10:54.720
at the Execute function where we're supposed to use them.

00:10:54.720 --> 00:10:59.000
This comment, it has to go, because we no longer creating 600 monkeys

00:10:59.000 --> 00:11:04.240
in rows of 25, but it's all flexible, so let's remove that for now.

00:11:04.240 --> 00:11:08.080
Now we have to access the properties. So we've declared them

00:11:08.080 --> 00:11:12.360
and this "self" gives us access to the actual value.

00:11:12.360 --> 00:11:15.960
"Self" is a point thing and I won't go into detail here

00:11:15.960 --> 00:11:20.080
about what it represents. Just know that, if you declare

00:11:20.080 --> 00:11:23.840
a property here as count X, then you can access it here as "self.count X".

00:11:25.960 --> 00:11:27.480
So the total number of monkeys

00:11:28.840 --> 00:11:32.840
is the number of monkeys in the X and in the Y direction,

00:11:32.840 --> 00:11:36.480
and this 25 here was the number of monkeys in the X direction.

00:11:41.480 --> 00:11:43.960
And then, all that is left is to set a size, and that's it.

00:11:45.000 --> 00:11:47.120
Let's give it a try.

00:11:49.840 --> 00:11:51.480
Let's see what happens in the Console.

00:11:55.720 --> 00:11:58.360
There you can see our Properties, count X, count Y, size,

00:11:58.360 --> 00:12:02.080
and they're all equal to 0, because we haven't set any default yet.

00:12:09.360 --> 00:12:13.240
And there, we have our three monkeys.

00:12:13.240 --> 00:12:16.600
Before we actually call it from the Viewport,

00:12:16.600 --> 00:12:17.840
let's set some sensible defaults.

00:12:20.960 --> 00:12:22.080
Default is 3.

00:12:23.840 --> 00:12:27.080
For the Y, default is 2, I choose different values there on purpose.

00:12:27.080 --> 00:12:30.960
This is default, so when somebody clicks on monkey grid button,

00:12:30.960 --> 00:12:33.960
or select it from the F3 list",

00:12:33.960 --> 00:12:38.120
this will be what they see. Because they see a 3x2 grid,

00:12:38.120 --> 00:12:41.080
they immediately know what they need to change.

00:12:41.080 --> 00:12:43.840
If they want to change the 3 to a 4, that just change the 3 to a 4,

00:12:43.840 --> 00:12:46.960
without having to think about whether it's the X or the Y direction.

00:12:46.960 --> 00:12:50.840
So if we were to give them the same default,

00:12:50.840 --> 00:12:52.960
then they wouldn't be able to see it. And then, they would have the thing

00:12:52.960 --> 00:12:56.000
like which direction is X, which direction is Y,

00:12:56.000 --> 00:12:59.240
which value do I want to change. And this is why I give them distinct values.

00:13:04.600 --> 00:13:07.720
Finally, default for the size, run again,

00:13:10.000 --> 00:13:11.360
delete everything.

00:13:16.120 --> 00:13:18.480
And there, you can see your defaults. And when we execute

00:13:18.480 --> 00:13:21.480
without any values, it just uses those default.

00:13:24.080 --> 00:13:27.120
And the same for the F3 menu. There's one more step left,

00:13:27.120 --> 00:13:30.360
and that is, to get that Redo panel.  We have the properties,

00:13:30.360 --> 00:13:33.720
so Blender knows what should hypothetically go in there,

00:13:33.720 --> 00:13:37.600
it just doesn't know yet that we support that Redo panel.

00:13:37.600 --> 00:13:40.960
So let's tell Blender that we do.

00:13:43.480 --> 00:13:46.720
This is done through "bl options". The default value is "register",

00:13:47.960 --> 00:13:53.840
and we have to add "undo" to it. This will give us the final ingredient.

00:13:53.840 --> 00:13:57.600
There you go.

00:13:58.960 --> 00:14:02.240
Now we can make them big and small, and give them even invalid values.

00:14:02.240 --> 00:14:06.080
So to make it pleasant to use for people,

00:14:06.080 --> 00:14:09.720
we should really set limits to the slider, so that,

00:14:09.720 --> 00:14:12.840
it's all sensible values that you can select there.

00:14:12.840 --> 00:14:14.120
Fortunately, this is quite simple.

00:14:15.240 --> 00:14:18.720
We can set a minimum. Let's set it to 1 because creating 0 monkey

00:14:18.720 --> 00:14:22.480
doesn't make sense. And creating negative monkeys even less.

00:14:22.480 --> 00:14:27.600
So let's start at 1, let's set the maximum to 10 for now.

00:14:30.480 --> 00:14:32.120
We can do the same for the count Y,

00:14:33.120 --> 00:14:37.600
and we can set the size 0 to minimum, and the maximum,

00:14:37.600 --> 00:14:39.080
let's set it to 1.

00:14:45.080 --> 00:14:48.600
And now, we can drag and things are still nice and sane.

00:14:51.360 --> 00:14:53.600
You can see that, it already gets little bit slower

00:14:53.600 --> 00:14:58.000
when these numbers increase. And we still can't get to the 600 we had before,

00:14:58.000 --> 00:15:01.840
even when I type 100 here, it is cut off to the maximum.

00:15:01.840 --> 00:15:05.600
So this is why Blender has a soft limit.

00:15:05.600 --> 00:15:09.240
The hard limit is what we set now, that's the absolute limit

00:15:09.240 --> 00:15:12.120
of the value of the property.
Whereas the soft limit is

00:15:12.120 --> 00:15:14.240
what the slider will do when you drag around.

00:15:15.240 --> 00:15:18.960
So if you want to allow maximum values that are bigger than 10,

00:15:18.960 --> 00:15:22.720
or sizes that are bigger than 1, but still want these limits

00:15:22.720 --> 00:15:26.240
as the limit for the slider, you can change the maximum into a soft maximum.

00:15:26.240 --> 00:15:30.080
The minimum that we have now really is a minimum,

00:15:30.080 --> 00:15:32.480
because creating 0 monkeys doesn't make sense,

00:15:32.480 --> 00:15:35.480
negative monkeys is impossible, also, creating a negatively sized monkey

00:15:35.480 --> 00:15:39.080
is impossible. So let's change the maximum to soft.

00:15:44.840 --> 00:15:53.120
Now the dragging is still the same, but we can set it to create

00:15:53.120 --> 00:15:56.720
much more monkeys than you would get with dragging.

00:15:56.720 --> 00:16:00.120
Now, let's get back to that class declaration.

00:16:00.120 --> 00:16:03.080
I'll explain a little bit more about how classes work in an inituitive way,

00:16:03.080 --> 00:16:06.720
I hope, without going too much into technical details.

00:16:06.720 --> 00:16:10.360
Classes use a system called inheritance,

00:16:10.360 --> 00:16:15.080
just like with people, it's like a parent-child structure.

00:16:15.080 --> 00:16:20.480
So in this case, "bpy.types.operator" is the parent, and "mesh OT monkey grid"

00:16:20.480 --> 00:16:24.120
access to the child. If you ask a child a question that

00:16:24.120 --> 00:16:27.720
you know the answer to, say you want to have a cookie,

00:16:27.720 --> 00:16:30.360
the child will say yes immediately without asking the parent, of course.

00:16:30.360 --> 00:16:35.000
But if you ask about taxes, then "Mom, please help me out here,

00:16:35.000 --> 00:16:38.240
because I don't know anything!" and then the child defers

00:16:38.240 --> 00:16:43.080
that question to the parent. This is the same way

00:16:43.080 --> 00:16:46.080
that Classes work in Python, roughly.

00:16:47.080 --> 00:16:50.000
We could do without the "bl" options. Our child didn't know

00:16:50.000 --> 00:16:53.600
anything about it, so Python asked the parent.

00:16:54.720 --> 00:16:57.480
And when we want to have something different,

00:16:57.480 --> 00:17:02.480
we can add "bl" options to our child, to our class. And then, that is asked first,

00:17:02.480 --> 00:17:05.480
so that takes precedence over whatever the parents wants.

00:17:05.480 --> 00:17:08.840
So we always have lucky children who gets all the cookies they want.

00:17:11.600 --> 00:17:14.000
So before I end this video, I have two more things

00:17:14.000 --> 00:17:18.240
I want to tell you. One, again, we look at the Execute function.

00:17:18.240 --> 00:17:21.480
You see that it gets a Context Parameter and this is pretty much like

00:17:21.480 --> 00:17:25.240
the context we've seen before. It gives us "context. object",

00:17:25.240 --> 00:17:28.960
"context.scene", "context.selected object",

00:17:28.960 --> 00:17:32.000
all these things you've seen before in "bpy.context",

00:17:32.000 --> 00:17:36.240
it gets here as well, but then, localized specifically for this operator.

00:17:36.240 --> 00:17:39.720
So as a general rule of thumb,

00:17:39.720 --> 00:17:43.480
if you have a function that gets a Context, use that Context,

00:17:43.480 --> 00:17:46.840
don't use "bpy.context. So if you want to do something

00:17:46.840 --> 00:17:50.960
with all the selected pose bones in this Execute function,

00:17:50.960 --> 00:17:53.080
you would use "context.selected pose bone".

00:17:57.720 --> 00:17:59.840
Another function and that is the second thing that I wanted to show you,

00:17:59.840 --> 00:18:03.240
another function that gets a Context is the Poll function,

00:18:03.240 --> 00:18:08.240
and it's written in a bit weird way, but just take it from me,

00:18:08.240 --> 00:18:09.720
it works like that.

00:18:18.080 --> 00:18:21.360
Again, you get a Context in this function. But instead of

00:18:21.360 --> 00:18:25.600
doing something like, instead of performing an action,

00:18:25.600 --> 00:18:28.240
this function is meant to check whether that action will be possible.

00:18:28.240 --> 00:18:32.360
So this Poll function is called by Blender

00:18:32.360 --> 00:18:35.960
every time this Operator is supposed to show up in a menu,

00:18:35.960 --> 00:18:39.960
or as a button on a panel. I can show you how this works.

00:18:39.960 --> 00:18:43.840
Right now, returns "true", which means that it is always allowed,

00:18:43.840 --> 00:18:47.960
just as it was before. And just as it was before,

00:18:47.960 --> 00:18:49.240
it shows up here in the F3 menu.

00:18:50.240 --> 00:18:51.720
When I change it to "false",

00:18:53.240 --> 00:18:57.120
it will never show up anywhere, which is kind of useless.

00:18:57.120 --> 00:18:59.720
Let's tweak this to make it a bit more useful.

00:19:00.720 --> 00:19:02.360
You can see here, in the Console,

00:19:04.480 --> 00:19:07.120
we have Autocomplete, which makes sense in a Python Console.

00:19:07.120 --> 00:19:10.960
But that same operator does not work

00:19:11.960 --> 00:19:16.080
in the 3D Viewport, because the context is wrong. This is also something

00:19:16.080 --> 00:19:19.360
we can do ourselves.  Right now, when I change this to "true" again,

00:19:23.240 --> 00:19:26.600
the monkey grid operator also shows up in the context of the Python comes on.

00:19:26.600 --> 00:19:29.720
And it will show up anywhere in Blender,

00:19:29.720 --> 00:19:33.240
which is not exactly the right way to go. Let's take another look

00:19:33.240 --> 00:19:35.960
at a variable inside that context.

00:19:37.240 --> 00:19:41.120
"Context.area" gives you the area that is currently active

00:19:41.120 --> 00:19:44.240
in Blender User Interface. So in this case, it would be the Console.

00:19:44.240 --> 00:19:47.960
But if the mouse is here, and we pull up the 3 menus,

00:19:47.960 --> 00:19:51.240
then all of a sudden, its 3D Viewport that is active, and here,

00:19:51.240 --> 00:19:55.120
would be the Outliner. So every area in Blender has its own area type

00:19:55.120 --> 00:19:59.080
and we can use that in our Poll function to make sure that

00:19:59.080 --> 00:20:02.120
it's only working in the area

00:20:02.120 --> 00:20:05.720
where we wanted to work. One thing I don't really like is guesswork.

00:20:05.720 --> 00:20:09.720
So we know now that the Area Type of the console is Console,

00:20:09.720 --> 00:20:14.960
but is it in 3D Viewport? Is it "3D View"? "3D_view", is it "3D Viewport"?

00:20:14.960 --> 00:20:19.840
I don't know, so let's make our script tell us instead.

00:20:19.840 --> 00:20:27.720
I can just say "print my area is context.area.type"

00:20:30.240 --> 00:20:33.720
And let's see what happens on the terminal where all these prints

00:20:33.720 --> 00:20:35.080
are sent to.

00:20:36.240 --> 00:20:40.120
Here, you seen the console, and immediately, you see it being called

00:20:40.120 --> 00:20:43.720
"My area is view 3D". But when I do it here in the Outliner,

00:20:43.720 --> 00:20:47.360
my area is Outliner. If I do it here in the Properties panel,

00:20:47.360 --> 00:20:52.000
my area is Properties. So that way, you can just use these print statements

00:20:52.000 --> 00:20:56.360
to know what you have to put where.

00:20:56.360 --> 00:20:59.600
So now, we know which value to use for the 3D Viewport,

00:20:59.600 --> 00:20:59.960
so let's just do that.

00:21:00.960 --> 00:21:07.600
If "context.area.type=view 3D" then return "true",

00:21:07.600 --> 00:21:11.960
otherwise, we can return "false". Let's see how this works.

00:21:15.480 --> 00:21:16.960
Here, it still shows up.

00:21:18.360 --> 00:21:23.000
But here is no longer there and, of course, here and there,

00:21:23.000 --> 00:21:27.120
now it only shows up where we want it to show up. One final thing,

00:21:28.240 --> 00:21:31.600
this kind of construct, I see them a lot, also from experienced programmers,

00:21:31.600 --> 00:21:34.480
it's more complex than necessary.

00:21:34.480 --> 00:21:39.240
Because this guy is already an expression that is true or false.

00:21:39.240 --> 00:21:43.240
So basically, what the code is saying is that

00:21:43.240 --> 00:21:48.480
if the value of this thing, this selected expression,

00:21:48.480 --> 00:21:52.240
if the value of that thing is true, return true, and if the value

00:21:52.240 --> 00:21:56.720
of that thing is false, return false. So that basically means

00:21:56.720 --> 00:22:00.480
return the value of this thing, which you can of course write

00:22:00.480 --> 00:22:00.960
as this.

00:22:05.840 --> 00:22:08.600
So that was it for this episode of Scripting for Artists.

00:22:08.600 --> 00:22:10.960
If you have any questions or remarks, please leave a comment below,

00:22:10.960 --> 00:22:12.840
and I will see you soon.