Technical question
Moderators: Víctor Paredes, Belgarath, slowtiger
- synthsin75
- Posts: 10280
- Joined: Mon Jan 14, 2008 11:20 pm
- Location: Oklahoma
- Contact:
Technical question
How do you get a layer's, shape's, point's, internal ID? All I can find in the scripting reference is how you select by ID. So far, I've only been able to provide an ID by using the few things I can find that actually return one. (i.e. moho.layer:Parent will return the parent layer's ID)
I'm trying to move through the layers (vector) of a group using SetSelLayer(). Unless there is any other way to get info from a layer, for a tool, I need to provide this with the layer ID.
I'm trying to move through the layers (vector) of a group using SetSelLayer(). Unless there is any other way to get info from a layer, for a tool, I need to provide this with the layer ID.
Below is a snippet of code from a tool script I created recently that goes through layers in a switch using the arrow keys. This should work with any group layer as well.
First it checks for the keydown event (up arrow, down arrow). Then it counts how many layers are in the parent group layer, determines which layer it is on by comparing the name of the selected layer to all the other layers. Remember the selected layer is still the "main layer":
but I also can access all the other layers in the same group buy using the parent:
That is the part you may want to look at. The other stuff is to keep from doing anything with the up/down arrow keys when reaching the last or first layers in the group.
A layer ID is useless when using SetSelLayer(layer) function. It needs an ACTUAL layer object or it won't work. Also moho.layer.Parent() returns a GROUP LAYER object, not an ID. It is an actual layer reference.
A tip on reading the scripting reference:
"GroupLayer" indicates what is returned by the function. Sometimes you see the word "void" in front of the function. This means that function does not return a value. This is helpful to understand what each of those functions gives you. It is important because if you don't have the right type of object and use it somewhere else it won't work.
-vern
First it checks for the keydown event (up arrow, down arrow). Then it counts how many layers are in the parent group layer, determines which layer it is on by comparing the name of the selected layer to all the other layers. Remember the selected layer is still the "main layer":
Code: Select all
local layer = moho.layer
Code: Select all
local pLayer = layer:Parent()
Code: Select all
function HV_Layer_Selector:OnKeyDown(moho, keyEvent, view)
local layer = moho.layer
if (keyEvent.keyCode == LM.GUI.KEY_DOWN) then
local pLayer = layer:Parent()
for i= 0, pLayer:CountLayers()-1 do
local sLayer = pLayer:Layer(i)
local x = layer
if(layer:Name() == sLayer:Name()) then
if(i > 0) then
x = pLayer:Layer(i-1)
end
moho:SetSelLayer(x)
end
end
end
if (keyEvent.keyCode == LM.GUI.KEY_UP) then
local pLayer = layer:Parent()
for i= 0, pLayer:CountLayers()-1 do
local sLayer = pLayer:Layer(i)
local x = layer
if(layer:Name() == sLayer:Name()) then
if(i < pLayer:CountLayers()-1) then
x = pLayer:Layer(i+1)
end
moho:SetSelLayer(x)
end
end
end
end
A tip on reading the scripting reference:
Code: Select all
GroupLayer Parent()
-vern
Additional info:
If you have no group layers you get a layer using:
In the code above the layers are accessed at the DOCUMENT level. The TOP level. That is how you would get layers not in a group.
------
A little more explanation for the code in the previous post:
Here I assign the variable "x" as a sub layer inside the parent layer. pLayer:Layer() always returns a layer object (of course "pLayer" is a variable I created from "moho.layer:Parent()"). You CAN use ID numbers to get to a layer but you MUST get a layer object using the format that will RETURN a layer object not just the ID.
Lots of times I will just store a number ID value in a table... but sometimes I store the actual layer itself. These types of values are called "userdata". If you tried to print to string the value of a layer object you would get a bunch of numbers and letters that are the internal reference to that object. You would not get the ID number.
Have I totally confused you yet? 
-vern
If you have no group layers you get a layer using:
Code: Select all
for i=0, moho.document:CountLayers() - 1 do
local tLayer = moho.document:Layer(i)
..... do stuff to this layer or put it in a table or variable etc....
.......
.....
end
------
A little more explanation for the code in the previous post:
Here I assign the variable "x" as a sub layer inside the parent layer. pLayer:Layer() always returns a layer object (of course "pLayer" is a variable I created from "moho.layer:Parent()"). You CAN use ID numbers to get to a layer but you MUST get a layer object using the format that will RETURN a layer object not just the ID.
Lots of times I will just store a number ID value in a table... but sometimes I store the actual layer itself. These types of values are called "userdata". If you tried to print to string the value of a layer object you would get a bunch of numbers and letters that are the internal reference to that object. You would not get the ID number.
Code: Select all
if(i > 0) then
x = pLayer:Layer(i-1)
end
moho:SetSelLayer(x)
end

-vern
- synthsin75
- Posts: 10280
- Joined: Mon Jan 14, 2008 11:20 pm
- Location: Oklahoma
- Contact:
Thank you, thank you, thank you! I'll have to read over that better tomorrow, but you already cleared a few things up. I had already done that 'print to string' on the layer (and group) objects (userdata).
So what I need is the object, and I think you've provided the code for doing just that. I had been thinking that the ID was the internal reference.
So the ID is just the layer order in the document, the layer object is the internal reference to the actual layer, and the layer name is what you see in the UI?
With this new knowledge, I'm pretty confident I'll have a new tool done ....oh....in a week or two (knowing my pace).
So what I need is the object, and I think you've provided the code for doing just that. I had been thinking that the ID was the internal reference.
So the ID is just the layer order in the document, the layer object is the internal reference to the actual layer, and the layer name is what you see in the UI?
With this new knowledge, I'm pretty confident I'll have a new tool done ....oh....in a week or two (knowing my pace).

Yes:synthsin75 wrote: So the ID is just the layer order in the document and the layer object is the internal reference to the actual layer
Code: Select all
moho.layer
Code: Select all
local skel = moho:Skeleton()
Code: Select all
for i = 0, skel:CountBones() - 1 do
local bone = skel:Bone(i)
do suff....
.......
Code: Select all
local bone = skel:Bone(27)
One thing different though. Bones have a way to get the ID from the bone object directly:
Code: Select all
local boneID = skel:BoneID(bone)
Here are two ways to get a layer "object":
Code: Select all
for i=0, moho.document:CountLayers() - 1 do
local layer = moho.document:Layer(i)
do suff....
.......
Code: Select all
local layer = moho.document:Layer(6)
So bones actually have more ways to access them than layers. They have the bone object and the bone ID and you can convert them back and forth. If you for instance have a bone ID you can create a variable that is a bone object. If you have a bone object and just need the ID you can find the ID.
Layers on the other hand can only be accessed by ID and you can't get the ID from the layer object. You either find it using a "for loop" and checking the order or name, or looking at the layer palette and counting the layers. You can't ask for the ID of a layer from a layer object. This is a bit annoying but not a deal breaker. It just requires a bit more coding but you end up with the same thing.
Yes. And you can get the name of a layer by assigning it to a variable (layerName in this example):and the layer name is what you see in the UI
Code: Select all
local layerName = moho.layer:Name()
-vern
- synthsin75
- Posts: 10280
- Joined: Mon Jan 14, 2008 11:20 pm
- Location: Oklahoma
- Contact:
- synthsin75
- Posts: 10280
- Joined: Mon Jan 14, 2008 11:20 pm
- Location: Oklahoma
- Contact:
Woohoo!!!!!
I was just about to post a question, but while I was writing it, a solution occurred to me. And it works! I've been trying to be tight lipped about this until I could verify that it would work. And it does.
I'm not quite ready to post the script yet (as I have more I still want to do with it), but I can let the cat out of the bag. Sorry, I may be too excited about this.
What it does:
This script allows you to select layers by clicking on a visible shape in that layer. (I think Slowtiger had recently mentioned this functionality of other apps.) In other words, if you have a group (bone etc.) filled with vector layers and you have one of those vector layers selected (for the time being anyway), clicking with this tool will select any layer in the group that has a shape at that location.
Eventually this will become part of a universal shape/layer tool, but there's still a lot of work to get that far. As a standalone tool, I guess I could modify other scripts to call it with a modifier key, but I don't know if I'll bother doing that.
I still have to work out some implementation issues. Right now, if you click overlapping shapes, you don't really have a say of which one (shape & layer) it selects.
Since a 'for' loop only evaluates its expressions once, how would I go about having the loop be dependant on the current or last selection? In other words, looping through the layers, I need it to always start from the current layer down and then cycle back to catch the higher layers if no shape is found.



I was just about to post a question, but while I was writing it, a solution occurred to me. And it works! I've been trying to be tight lipped about this until I could verify that it would work. And it does.
I'm not quite ready to post the script yet (as I have more I still want to do with it), but I can let the cat out of the bag. Sorry, I may be too excited about this.

What it does:
This script allows you to select layers by clicking on a visible shape in that layer. (I think Slowtiger had recently mentioned this functionality of other apps.) In other words, if you have a group (bone etc.) filled with vector layers and you have one of those vector layers selected (for the time being anyway), clicking with this tool will select any layer in the group that has a shape at that location.
Eventually this will become part of a universal shape/layer tool, but there's still a lot of work to get that far. As a standalone tool, I guess I could modify other scripts to call it with a modifier key, but I don't know if I'll bother doing that.
I still have to work out some implementation issues. Right now, if you click overlapping shapes, you don't really have a say of which one (shape & layer) it selects.
Since a 'for' loop only evaluates its expressions once, how would I go about having the loop be dependant on the current or last selection? In other words, looping through the layers, I need it to always start from the current layer down and then cycle back to catch the higher layers if no shape is found.

- Víctor Paredes
- Site Admin
- Posts: 5818
- Joined: Wed Jan 26, 2005 12:18 am
- Location: Barcelona/Chile
- Contact:
synthsin75 wrote:This script allows you to select layers by clicking on a visible shape in that layer. (I think Slowtiger had recently mentioned this functionality of other apps.) In other words, if you have a group (bone etc.) filled with vector layers and you have one of those vector layers selected (for the time being anyway), clicking with this tool will select any layer in the group that has a shape at that location.
Eventually this will become part of a universal shape/layer tool, but there's still a lot of work to get that far. As a standalone tool, I guess I could modify other scripts to call it with a modifier key, but I don't know if I'll bother doing that.
I still have to work out some implementation issues. Right now, if you click overlapping shapes, you don't really have a say of which one (shape & layer) it selects.
Since a 'for' loop only evaluates its expressions once, how would I go about having the loop be dependant on the current or last selection? In other words, looping through the layers, I need it to always start from the current layer down and then cycle back to catch the higher layers if no shape is found.


FAN-FREAKING-TASTIC!!!!
You beat me to it!!! I was just thinking about playing around with a script like that!
When you are ready there is a really really really easy way to stick a reference to your new tool script inside any other tool script. Of course it means modifying the other tool but it's only like two or three lines and very simple. I use this all the time.
Basically you just add the the keydown reference to any tool that you want that functionality.
I have a tool (HV_Layer_Selector) that uses the arrow keys to move up and down the layers in a switch layer. I just added this code to the select point and translate points tool "OnKeyDown()" function:
The HV_Layer_Selector tool has a keydown function in it. I am calling the keydown function of that tool from another tool. The current tools in AS do this already. The different bone tools will call fucntions in the bone selection tool. Even if the tool doesn't already have a keydown function just stick one in there and add the tool you want to USE the keydown function from.
You could even create a utility script, put the keydown function in there and reference that instead:
-vern
You beat me to it!!! I was just thinking about playing around with a script like that!
When you are ready there is a really really really easy way to stick a reference to your new tool script inside any other tool script. Of course it means modifying the other tool but it's only like two or three lines and very simple. I use this all the time.
Basically you just add the the keydown reference to any tool that you want that functionality.
I have a tool (HV_Layer_Selector) that uses the arrow keys to move up and down the layers in a switch layer. I just added this code to the select point and translate points tool "OnKeyDown()" function:
Code: Select all
function FA_SelectPoints:OnKeyDown(moho,keyEvent)
HV_Layer_Selector:OnKeyDown(moho, keyEvent, view)
.... other stuff....
You could even create a utility script, put the keydown function in there and reference that instead:
Code: Select all
function FA_SelectPoints:OnKeyDown(moho,keyEvent)
-- **************************************************
-- OnKeyDown - New code for Bone Groups
-- **************************************************
HV_SharedUtils:OnKeyDown(moho, keyEvent)
moho:UpdateUI()
keyEvent.view:DrawMe()
.... more stuff....
- synthsin75
- Posts: 10280
- Joined: Mon Jan 14, 2008 11:20 pm
- Location: Oklahoma
- Contact:
You beat me to it!!! I was just thinking about playing around with a script like that!

Yeah I've seen plenty of scripts that call others. I might do that once I get some more things worked out.
First, I still need to:
1) Get it to do nothing if no shape exists below mouse click.
2) Solve some slight issues with multiple shapes on a layer, including getting it to deselect the previous shape on the same layer.
Once these are done (and perhaps a few more), I plan on implementing a 'shape sort' functionality for layers. Does anyone know what the channel code for the 'layer sort channel' would be?

