Adding Skins

Post Reply
ColinP
Posts: 1000
Joined: Mon Aug 03, 2020 7:46 pm

Adding Skins

Post by ColinP »

I'm working on adding a basic skinning mechanism to allow users to select a plain background for Adroit modules rather than the current image.

There doesn't seem to be any support for skins in the API so at the moment all I'm doing is using AddComponent() to attach a rectangle that's the same size as the module.

It works fine except that I can't figure out how to stop it obscuring the yellow outline that VM displays to indicate selected modules.

I've tried playing with SetZorder() to no avail. One would expect SetZOrder( 0 ) to work but CA's yellow outline appears to have a lower Z order than the minimum.

If I shrink my rectangle then I end up with a border of the wrong color when a module is not selected.

Has anyone figured out how to code a dynamic custom module background that doesn't obscure the yellow selection outline?
ColinP
Posts: 1000
Joined: Mon Aug 03, 2020 7:46 pm

Re: Adding Skins

Post by ColinP »

OK, I've spent a fair amount of time on this and it looks like the VM drawing order is...

1. Background image or solid color specified in VMD Module Properties
2. Any GUI elements with "Is Background Object" checked
3. The yellow selection outline
4. Other GUI elements in Z-order - although VDM simply rearranges the initialisation order of elements when you use right click Bring Forward, Send Backwards etc. Presumably as an optimization so that only if an element has SetZOrder() called on it is a Z sort done.

I don't understand why the yellow selection outline is drawn before the rest of the GUI, there appears to be no way to gain any programmatic access to the background and there's no event notification of selection change so one can't simulate the yellow outline.

So unless I'm missing something this issue seems impossible to work around. If you want to be able to dynamically change the background the only option seems to be having a two pixel wide border that is the "wrong color" so that the yellow selection outline still works.

Fortunately this doesn't look too bad in practice, so I'm going to go with it unless someone has developed a cunning way to fix this problem.
ColinP
Posts: 1000
Joined: Mon Aug 03, 2020 7:46 pm

Re: Adding Skins

Post by ColinP »

A word of warning to other developers. VM's Z sort is buggy.

I've just wasted almost a whole day trying to figure out why my skinning code for the LSSP Progression module doesn't work and ended up creating a test rig and the result is an unpredictable sort depending on the z depth figures used and the number of elements being sorted.

So for instance

Code: Select all

   rectangle0.SetZOrder( 4 );
   rectangle1.SetZOrder( 3 );
   rectangle2.SetZOrder( 2 );
   rectangle3.SetZOrder( 1 );
does not work as expected but

Code: Select all

   
   rectangle0.SetZOrder( 8 );
   rectangle1.SetZOrder( 7 );
   rectangle2.SetZOrder( 6 );
   rectangle3.SetZOrder( 5 );
does work.

Also if I add four extra rectangles by copying then the first code example works OK but the second one doesn't.

This is reflected inside VM Designer too. Simply creating four overlapping rectangles and copying them produces a copy with the incorrect z-order - even though in the auto generated code InitializeControls() the initialization order is correct.
jclounge
Posts: 14
Joined: Fri Aug 06, 2021 5:19 am

Re: Adding Skins

Post by jclounge »

Hi Colin, what if you instead only ever set Z order with increasing values? I know it's not ideal, but that's what I've been doing and so far it seems to be working.
ColinP
Posts: 1000
Joined: Mon Aug 03, 2020 7:46 pm

Re: Adding Skins

Post by ColinP »

Hi,

That has me a little confused.

If you mean that setting z-order to be the same as the initialization order works then what's the point of having z-ordering? Couldn't you just drop the calls to SetZOrder() and get an identical result?

What I'm trying to do is use multiple classes working together where GUI components from each class slide together in a determinate z-order.

So for instance in the LSSP Progression module I have a SkinHelper class that provides the skin that needs to be at the back, then an SPoly class that provides an illuminated ring and a poly socket. Then I have an active ring that shows which chord input socket is active and this needs to be above the skin, above the S-Poly ring but below the socket.

