Transform Questions

I basically took an what was an Expression case statement to determine background color on a box, and turned each case into an IF/ELIF to put into a script, and then added the transform to add some dark mode compatibility to some things that didn't look so nice in dark mode. Just kind of messing around with it, but notice on the application if I change screens back and forth, it defaults the #FFFFFF quite often, and if I don't even put an else it will just lose the background color property all together and show an error. So clearly I am doing something I shouldn't be, but I don't quite understand the issue. if I open it in the designer, it always knows the right output for the color field, but in application it almost seems like maybe the script takes too long and it just errors?

Here is another example. Some more context is when in Dark mode, it works perfectly. The issues are only when not in Dark mode.

Sorry, I looked at the Wikihow thing you linked don't really see this </> box.

if "dark" in value:
	if self.getSibling("Label_55").props.text == 'First Shift':
		return "var(--qual-8)"
	elif self.getSibling("Label_55").props.text == 'Second Shift':
		return "var(--qual-9)"
	elif self.getSibling("Label_55").props.text == 'Third Shift':
		return "var(--qual-10)"

else:
	if self.props.ControlIndicator == 0:
		return self.props.States[0].FillColor
	elif self.props.ControlIndicator == 1:
		return self.props.States[1].FillColor
	elif self.props.ControlIndicator == 2:
		return self.props.States[2].FillColor
	elif self.props.ControlIndicator == 3:
		return self.props.States[3].FillColor
	elif self.props.ControlIndicator == 4:
		return self.props.States[4].FillColor
	else :
		return '#FFFFFF'

You may need to use an expression structure binding instead. What you may be running into is that the only time the transforms will execute is when the bound value changes. Since this is a single value, any other values that get evaluated to make a color choice won't change the color unless the binding value changes. If the binding value updates before the other values in your transform script, the script may return your default value.

When using the expression structure, put your other properties in the structure as well so that when any of them change, the transform is re-evaluated/executed to update the color properly.

That's my guess as to why it's not working as expected.

1 Like

Ideally you would use a Map Transform and let the built-in theme colors sort themselves out and give good contrast for light and dark themes.

The other thing I would recommend is that you create a custom property on the view to hold the shift selection. That way you can avoid all the getSibling syntax which can easily break when you move stuff in and out of containers. The property binding would be simply, view.custom.shiftName (or whatever you've called it).

I'd also probably change it to view.custom.shiftNumber (1, 2 or 3) and use that instead of strings. Wherever you want to display the string use a map transform on the label's text binding to convert 1 to "First Shift", etc.

If you're going to need the string in several places then create view.custom.shiftString as well and put the map transform on that. Then all your labels can just point to that custom property and if you ever need to modify the text it only has to be done once. (If it's used across multiple views then move both out to session variables.)

2 Likes

Script transforms should be your last resort. If you can do it using another method, that should always be used for performance and scalability.

Also, it seems like you're misunderstanding the power that CSS provides in particular for theming, by allowing you to simply use colour variables in your UI, and these can change actual colour values when you switch between themes.

When the theme changes in Ignition, the CSS styling files are swapped out accordingly. Some of these theme files include colour variables such as --neutral-20 which is included in IA's themes. --neutral-20 in the light theme is a dark grey, however it is defined as a light grey in the dark theme. In a similar fashion, you should be creating your own light and dark themes which inherit from IA's theme files, and within it add colour variables for what you need. For example, you might have a --label-font-colour: #2b2b2b; variable defined in your light theme variable CSS file, and define it as --label-font-colour: #fff; in your dark theme.

You should never be swapping out colours based on theme using bindings. Doing this will waste server resources on functionality that can be handled by the client.

Another thing, I don't normally recommend referencing CSS variables directly in your UI; I prefer to reference these within Perspective Styles and then use these in your UI instead. The main reason is that CSS variables aren't transparent; they don't appear in dropdown lists for selection, and their definitions are hidden away in the theme files / adv. stylesheet which most users will not have the knowledge about.

2 Likes

Built-in Theme Colors.

1 Like

I wish there were descriptions/examples of what these colours are used for. I've never worked out what the --div* and --seq* colours are for...

Also, I don't know how possible it is with html/css, but it'd also be nice if the columns with the same colour for diff themes were merged:

1 Like

