Skip to content

Commit ac563c9

Browse files
committed
Added swing based visual cue for lower latency
1 parent f8716e3 commit ac563c9

File tree

5 files changed

+57
-40
lines changed

5 files changed

+57
-40
lines changed

res/layout/mainFrame.fxml

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22

3+
<?import javafx.embed.swing.SwingNode?>
34
<?import javafx.scene.control.Button?>
45
<?import javafx.scene.control.Label?>
56
<?import javafx.scene.control.Tab?>
@@ -8,7 +9,6 @@
89
<?import javafx.scene.image.ImageView?>
910
<?import javafx.scene.layout.AnchorPane?>
1011
<?import javafx.scene.layout.VBox?>
11-
<?import javafx.scene.shape.Rectangle?>
1212
<?import javafx.scene.text.Font?>
1313

1414
<VBox maxHeight="345.0" maxWidth="430.0" minHeight="345.0" minWidth="430.0" prefHeight="345.0" prefWidth="430.0" xmlns="http://javafx.com/javafx/10.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="stringflow.cheatontimer.FixedOffsetTab">
@@ -24,11 +24,6 @@
2424
<content>
2525
<AnchorPane fx:id="layout" maxWidth="430.0" minWidth="430.0" prefWidth="430.0">
2626
<children>
27-
<AnchorPane prefHeight="200.0" prefWidth="200.0">
28-
<children>
29-
<Rectangle fx:id="visualCueRect" arcHeight="5.0" arcWidth="5.0" fill="#ffffff00" height="55.0" stroke="#ffffff00" strokeType="INSIDE" width="120.0" />
30-
</children>
31-
</AnchorPane>
3227
<Label layoutX="206.0" layoutY="16.0" />
3328
<Label layoutX="145.0" layoutY="13.0" maxWidth="55.0" minHeight="20.0" minWidth="55.0" prefHeight="20.0" prefWidth="55.0" text="Name" />
3429
<Label layoutX="205.0" layoutY="13.0" maxWidth="55.0" minHeight="20.0" minWidth="55.0" prefHeight="20.0" prefWidth="55.0" text="Offset" />
@@ -45,11 +40,7 @@
4540
</Tab>
4641
</tabs>
4742
</TabPane>
48-
<Label fx:id="timerLabel" layoutX="9.0" layoutY="34.0" prefHeight="44.0" prefWidth="113.0" text="0.000">
49-
<font>
50-
<Font name="Verdana" size="30.0" />
51-
</font>
52-
</Label>
43+
<SwingNode fx:id="swingNode" layoutY="30.0" />
5344
<Button fx:id="startButton" focusTraversable="false" layoutX="10.0" layoutY="85.0" maxHeight="25.0" maxWidth="100.0" minHeight="25.0" minWidth="100.0" mnemonicParsing="false" onAction="#onStartButtonPress" prefHeight="25.0" prefWidth="100.0" text="Start" />
5445
<Button fx:id="resetButton" focusTraversable="false" layoutX="10.0" layoutY="115.0" maxHeight="25.0" maxWidth="100.0" minHeight="25.0" minWidth="100.0" mnemonicParsing="false" onAction="#onResetButtonPress" prefHeight="25.0" prefWidth="100.0" text="Reset" />
5546
<Button fx:id="settingsButton" focusTraversable="false" layoutX="10.0" layoutY="145.0" maxHeight="25.0" maxWidth="100.0" minHeight="25.0" minWidth="100.0" mnemonicParsing="false" onAction="#onSettingsButtonPress" prefHeight="25.0" prefWidth="100.0" text="Settings" />

src/stringflow/cheatontimer/FixedOffsetTab.java

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,20 @@
11
package stringflow.cheatontimer;
22

