Skip to content

Commit 2d95f7b

Browse files
authored
Merge pull request JMRI#13744 from CGMRC/immediate_feedback
Highlight cursor position on layout editor panels: for touchscreens
2 parents 0f8b650 + d30c136 commit 2d95f7b

8 files changed

Lines changed: 112 additions & 7 deletions

File tree

help/en/package/jmri/jmrit/display/LayoutEditor.shtml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,17 @@
597597
the drawn panel, but it does take longer to refresh the panel. Check antialiasing for a
598598
better looking panel. Uncheck antialiasing for faster refresh.</li>
599599

600+
<li><strong>Toggle Track labels in Edit mode</strong> - If this item is selected, the
601+
panel is displayed with the internal names for track items such as anchor points,
602+
track sengments, turnouts, etc.</li>
603+
604+
<li><strong>Highlight Cursor Position</strong> <span class="since">since 5.11.3</span>
605+
- If this item is selected, the cursor will have a colored box drawn around the mouse
606+
pointer when the mouse has been clicked and held. This option is not active when the
607+
panel is in edit mode. The primary purpose is to provide an enhanced mouse pointer on touch
608+
screens. For turnouts, the turnout control circle will also flash a couple of times
609+
while the turnout is moving.</li>
610+
600611
<li><strong>New Title...</strong> - Selecting this item brings up a small window that
601612
allows a new panel window title to be entered.</li>
602613

help/en/releasenotes/current-draft-note.shtml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,9 @@
425425
<ul>
426426
<li></li>
427427
</ul>
428+
<ul>
429+
<li>Added "Highlight cursor position" option to enable drawing of a square around finger/mouse press/drag area. Useful for touchscreens.
430+
</ul>
428431

429432
<h4>NX - Entry/Exit Tool</h4>
430433
<ul>

java/src/jmri/jmrit/display/layoutEditor/LayoutEditor.java

