Skip to content

Commit 23c47b8

Browse files
authored
Merge pull request #3245 from ControlSystemStudio/CSSTUDIO-2939
CSSTUDIO-2939 Add property "SVG Rendering Resolution Factor" to the Picture and Symbol widgets
2 parents 9d7b218 + 5a25367 commit 23c47b8

File tree

8 files changed

+90
-5
lines changed

8 files changed

+90
-5
lines changed

app/display/model/src/main/java/org/csstudio/display/builder/model/Messages.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,7 @@ public class Messages
267267
WidgetProperties_ReadbackPVName,
268268
WidgetProperties_ReadbackPVValue,
269269
WidgetProperties_ResizeBehavior,
270+
WidgetProperties_SVGRenderingResolutionFactor,
270271
WidgetProperties_RingColor,
271272
WidgetProperties_RingWidth,
272273
WidgetProperties_Rotation,

app/display/model/src/main/java/org/csstudio/display/builder/model/Preferences.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ public class Preferences
3737
@Preference(name="macros") private static String macro_spec;
3838
/** Preference setting */
3939
@Preference public static boolean enable_saved_on_comments;
40+
/** Preference setting */
41+
@Preference public static boolean enable_svg_rendering_resolution_factor;
42+
4043
private static Macros macros;
4144

4245
static

app/display/model/src/main/java/org/csstudio/display/builder/model/widgets/PictureWidget.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import java.util.List;
1616

1717
import org.csstudio.display.builder.model.Messages;
18+
import org.csstudio.display.builder.model.Preferences;
1819
import org.csstudio.display.builder.model.Version;
1920
import org.csstudio.display.builder.model.Widget;
2021
import org.csstudio.display.builder.model.WidgetCategory;
@@ -103,6 +104,10 @@ public boolean configureFromXML(final ModelReader model_reader, final Widget wid
103104
public static final WidgetPropertyDescriptor<Boolean> propStretch =
104105
newBooleanPropertyDescriptor(WidgetPropertyCategory.DISPLAY, "stretch_image", Messages.WidgetProperties_StretchToFit);
105106

107+
/** 'svg_rendering_resolution_factor': */
108+
public static final WidgetPropertyDescriptor<Double> propSVGRenderingResolutionFactor =
109+
newDoublePropertyDescriptor(WidgetPropertyCategory.DISPLAY, "svg_rendering_resolution_factor", Messages.WidgetProperties_SVGRenderingResolutionFactor);
110+
106111
/**
107112
* An opacity property. Controlling it from a rule or script works as a
108113
* way to do a simple animation.
@@ -114,6 +119,7 @@ public boolean configureFromXML(final ModelReader model_reader, final Widget wid
114119
private volatile WidgetProperty<Boolean> stretch_image;
115120
private volatile WidgetProperty<Double> rotation;
116121
private volatile WidgetProperty<Double> opacity;
122+
private volatile WidgetProperty<Double> svgRenderingResolutionFactor;
117123

118124
/** Constructor */
119125
public PictureWidget()
@@ -129,7 +135,10 @@ protected void defineProperties(final List<WidgetProperty<?>> properties)
129135
properties.add(stretch_image = propStretch.createProperty(this, false));
130136
properties.add(rotation = propRotation.createProperty(this, 0.0));
131137
properties.add(opacity = propOpacity.createProperty(this, 1.0));
132-
138+
svgRenderingResolutionFactor = propSVGRenderingResolutionFactor.createProperty(this, 1.0);
139+
if (Preferences.enable_svg_rendering_resolution_factor) {
140+
properties.add(svgRenderingResolutionFactor);
141+
}
133142
}
134143

135144
/** @return 'rotation' property */
@@ -156,6 +165,11 @@ public WidgetProperty<Double> propOpacity()
156165
return opacity;
157166
}
158167

168+
/** @return 'svgRenderingResolutionFactor' property */
169+
public WidgetProperty<Double> propSVGRenderingResolutionFactor() {
170+
return svgRenderingResolutionFactor;
171+
}
172+
159173
@Override
160174
public WidgetConfigurator getConfigurator(final Version persisted_version)
161175
throws Exception

