Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ public class Messages
WidgetProperties_ConfirmMessage,
WidgetProperties_Connected,
WidgetProperties_CornerHeight,
WidgetProperties_CornerRadius,
WidgetProperties_CornerWidth,
WidgetProperties_CursorCrosshair,
WidgetProperties_CursorInfo,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,15 @@
import java.util.List;

import org.csstudio.display.builder.model.MacroizedWidgetProperty;
import org.csstudio.display.builder.model.Messages;
import org.csstudio.display.builder.model.Version;
import org.csstudio.display.builder.model.Widget;
import org.csstudio.display.builder.model.WidgetCategory;
import org.csstudio.display.builder.model.WidgetConfigurator;
import org.csstudio.display.builder.model.WidgetDescriptor;
import org.csstudio.display.builder.model.WidgetProperty;
import org.csstudio.display.builder.model.WidgetPropertyCategory;
import org.csstudio.display.builder.model.WidgetPropertyDescriptor;
import org.csstudio.display.builder.model.persist.ModelReader;
import org.csstudio.display.builder.model.persist.NamedWidgetFonts;
import org.csstudio.display.builder.model.persist.WidgetFontService;
Expand Down Expand Up @@ -223,6 +226,9 @@
return new ActionButtonConfigurator(persisted_version);
}

public static final WidgetPropertyDescriptor<Integer> propCornerRadius =
CommonWidgetProperties.newIntegerPropertyDescriptor(WidgetPropertyCategory.DISPLAY, "corner_radius", Messages.WidgetProperties_CornerRadius);

// Has pv_name and pv_writable, but no pv_value which would make it a WritablePVWidget
private volatile WidgetProperty<Boolean> enabled;
private volatile WidgetProperty<String> text;
Expand All @@ -237,6 +243,7 @@
private volatile WidgetProperty<Boolean> confirm_dialog;
private volatile WidgetProperty<String> confirm_message;
private volatile WidgetProperty<String> password;
private volatile WidgetProperty<Integer> corner_radius;

Check warning on line 246 in app/display/model/src/main/java/org/csstudio/display/builder/model/widgets/ActionButtonWidget.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Rename this field "corner_radius" to match the regular expression '^[a-z][a-zA-Z0-9]*$'.

See more on https://sonarcloud.io/project/issues?id=ControlSystemStudio_phoebus&issues=AaF9TmMKCRnYTt1RP2cG&open=AaF9TmMKCRnYTt1RP2cG&pullRequest=3990

/** Constructor */
public ActionButtonWidget()
Expand Down Expand Up @@ -271,6 +278,7 @@
properties.add(confirm_dialog = propConfirmDialog.createProperty(this, false));
properties.add(confirm_message = propConfirmMessage.createProperty(this, "Are your sure you want to do this?"));
properties.add(password = propPassword.createProperty(this, ""));
properties.add(corner_radius = propCornerRadius.createProperty(this, 3));

Check warning on line 281 in app/display/model/src/main/java/org/csstudio/display/builder/model/widgets/ActionButtonWidget.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Extract the assignment out of this expression.

See more on https://sonarcloud.io/project/issues?id=ControlSystemStudio_phoebus&issues=AaF9TmMKCRnYTt1RP2cF&open=AaF9TmMKCRnYTt1RP2cF&pullRequest=3990
}

@Override
Expand Down Expand Up @@ -310,13 +318,13 @@
{
return transparent;
}

/** @return 'horizontal_alignment' property */
public WidgetProperty<HorizontalAlignment> propHorizontalAlignment()
{
return horizontal_alignment;
}