Lines changed: 81 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ public LayoutEditorToolBarPanel getLayoutEditorToolBarPanel() {
161161
private JCheckBoxMenuItem turnoutFillControlCirclesCheckBoxMenuItem = null;
162162
private JCheckBoxMenuItem hideTrackSegmentConstructionLinesCheckBoxMenuItem = null;
163163
private JCheckBoxMenuItem useDirectTurnoutControlCheckBoxMenuItem = null;
164+
private JCheckBoxMenuItem highlightCursorCheckBoxMenuItem = null;
164165
private ButtonGroup turnoutCircleSizeButtonGroup = null;
165166

166167
private boolean turnoutDrawUnselectedLeg = true;
@@ -308,6 +309,7 @@ public LayoutEditorFindItems getFinder() {
308309
private double xOverHWid = LayoutTurnout.xOverHWidDefault;
309310
private double xOverShort = LayoutTurnout.xOverShortDefault;
310311
private boolean useDirectTurnoutControl = false; // Uses Left click for closing points, Right click for throwing.
312+
private boolean highlightCursor = false; // Highlight finger/mouse press/drag area, good for touchscreens
311313

312314
// saved state of options when panel was loaded or created
313315
private boolean savedEditMode = true;
@@ -1104,6 +1106,15 @@ private JMenu setupOptionMenu(@Nonnull JMenuBar menuBar) {
11041106
});
11051107
drawLayoutTracksLabelCheckBoxMenuItem.setSelected(drawLayoutTracksLabel);
11061108

1109+
// add "Highlight cursor position" - useful for touchscreens
1110+
highlightCursorCheckBoxMenuItem = new JCheckBoxMenuItem(Bundle.getMessage("HighlightCursor"));
1111+
optionMenu.add(highlightCursorCheckBoxMenuItem);
1112+
highlightCursorCheckBoxMenuItem.addActionListener((ActionEvent event) -> {
1113+
highlightCursor = highlightCursorCheckBoxMenuItem.isSelected();
1114+
redrawPanel();
1115+
});
1116+
highlightCursorCheckBoxMenuItem.setSelected(highlightCursor);
1117+
11071118
//
11081119
// edit title
11091120
//
@@ -1958,11 +1969,8 @@ private void setupZoomMenu(@Nonnull JMenuBar menuBar) {
19581969
// get the window specific saved zoom user preference
19591970
InstanceManager.getOptionalDefault(UserPreferencesManager.class).ifPresent((prefsMgr) -> {
19601971
Object zoomProp = prefsMgr.getProperty(getWindowFrameRef(), "zoom");
1961-
19621972
log.debug("{} zoom is {}", getWindowFrameRef(), zoomProp);
1963-
1964-
if (zoomProp
1965-
!= null) {
1973+
if (zoomProp != null) {
19661974
setZoom((Double) zoomProp);
19671975
}
19681976
}
@@ -2172,7 +2180,6 @@ public void mouseWheelMoved(@Nonnull MouseWheelEvent event) {
21722180
* @param zoomFactor eg. 0.5 ( 1/2 zoom ), 1.0 ( no zoom ), 2.0 ( 2x zoom )
21732181
*/
21742182
private void selectZoomMenuItem(double zoomFactor) {
2175-
21762183
double zoom = zoomFactor * 100;
21772184

21782185
// put zoomFactor on 100% increments
@@ -2957,6 +2964,29 @@ private Point2D calcLocation(JmriMouseEvent event) {
29572964
return calcLocation(event, 0, 0);
29582965
}
29592966

2967+
/**
2968+
* Check for highlighting of cursor position.
2969+
*
2970+
* If in "highlight" mode, draw a square at the location of the
2971+
* event. If there was already a square, just move its location.
2972+
* In either case, redraw the panel so the previous square will
2973+
* disappear and the new one will appear immediately.
2974+
*/
2975+
private void checkHighlightCursor() {
2976+
if (!isEditable() && highlightCursor) {
2977+
// rectangle size based on turnout circle size: rectangle should
2978+
// be bigger so it can more easily surround turnout on screen
2979+
int halfSize = (int)(circleRadius) + 8;
2980+
if (_highlightcomponent == null) {
2981+
_highlightcomponent = new Rectangle(
2982+
xLoc - halfSize, yLoc - halfSize, halfSize * 2, halfSize * 2);
2983+
} else {
2984+
_highlightcomponent.setLocation(xLoc - halfSize, yLoc - halfSize);
2985+
}
2986+
redrawPanel();
2987+
}
2988+
}
2989+
29602990
/**
29612991
* Handle a mouse pressed event
29622992
* <p>
@@ -2974,6 +3004,8 @@ public void mousePressed(JmriMouseEvent event) {
29743004
_lastY = _anchorY;
29753005
calcLocation(event);
29763006

3007+
checkHighlightCursor();
3008+
29773009
// TODO: Add command-click on nothing to pan view?
29783010
if (isEditable()) {
29793011
boolean prevSelectionActive = selectionActive;
@@ -3505,6 +3537,13 @@ public void mouseReleased(JmriMouseEvent event) {
35053537
// initialize mouse position
35063538
calcLocation(event);
35073539

3540+
if (!isEditable() && _highlightcomponent != null && highlightCursor) {
3541+
_highlightcomponent = null;
3542+
// see if we moused up on an object
3543+
checkControls(true);
3544+
redrawPanel();
3545+
}
3546+
35083547
// if alt modifier is down invert the snap to grid behaviour
35093548
snapToGridInvert = event.isAltDown();
35103549

@@ -3654,6 +3693,19 @@ && allControlling() && !event.isMetaDown() && !event.isAltDown() && !event.isPop
36543693
t.setState(Turnout.CLOSED);
36553694
} else {
36563695
t.toggleTurnout();
3696+
if (highlightCursor && !t.isDisabled()) {
3697+
// flash the turnout circle a few times so the user knows it's being toggled
3698+
javax.swing.Timer timer = new javax.swing.Timer(150, null);
3699+
timer.addActionListener(new ActionListener(){
3700+
int count = 1;
3701+
public void actionPerformed(ActionEvent ae){
3702+
if(count % 2 != 0) t.setDisabled(true);
3703+
else t.setDisabled(false);
3704+
if(++count > 8) timer.stop();
3705+
}
3706+
});
3707+
timer.start();
3708+
}
36573709
}
36583710
} else if ((selectedObject != null) && ((selectedHitPointType == HitPointType.SLIP_LEFT)
36593711
|| (selectedHitPointType == HitPointType.SLIP_RIGHT))
@@ -3997,6 +4049,11 @@ public void mouseClicked(@Nonnull JmriMouseEvent event) {
39974049
// initialize mouse position
39984050
calcLocation(event);
39994051

4052+
if (!isEditable() && _highlightcomponent != null && highlightCursor) {
4053+
_highlightcomponent = null;
4054+
redrawPanel();
4055+
}
4056+
40004057
// if alt modifier is down invert the snap to grid behaviour
40014058
snapToGridInvert = event.isAltDown();
40024059

@@ -4837,6 +4894,8 @@ public void mouseDragged(@Nonnull JmriMouseEvent event) {
48374894
// initialize mouse position
48384895
calcLocation(event);
48394896

4897+
checkHighlightCursor();
4898+
48404899
// ignore this event if still at the original point
48414900
if ((!isDragging) && (xLoc == getAnchorX()) && (yLoc == getAnchorY())) {
48424901
return;
@@ -7477,6 +7536,10 @@ public boolean isTurnoutDrawUnselectedLeg() {
74777536
return turnoutDrawUnselectedLeg;
74787537
}
74797538

7539+
public boolean isHighlightCursor() {
7540+
return highlightCursor;
7541+
}
7542+
74807543
public String getLayoutName() {
74817544
return layoutName;
74827545
}
@@ -7690,6 +7753,19 @@ public void setTurnoutDrawUnselectedLeg(boolean state) {
76907753
}
76917754
}
76927755

7756+
/**
7757+
* Should only be invoked on the GUI (Swing) thread.
7758+
*
7759+
* @param state true to enable highlighting the cursor (mouse/finger press/drag)
7760+
*/
7761+
@InvokeOnGuiThread
7762+
public void setHighlightCursor(boolean state) {
7763+
if (highlightCursor != state) {
7764+
highlightCursor = state;
7765+
highlightCursorCheckBoxMenuItem.setSelected(highlightCursor);
7766+
}
7767+
}
7768+
76937769
/**
76947770
* @param color value to set the default text color to.
76957771
*/

java/src/jmri/jmrit/display/layoutEditor/LayoutEditorBundle.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,7 @@ AntialiasingOn = Enable antialiasing (Smoother lines)
406406
DrawLayoutTracksLabel = Toggle Track labels in Edit mode
407407
DrawLayoutTracksMnemonic = T
408408
DrawLayoutTracksAccelerator = T
409+
HighlightCursor = Highlight Cursor Position
409410
NewTitle = New Title
410411
EditTitle = Edit Title
411412

java/src/jmri/jmrit/display/layoutEditor/LayoutEditorViewContext.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,7 @@ final public void setYScale(double scale) {
272272
273273
<xs:attribute name="openDispatcher" type="yesNoType" default="no"/>
274274
<xs:attribute name="useDirectTurnoutControl" type="yesNoType" default="no"/>
275+
<xs:attribute name="highlightCursor" type="yesNoType" default="no"/>
275276
276277
*/
277278

java/src/jmri/jmrit/display/layoutEditor/configurexml/LayoutEditorXml.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,9 @@ public Element store(Object o) {
115115
p.resetDirty();
116116
panel.setAttribute("openDispatcher", p.getOpenDispatcherOnLoad() ? "yes" : "no");
117117
panel.setAttribute("useDirectTurnoutControl", p.getDirectTurnoutControl() ? "yes" : "no");
118+
if (p.isHighlightCursor()) {
119+
panel.setAttribute("highlightCursor", "yes");
120+
}
118121

119122
// store layout track drawing options
120123
try {
@@ -590,7 +593,7 @@ public boolean load(Element shared, Element perNode) {
590593
} catch (DataConversionException e) {
591594
log.warn("Could not parse color attributes!");
592595
} catch (NullPointerException e) { // considered normal if the attributes are not present
593-
log.debug("missing backbround color attributes");
596+
log.debug("missing background color attributes");
594597
}
595598

596599
try {
@@ -601,6 +604,15 @@ public boolean load(Element shared, Element perNode) {
601604
log.debug("missing useDirectTurnoutControl attribute");
602605
}
603606

607+
try {
608+
panel.setHighlightCursor(shared.getAttribute("highlightCursor").getBooleanValue());
609+
} catch (DataConversionException e) {
610+
log.warn("unable to convert highlightCursor attribute");
611+
} catch (NullPointerException e) { // considered normal if the attribute is not present
612+
log.debug("missing highlightCursor attribute");
613+
}
614+
615+
604616
// Set editor's option flags, load content after
605617
// this so that individual item flags are set as saved
606618
panel.initView();

java/test/jmri/jmrit/display/layoutEditor/LayoutEditorTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -804,7 +804,7 @@ public void testSetHighlightSelectedBlockFalse() {
804804
public void checkOptionsMenuExists() {
805805
JMenuOperator jmo = new JMenuOperator(jfo, Bundle.getMessage("MenuOptions"));
806806
Assert.assertNotNull("Options Menu Exists", jmo);
807-
Assert.assertEquals("Menu Item Count", 19, jmo.getItemCount());
807+
Assert.assertEquals("Menu Item Count", 20, jmo.getItemCount());
808808
}
809809

810810
@Test

xml/schema/types/layouteditor.xsd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@
129129
<xs:attribute name="gridSize2nd" type="xs:integer"/>
130130
<xs:attribute name="openDispatcher" type="yesNoType" default="no"/>
131131
<xs:attribute name="useDirectTurnoutControl" type="yesNoType" default="no"/>
132+
<xs:attribute name="highlightCursor" type="yesNoType" default="no"/>
132133
<xs:attribute name="zoom" type="xs:float" default="1.0"/>
133134
</xs:complexType>
134135

0 commit comments

Comments
 (0)