- synthsin75
- Posts: 10280
- Joined: Mon Jan 14, 2008 11:20 pm
- Location: Oklahoma
- Contact:
- synthsin75
- Posts: 10280
- Joined: Mon Jan 14, 2008 11:20 pm
- Location: Oklahoma
- Contact:
Okay, this is probably to the point of being useful, so I went ahead and added it to a modified select shape tool.
Using the syn_select_shape tool, you can hold CTRL+SHIFT and clicking on a visible shape (within the current layer's group), and that shape's layer will be selected.
Overlapping shape-layers are selectable from the top layer down, so if a lower shape is covered, you have to find an exposed edge to select its layer.
Note: If you CTRL+SHIFT select over no shape, it will default to the bottom layer. I haven't yet figured out how to make it stay where it is.
Let me know what you think, and if I should go ahead and post this for general use.
Download it here.
Using the syn_select_shape tool, you can hold CTRL+SHIFT and clicking on a visible shape (within the current layer's group), and that shape's layer will be selected.
Overlapping shape-layers are selectable from the top layer down, so if a lower shape is covered, you have to find an exposed edge to select its layer.
Note: If you CTRL+SHIFT select over no shape, it will default to the bottom layer. I haven't yet figured out how to make it stay where it is.
Let me know what you think, and if I should go ahead and post this for general use.

Download it here.
Oh wow! This is.... WICKED COOL BABY! I LOVE IT! Yeehaaaa!
I will be adding this to my FA vector tools. This is really great. Very very very useful. A great time saver!
p.s. I poked around in the script reference looking for a way to NOT select a layer if the "eyeball" is turned off... dagnabbit... no way to do it. I just can't find any reference for the layer being "on" or not. This could eliminate the problem with overlapping layers.
A really cool simple workaround is to just have a tiny filled box on each layer making sure they don't overlap so you can select them.
This is great. I've always had this idea in the back of my head as a great time saver. Thanks dude!
-vern
I will be adding this to my FA vector tools. This is really great. Very very very useful. A great time saver!
p.s. I poked around in the script reference looking for a way to NOT select a layer if the "eyeball" is turned off... dagnabbit... no way to do it. I just can't find any reference for the layer being "on" or not. This could eliminate the problem with overlapping layers.
A really cool simple workaround is to just have a tiny filled box on each layer making sure they don't overlap so you can select them.
This is great. I've always had this idea in the back of my head as a great time saver. Thanks dude!
-vern
Suggestions;
I haven't looked at the code yet so I don't know exactly how you are picking the layers. I am guessing you are using the SHAPE to determine which layer is selected.
What about using a point in the mesh of the layer instead of the shape? For instance the select points tool can select the nearest point to the mouse click. Not sure if this is actually "better". It may cause difficulties with points close to each other on several layers... just brainstorming.
One thing it would do is allow the switching of layers when fills are "turned off" in the display settings. The layer switching won't work if fills are not visible (or don't exist). Not a big deal really... even Adobe Illustrator has problems with this when in outline view.
-vern
I haven't looked at the code yet so I don't know exactly how you are picking the layers. I am guessing you are using the SHAPE to determine which layer is selected.
What about using a point in the mesh of the layer instead of the shape? For instance the select points tool can select the nearest point to the mouse click. Not sure if this is actually "better". It may cause difficulties with points close to each other on several layers... just brainstorming.
One thing it would do is allow the switching of layers when fills are "turned off" in the display settings. The layer switching won't work if fills are not visible (or don't exist). Not a big deal really... even Adobe Illustrator has problems with this when in outline view.

-vern
I figured out how to stay on the current layer if no shape was picked:
First I created another variable called "prevLayer" in that spot where all the other variables are created. This var is the layer that is selected at that moment before actually clicking anywhere:
Then I added a single "else" to the last bit that sets the selected layer to that layer if no shape was clicked:
Bingo! Works like a charm!
-vern
First I created another variable called "prevLayer" in that spot where all the other variables are created. This var is the layer that is selected at that moment before actually clicking anywhere:
Code: Select all
local prevLayer = moho.layer
Then I added a single "else" to the last bit that sets the selected layer to that layer if no shape was clicked:
Code: Select all
if (shapefound == true) then
break
else
moho:SetSelLayer(prevLayer)
end
-vern