I normally code the active ring as simply an ellipse with a border (as GPU's can knock out an ellipse with a nice anti-aliased border in no time) but couldn't set the z-order of the active ring to be correct as VM got the z-sort wrong no matter what z values I tried for everything. So I had to recode it to draw the active ring as two separate ellipse border components instead to overcome the problem. It's probably about the same GPU cost but the z-order not working as I expected threw me.
jclounge
Posts: 14
Joined: Fri Aug 06, 2021 5:19 am

Re: Adding Skins

Post by jclounge »

Whether it's good I'm not sure, but this seems to be working:

- Every time anything at all needs to be reordered, I call my module method updateComponentZOrdering(), and it reorders everything that will ever be reordered.

- The method starts off with a Z value of 10000 just for the sake of it, my comment to myself was "hopefully this z is high enough to be in front of everything else".

- Then it traverses every component that I worry about the ordering of, setting its Z order and incrementing the Z value for the next component.

- It's a bit awkward, but the way this manages to order things differently is to traverse the components in a different order as it increments Z.

- I've had to include almost every component in the whole module in this method. With something like 100 components, performance does not appear to be a problem so far. Also code-wise it's not just one huge crazy function, since it also calls out to objects to tell them to order their components starting at the current Z, and they return what Z they got up to so it can resume from there.

Even if you never want to reorder things dynamically (which this does do), there's still at least one example I can think of to set Z ordering in code. You might have something like tinting rectangles or shadow overlays placed on top of other components, but in the designer editor they might get in the way of selecting the components under them. So you can put them to the back and out of the way in the editor, and then when your module runs they can get placed in the correct order.
ColinP
Posts: 1000
Joined: Mon Aug 03, 2020 7:46 pm

Re: Adding Skins

Post by ColinP »

Hi jclounge, it sounds like you are doing some serious development work but after a quick trawl through the forum I haven't been able to link you to any of the existing "manufacturers". Maybe I've missed something or you are a new developer poised to release some awesome new modules.

I did follow up your tip and tested calling SetZOrder() with ascending z values and indeed although...

Code: Select all

   rectangle0.SetZOrder( 4 );
   rectangle1.SetZOrder( 3 );
   rectangle2.SetZOrder( 2 );
   rectangle3.SetZOrder( 1 );
fails,

Code: Select all

   rectangle3.SetZOrder( 1 );
   rectangle2.SetZOrder( 2 );
   rectangle1.SetZOrder( 3 );
   rectangle0.SetZOrder( 4 );
works.

Both cases should produce exactly the same result but the bug doesn't show in the second case, as indeed you indicated.

Your solution sounds like a hell of a lot of tedious effort to work around a bug. If I understand your explanation correctly you are hand coding up to 100 lines each with different identifiers just to get z-sorting to work, right? Or have I misunderstood?
jclounge
Posts: 14
Joined: Fri Aug 06, 2021 5:19 am

Re: Adding Skins

Post by jclounge »

Oh cool, I'm glad that works! Funnily enough it was just what I coded up in the first place since it happened to make enough sense at the time, so I never knew there was a bug until you mentioned it. Just lucky really since you would expect it to work no matter what order you set them in.

Wow, it looks like you're quite prolific on the module store, cool stuff! Yeah, I'm still new around these parts and haven't published any modules yet, hopefully my first one will be ready soon, trying to make it as good as I can right now.

Spoiler alert: My module has 4 'submodules' inside it that can be dragged up and down to reorder them. I wanted to be able to bypass the whole module with a bypass button, so I added that, but I also wanted to make the module darken when bypassed, so I added a translucent rectangle to show/hide. That's when Z ordering first became relevant. Since then, I also added bypass buttons to each submodule, and they each have their own tinting rectangles. Since these submodules can be dragged up and down, it made enough sense to gather up their components into lists to be managed as groups. Since they were already being added to lists, it was no big deal to add them in the order I need them Z sorted. Whenever the main Z update method is called, it calls out to the submodule objects to sort their things, which is effectively just a short loop calling other short loops. That structure has since made it easy to add shadow overlays to each submodule, and to temporarily bring the dragged submodule in front of all the other ones, and to sort the submodules from bottom to top in Z order so their little overhang shadows overlap to the next submodule correctly. So yeah it was a bit of tedium, but it was incremental tedium that offered something more each step of the way. :)
ColinP
Posts: 1000
Joined: Mon Aug 03, 2020 7:46 pm

Re: Adding Skins

Post by ColinP »

Sounds very interesting.

I'm looking forward to seeing your work published.
Post Reply

Return to “Module Designer”