Skip to content

Commit

Permalink
Merge pull request #2182 from ControlSystemStudio/CSSTUDIO-1508
Browse files Browse the repository at this point in the history
Aligning focus behavior for Spinner widget
  • Loading branch information
georgweiss authored Mar 18, 2022
2 parents 73a9739 + b1f3a84 commit 75ecd34
Showing 1 changed file with 87 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,15 @@

import java.util.logging.Level;

import javafx.application.Platform;
import javafx.scene.Cursor;
import org.csstudio.display.builder.model.DirtyFlag;
import org.csstudio.display.builder.model.UntypedWidgetPropertyListener;
import org.csstudio.display.builder.model.WidgetProperty;
import org.csstudio.display.builder.model.WidgetPropertyListener;
import org.csstudio.display.builder.model.persist.NamedWidgetColors;
import org.csstudio.display.builder.model.persist.WidgetColorService;
import org.csstudio.display.builder.model.properties.WidgetColor;
import org.csstudio.display.builder.model.widgets.SpinnerWidget;
import org.csstudio.display.builder.representation.javafx.Cursors;
import org.csstudio.display.builder.representation.javafx.JFXUtil;
Expand All @@ -34,10 +38,6 @@
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.CornerRadii;
import javafx.scene.paint.Color;
import javafx.util.StringConverter;

/** Creates JavaFX item for model widget
Expand All @@ -61,47 +61,57 @@ public class SpinnerRepresentation extends RegionBaseRepresentation<Spinner<Stri
private volatile double value_max = 100.0;
private volatile double value_min = 0.0;

private static WidgetColor active_color = WidgetColorService.getColor(NamedWidgetColors.ACTIVE_TEXT);


@Override
protected final Spinner<String> createJFXNode() throws Exception
{
final Spinner<String> spinner = new Spinner<>();

spinner.setValueFactory(createSVF());
spinner.focusedProperty().addListener((property, oldval, newval)->
{
if (!spinner.isFocused())
restore();
active = false;
});

spinner.getEditor().setOnKeyPressed((final KeyEvent event) ->
spinner.getEditor().focusedProperty().addListener((property, oldval, focused)->
{
switch (event.getCode())
if (active && !focused)
{
case ESCAPE: //TODO: fix: escape key event not sensed
// Revert original value, leave active state
restore();
active = false;
break;
case ENTER:
// Submit value, leave active state
submit();
active = false;
break;
//incrementing by keyboard
case UP:
case PAGE_UP:
if (!active)
spinner.getValueFactory().increment(1);
break;
case DOWN:
case PAGE_DOWN:
if (!active)
spinner.getValueFactory().decrement(1);
break;
default:
// Any other key results in active state
active = true;
setActive(false);
}
else if(focused){
// Need to call selectAll() in this fashion, even if already on JavaFX application thread.
Platform.runLater(() -> spinner.getEditor().selectAll());
}
});

spinner.addEventFilter(KeyEvent.KEY_PRESSED, event -> {
switch(event.getCode()){
case ESCAPE:
if (active)
{ // Revert original value, leave active state
restore();
setActive(false);
}
break;
case ENTER:
// Submit value, leave active state
submit();
setActive(false);
break;
//incrementing by keyboard
case UP:
case PAGE_UP:
if (!active)
spinner.getValueFactory().increment(1);
break;
case DOWN:
case PAGE_DOWN:
if (!active)
spinner.getValueFactory().decrement(1);
break;
default:
// Any other key results in active state
setActive(true);
}
});

Expand All @@ -127,6 +137,17 @@ protected final Spinner<String> createJFXNode() throws Exception

spinner.getEditor().setPadding(new Insets(0, 0, 0, 0));

spinner.getEditor().setOnMouseClicked(event -> {
// Secondary mouse button should bring up context menu
// but not enable editing.
if(event.getButton().equals(MouseButton.PRIMARY)){
setActive(true);
}
else{
spinner.getEditor().setEditable(false);
}
});

return spinner;
}

Expand All @@ -136,7 +157,7 @@ protected final Spinner<String> createJFXNode() throws Exception
private void restore()
{
//The old value is restored.
jfx_node.getEditor().setText(jfx_node.getValueFactory().getValue());
jfx_node.getEditor().setText(value_text);
}

/** Submit value entered by user */
Expand Down Expand Up @@ -460,10 +481,16 @@ public void updateChanges()
super.updateChanges();
if (dirty_style.checkAndClear())
{
final String color = JFXUtil.webRGB(model_widget.propForegroundColor().getValue());
jfx_node.editorProperty().getValue().setStyle("-fx-text-fill:" + color);
final Color background = JFXUtil.convert(model_widget.propBackgroundColor().getValue());
jfx_node.editorProperty().getValue().setBackground(new Background(new BackgroundFill(background, CornerRadii.EMPTY, Insets.EMPTY)));
final StringBuilder style = new StringBuilder(100);
style.append("-fx-text-fill:");
JFXUtil.appendWebRGB(style, model_widget.propForegroundColor().getValue()).append(";");

// http://stackoverflow.com/questions/27700006/how-do-you-change-the-background-color-of-a-textfield-without-changing-the-border
final WidgetColor back_color = active ? active_color : model_widget.propBackgroundColor().getValue();
style.append("-fx-control-inner-background: ");
JFXUtil.appendWebRGB(style, back_color).append(";");

jfx_node.editorProperty().getValue().setStyle(style.toString());
jfx_node.resize(model_widget.propWidth().getValue(), model_widget.propHeight().getValue());

// Enable if enabled by user and there's write access
Expand Down Expand Up @@ -543,4 +570,24 @@ protected void attachTooltip()
// Show the tooltip for the editor part too
TooltipSupport.attach(jfx_node.getEditor(), model_widget.propTooltip(), () -> value_text);
}

private void setActive(final boolean active)
{
if (this.active == active)
return;

// When activated, start by selecting all in a plain text.
// For multi-line, leave it to the user to click or cursor around,
// because when all is selected, there's a larger risk of accidentally
// replacing some long, carefully crafted text.
if (active)
jfx_node.getEditor().selectAll();

// Don't enable when widget is disabled
if (active && !model_widget.propEnabled().getValue())
return;
this.active = active;
dirty_style.mark();
updateChanges();
}
}

0 comments on commit 75ecd34

Please sign in to comment.