I'm having a hard time understanding the way MatchingArtSet and AIArtSpec work together. I understand if use the following:
AIArtSpec selectedSpecs[] = { { kAnyArt , kArtSelected , kArtSelected } };
sAIArtSet->MatchingArtSet( selectedSpecs , 1, artSet );
I get an art set that contains all the selected objects. Great.
What I don't understand is the behavior of the other AIArtUserAttr options. What I am trying to do specifically, is gather an art set of all the selected art, ignoring any art inside of a selected group.
I have tried various combinations of kArtSelectedTopLevelGroups, kArtSelectedLeaves, kArtFullySelected, all with no luck. The art set that is returned usually contains 0 items, or all the items. The docs on selecting matching specs are somewhat confusing.
Am I supposed to use different options for the first and second?
I have tried:
{ kAnyArt , kArtSelected , kArtSelectedTopLevelGroups }, etc, etc.
I am certainly open to using the art set "logic" functions to remove objects from the set of all selected objects, but I can't seem to get a set of just the selected leaf objects either.
Anyone have any experience with matching art?
Once you have your art set of selected art, how about just removing the art that is part of a group (i.e. has something other than a layer group as a parent). Maybe:
ai::int32 artSetSize;
sAIArtSet->CountArtSet( artSet, &artSetSize );
AIArtHandle art, parent;
for ( indexArtSet = artSetSize - 1; indexArtSet >= 0; --indexArtSet ) {
error = sAIArtSet->IndexArtSet( artSet, indexArtSet, &art );
ASBoolean parentLayerGroup;
sAIArt->GetArtParent( art, &parent );
if ( parent ) {
sAIArt->IsArtLayerGroup( parent, &parentLayerGroup );
if ( !parentLayerGroup ) {
sAIArtSet->RemoveArtFromArtSet( artSet, art );
}
}
}
The fields whichAttr and attr can be used to narrow the match by specifying
user attributes to include in the search. These attributes are boolean
values stored as bit flags in an object attributes variable.
Pass the desired user attribute for whichAttr. Pass 0 for attr if objects
without the state are desired, or the attribute mask for attr if objects with
it are desired. If whichAttr is 0 (no attributes selected), only the object type
is compared.
AIMatchingArtSpec spec;
AIArtHandle **unselectedPaths, **allLockedArt, **allGroups;
long numMatches;
// get a list of unselected paths
spec.type = kPathArt;
spec.whichAttr = kArtSelected;
spec.attr = 0;
error = GetMatchingArt( &spec, 1, &unselectedPaths, &numMatches );
// get a list of locked objects
spec.type = kAnyArt;
spec.whichAttr = kArtLocked;
spec.attr = kArtLocked;
error = GetMatchingArt( &spec, 1, &allLockedArt, &numMatches );
// get a list of groups, selected or not
spec.type = kGroupArt;
spec.whichAttr = 0;
error = GetMatchingArt( &spec, 1, &allGroups, &numMatches );
This should be helpful!
Regards,
Thomas.
That's really helpful actually.
I don't understand why I'm seeing the following behavior though:
I create a document with 3 rectangles on it and group them together. So my art tree looks like:
Layer -> Group -> Obj1, Obj2, Obj3
I select all objects.
Then I use
{ kAnyArt , kArtSelectedLeaves , kArtFullySelected }
I would understand this to give me either the group object, as it is a fully selected leaf of the Layer object. Or I would expect it to give me the 3 rectangles as they are fully selected leaves of the Group object. Or I would even understand if it gave me all 4 objects as they are all fully selected leaves of something.
What I actually get is just Obj1. This doesn't make any sense to me at all.
I'm not sure to fully understand what you are trying to do with this attributes.
I have just take a look a AIArt.h for more details about those values.
Here it is what I have found:
/** Matches only fully selected top level objects and not their children; valid only for matching.*/
kArtSelectedTopLevelGroups = 0x00000040,
/** Matches only leaf selected objects and not their containers; valid only for matching; see also \c kArtSelectedTopLevelGroups */
kArtSelectedLeaves = 0x00000080,
/** Matches only top level selected objects that have a stroke or fill; valid only for matching; see also \c kArtSelectedTopLevelGroups */
kArtSelectedTopLevelWithPaint = 0x00000100, // Top level groups that have a stroke or fill, or leaves
you should something like this:
spec.type = kAnyArt;
spec.whichAttr = kArtSelectedLeaves; // mask bits
spec.attr = kArtSelectedLeaves;
error = GetMatchingArt( &spec, 1, &.., &.. );
or like that:
spec.type = kAnyArt;
spec.whichAttr = kArtSelectedTopLevelGroups; //mask bits
spec.attr = kArtSelectedTopLevelGroups;
error = GetMatchingArt( &spec, 1, &.., &.. );
or:
spec.type = kAnyArt;
spec.whichAttr = kArtSelectedTopLevelGroups l kArtSelectedLeaves; // pipe char between value, mask bits
spec.attr = kArtSelectedTopLevelGroups l kArtSelectedLeaves;
error = GetMatchingArt( &spec, 1, &.., &.. );
Attr = the flag in the same positions as the mask bits indicating whether that attribute is on or off.
It looks from the header, that
attr = 1
is the same as
attr = kArtSelected
Based on that, I would expect
{ kAnyArt , kArtSelectedLeaves , kArtFullySelected }
to search All Art Types for Selected Leaf objects that are Fully Selected. In practice, what I've been getting is only 1 object. From what I've been able to piece together, it seems to be the first object in the tree that matches, the rest are ignored. I have seen this behavior with kArtSelectedTopLevelGroups as well.
Using the same tree as above, Layer -> Group -> Obj1, Obj2, Ob3 , selecting all again, and using
{ { kAnyArt , kArtSelectedLeaves , kArtSelectedLeaves } }
Returns 0 items. Baffling.
For all kind of objects, if you are only looking for leaf selected object, I would use this:
All kind of objects whichAttr: leaf selected object value: keep in mind, this is mask stuff. by using kArtSelectedLeaves you will set the right bit to 1.
{ kAnyArt , kArtSelectedLeaves , kArtSelectedLeaves }
By aware of setting the right bit(s) to one. Otherwise this won't work.
Ok... now I'm getting somewhere. The bitwise OR stuff seems to be getting closer, but I'm still having trouble getting the results I'm looking for.
Same tree as before: Layer -> Group -> Obj1, Obj2, Ob3
Using this:
{ kAnyArt , kArtSelected , kArtSelected | kArtSelectedTopLevelGroups }
Returns all 5 objects.
This:
{ kAnyArt , kArtSelected | kArtSelectedTopLevelGroups , kArtSelected | kArtSelectedTopLevelGroups }
Returns 0 objects.
This:
{ kAnyArt , kArtSelected , kArtSelectedTopLevelGroups }
Returns 0 objects.
This:
{ kAnyArt , kArtSelectedTopLevelGroups , kArtSelectedTopLevelGroups }
returns 0 objects.
Based on that, I would guess that the first one is equivalent to:
{ kAnyArt , kArtSelected , kArtSelected }
And including kArtSelectedTopLevelGroups isn't actually having any effect.
edit:
Using
{ kAnyArt , kArtSelectedLeaves , kArtSelectedLeaves }
as you suggested above, also returns 0 objects.
{ kAnyArt , kArtSelectedLeaves , kArtSelected }
Returns 1 object, Obj1.
{ kAnyArt , kArtSelectedLeaves , kArtSelected | kArtSelectedLeaves }
Returns 0 objects.
{ kAnyArt , kArtSelected , kArtSelected | kArtSelectedLeaves }
Returns all 5 objects.
AIArtSetSuite Struct Reference says this (note the italicized part):
Selection while matching: kArtSelectedTopLevelGroups, kArtSelectedLeaves, and kArtSelectedTopLevelWithPaint are used only with AIMatchingArtSuite::GetMatchingArt. These values cause an error in AIArtSuite::SetArtUserAttr(). They are mutually exclusive; you can specify only one, and they cannot be combined with other flags.
I thought you had something there. When I started with this, I had read that in the docs and thought "I'm not using SetArtUserAttr, this should work for me."
Then you posted this, I read it again, and realized I'm using MatchingArtSet, not GetMatchingArt. Problem solved, right? But then I switched my code around to use GetMatchingArt instead, and I'm getting the same results as before.
{ kAnyArt , kArtSelectedLeaves , kArtSelectedLeaves }
Returns 0 matches.
Based on that, I would guess that the first one is equivalent to:
{ kAnyArt , kArtSelected , kArtSelected }
And including kArtSelectedTopLevelGroups isn't actually having any effect.
That's correct. If you're looking to combine things I think you'd do it like you specified for:
{ kAnyArt , kArtSelected | kArtSelectedTopLevelGroups , kArtSelected | kArtSelectedTopLevelGroups }
I'm not sure though. I believe this one says "selected art that is also a selected top-level group". That said, it didn't seem to do what we'd expect.
Also, note that kArtSelectedTopLevelGroups & kArtSelectedLeaves are apparently mutually exclusive, according to the documentation of AIArtUserAttr.
If you want to do something like A or B, you'd create two different specs, add them to an array (size 2 in this case) and pass the array in instead of just one (plus set size to 2 obviously). I think that means "match art that meets any of the specs I specify".
You would think, huh? But I can't figure any way to actually include kArtSelectedTopLevelGroups. I tried every permutation of that I could think of, and the only way I got any matches was
{ kAnyArt , kArtSelected , kArtSelected | kArtSelectedTopLevelGroups }
Which, as we've stated, seems to be equivalent to just using
{ kAnyArt , kArtSelected , kArtSelected }
At this point, I'm not even trying to combine things, I'm just trying to figure out how to use kArtSelectedTopLevelGroups and kArtSelectedLeaves. Everything I've thought of, or anyone has suggested has not given the results I would expect.
North America
Europe, Middle East and Africa
Asia Pacific