3+
import javafx.embed.swing.SwingNode;
34
import javafx.fxml.FXML;
45
import javafx.scene.control.Alert;
56
import javafx.scene.control.Button;
6-
import javafx.scene.control.Label;
77
import javafx.scene.control.TabPane;
88
import javafx.scene.image.ImageView;
99
import javafx.scene.layout.AnchorPane;
10+
import javafx.scene.layout.StackPane;
1011
import javafx.scene.shape.Rectangle;
1112
import javafx.stage.FileChooser;
1213
import javafx.stage.Stage;
1314
import stringflow.cheatontimer.timerFile.TimerFileUtil;
1415

16+
import javax.swing.*;
17+
import java.awt.*;
1518
import java.io.File;
1619
import java.util.ArrayList;
1720
import java.util.Collection;
@@ -35,12 +38,13 @@ public class FixedOffsetTab {
3538
public Button settingsButton;
3639
public Button importButton;
3740
public Button exportButton;
38-
public Label timerLabel;
39-
public Rectangle visualCueRect;
41+
public SwingNode swingNode;
4042
public ImageView pinIcon;
4143
public ImageView unpinIcon;
4244

4345
public String saveLocationBuffer;
46+
public JLabel timerLabel;
47+
public TimerPanel swingPanel;
4448

4549
private LinkedList<TimerEntry> timers = new LinkedList<>();
4650
private TimerEntry activeTimer;
@@ -51,6 +55,15 @@ public FixedOffsetTab() {
5155

5256
@FXML
5357
public void initialize() {
58+
swingPanel = new TimerPanel();
59+
swingPanel.setBackground(new Color(0xF4F4F4));
60+
swingPanel.setLayout(null);
61+
swingPanel.setBounds(20, 0, 120, 50);
62+
timerLabel = new JLabel("0.000");
63+
timerLabel.setFont(new Font("Verdana", 0, 30));
64+
timerLabel.setBounds(9, 0, 150, 50);
65+
swingPanel.add(timerLabel);
66+
swingNode.setContent(swingPanel);
5467
addNewTimer("Initial", 2500, 500, 5, false);
5568
getTimer(0).select();
5669
recalcAddButton();

src/stringflow/cheatontimer/FlowTimer.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ public void start(Stage primaryStage) throws Exception {
3939
String mode = ini.get("Audio", "mode");
4040
audioCue = mode.toLowerCase().contains("audio");
4141
visualCue = mode.toLowerCase().contains("visual");
42-
audioEngine.setVolume(Float.valueOf(String.valueOf(ini.get("Audio", "volume"))));
4342
mainFrame = primaryStage;
4443
setupNativeHook();
4544
GlobalScreen.registerNativeHook();
@@ -94,7 +93,6 @@ public void start(Stage primaryStage) throws Exception {
9493
settingsWindow.setScene(new Scene(FXMLLoader.load(getClass().getResource("/layout/settingsWindow.fxml")), 265, 160));
9594
settingsWindow.initModality(Modality.APPLICATION_MODAL);
9695

97-
9896
// Check for 1.4.1 settings
9997
if(ini.get("General") == null) {
10098
ini.add("General");
@@ -123,6 +121,8 @@ public void start(Stage primaryStage) throws Exception {
123121
} else {
124122
SettingsWindow.instance.popAudioFile.setSelected(true);
125123
}
124+
audioEngine.setVolume(0);
125+
currentBeep.play();
126126
SettingsWindow.instance.startInputField1.set(ini.get("Input", "start1Name"), Integer.valueOf(String.valueOf(ini.get("Input", "start1"))));
127127
SettingsWindow.instance.startInputField2.set(ini.get("Input", "start2Name"), Integer.valueOf(String.valueOf(ini.get("Input", "start2"))));
128128
SettingsWindow.instance.resetInputField1.set(ini.get("Input", "reset1Name"), Integer.valueOf(String.valueOf(ini.get("Input", "reset1"))));
@@ -136,6 +136,7 @@ public void start(Stage primaryStage) throws Exception {
136136
SettingsWindow.instance.volumeSlider.setValue(Double.valueOf(String.valueOf(ini.get("Audio", "volume"))) * 100.0);
137137
SettingsWindow.instance.choiceBox.setValue(mode);
138138
SettingsWindow.instance.setUpListeners();
139+
audioEngine.setVolume(Float.valueOf(String.valueOf(ini.get("Audio", "volume"))));
139140
}
140141

141142
private static Wini loadIniAndSetAudioEngine() throws Exception {

src/stringflow/cheatontimer/Timer.java

Lines changed: 5 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -20,25 +20,6 @@ public class Timer {
2020
public static long maxOffset;
2121
public static long cutoff;
2222
public static long elapsedTime;
23-
public static boolean visualCue;
24-
public static boolean lastVisualCue;
25-
26-
private static Timeline animation;
27-
28-
static {
29-
animation = new Timeline(new KeyFrame(Duration.millis(1), (ActionEvent e) -> {
30-
if(visualCue != lastVisualCue) {
31-
FixedOffsetTab.instance.visualCueRect.setFill(visualCue ? Color.BLACK : Color.TRANSPARENT);
32-
}
33-
long time = (maxOffset - elapsedTime) / 1000000L;
34-
if(time < 0) {
35-
time = 0;
36-
}
37-
FixedOffsetTab.instance.setTimerLabel(time);
38-
lastVisualCue = visualCue;
39-
}));
40-
animation.setCycleCount(Timeline.INDEFINITE);
41-
}
4223

4324
public static void calcCurrentTime(TimerEntry entry) {
4425
int numBeeps = entry.getOffsets().length * entry.getNumBeeps();
@@ -71,13 +52,11 @@ public static void start() {
7152
currentTimerThread.stop();
7253
}
7354
new Thread(currentTimerThread = new TimerThread()).start();
74-
animation.play();
7555
FixedOffsetTab.instance.setElements(true);
7656
}
7757

7858
public static void reset() {
7959
if(isTimerRunning) {
80-
animation.stop();
8160
currentTimerThread.stop();
8261
currentTimerThread.finish();
8362
}
@@ -101,9 +80,11 @@ public void run() {
10180
beepIndex++;
10281
}
10382
if(elapsedTime >= visualCues[visualCueIndex]) {
104-
visualCue = !visualCue;
83+
FixedOffsetTab.instance.swingPanel.toggleVisualCue();
84+
FixedOffsetTab.instance.swingPanel.repaint();
10585
visualCueIndex++;
10686
}
87+
FixedOffsetTab.instance.setTimerLabel((maxOffset - elapsedTime) / 1000000);
10788
if(elapsedTime >= maxOffset) {
10889
finish();
10990
return;
@@ -137,10 +118,10 @@ public void run() {
137118
try {
138119
if(FlowTimer.visualCue) {
139120
Thread.sleep(visualDuration);
140-
visualCue = !visualCue;
121+
FixedOffsetTab.instance.swingPanel.setVisualCue(false);
122+
FixedOffsetTab.instance.swingPanel.repaint();
141123
}
142124
Thread.sleep(34);
143-
animation.stop();
144125
Platform.runLater(() -> {
145126
FixedOffsetTab.instance.setTimerLabel(0);
146127
FixedOffsetTab.instance.setActiveTimer(FixedOffsetTab.instance.getSelectedTimer());
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package stringflow.cheatontimer;
2+
3+
import javax.swing.*;
4+
import java.awt.*;
5+
6+
public class TimerPanel extends JPanel {
7+
8+
private static final Color BLACK = new Color(0, false);
9+
private static final Color BLANK = new Color(0, true);
10+
11+
private boolean visualCue;
12+
13+
public TimerPanel() {
14+
visualCue = false;
15+
repaint();
16+
}
17+
18+
public void paint(Graphics g) {
19+
super.paint(g);
20+
g.setColor(visualCue ? BLACK : BLANK);
21+
g.fillRect(0, 0, 150, 150);
22+
}
23+
24+
public void setVisualCue(boolean value) {
25+
visualCue = value;
26+
}
27+
28+
public void toggleVisualCue() {
29+
visualCue = !visualCue;
30+
}
31+
}

0 commit comments

Comments
 (0)