Skip to content

Commit c22200e

Browse files
authored
Merge pull request #3376 from ControlSystemStudio/CSSTUDIO-3196
CSSTUDIO-3196 Change the semantics of colors defined to be equal to other colors
2 parents 0518d3c + 4dcc8a2 commit c22200e

File tree

2 files changed

+82
-24
lines changed

2 files changed

+82
-24
lines changed

app/display/model/src/main/java/org/csstudio/display/builder/model/persist/NamedWidgetColors.java

Lines changed: 69 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
import java.util.Collection;
1111
import java.util.Collections;
12+
import java.util.HashSet;
1213
import java.util.LinkedHashMap;
1314
import java.util.Map;
1415
import java.util.Optional;
@@ -133,6 +134,15 @@ void define(final NamedWidgetColor color)
133134
colors.put(color.getName(), color);
134135
}
135136

137+
/** Define a name to point to a named color
138+
* @param name Name of the color
139+
* @param color Named color
140+
*/
141+
void defineAlias(String name, final NamedWidgetColor color)
142+
{
143+
colors.put(name, color);
144+
}
145+
136146
/** Get named color
137147
* @param name Name of the color
138148
* @return Named color, if known
@@ -142,6 +152,51 @@ public Optional<NamedWidgetColor> getColor(final String name)
142152
return Optional.ofNullable(colors.get(name));
143153
}
144154

155+
sealed interface ColorDefinition permits RGBA, FromNamedWidgetColor, Alias {}
156+
private record RGBA (int red, int green, int blue, int alpha) implements ColorDefinition { }
157+
private record FromNamedWidgetColor(NamedWidgetColor namedWidgetColor) implements ColorDefinition { };
158+
private record Alias (NamedWidgetColor color) implements ColorDefinition { };
159+
160+
/** Parse the color definition
161+
* @param colorDefinitionString Color definition
162+
* @return Optionally (when successful), an instance of ColorDefinition representing the result of parsing
163+
*/
164+
public Optional<ColorDefinition> parseColorDefinition(final String colorDefinitionString)
165+
{
166+
String colorDefinitionStringTrimmed = colorDefinitionString.trim();
167+
if (colorDefinitionStringTrimmed.startsWith("alias")) {
168+
String colorDefinitionsStringWithoutAlias = colorDefinitionStringTrimmed.substring(5).trim();
169+
if (colorDefinitionsStringWithoutAlias.startsWith("(") && colorDefinitionsStringWithoutAlias.endsWith(")")) {
170+
String colorName = colorDefinitionsStringWithoutAlias.substring(1,colorDefinitionsStringWithoutAlias.length()-1).trim();
171+
if (colors.containsKey(colorName)) {
172+
NamedWidgetColor color = colors.get(colorName);
173+
return Optional.of(new Alias(color));
174+
} else {
175+
return Optional.empty();
176+
}
177+
}
178+
else {
179+
return Optional.empty();
180+
}
181+
}
182+
else if (colors.containsKey(colorDefinitionStringTrimmed)) {
183+
NamedWidgetColor color = colors.get(colorDefinitionStringTrimmed);
184+
return Optional.of(new FromNamedWidgetColor(color));
185+
}
186+
else {
187+
final StringTokenizer tokenizer = new StringTokenizer(colorDefinitionString, ",");
188+
try {
189+
final int red = Integer.parseInt(tokenizer.nextToken().trim());
190+
final int green = Integer.parseInt(tokenizer.nextToken().trim());
191+
final int blue = Integer.parseInt(tokenizer.nextToken().trim());
192+
final int alpha = tokenizer.hasMoreTokens() ? Integer.parseInt(tokenizer.nextToken().trim()) : 255;
193+
return Optional.of(new RGBA(red, green, blue, alpha));
194+
} catch (Throwable throwable) {
195+
return Optional.empty();
196+
}
197+
}
198+
}
199+
145200
/** Resolve a named color
146201
* @param color Predefined color
147202
* @return Color as provided unless it was redefined
@@ -156,35 +211,26 @@ public NamedWidgetColor resolve(final NamedWidgetColor color)
156211
*/
157212
public Collection<NamedWidgetColor> getColors()
158213
{
159-
return Collections.unmodifiableCollection(colors.values());
214+
return Collections.unmodifiableSet(new HashSet<>(colors.values()));
160215
}
161216