Ah these were originally in Expression structure, but I read about script tranforms and re wrote the Case/Switch statement (Forget which it was in) to an If/elif and threw it into the script transform.

Perhaps I will re write the old expression and try it that way!

Interesting, I was not aware of this Map functionality. I will give this a look, thanks!!

Stick to the Expression Structure where at all possible. They don't have the overhead of firing up the script interpreter so they're faster and don't load the gateway so much. Their bigger bonus is that any references in the expression are (behind the scenes) added to an Ignition trigger list (I don't know the proper term) so that if a tag or property used in the expression changes, the expression automatically re-evaluates and your view will update. It's brilliant!

1 Like

That makes sense. It worked great until I tried the script transform, so may as well just go back to it! Thanks!

Subscription.

2 Likes

Not sure if this is the best way to do it, but threw the one box into an expression transform bound to session.props.theme property and it seems to have no issues now! I will have to look at the other suggestions still and work through them.

if({value} = 'dark' || {value} = 'dark-cool' || {value} = 'dark-warm' , {session.custom.TextBoxColors.LabelDark}, case(
{this.props.ControlIndicator},
0, {this.props.States[0].FillColor},
1, {this.props.States[1].FillColor},
2, {this.props.States[2].FillColor},
3, {this.props.States[3].FillColor},
4, {this.props.States[4].FillColor},
'#FFFFFF'
))

This syntax might be a little clearer and automatically include any future dark-xxxx themes.

if(
    left({session.props.theme}, 4) = "dark", 
   {session.custom.TextBoxColors.LabelDark}, 
    case(
        {this.props.ControlIndicator},
        0, {this.props.States[0].FillColor},
        1, {this.props.States[1].FillColor},
        2, {this.props.States[2].FillColor},
        3, {this.props.States[3].FillColor},
        4, {this.props.States[4].FillColor},
        '#FFFFFF'
    )
)

I might also move your States[x].FillColor array out to the session properties so that they'd be available to all views and components. Otherwise you have to edit them anytime you change your theme. Of course, you should really be using CSS styles and not hard-coding!

2 Likes

Can you explain what CSS styles means, is that the --Qual-8 stuff? That button specifically is unique with all of them colors and not re-used anywhere else. Right now, I have been moving all colors into custom session bindings and using the theme colors. I just started this project with hard coding before recently stumbling on those theme colors when I wanted to figure out why my project looked so absolutely awful in dark mode. As a lover of dark mode, it was truly hurting my feelings.

CSS stands for Cascading Style Sheets and is an underlying technology of modern web design. Go through the Themes and Styles videos on Inductive University Course List - Learn Ignition Free.

1 Like

I guess just keep on banging down the non-CSS theme route then.. It's nowhere near as performant as using css theme variables and it will limit your scalability :person_shrugging:

4 Likes

So, the Ideal or generally accepted intelligent method is what? binding everything to a single CSS theme, no coding to change depending on situation? Because I changed basically every color to a CSS style bound to the custom session.props so that way if I change the color in the custom session prop it updates the entire project and all screens referencing it at the same time. I can tell from everyone's tone I am doing it wrong, but I am not understanding what is "right". If i knew how to do it "right" I don't think I would be here right now typing this!

css is vast, and you should really read some tutorials. There's a quadrillion of them on the internet.
Just learn enough to know what it's used for. You'll learn how to use it along the way. No one in their right mind tries to learn ALL of css anyway, when you can just google.

In your particular case, here's what you need to know:
Your browser, when displaying a web page, can apply styles to change how it is rendered. Color, shape, position, animations...
The themes work by switching a collection of style to another one. Not by changing anything on the components themselves.
For example, you have a button. You could hard code its color, let's say red, and change that to blue based on whether a style is selected or not. But that makes things complicated and inefficient.
Now let's make your button's color a css variable, let's say --some-button-color. Now you can assign red to this variable's value in a theme, and blue in another one. When the theme changes, the value changes as well, and your button's color will change.

If your button needs to have different colors for different cases, inside of one theme, you'll use a binding to change the css variable, so that it will update the 'state' color depending on some value, and then for each state the client, through css, will know what color to use depending on what theme is selected.

So you still have a binding on your component's color, something like

case ({some.prop},
    'state1', '--color-state-1',
    'state2', '--color-state-2',
    'state3', '--color-state-3',
    '--some-default-color'
)

Of course, don't use stupid names like these.