One minor improvement: MultipleGradientPaint
is the supertype for all the gradient paints, so you can just isinstance()
for that, instead of importing all the subclasses. The rest of it looks pretty solid though.
1 Like
Thanks Paul! That definitely helped clean up that ugly part of the script. In case it helps anyone, here is the current iteration of the script module. Added in the optional ability to replace the gradient paints with an approximate average color representation of the gradient (place in a script module and then call the main()
function passing in a reference to your window root container).
"""MacOS has significant issues in the Designer with gradient paints due
to a bug, but there is no anticipated fix date. Instead need to change
all gradient paint properties to a solid paint. This module is to help
speed up the process of locating properties with gradient data types and,
if desired, automatically replacing values with a solid color.
Todo:
* Fix docstring Args type hints.
"""
from java.awt import Color
from com.inductiveautomation.factorypmi.application.components.template import VisionTemplate
from com.inductiveautomation.ignition.client.util.gui.paints import MultipleGradientPaint
def get_avg_gradient_color(gradient):
"""Takes a gradient paint value and returns the rough approximation of the average of
the gradient colors. Note that this does not account for the spacing of the gradient
inflection points and therefore will give equal weight to all colors in the gradient.
Args:
gradient (MultipleGradientPaint): A gradient paint class object of the
MultipleGradientPaint class or sub classes.
Returns:
java.awt.Color: Avg color of the input gradient paint.
"""
colors = gradient.getColors()
r, g, b = 0, 0, 0
for c in colors:
r += c.getRed()**2
g += c.getGreen()**2
b += c.getBlue()**2
avg_color = Color(
int((r / len(colors)) ** 0.5),
int((g / len(colors)) ** 0.5),
int((b / len(colors)) ** 0.5)
)
return avg_color
def _gradient_find_and_replace(comp, replace_color=False, path="", template_name=None):
"""Recursively iterates through nested objects to find properties
that are gradient paint data types and prints the object path/property
to the console. Can optionally replace the property values with a solid
color.
Args:
comp (component): Object to start the search at. Typically pass in the window
root container.
replace_color (bool, optional): Defaults to False. If true, the function will
set the properties that contain gradient paints to a solid color that is an
average of the gradient colors. Note that this CANNOT change Template Instance
properties permanently (they will revert when you reopen the window). You
would need to run this script within a template definition and save it.
path (str, optional): Used in the recursion to keep track of the object path. When
calling this function, this arg should be omitted.
template_name (str, optional): Used in the recursion to keep track if one of the
objects parents is a template. When calling this function, this arg should be
omitted.
Returns:
None
Function is purely a helper function that prints to the console.
"""
path = "{}/{}".format(path, comp.name)
for obj in comp.getComponents():
# Iterate through objects that contain other objects.
if hasattr(obj, "getComponents"):
if isinstance(obj, VisionTemplate):
template_name, path = obj.name, ""
_gradient_find_and_replace(obj, replace_color, path, template_name)
# Find object properties that have gradient data types
root_type = "Window" if template_name is None else "Template"
print_strings = ["{} Path: {}/{}".format(root_type, path, obj.name)]
for el in dir(obj):
try:
if isinstance(getattr(obj, el), MultipleGradientPaint):
sub_print_str = " Property Name: {}"
# Replace with the average color if indicated.
if replace_color:
setattr(obj, el, get_avg_gradient_color(getattr(obj, el)))
sub_print_str += " (color replaced)"
print_strings.append(sub_print_str.format(el))
except:
# Many legitimate reasons the try can fail.
pass
if len(print_strings) > 1:
print "\n".join(print_strings)
return
def main(comp, replace_color=False):
"""Used as an abstraction layer on top of the gradient util function(s) to simplify
running the helper module
Arguments:
comp (component): Object to start the search at. Typically pass in the window
root container.
replace_color (bool, optional): Defaults to False. If true, the function will
set the properties that contain gradient paints to a solid color that is an
average of the gradient colors. Note that this CANNOT change Template Instance
properties permanently (they will revert when you reopen the window). You
would need to run this script within a template definition and save it.
Return:
None
"""
print "\nGradient paint search starting.\n"
_gradient_find_and_replace(comp, replace_color)
print "\nGradient paint search complete.\n"
return