/** @return 'vertical_alignment' property */
public WidgetProperty<VerticalAlignment> propVerticalAlignment()
{
Expand Down Expand Up @@ -358,4 +366,10 @@
{
return password;
}

/** @return 'corner_radius' property */
public WidgetProperty<Integer> propCornerRadius()

Check failure on line 371 in app/display/model/src/main/java/org/csstudio/display/builder/model/widgets/ActionButtonWidget.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Rename method "propCornerRadius" to prevent any misunderstanding/clash with field "propCornerRadius".

See more on https://sonarcloud.io/project/issues?id=ControlSystemStudio_phoebus&issues=AaF9TmMKCRnYTt1RP2cH&open=AaF9TmMKCRnYTt1RP2cH&pullRequest=3990
{
return corner_radius;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ WidgetProperties_ConfirmDialog=Confirmation Dialog
WidgetProperties_ConfirmMessage=Confirmation Message
WidgetProperties_Connected=Connected
WidgetProperties_CornerHeight=Corner Height
WidgetProperties_CornerRadius=Corner Radius
WidgetProperties_CornerWidth=Corner Width
WidgetProperties_CursorCrosshair=Cursor Crosshair
WidgetProperties_CursorInfo=Cursor Info
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ WidgetProperties_ConfirmDialog=Dialogue de confirmation
WidgetProperties_ConfirmMessage=Message de confirmation
WidgetProperties_Connected=Connecté
WidgetProperties_CornerHeight=Hauteur du coin
WidgetProperties_CornerRadius=Rayon du coin
WidgetProperties_CornerWidth=Largeur du coin
WidgetProperties_CursorCrosshair=Curseur en croix
WidgetProperties_CursorInfo=Info du curseur
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
/*******************************************************************************
* Copyright (c) 2025 Oak Ridge National Laboratory.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package org.csstudio.display.builder.model.widgets;

import org.csstudio.display.builder.model.DisplayModel;
import org.csstudio.display.builder.model.Widget;
import org.csstudio.display.builder.model.persist.ModelReader;
import org.csstudio.display.builder.model.persist.ModelWriter;
import org.csstudio.display.builder.model.persist.NamedWidgetFonts;
import org.csstudio.display.builder.model.persist.WidgetFontService;
import org.csstudio.display.builder.model.properties.HorizontalAlignment;
import org.csstudio.display.builder.model.properties.NamedWidgetFont;
import org.csstudio.display.builder.model.properties.RotationStep;
import org.csstudio.display.builder.model.properties.VerticalAlignment;
import org.junit.jupiter.api.Test;
import org.phoebus.ui.color.NamedWidgetColor;
import org.phoebus.ui.color.NamedWidgetColors;
import org.phoebus.ui.color.WidgetColorService;

import java.util.List;

import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;

/**
*Unit tests for {@link ActionButtonWidget}.
*/
@SuppressWarnings("nls")
public class ActionButtonWidgetTest

Check warning on line 37 in app/display/model/src/test/java/org/csstudio/display/builder/model/widgets/ActionButtonWidgetTest.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove redundant visibility modifiers from the methods of this test class.

See more on https://sonarcloud.io/project/issues?id=ControlSystemStudio_phoebus&issues=AaF9TmTBCRnYTt1RP2cI&open=AaF9TmTBCRnYTt1RP2cI&pullRequest=3990
{
/**
* Verify ActionButton default property values.
*/
@Test
public void testActionButtonWidgetDefaults()
{
final ActionButtonWidget button = new ActionButtonWidget();

assertThat(button.propText().getValue(), equalTo("No actions"));
assertThat(button.propFont().getValue(), equalTo(WidgetFontService.get(NamedWidgetFonts.DEFAULT)));
assertThat(button.propForegroundColor().getValue(), equalTo(WidgetColorService.getColor(NamedWidgetColors.TEXT)));
assertThat(button.propBackgroundColor().getValue(), equalTo(WidgetColorService.getColor(NamedWidgetColors.BUTTON_BACKGROUND)));
assertThat(button.propTransparent().getValue(), equalTo(false));
assertThat(button.propHorizontalAlignment().getValue(), equalTo(HorizontalAlignment.CENTER));
assertThat(button.propVerticalAlignment().getValue(), equalTo(VerticalAlignment.MIDDLE));
assertThat(button.propRotationStep().getValue(), equalTo(RotationStep.NONE));
assertThat(button.propEnabled().getValue(), equalTo(true));
assertThat(button.runtimePropPVWritable().getValue(), equalTo(true));
assertThat(button.propConfirmDialog().getValue(), equalTo(false));
assertThat(button.propConfirmMessage().getValue(), equalTo("Are your sure you want to do this?"));
assertThat(button.propPassword().getValue(), equalTo(""));
assertThat(button.propCornerRadius().getValue(), equalTo(3));
}

/**
* Test that changed (i.e. non-default) properties persist
* in the XML write/read.
*
* @throws Exception if cannot be converted
*/
@Test
public void testNonDefaultPropertiesInXml() throws Exception
{
// Test (non-default) values
String text = "Testing";
NamedWidgetColor backgroundColor = WidgetColorService.getColor(NamedWidgetColors.WRITE_BACKGROUND);
NamedWidgetColor foregroundColor = WidgetColorService.getColor(NamedWidgetColors.ACTIVE_TEXT);
NamedWidgetFont font = WidgetFontService.get(NamedWidgetFonts.DEFAULT_BOLD);
HorizontalAlignment hAlign = HorizontalAlignment.LEFT;
VerticalAlignment vAlign = VerticalAlignment.TOP;
RotationStep rotation = RotationStep.NINETY;
String confirmMessage = "Is this OK?";
String password = "pw";
int radii = 10;

ActionButtonWidget button = new ActionButtonWidget();

button.propText().setValue(text);
button.propFont().setValue(font);
button.propForegroundColor().setValue(foregroundColor);
button.propBackgroundColor().setValue(backgroundColor);
button.propTransparent().setValue(true);
button.propHorizontalAlignment().setValue(hAlign);
button.propVerticalAlignment().setValue(vAlign);
button.propRotationStep().setValue(rotation);
button.propEnabled().setValue(false);
button.propConfirmDialog().setValue(true);
button.propConfirmMessage().setValue(confirmMessage);
button.propPassword().setValue(password);
button.propCornerRadius().setValue(radii);

final String xml = ModelWriter.getXML(List.of(button));

final DisplayModel model = ModelReader.parseXML(xml);
final List<Widget> widgets = model.getChildren();
assertThat(widgets.size(), equalTo(1));
assertThat(widgets.getFirst(), instanceOf(ActionButtonWidget.class));
button = (ActionButtonWidget) widgets.getFirst();

assertThat(button.propText().getValue(), equalTo(text));
assertThat(button.propFont().getValue(), equalTo(font));
assertThat(button.propForegroundColor().getValue(), equalTo(foregroundColor));
assertThat(button.propBackgroundColor().getValue(), equalTo(backgroundColor));
assertThat(button.propTransparent().getValue(), equalTo(true));
assertThat(button.propHorizontalAlignment().getValue(), equalTo(hAlign));
assertThat(button.propVerticalAlignment().getValue(), equalTo(vAlign));
assertThat(button.propRotationStep().getValue(), equalTo(rotation));
assertThat(button.propEnabled().getValue(), equalTo(false));
assertThat(button.propConfirmDialog().getValue(), equalTo(true));
assertThat(button.propConfirmMessage().getValue(), equalTo(confirmMessage));
assertThat(button.propPassword().getValue(), equalTo(password));
assertThat(button.propCornerRadius().getValue(), equalTo(radii));
}

/**
* Test that the properties with default values do not get saved
* to the XML.
*
* @throws Exception if cannot be converted
*/
@Test
public void testOptionalPropertiesInXml() throws Exception
{
ActionButtonWidget button = new ActionButtonWidget();
final String xml = ModelWriter.getXML(List.of(button));

assertThat(xml, not(containsString("<enabled>")));
assertThat(xml, not(containsString("<text>")));
assertThat(xml, not(containsString("<font>")));
assertThat(xml, not(containsString("<foreground>")));
assertThat(xml, not(containsString("<background>")));
assertThat(xml, not(containsString("<transparent>")));
assertThat(xml, not(containsString("<horizontal_alignment>")));
assertThat(xml, not(containsString("<vertical_alignment>")));
assertThat(xml, not(containsString("<rotation_step>")));
assertThat(xml, not(containsString("<pv_writable>")));
assertThat(xml, not(containsString("<confirm_dialog>")));
assertThat(xml, not(containsString("<confirm_message>")));
assertThat(xml, not(containsString("<password>")));
assertThat(xml, not(containsString("<corner_radius>")));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ public class ActionButtonRepresentation extends RegionBaseRepresentation<Pane, A
private final DirtyFlag dirty_actionls = new DirtyFlag();

private volatile ButtonBase base;
private volatile String style;
private volatile String style = "";
private volatile String button_text;
private volatile boolean enabled = true;
private volatile boolean writable = true;
Expand Down Expand Up @@ -108,6 +108,7 @@ protected boolean isFilteringEditModeClicks() {
@Override
public Pane createJFXNode() throws Exception {
updateColors();
updateCorners();
base = makeBaseButton();

Pane pane = new Pane();
Expand Down Expand Up @@ -300,6 +301,7 @@ private void handleAction(ActionInfo action) {
@Override
protected void registerListeners() {
updateColors();
updateCorners();
super.registerListeners();
pos = JFXUtil.computePos(model_widget.propHorizontalAlignment().getValue(),
model_widget.propVerticalAlignment().getValue());
Expand All @@ -308,6 +310,7 @@ protected void registerListeners() {
model_widget.propText().addUntypedPropertyListener(representationChangedListener);
model_widget.propFont().addUntypedPropertyListener(representationChangedListener);
model_widget.propRotationStep().addUntypedPropertyListener(representationChangedListener);
model_widget.propCornerRadius().addUntypedPropertyListener(representationChangedListener);

model_widget.propEnabled().addPropertyListener(enablementChangedListener);
model_widget.runtimePropPVWritable().addPropertyListener(enablementChangedListener);
Expand All @@ -334,6 +337,7 @@ protected void unregisterListeners() {
model_widget.propText().removePropertyListener(representationChangedListener);
model_widget.propFont().removePropertyListener(representationChangedListener);
model_widget.propRotationStep().removePropertyListener(representationChangedListener);
model_widget.propCornerRadius().removePropertyListener(representationChangedListener);
model_widget.propEnabled().removePropertyListener(enablementChangedListener);
model_widget.runtimePropPVWritable().removePropertyListener(enablementChangedListener);
model_widget.propBackgroundColor().removePropertyListener(buttonChangedListener);
Expand Down Expand Up @@ -366,6 +370,7 @@ private void buttonChanged(final WidgetProperty<?> property, final Object old_va
*/
private void representationChanged(final WidgetProperty<?> property, final Object old_value, final Object new_value) {
updateColors();
updateCorners();
dirty_representation.mark();
toolkit.scheduleUpdate(this);
}
Expand Down Expand Up @@ -398,6 +403,19 @@ private void updateColors() {
style += " -fx-text-base-color: " + fg_css + ";";
}

/**
* Add the corner radii to the style
*/
private void updateCorners() {
style += " -fx-background-radius: "+ model_widget.propCornerRadius().getValue()+" ;";
}

@Override
public int[] getBorderRadii()
{
return new int[] {model_widget.propCornerRadius().getValue(),model_widget.propCornerRadius().getValue()};
}

@Override
public void updateChanges() {
super.updateChanges();
Expand Down
Loading