app/display/model/src/main/java/org/csstudio/display/builder/model/widgets/SymbolWidget.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626
import org.csstudio.display.builder.model.ArrayWidgetProperty;
2727
import org.csstudio.display.builder.model.Messages;
28+
import org.csstudio.display.builder.model.Preferences;
2829
import org.csstudio.display.builder.model.Version;
2930
import org.csstudio.display.builder.model.Widget;
3031
import org.csstudio.display.builder.model.WidgetCategory;
@@ -87,6 +88,9 @@ public Widget createWidget ( ) {
8788
/** Property */
8889
public static final WidgetPropertyDescriptor<String> propFallbackSymbol = newFilenamePropertyDescriptor (WidgetPropertyCategory.BEHAVIOR, "fallback_symbol", Messages.WidgetProperties_FallbackSymbol);
8990
public static final WidgetPropertyDescriptor<Boolean> propRunActionsOnMouseClick = newBooleanPropertyDescriptor (WidgetPropertyCategory.BEHAVIOR, "run_actions_on_mouse_click", Messages.WidgetProperties_RunActionsOnMouseClick);
91+
/** 'svg_rendering_resolution_factor': */
92+
public static final WidgetPropertyDescriptor<Double> propSVGRenderingResolutionFactor = newDoublePropertyDescriptor(WidgetPropertyCategory.DISPLAY, "svg_rendering_resolution_factor", Messages.WidgetProperties_SVGRenderingResolutionFactor);
93+
9094

9195
/** 'items' property: list of items (string properties) for combo box */
9296
public static final ArrayWidgetProperty.Descriptor<WidgetProperty<String> > propSymbols = new ArrayWidgetProperty.Descriptor< >(
@@ -121,6 +125,7 @@ public Widget createWidget ( ) {
121125
private volatile WidgetProperty<String> fallbackSymbol;
122126
private volatile WidgetProperty<WidgetColor> disconnectOverlayColor;
123127
private volatile WidgetProperty<Boolean> run_actions_on_mouse_click;
128+
private volatile WidgetProperty<Double> svgRenderingResolutionFactor;
124129

125130
/** Returns 'symbol' property: element for list of 'symbols' property */
126131
private static WidgetPropertyDescriptor<String> propSymbol( int index ) {
@@ -225,6 +230,11 @@ public WidgetProperty<Boolean> propRunActionsOnMouseClick() {
225230
return run_actions_on_mouse_click;
226231
}
227232

233+
/** @return 'svgRenderingResolutionFactor' property */
234+
public WidgetProperty<Double> propSVGRenderingResolutionFactor() {
235+
return svgRenderingResolutionFactor;
236+
}
237+
228238
@Override
229239
protected void defineProperties ( final List<WidgetProperty<?>> properties ) {
230240

@@ -243,6 +253,12 @@ protected void defineProperties ( final List<WidgetProperty<?>> properties ) {
243253
properties.add(enabled = propEnabled.createProperty(this, true));
244254
properties.add(preserve_ratio = propPreserveRatio.createProperty(this, true));
245255
properties.add(fallbackSymbol = propFallbackSymbol.createProperty(this, DEFAULT_SYMBOL));
256+
257+
svgRenderingResolutionFactor = propSVGRenderingResolutionFactor.createProperty(this, 1.0);
258+
if (Preferences.enable_svg_rendering_resolution_factor) {
259+
properties.add(svgRenderingResolutionFactor);
260+
}
261+
246262
WidgetColor alarmInvalidColor =
247263
WidgetColorService.getColor(NamedWidgetColors.ALARM_INVALID);
248264
WidgetColor defaultDisconnectedOverlayColor =

app/display/model/src/main/resources/display_model_preferences.properties

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,3 +88,10 @@ skip_defaults=true
8888

8989
# Add a comment containing the date, time, and username when saving an OPI in the Display Editor.
9090
enable_saved_on_comments=true
91+
92+
# Enable the "SVG Rendering Resolution Factor" widget property to the Symbol and Picture widgets.
93+
# This functionality can enable a sharper image when zooming in, at the expense of a quadratic
94+
# increase in memory consumption. E.g., by setting the SVG rendering resolution factor to 2.0, an
95+
# SVG can be rendered at twice the width and twice the height, but the memory required to
96+
# represent the image grows by a factor of four.
97+
org.csstudio.display.builder.model/enable_svg_rendering_resolution_factor=false

app/display/model/src/main/resources/org/csstudio/display/builder/model/messages.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,7 @@ WidgetProperties_Skin=Skin
285285
WidgetProperties_Square=Square
286286
WidgetProperties_StartFromZero=Start From Zero
287287
WidgetProperties_StretchToFit=Stretch to Fit
288+
WidgetProperties_SVGRenderingResolutionFactor=SVG Rendering Resolution Factor
288289
WidgetProperties_Symbol=Symbol
289290
WidgetProperties_Symbols=Symbols
290291
WidgetProperties_SymbolValue=Text Symbol value

app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/PictureRepresentation.java

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ public class PictureRepresentation extends JFXBaseRepresentation<ImageView, Pict
4545
/** Change the image size, rotation or preserve_ratio */
4646
private final DirtyFlag dirty_style = new DirtyFlag();
4747
private final UntypedWidgetPropertyListener styleChangedListener = this::styleChanged;
48+
private final UntypedWidgetPropertyListener svgRenderingResolutionFactorChangedListener = this::svgRenderingResolutionFactorChanged;
4849
private final WidgetPropertyListener<String> contentChangedListener = this::contentChanged;
4950

5051
private volatile Image img_loaded;
@@ -96,6 +97,7 @@ protected void registerListeners()
9697
model_widget.propStretch().addUntypedPropertyListener(styleChangedListener);
9798
model_widget.propRotation().addUntypedPropertyListener(styleChangedListener);
9899
model_widget.propOpacity().addUntypedPropertyListener(styleChangedListener);
100+
model_widget.propSVGRenderingResolutionFactor().addUntypedPropertyListener(svgRenderingResolutionFactorChangedListener);
99101
// styleChanged() will be called by contentChanged()
100102

101103
model_widget.propFile().addPropertyListener(contentChangedListener);
@@ -117,6 +119,7 @@ protected void unregisterListeners()
117119
model_widget.propRotation().removePropertyListener(styleChangedListener);
118120
model_widget.propOpacity().removePropertyListener(styleChangedListener);
119121
model_widget.propFile().removePropertyListener(contentChangedListener);
122+
model_widget.propSVGRenderingResolutionFactor().removePropertyListener(svgRenderingResolutionFactorChangedListener);
120123
super.unregisterListeners();
121124
}
122125

@@ -126,6 +129,12 @@ private void styleChanged(final WidgetProperty<?> property, final Object old_val
126129
toolkit.scheduleUpdate(this);
127130
}
128131

132+
private void svgRenderingResolutionFactorChanged(final WidgetProperty<?> property, final Object oldValue, Object newValue) {
133+
// Update the rendered SVG:
134+
contentChanged(model_widget.propFile(), model_widget.propFile().getValue(), model_widget.propFile().getValue());
135+
}
136+
137+
129138
private void contentChanged(final WidgetProperty<String> property, final String old_value, final String new_value)
130139
{
131140
// Imagine if updateChanges executes here. Mark is cleared and image updated before new image loaded.
@@ -262,10 +271,23 @@ else if (h_prime < pic_h)
262271
* @param height
263272
* @return An {@link Image} or <code>null</code>.
264273
*/
265-
private void loadSVG(String fileName, double width, double height){
266-
274+
private void loadSVG(String fileName, double width, double height) {
267275
String imageFileName = resolveImageFile(fileName);
268-
img_loaded = SVGHelper.loadSVG(imageFileName, width, height);
276+
277+
double svg_rendering_resolution_factor = model_widget.propSVGRenderingResolutionFactor().getValue();
278+
279+
double renderingWidth;
280+
double renderingHeight;
281+
if (!Double.isNaN(svg_rendering_resolution_factor) && svg_rendering_resolution_factor > 0) {
282+
renderingWidth = svg_rendering_resolution_factor * width;
283+
renderingHeight = svg_rendering_resolution_factor * height;
284+
} else {
285+
logger.log(Level.WARNING, "The SVG Rendering Factor is not set to a value greater than 0.0! Setting it to 1.0.");
286+
renderingWidth = width;
287+
renderingHeight = height;
288+
}
289+
290+
img_loaded = SVGHelper.loadSVG(imageFileName, renderingWidth, renderingHeight);
269291
if(img_loaded == null){
270292
loadDefaultImage();
271293
}

app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/SymbolRepresentation.java

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ public class SymbolRepresentation extends RegionBaseRepresentation<StackPane, Sy
100100
private final UntypedWidgetPropertyListener contentListener = this::contentChanged;
101101
private final UntypedWidgetPropertyListener geometryListener = this::geometryChanged;
102102
private final UntypedWidgetPropertyListener styleListener = this::styleChanged;
103+
private final UntypedWidgetPropertyListener svgRenderingResolutionFactorChangedListener = this::svgRenderingResolutionFactorChanged;
103104
private final WidgetPropertyListener<VType> valueListener = this::valueChanged;
104105
private final WidgetPropertyListener<List<WidgetProperty<String>>> symbolsListener = this::symbolsChanged;
105106
private final WidgetPropertyListener<Integer> indexListener = this::initialIndexChanged;
@@ -610,6 +611,7 @@ protected void registerListeners()
610611
model_widget.propEnabled().addUntypedPropertyListener(styleListener);
611612
model_widget.propShowIndex().addUntypedPropertyListener(styleListener);
612613
model_widget.propTransparent().addUntypedPropertyListener(styleListener);
614+
model_widget.propSVGRenderingResolutionFactor().addUntypedPropertyListener(svgRenderingResolutionFactorChangedListener);
613615

614616
if (!toolkit.isEditMode())
615617
model_widget.runtimePropValue().addPropertyListener(valueListener);
@@ -639,6 +641,7 @@ protected void unregisterListeners()
639641
model_widget.propEnabled().removePropertyListener(styleListener);
640642
model_widget.propShowIndex().removePropertyListener(styleListener);
641643
model_widget.propTransparent().removePropertyListener(styleListener);
644+
model_widget.propSVGRenderingResolutionFactor().removePropertyListener(svgRenderingResolutionFactorChangedListener);
642645

643646
if (!toolkit.isEditMode())
644647
model_widget.runtimePropValue().removePropertyListener(valueListener);
@@ -788,6 +791,11 @@ void setSymbolSize ( double width, double height, boolean preserveRatio ) {
788791
}
789792
}
790793

794+
private void svgRenderingResolutionFactorChanged(final WidgetProperty<?> property, final Object oldValue, Object newValue) {
795+
// Update the rendered SVG:
796+
symbolChanged(null, null, null);
797+
}
798+
791799
private void styleChanged ( final WidgetProperty<?> property, final Object oldValue, final Object newValue ) {
792800
dirtyStyle.mark();
793801
toolkit.scheduleUpdate(this);
@@ -1027,7 +1035,20 @@ void resize(double width, double height, boolean preserveRatio){
10271035
* @return An {@link Image} or <code>null</code>.
10281036
*/
10291037
Image loadSVG(final String imageFileName, double width, double height){
1030-
return SVGHelper.loadSVG(imageFileName, width, height);
1038+
double svg_rendering_resolution_factor = model_widget.propSVGRenderingResolutionFactor().getValue();
1039+
1040+
double renderingWidth;
1041+
double renderingHeight;
1042+
if (!Double.isNaN(svg_rendering_resolution_factor) && svg_rendering_resolution_factor > 0) {
1043+
renderingWidth = svg_rendering_resolution_factor * width;
1044+
renderingHeight = svg_rendering_resolution_factor * height;
1045+
} else {
1046+
logger.log(Level.WARNING, "The SVG Rendering Factor is not set to a value greater than 0.0! Setting it to 1.0.");
1047+
renderingWidth = width;
1048+
renderingHeight = height;
1049+
}
1050+
1051+
return SVGHelper.loadSVG(imageFileName, renderingWidth, renderingHeight);
10311052
}
10321053
}
10331054
}

0 commit comments

Comments
 (0)