Can somebody explain the logic behind adornment layer positioning?

SyntaxEditor for WPF Forum

Posted 7 years ago by Will Sullivan
Version: 12.1.0560
Avatar

I've got a few adornment layers I'm adding to the syntax editor.  My close reading of the documentation apparently has not helped me understand the logic behind how layers are positioned.

Let me concentrate on two of the adornment definitions I have that illustrate the problem I'm hainvg--your alternating row adorner, which renders alternating row background colors, and my block adorner, which allows users to draw boxes over text.

Here's the definition for the alternating rows adorner:

private static AdornmentLayerDefinition layerDefinition =
    new AdornmentLayerDefinition(
        "AlternatingRows", 
        new Ordering(AdornmentLayerDefinitions.TextBackground.Key, OrderPlacement.After));

 From what I understand, this layer should appear BELOW the TextBackground adornment layer.  

(By the way, whoever chose "before" and "after" needs to get docked a month's pay.  It should have been BELOW/ABOVE.  Is "After" below or above?  Hell, I don't know!  It depends on your perspective, doesn't it?)  

That seems to me to be the bottom of the adornment layer stack.  As in, everybody else should be rendered ontop of that layer.

Here's the definition for my block adornment layer

private static readonly AdornmentLayerDefinition layerDefinition = 
    new AdornmentLayerDefinition(
        "BlockAdornments", 
        new Ordering(AdornmentLayerDefinitions.TextForeground.Key, OrderPlacement.Before));

 This seems to me to say that my blocks should be rendered in an adornment layer that sits ABOVE the text foreground layer, where text is rendered.  So it should be way up high in the stack.  As in, only the caret should be rendered on top of my precious blocks!

But is this the case?

HELL NO!

There's something else going on here...  The order of the adornment layers also depends on the order in which each is registered with the SyntaxLanguage!

What black magic is this?  It makes absolutely no sense to me as subtle changes in the order layers are registered can cause bizzarre results in the editor!

For example, if you register the two layers in this order:

this.RegisterService(
    new AdornmentManagerProvider<AlternatingRowsAdornmentManager>(
        typeof(AlternatingRowsAdornmentManager)));
this.RegisterService(
    new AdornmentManagerProvider<BlockAdornmentManager>(
        typeof(BlockAdornmentManager)));

 You tend to get the expected result.  The alternating rows are rendered on the bottom of the stack, and my beautiful blocks sit regally on top.  However, reverse the two:

this.RegisterService(
    new AdornmentManagerProvider<BlockAdornmentManager>(
        typeof(BlockAdornmentManager)));
this.RegisterService(
    new AdornmentManagerProvider<AlternatingRowsAdornmentManager>(
        typeof(AlternatingRowsAdornmentManager)));

 And now the alternating rows are rendered on top of everything, including text, while my precious blocks are at the bottom of the heap, below even the text background!

It gets even weirder when you throw on more layers, as even though the BlockAdornmentManager gets registered at the end it still can show up underneath all other layers!!!

Can anybody explain to me what the hell is going on here?  Is this a bug?  Is it expected behavior?  And, if it is expected, what is the exact algorithm that decides the order of adornment layers??  I need to know so that, when it starts not working again, I can fix the ordering problem without spending half a day juggling lines of code in hopes that the problem goes away!

 


[Modified 7 years ago]

Comments (2)

Answer - Posted 7 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar

Hi Will,

There currently are some issues with the IOrderable sorting algorithm not working as expected in certain scenarios, and they show up more when there are many items being sorted such as all the built-in adornment layers and your own layers as seen here.

Ideally what you'd be able to do is specify you want a layer before (in front of) one layer and after (behind) another one and it would work correctly.  We already have started making some unit tests in this area so that we can work on rewriting a good chunk of the algorithm to use more of a tree structure and ensure it's working as expected.

In the meantime, a workaround is to fully specify the before (in front of) and after (behind) for every known layer.  For instance if you were making something that you wanted only behind the caret, your orderings would look something like:

new Ordering[] { 
	new Ordering(AdornmentLayerDefinitions.TextBackground.Key, OrderPlacement.Before),
	new Ordering(AdornmentLayerDefinitions.Highlight.Key, OrderPlacement.Before),
	new Ordering(AdornmentLayerDefinitions.Selection.Key, OrderPlacement.Before),
	new Ordering(AdornmentLayerDefinitions.CollapsedRegion.Key, OrderPlacement.Before),
	new Ordering(AdornmentLayerDefinitions.Squiggle.Key, OrderPlacement.Before),
	new Ordering(AdornmentLayerDefinitions.TextForeground.Key, OrderPlacement.Before),
	new Ordering(AdornmentLayerDefinitions.Caret.Key, OrderPlacement.After),
};

Be sure to include your custom layers in that list as well.  I believe if you do that for now, it will work around the issue until we get our new algorithm in place.  Sorry for the hassle in the meantime.


Actipro Software Support

Answer - Posted 7 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar

Hi Will,

We've completed our updates for this and they should be in the next 2012.2 maintenance release.


Actipro Software Support

The latest build of this product (v2019.1 build 0683) was released 1 month ago, which was after the last post in this thread.

Add Comment

Please log in to a validated account to post comments.