How to transform a component inside of a vision template

Nope. While groups definitely exhibit the same scaling behaviors as templates when you squish them or expand them, a simple transform still works as expected on a group's individual components because the components' bounds are still relative to their location within the window editor in the designer.

That said, I've finally got my head around what I was observing. The bounds of the template are always relative to the template editor in the designer. Therefore, my erroneous expectation was for the internal components to shift relative to the window they were placed in.

Case Study 1:
Assume I design my test template at dimensions of 400 x 300:
image

When I embed it into a window, I ensure that it remains neither compressed nor stretched. Upon executing my transform, it functions as expected:

button = event.source.parent.getComponent('TestTemplate').getComponent(0).getComponent(0)
system.gui.transform(button, 100, 100, 100, 100)

image

However, if I squish the template in the window down to 200 x 100, and run the same script, the result positions the internal component to approximately where `Rectangle(100, 100, 100, 100) would have been in the template. I say approximately because I believe there are some floating point calculation errors that take place which would explain the up to 4 pixel 'wobble' I had observed in my earlier testing.
image

That said, the effect is obvious when you're squishing the template, but in my case, I was expanding the template.

Case Study 2:
Assume I designed the template at a generic size of 200 x 50:
image

..but in a window, for whatever reason, it is desirable to make the template significantly larger:
image

Attempting to transform this button to a y-coordinate position of 100, my original expectation was for it to shift relative to the window editor. However, since the shift happens relative to the template in the editor, and since the template has been magnified from 50 pixels to 200 pixels, every 50 pixels in the newY parameter of the transform will cause the object to shift 200 pixels. Consequently, relative to the window editor, the object will position itself at y = 400 pixels [outside of the visible area]. Obviously, this principle applies to all other dimensions as well, including the x dimension, which I must not have observed in my initial testing because the width dimension of my template simply didn't change much when I resized the template within my window.

Therefore, using a relative coordinate space for the transform has no perceivable effect because, as I've already stated multiple times, the parameter is relative to the window editor and not the template editor. Thus, in order to get the desired effect of a template that has been resized in a designer window, a ratio that represents how much the template has been scaled is needed.

Which brings me back to what I had developed earlier to make my template work before I understood the reason why it was needed:

# Import FPMILayout
from com.inductiveautomation.factorypmi.application.components.util import FPMILayout

#Retrieve the component
component = # Put relative path to component here

# Get the FPMILayout
# In most cases, this could probably be simplified to temlateInsance.layout 
# ...eliminating the need for the FPMILayout import
layout = FPMILayout.getOffsettingParent(component).layout

# Make sure there is no possiblility of dividing by zero
widthDivisor, heightDivisor = max(1, layout.getBounds(component).width), max(1, layout.getBounds(component).height)

# Define the scale ratios by dividing the template bounds (.preferredBounds) by the window bounds(.bounds)
widthRatio = float(layout.getPreferredBounds(component).width) / widthDivisor # for scaling x and width
heightRatio = float(layout.getPreferredBounds(component).height) / heightDivisor # for scaling y and height

Edit: added the word editor to further clarify the difference between the designer window environment and the designer template environment, and added a missing import from the preceding code example

3 Likes