162217
@Override
163218
protected void parse ( final String name, final String value ) throws Exception {
219+
Optional<ColorDefinition> optionalColorDefinition = parseColorDefinition(value);
164220

165-
Optional<NamedWidgetColor> optionalColor = getColor(value);
166-
167-
if ( optionalColor.isPresent() ) {
168-
169-
NamedWidgetColor namedColor = optionalColor.get();
170-
171-
define(new NamedWidgetColor(name, namedColor.getRed(), namedColor.getGreen(), namedColor.getBlue(), namedColor.getAlpha()));
172-
221+
if (optionalColorDefinition.isEmpty()) {
222+
throw new Exception("Cannot parse color '" + name + "' from '" + value + "'");
173223
} else {
174-
175-
final StringTokenizer tokenizer = new StringTokenizer(value, ",");
176-
177-
try {
178-
179-
final int red = Integer.parseInt(tokenizer.nextToken().trim());
180-
final int green = Integer.parseInt(tokenizer.nextToken().trim());
181-
final int blue = Integer.parseInt(tokenizer.nextToken().trim());
182-
final int alpha = tokenizer.hasMoreTokens() ? Integer.parseInt(tokenizer.nextToken().trim()) : 255;
183-
184-
define(new NamedWidgetColor(name, red, green, blue, alpha));
185-
186-
} catch ( Throwable ex ) {
187-
throw new Exception("Cannot parse color '" + name + "' from '" + value + "'", ex);
224+
ColorDefinition colorDefinition = optionalColorDefinition.get();
225+
if (colorDefinition instanceof RGBA rgba) {
226+
define(new NamedWidgetColor(name, rgba.red, rgba.green, rgba.blue, rgba.alpha));
227+
} else if (colorDefinition instanceof FromNamedWidgetColor fromNamedWidgetColor) {
228+
NamedWidgetColor namedWidgetColor = fromNamedWidgetColor.namedWidgetColor;
229+
define(new NamedWidgetColor(name, namedWidgetColor.getRed(), namedWidgetColor.getGreen(), namedWidgetColor.getBlue(), namedWidgetColor.getAlpha()));
230+
} else if (colorDefinition instanceof Alias alias) {
231+
defineAlias(name, alias.color);
232+
} else {
233+
throw new Exception("Unhandled case: " + colorDefinition.toString()); // This should never happen.
188234
}
189235

190236
}

app/display/model/src/main/resources/examples/color.def

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,23 @@
11
# Named colors
22
#
33
# Format:
4-
# NameOfColor = red, green, blue [, alpha ] | PreviouslyDefinedNameOfColor
4+
# NameOfColor = red, green, blue [, alpha ] | PreviouslyDefinedNameOfColor | alias(PreviouslyDefinedNameOfColor)
55
# with values in 0..255 range.
66
#
77
# Whenever possible, use named colors in displays
88
# instead of arbitrary red/green/blue values.
9+
#
10+
# Writing 'NameOfColor = PreviouslyDefinedNameOfColor' defines
11+
# a new color with the name 'NameOfColor', whose RGB-values
12+
# are identical to the RGB-values of 'PreviouslyDefinedNameOfColor'.
13+
#
14+
# In contrast, writing 'NameOfColor = alias(PreviouslyDefinedNameOfColor)'
15+
# will result in the color name 'NameOfColor' redirecting to the color
16+
# 'PreviouslyDefinedNameOfColor'. The effect is that the color
17+
# 'PreviouslyDefinedColor' replaces occurrences of the color 'NameOfColor'.
18+
#
19+
# Color names as well as the keyword 'alias' are case-sensitive.
20+
#
921

1022
# ------- Predefined colors ----------------
1123
# May be overridden in here

0 commit comments

Comments
 (0)