Hello,
looking for a solution to a problem (described in the last replies of this thread here), I've decided I'm old enough to finally grasp what ActionManager code means. Or am I too old to do it? This will lead to all sort of frustration, but that's life anyway.
I'm sorry in advance, I won't be particularly "correct" with terminology, and possibly confused as well.
I'm trying to keep in mind all the things that I've read here, last but not least what Jacobolus said about ActionReference:
It’s a stack implemented as a linked list: i.e. it has a bunch of nodes each with some content and a pointer to the next node. You build it from “tail” (most specific) to “head” (least specific) node of the list, and then Photoshop uses the result to locate an internal object by recursing from the head to the tail.
Since in the thread I've mentioned I was dealing with the creation of Adjustment Layers, here it is the ScriptingListener code (I've just added line numbers) that makes a new one:
Code: Select all1. var idMk = charIDToTypeID( "Mk " );
2. var desc3 = new ActionDescriptor();
3. var idnull = charIDToTypeID( "null" );
4. var ref1 = new ActionReference();
5. var idAdjL = charIDToTypeID( "AdjL" );
6. ref1.putClass( idAdjL );
7. desc3.putReference( idnull, ref1 );
8. var idUsng = charIDToTypeID( "Usng" );
9. var desc4 = new ActionDescriptor();
10. var idType = charIDToTypeID( "Type" );
11. var desc5 = new ActionDescriptor();
12. var idpresetKind = stringIDToTypeID( "presetKind" );
13. var idpresetKindType = stringIDToTypeID( "presetKindType" );
14. var idpresetKindDefault = stringIDToTypeID( "presetKindDefault" );
15. desc5.putEnumerated( idpresetKind, idpresetKindType, idpresetKindDefault );
16. var idCrvs = charIDToTypeID( "Crvs" );
17. desc4.putObject( idType, idCrvs, desc5 );
18. var idAdjL = charIDToTypeID( "AdjL" );
19. desc3.putObject( idUsng, idAdjL, desc4 );
20. executeAction( idMk, desc3, DialogModes.NO );
As far as I understand, each event has its own ID. The executeAction() at the very end (line 20) needs the event ID to know which action to take - so in this case the variable is:
Code: Select all1. var idMk = charIDToTypeID( "Mk " );
'Mk ' stands for Make - the number 1298866208.
Code: Select all2. var desc3 = new ActionDescriptor();
An ActionDescriptor, according to the JS reference is a: "dictionary-style mechanism for storing data as key-value pairs". Ok.
Code: Select all3. var idnull = charIDToTypeID( "null" );
No idea about why I would need to store null as a number (TypeID), but let's have faith.
Code: Select all4. var ref1 = new ActionReference();
ActionReference: "This object provides information about what the action is referring to [...] Contains data associated with an ActionDescriptor". Uhmm. Is it kind of a container of extra data for the ActionDescriptor? Referred to the ActionDescriptor itself as a dictionary, or to one of the key-value pair that it stores? This is a point I don't really understand. Anyway.
Code: Select all5. var idAdjL = charIDToTypeID( "AdjL" );
It stores the "AdjL" string as a TypeID (a number) in a variable.
Code: Select all6. ref1.putClass( idAdjL );
So the ActionReference now contains a numeric version of "AdjL" as... a Class? Does this mean: hey, you have this dictionary-like object called ActionDescriptor, with a "sidecar" object called ActionReference that contains extra info - i.e. a class called AdjL. Not that much sure this interpretation holds true.
Code: Select all7. desc3.putReference( idnull, ref1 );
ActionDescriptor.putReference(key, value) "Sets the value for a key whose type is an object reference." Is it that the ActionDescriptor, this dictionary of key-value pairs now contains a key (a bizarre one: the null) which associated value is... an object called ActionReference that in turn contains "AdjL" as a class? Still I'm afraid I don't understand the nature and the why of the ActionReference.
I know, I grope in the dark
Similarly, I guess the following lines:
Code: Select all11. var desc5 = new ActionDescriptor();
12. var idpresetKind = stringIDToTypeID( "presetKind" );
13. var idpresetKindType = stringIDToTypeID( "presetKindType" );
14. var idpresetKindDefault = stringIDToTypeID( "presetKindDefault" );
15. desc5.putEnumerated( idpresetKind, idpresetKindType, idpresetKindDefault );
Put into another ActionDescriptor those three values (key, enumType, value) - I don't understand what the enumType is (kind of a counter?), but it's the minor of my problems. I've let alone the previous three lines:
Code: Select all8. var idUsng = charIDToTypeID( "Usng" );
9. var desc4 = new ActionDescriptor();
10. var idType = charIDToTypeID( "Type" );
For I didn't know what they appeared in that position for. The order of the commands is rather weird to me.
Code: Select all16. var idCrvs = charIDToTypeID( "Crvs" );
17. desc4.putObject( idType, idCrvs, desc5 );
Ok, now things get perverted. So, there's the "Crvs" which stands for Curves.
I put "Curves" into another ActionDescriptor using putObject(key, classID, value): "Sets the value for a key whose type is an object, represented by an Action Descriptor."
So my dictionary contains a key ("Type"), which class is "Curves", which value is another ActionDescriptor (the default preset kind of a curve).
I'm getting frustrated.
Code: Select all18. var idAdjL = charIDToTypeID( "AdjL" );
19. desc3.putObject( idUsng, idAdjL, desc4 );
Line 18 is a duplicate var of line 5 - is there any reason?
Line 19: First ActionDescriptor: key = "using", class = "Adjustment Layer", value = the mess of the actionDescriptor that contains Curves default preset.
Code: Select all20. executeAction( idMk, desc3, DialogModes.NO );
Make it! And show no dialog.
Phew.
So, to resume (please notice the italian humor):
ActionDescriptor "desc3" seems to contain 2 key/value pairs:
1) key: null / value: ActionReference(AdjustmentLayer as a class) - why null, I can't say.
2) key: using / class: AdjustmentLayer / ActionDescriptor.
This last ActionDescriptor is a matrioshka: it contains another AD, desc4: type, class Curves, value another inner ActionDescriptor (containing info about the kind of curve).
I'm not willing to understand the why of this setup of onion-skin AD - I'd like to know what the flaws of my interpretation are.
As far as I can get it, this is crucial for the second, more interesting step: to start looking for "things" inside AD we are exploring.
Thanks in advance for your comments and sorry for the long, messed up post!
Davide
ActionManager code
ActionManager code
Here is my understanding of Action Manager...
I'll start with IDs. Everything in Action Manager is done with typeIDs. A typeID is an integer. Most are 10 digits long although some can be as short as 4 digits. Because humans have a hard time remembering a long string of numbers, Adobe created the charID. A charID is a four char string that has the typeID encoded into the chars( spaces count ). charIDs always map to a 10 digit typeID. Because of the 4 char limit Adobe ran out of usable charIDs and created stringIDs. StringIDs can be any length and map to a shorter typeID( typically 4 digits ) but that mapping changes from Photoshop session to session. So unlike charIDs you have to use the stringIDToTypeID method( or a wrapper that calls that method ).
TypeIDs can be event, key, class, enum, or value depending on how they are being used. For example:
Code: Select allref.putEnumerated( charIDToTypeID( "Chnl" ), charIDToTypeID( "Chnl" ), charIDToTypeID( "Msk " );
Here the charID 'Chnl' is being used as both the key and the enumType. As an aside the charID 'null' does not mean the javascript reserved work null, is means the typeID 1853189228.
So with that in mind lets look at a cleaned up version of your sample scriptlistener log with comments.
Code: Select all var desc = new ActionDescriptor();// a desc for the make event.
var ref = new ActionReference();// a ref for what to make
ref.putClass( charIDToTypeID('AdjL') );// the class adjustment layer
desc.putReference( charIDToTypeID('null'), ref );// store the ref
var desc1 = new ActionDescriptor();// a desc for the adjustment layer
var desc2 = new ActionDescriptor();// a desc for the type of adjustment
desc2.putEnumerated( stringIDToTypeID('presetKind'), stringIDToTypeID('presetKindType'), stringIDToTypeID('presetKindDefault') );// the type of adjustment
desc1.putObject( charIDToTypeID('Type'), charIDToTypeID('Crvs'), desc2 );// store the type desc in the AdjL desc
desc.putObject( charIDToTypeID('Usng'), charIDToTypeID('AdjL'), desc1 );// store the AdjL desc in the make desc
executeAction( charIDToTypeID('Mk '), desc, DialogModes.NO );// execute the event(command)
I think null is used either because Adjl is a class or because AdjL is not part of the AdjL descriptor( sort of a self reference ).
Does that help? I wouldn't worry about things like 'It’s a stack implemented as a linked list'. You don't need that level of understanding to work with Action Manager.
I'll start with IDs. Everything in Action Manager is done with typeIDs. A typeID is an integer. Most are 10 digits long although some can be as short as 4 digits. Because humans have a hard time remembering a long string of numbers, Adobe created the charID. A charID is a four char string that has the typeID encoded into the chars( spaces count ). charIDs always map to a 10 digit typeID. Because of the 4 char limit Adobe ran out of usable charIDs and created stringIDs. StringIDs can be any length and map to a shorter typeID( typically 4 digits ) but that mapping changes from Photoshop session to session. So unlike charIDs you have to use the stringIDToTypeID method( or a wrapper that calls that method ).
TypeIDs can be event, key, class, enum, or value depending on how they are being used. For example:
Code: Select allref.putEnumerated( charIDToTypeID( "Chnl" ), charIDToTypeID( "Chnl" ), charIDToTypeID( "Msk " );
Here the charID 'Chnl' is being used as both the key and the enumType. As an aside the charID 'null' does not mean the javascript reserved work null, is means the typeID 1853189228.
So with that in mind lets look at a cleaned up version of your sample scriptlistener log with comments.
Code: Select all var desc = new ActionDescriptor();// a desc for the make event.
var ref = new ActionReference();// a ref for what to make
ref.putClass( charIDToTypeID('AdjL') );// the class adjustment layer
desc.putReference( charIDToTypeID('null'), ref );// store the ref
var desc1 = new ActionDescriptor();// a desc for the adjustment layer
var desc2 = new ActionDescriptor();// a desc for the type of adjustment
desc2.putEnumerated( stringIDToTypeID('presetKind'), stringIDToTypeID('presetKindType'), stringIDToTypeID('presetKindDefault') );// the type of adjustment
desc1.putObject( charIDToTypeID('Type'), charIDToTypeID('Crvs'), desc2 );// store the type desc in the AdjL desc
desc.putObject( charIDToTypeID('Usng'), charIDToTypeID('AdjL'), desc1 );// store the AdjL desc in the make desc
executeAction( charIDToTypeID('Mk '), desc, DialogModes.NO );// execute the event(command)
I think null is used either because Adjl is a class or because AdjL is not part of the AdjL descriptor( sort of a self reference ).
Does that help? I wouldn't worry about things like 'It’s a stack implemented as a linked list'. You don't need that level of understanding to work with Action Manager.
ActionManager code
Hello Mike,
of course it helps, I'm slowly getting it! I'm afraid I will take advantage of your knowledge some more
Could you gently explain how an ActionDescriptor and an ActionReference are different? Even if the JS reference says that:
This object provides information about what the action is refering to. For example, when referring to the name of something you might use keyName. The reference would also need to know what name you are referring to. In this case you could use classDocument for the name of the document or classLayer for the name of the layer. It can be used for low-level access into Photoshop.Contains data associated with an ActionDescriptor.
Does it mean that an AD (the dictionary) must have an AR only - which duty is to specify the context of it - or each key/value pair may have its own AR?
Thanks again!
Davide
of course it helps, I'm slowly getting it! I'm afraid I will take advantage of your knowledge some more
Could you gently explain how an ActionDescriptor and an ActionReference are different? Even if the JS reference says that:
This object provides information about what the action is refering to. For example, when referring to the name of something you might use keyName. The reference would also need to know what name you are referring to. In this case you could use classDocument for the name of the document or classLayer for the name of the layer. It can be used for low-level access into Photoshop.Contains data associated with an ActionDescriptor.
Does it mean that an AD (the dictionary) must have an AR only - which duty is to specify the context of it - or each key/value pair may have its own AR?
Thanks again!
Davide
ActionManager code
The best documentation I know is the Adobe® Photoshop® 5.5 Actions Event Guide, from 1999, which is part of the SDK download. It still doesn’t do the greatest job of explaining all the context though. I’ll try to write a quick overview of my understanding of things sometime in the next few days.
ActionManager code
jacobolus wrote:The best documentation I know is the Adobe® Photoshop® 5.5 Actions Event Guide, from 1999
Adobe is known to be always up-to-date with documentation
jacobolus wrote:I’ll try to write a quick overview of my understanding of things sometime in the next few days.
That would be great, thanks so much Jacob!
Hope to survive to the hot italian summer for at least a week or so (we've been quite busy in the last month here)
Davide
Adobe is known to be always up-to-date with documentation
jacobolus wrote:I’ll try to write a quick overview of my understanding of things sometime in the next few days.
That would be great, thanks so much Jacob!
Hope to survive to the hot italian summer for at least a week or so (we've been quite busy in the last month here)
Davide
ActionManager code
Mike wrote:I'll start with IDs. Everything in Action Manager is done with typeIDs. A typeID is an integer. Most are 10 digits long although some can be as short as 4 digits. Because humans have a hard time remembering a long string of numbers, Adobe created the charID. A charID is a four char string that has the typeID encoded into the chars( spaces count ). charIDs always map to a 10 digit typeID. Because of the 4 char limit Adobe ran out of usable charIDs and created stringIDs. StringIDs can be any length and map to a shorter typeID( typically 4 digits ) but that mapping changes from Photoshop session to session. So unlike charIDs you have to use the stringIDToTypeID method( or a wrapper that calls that method ).
This is mostly right, but I think mixes up cause and effect a bit.
Photoshop was originally written in the late-1980s in some mix of Pascal and 68k Assembly code, for the Macs of the time, and then later rewritten to keep up with Apple’s changing programming requirements (PPC architecture, C++ code, Intel architecture, OS X, etc.). A big part of Photoshop’s engineering effort has been running just to stay in the same place.
Anyhow, one trick used by the Mac operating system in the 1980s and 90s was to represent many identifiers for things as 32-bit integers represented by mnemonic 4-character codes (for instance, the "resources" that went in a "resource fork" of a file, file type and creator metadata, identifiers in various core APIs, and the IDs inside of Apple event descriptors, which were used for AppleScript). I’m not exactly sure what the earliest core infrastructure of Photoshop looked like, but by the time Actions were included, in Photoshop 3 or 4 or whatever, they had this object oriented internal messaging system with messages somewhat similar to the kind used by Apple events, and an API that looks roughly like what we’re dealing with today.
So okay, all event codes, object types, references to specific special application objects, keys inside the objects passed around to describe messages, etc., were these 32-bit integers represented by mnemonic 4-character codes. This worked pretty well given the original constraints and environment of the system, but Photoshop has thousands of objects things to name, and so the names started to be reused in multiple contexts because they wanted to keep them mnemonic. Starting in Photoshop 5, this system just couldn’t keep up, so they added a way to use arbitrarily long strings instead of 4-character codes. But they still needed to maintain compatibility with the old system, so they built in a component (let’s call it X) that maintains a translation table for converting every string to a 32-bit integer, which can then be used in all the same functions that expected a 32-bit integer before. When you ask X to translate a string, it checks if there was already a 4-character code associated with that string, and if so, you get a number that’s just the same as the 4 characters interpreted as one integer. If there wasn’t a stored type, then X creates a new association between your string and an integer, with the integers just counting up from one. Every time Photoshop starts up, it begins by registering most of the string IDs it expects to use with X, so that they’ll have integer IDs, and presumably it initializes various objects to know what integer they should be called by. When you call stringIDToTypeID or typeIDToStringID, you’re just causing X to do a lookup. And you can add your own new string IDs to the table, if you want. If you call stringIDToTypeID('foo'), you’ll get an integer back (for me, just now, 2148), and if you pass that back in to typeIDToStringID, you’ll get back 'foo'. This lets Photoshop load components in any order, and potentially lets third-party plugins use the same system if they want to use their own string IDs.
This is mostly right, but I think mixes up cause and effect a bit.
Photoshop was originally written in the late-1980s in some mix of Pascal and 68k Assembly code, for the Macs of the time, and then later rewritten to keep up with Apple’s changing programming requirements (PPC architecture, C++ code, Intel architecture, OS X, etc.). A big part of Photoshop’s engineering effort has been running just to stay in the same place.
Anyhow, one trick used by the Mac operating system in the 1980s and 90s was to represent many identifiers for things as 32-bit integers represented by mnemonic 4-character codes (for instance, the "resources" that went in a "resource fork" of a file, file type and creator metadata, identifiers in various core APIs, and the IDs inside of Apple event descriptors, which were used for AppleScript). I’m not exactly sure what the earliest core infrastructure of Photoshop looked like, but by the time Actions were included, in Photoshop 3 or 4 or whatever, they had this object oriented internal messaging system with messages somewhat similar to the kind used by Apple events, and an API that looks roughly like what we’re dealing with today.
So okay, all event codes, object types, references to specific special application objects, keys inside the objects passed around to describe messages, etc., were these 32-bit integers represented by mnemonic 4-character codes. This worked pretty well given the original constraints and environment of the system, but Photoshop has thousands of objects things to name, and so the names started to be reused in multiple contexts because they wanted to keep them mnemonic. Starting in Photoshop 5, this system just couldn’t keep up, so they added a way to use arbitrarily long strings instead of 4-character codes. But they still needed to maintain compatibility with the old system, so they built in a component (let’s call it X) that maintains a translation table for converting every string to a 32-bit integer, which can then be used in all the same functions that expected a 32-bit integer before. When you ask X to translate a string, it checks if there was already a 4-character code associated with that string, and if so, you get a number that’s just the same as the 4 characters interpreted as one integer. If there wasn’t a stored type, then X creates a new association between your string and an integer, with the integers just counting up from one. Every time Photoshop starts up, it begins by registering most of the string IDs it expects to use with X, so that they’ll have integer IDs, and presumably it initializes various objects to know what integer they should be called by. When you call stringIDToTypeID or typeIDToStringID, you’re just causing X to do a lookup. And you can add your own new string IDs to the table, if you want. If you call stringIDToTypeID('foo'), you’ll get an integer back (for me, just now, 2148), and if you pass that back in to typeIDToStringID, you’ll get back 'foo'. This lets Photoshop load components in any order, and potentially lets third-party plugins use the same system if they want to use their own string IDs.
ActionManager code
When working with Action Manger you will run into three main objects. ActionDescriptor, ActionReference, and ActionList.
I like to think of ActionDescriptors as a holder for information. ActionReference is for what And/or where( a layer [and which layer] ). An ActonList is an array of ActionDescriptors.
ActionDescriptors can be nested. That is they can hold ActionDescriptors, ActionReferences, and/or ActionLists several levels deep. But they may not hold any of those. For example a descriptor for "RGBC" has three keys. Those keys are for the red, green, and blue values. No ActionReference nor ActionList.
And as an example of nesting that "RGBC" descriptor is put in another ActonDescriptor for "solidColorLayer" And that descriptor is put in yet another descriptor when building an 'setd' exectueAction.
Or to put it another way, a layer descriptor has a lot of keys. The number varies with the layer kind and not all layers have all keys. An adjustment layer will have a key for the adjustment. That key is an ActionList. That list holds the descriptor for the adjustment itself. The adjustment desc hold info about the adjustment settings. ( in new versions it holds all the data in one rawData key and is much harder to work with ).
So I think you would be better off working with the scriptlistener log. Perform some action in Photoshop's GUI and study the last log entry. Get a copy of Xbytor's getterDemo script and have a look at existing descriptors. Come up with so code like I have posted below that let you explore a descriptor one level at a time.
Code: Select allvar ref = new ActionReference();
ref.putEnumerated( charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );
var desc = executeActionGet(ref);
$.writeln( desc );
if(desc.typename == 'ActionReference'){
var c = desc.count;
for(var i=0;i<c;i++){ //enumerate reference. use getForm() to determine which get method to use
$.writeln('Key '+zeroPad( i+1, 2 )+' = '+desc.getReference(i).getIndex());
}
}
if(desc.typename == 'ActionList'){
var c = desc.count;
for(var i=0;i<c;i++){ //enumerate list
$.writeln('Key '+zeroPad( i+1, 2 )+' = '+desc.getType(i))
}
}
if(desc.typename == 'ActionDescriptor'){
var c = desc.count;
for(var i=0;i<c;i++){ //enumerate descriptor's keys
$.writeln('Key '+zeroPad( i+1, 2 )+' = '+IDTz(desc.getKey(i))+' : '+desc.getType(desc.getKey(i)))
}
}
function IDTz(id){
var isCharID = false;
try {
if( new String( id ).length == 10 ) {
isCharID = true;
var charID = '"'+typeIDToCharID( id )+'"';
var stringID = '"'+typeIDToStringID( id )+'"';
if( stringID.length <=2 ) {
stringID = ' NA ';
}else{
while( stringID.length < 25 ){
stringID += ' ';
}
}
}else{
var charID = ' NA ';
var stringID = '"'+typeIDToStringID( id )+'"';
while( stringID.length < 25 ){
stringID += ' ';
}
}
}catch(e){}
return charID+' | '+stringID;
}
function zeroPad(num,pad) {
var z = Math.pow(10,Number(pad))
return num <= z ? ((Number( num) + z).toString().substr(1)): num
}
I like to think of ActionDescriptors as a holder for information. ActionReference is for what And/or where( a layer [and which layer] ). An ActonList is an array of ActionDescriptors.
ActionDescriptors can be nested. That is they can hold ActionDescriptors, ActionReferences, and/or ActionLists several levels deep. But they may not hold any of those. For example a descriptor for "RGBC" has three keys. Those keys are for the red, green, and blue values. No ActionReference nor ActionList.
And as an example of nesting that "RGBC" descriptor is put in another ActonDescriptor for "solidColorLayer" And that descriptor is put in yet another descriptor when building an 'setd' exectueAction.
Or to put it another way, a layer descriptor has a lot of keys. The number varies with the layer kind and not all layers have all keys. An adjustment layer will have a key for the adjustment. That key is an ActionList. That list holds the descriptor for the adjustment itself. The adjustment desc hold info about the adjustment settings. ( in new versions it holds all the data in one rawData key and is much harder to work with ).
So I think you would be better off working with the scriptlistener log. Perform some action in Photoshop's GUI and study the last log entry. Get a copy of Xbytor's getterDemo script and have a look at existing descriptors. Come up with so code like I have posted below that let you explore a descriptor one level at a time.
Code: Select allvar ref = new ActionReference();
ref.putEnumerated( charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );
var desc = executeActionGet(ref);
$.writeln( desc );
if(desc.typename == 'ActionReference'){
var c = desc.count;
for(var i=0;i<c;i++){ //enumerate reference. use getForm() to determine which get method to use
$.writeln('Key '+zeroPad( i+1, 2 )+' = '+desc.getReference(i).getIndex());
}
}
if(desc.typename == 'ActionList'){
var c = desc.count;
for(var i=0;i<c;i++){ //enumerate list
$.writeln('Key '+zeroPad( i+1, 2 )+' = '+desc.getType(i))
}
}
if(desc.typename == 'ActionDescriptor'){
var c = desc.count;
for(var i=0;i<c;i++){ //enumerate descriptor's keys
$.writeln('Key '+zeroPad( i+1, 2 )+' = '+IDTz(desc.getKey(i))+' : '+desc.getType(desc.getKey(i)))
}
}
function IDTz(id){
var isCharID = false;
try {
if( new String( id ).length == 10 ) {
isCharID = true;
var charID = '"'+typeIDToCharID( id )+'"';
var stringID = '"'+typeIDToStringID( id )+'"';
if( stringID.length <=2 ) {
stringID = ' NA ';
}else{
while( stringID.length < 25 ){
stringID += ' ';
}
}
}else{
var charID = ' NA ';
var stringID = '"'+typeIDToStringID( id )+'"';
while( stringID.length < 25 ){
stringID += ' ';
}
}
}catch(e){}
return charID+' | '+stringID;
}
function zeroPad(num,pad) {
var z = Math.pow(10,Number(pad))
return num <= z ? ((Number( num) + z).toString().substr(1)): num
}
ActionManager code
jacobolus wrote:This is mostly right, but I think mixes up cause and effect a bit.
I may have mixed up cause and effect but I think I got the main points across. Action Manager uses integers for keys, charIDs are static, and stringIDs are dynamic.
I am also not sure that charIDToTypeID uses the same component as stringIDToTypeID. Because the typeID is hard coded into the charID there is no need for any lookup type structure to convert. I would think doing a straight conversion would be faster than searching through the lookup structure.
I may have mixed up cause and effect but I think I got the main points across. Action Manager uses integers for keys, charIDs are static, and stringIDs are dynamic.
I am also not sure that charIDToTypeID uses the same component as stringIDToTypeID. Because the typeID is hard coded into the charID there is no need for any lookup type structure to convert. I would think doing a straight conversion would be faster than searching through the lookup structure.
ActionManager code
Mike Hale wrote:I may have mixed up cause and effect but I think I got the main points across. Action Manager uses integers for keys, charIDs are static, and stringIDs are dynamic.
You got the main points across. Just trying to clarify the history, and point out that the direct inspiration seems to have been the Apple event system from ~1990. Char IDs are static. String IDs come in 2 flavors: (a) ones that map directly to static char IDS, (b) dynamic ones.
I am also not sure that charIDToTypeID uses the same component as stringIDToTypeID. Because the typeID is hard coded into the charID there is no need for any lookup type structure to convert.
You’ve got it. What I meant, but maybe I was unclear, was that for string IDs that fall into category (a), the translation table returns a static ID that corresponds to the char ID, whereas for new, unregistered strings, it creates a dynamic integer ID.
You got the main points across. Just trying to clarify the history, and point out that the direct inspiration seems to have been the Apple event system from ~1990. Char IDs are static. String IDs come in 2 flavors: (a) ones that map directly to static char IDS, (b) dynamic ones.
I am also not sure that charIDToTypeID uses the same component as stringIDToTypeID. Because the typeID is hard coded into the charID there is no need for any lookup type structure to convert.
You’ve got it. What I meant, but maybe I was unclear, was that for string IDs that fall into category (a), the translation table returns a static ID that corresponds to the char ID, whereas for new, unregistered strings, it creates a dynamic integer ID.
ActionManager code
Mike Hale wrote:I think null is used either because Adjl is a class or because AdjL is not part of the AdjL descriptor (sort of a self reference).
The char ID "null" is used to denote the "target" of a descriptor that represents an event. Events like "set", "get", "reset", "delete", "make", and so on all require a target, and that target is an ActionReference pointing at the desired object. The string ID to use in this context is, quite helpfully, "target", so feel free to use stringIDToTypeID('target') instead of charIDToTypeID('null') if it makes your code easier to read.
An ActonList is an array of ActionDescriptors.
Everything else you said is right on the money, but just one quick note: ActionLists can contain any kind of object (descriptors, references, lists, strings, integers, doubles, booleans, unit doubles, enums, classes, raw data, files). Some lists of strings that you might notice, for example, are the lists of font names inside the application descriptor.
The char ID "null" is used to denote the "target" of a descriptor that represents an event. Events like "set", "get", "reset", "delete", "make", and so on all require a target, and that target is an ActionReference pointing at the desired object. The string ID to use in this context is, quite helpfully, "target", so feel free to use stringIDToTypeID('target') instead of charIDToTypeID('null') if it makes your code easier to read.
An ActonList is an array of ActionDescriptors.
Everything else you said is right on the money, but just one quick note: ActionLists can contain any kind of object (descriptors, references, lists, strings, integers, doubles, booleans, unit doubles, enums, classes, raw data, files). Some lists of strings that you might notice, for example, are the lists of font names inside the application descriptor.