Skip to content

Commit c71bdf9

Browse files
committed
{GuiGraphic,Interaction}Frame: Convert toolbars to proper menu bar
And enable MacOS system integration
1 parent 04a0151 commit c71bdf9

File tree

5 files changed

+161
-134
lines changed

5 files changed

+161
-134
lines changed

lib/src/main/java/jtamaro/interaction/InteractionFrame.java

Lines changed: 108 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,31 @@
88
import java.awt.event.MouseEvent;
99
import java.awt.event.WindowAdapter;
1010
import java.awt.event.WindowEvent;
11+
import javax.swing.Box;
12+
import javax.swing.JButton;
1113
import javax.swing.JFrame;
14+
import javax.swing.JLabel;
15+
import javax.swing.JMenu;
16+
import javax.swing.JMenuBar;
17+
import javax.swing.JMenuItem;
18+
import javax.swing.JPanel;
19+
import javax.swing.KeyStroke;
1220
import javax.swing.SwingUtilities;
1321
import javax.swing.Timer;
1422
import jtamaro.graphic.Graphic;
1523
import jtamaro.graphic.GuiGraphicCanvas;
24+
import jtamaro.io.IO;
1625

1726
/**
1827
* GUI that allows the user to interact with an {@link Interaction}.
1928
*/
2029
final class InteractionFrame<M> extends JFrame {
2130

31+
static {
32+
// Use system menu bar on macOS
33+
System.setProperty("apple.laf.useScreenMenuBar", "true");
34+
}
35+
2236
private final Interaction<M> interaction;
2337

2438
private final InteractionState<M> state;
@@ -27,6 +41,12 @@ final class InteractionFrame<M> extends JFrame {
2741

2842
private final Timer timer;
2943

44+
private final JMenuItem startStopItem;
45+
46+
private final JButton startStopButton;
47+
48+
private final JLabel tickLabel;
49+
3050
private final GuiGraphicCanvas graphicCanvas;
3151

3252
public InteractionFrame(Interaction<M> interaction) {
@@ -36,14 +56,66 @@ public InteractionFrame(Interaction<M> interaction) {
3656
this.timer = new Timer(interaction.getMsBetweenTicks(), this::onTick);
3757

3858
setTitle(interaction.getName());
59+
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
60+
addWindowListener(new WindowAdapter() {
61+
@Override
62+
public void windowClosing(WindowEvent winEvt) {
63+
// No need to call the stopTimer() method, we don't need
64+
// to update UI components at this point.
65+
timer.stop();
66+
}
67+
});
68+
69+
// Menu bar
70+
final JMenuBar menuBar = new JMenuBar();
71+
setJMenuBar(menuBar);
72+
73+
final JMenu fileMenu = new JMenu("File");
74+
fileMenu.setMnemonic(KeyEvent.VK_F);
75+
menuBar.add(fileMenu);
76+
77+
startStopItem = new JMenuItem();
78+
startStopItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F8, 0));
79+
startStopItem.addActionListener(e -> toggleTimer());
80+
fileMenu.add(startStopItem);
81+
82+
final JMenuItem viewFrame = new JMenuItem("Inspect Frame");
83+
viewFrame.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0));
84+
viewFrame.addActionListener(e -> SwingUtilities.invokeLater(() -> {
85+
stopTimer();
86+
IO.show(interaction.getRenderer().apply(state.getModel()));
87+
}));
88+
fileMenu.add(viewFrame);
89+
90+
final JMenu viewMenu = new JMenu("View");
91+
viewMenu.setMnemonic(KeyEvent.VK_V);
92+
menuBar.add(viewMenu);
93+
94+
final JMenuItem viewTrace = new JMenuItem("Trace");
95+
viewTrace.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F2, 0));
96+
viewTrace.addActionListener(e -> SwingUtilities.invokeLater(() ->
97+
new TraceFrame(eventsTrace).setVisible(true)));
98+
viewMenu.add(viewTrace);
99+
100+
final JMenuItem viewModel = new JMenuItem("Model");
101+
viewModel.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F3, 0));
102+
viewModel.addActionListener(e -> SwingUtilities.invokeLater(() ->
103+
new ModelFrame<>(interaction, eventsTrace).setVisible(true)));
104+
viewMenu.add(viewModel);
39105

40106
// Toolbar
41-
final InteractionToolbar<M> toolbar = new InteractionToolbar<>(interaction,
42-
state,
43-
timer,
44-
eventsTrace);
107+
final JPanel toolbar = new JPanel();
45108
add(toolbar, BorderLayout.NORTH);
46109

110+
tickLabel = new JLabel();
111+
toolbar.add(tickLabel, BorderLayout.WEST);
112+
113+
toolbar.add(Box.createHorizontalStrut(20));
114+
115+
startStopButton = new JButton();
116+
startStopButton.addActionListener(e -> toggleTimer());
117+
toolbar.add(startStopButton, BorderLayout.EAST);
118+
47119
// Canvas component
48120
int canvasWidth = interaction.getCanvasWidth();
49121
int canvasHeight = interaction.getCanvasHeight();
@@ -104,14 +176,6 @@ public void mouseDragged(MouseEvent ev) {
104176
traceEvent(new TraceEvent.MouseMoved(coordinate));
105177
}
106178
});
107-
108-
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
109-
addWindowListener(new WindowAdapter() {
110-
@Override
111-
public void windowClosing(WindowEvent winEvt) {
112-
timer.stop();
113-
}
114-
});
115179
add(graphicCanvas, BorderLayout.CENTER);
116180

117181
pack();
@@ -122,18 +186,47 @@ public void windowClosing(WindowEvent winEvt) {
122186
graphicCanvas.requestFocus();
123187

124188
// Start the timer
125-
timer.start();
189+
startTimer();
126190
// The timer is now running, configure the toolbar buttons
127-
toolbar.configureButtons();
191+
viewFrame.setEnabled(true);
128192
});
129193
}
130194

195+
private void toggleTimer() {
196+
if (timer.isRunning()) {
197+
stopTimer();
198+
} else {
199+
startTimer();
200+
}
201+
}
202+
203+
private void stopTimer() {
204+
if (!timer.isRunning()) {
205+
return;
206+
}
207+
208+
startStopItem.setText("Start");
209+
startStopButton.setText("Start");
210+
timer.stop();
211+
}
212+
213+
private void startTimer() {
214+
if (timer.isRunning()) {
215+
return;
216+
}
217+
218+
startStopItem.setText("Stop");
219+
startStopButton.setText("Stop");
220+
timer.start();
221+
}
222+
131223
private void onTick(ActionEvent ev) {
132224
if (interaction.getStoppingPredicate().apply(state.getModel())) {
133-
timer.stop();
225+
stopTimer();
134226
} else {
135227
traceEvent(new TraceEvent.Tick());
136228
state.tick();
229+
tickLabel.setText(String.valueOf(state.getTick()));
137230
}
138231
}
139232

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,16 @@
11
package jtamaro.interaction;
22

3-
import java.util.ArrayList;
4-
import java.util.List;
53
import java.util.Objects;
64

75
final class InteractionState<M> {
86

9-
private final List<InteractionStateListener<M>> listeners;
10-
117
private final Interaction<M> interaction;
128

139
private M model;
1410

1511
private long tick;
1612

1713
public InteractionState(Interaction<M> interaction) {
18-
this.listeners = new ArrayList<>();
1914
this.interaction = interaction;
2015

2116
final M initialModel = interaction.getInitialModel();
@@ -31,7 +26,6 @@ public void tick() {
3126
public void update(String what, M model) {
3227
check(what, model);
3328
this.model = model;
34-
fireStateChanged();
3529
}
3630

3731
public long getTick() {
@@ -42,20 +36,10 @@ public M getModel() {
4236
return model;
4337
}
4438

45-
public void addBigBangStateListener(InteractionStateListener<M> listener) {
46-
listeners.add(listener);
47-
}
48-
4939
private void check(String what, M model) {
5040
Objects.requireNonNull(model);
5141
if (!interaction.getWellFormedPredicate().apply(model)) {
5242
throw new IllegalStateException(what + " is not well formed");
5343
}
5444
}
55-
56-
private void fireStateChanged() {
57-
for (final InteractionStateListener<M> listener : listeners) {
58-
listener.stateChanged(this);
59-
}
60-
}
6145
}

lib/src/main/java/jtamaro/interaction/InteractionStateListener.java

Lines changed: 0 additions & 6 deletions
This file was deleted.

lib/src/main/java/jtamaro/interaction/InteractionToolbar.java

Lines changed: 0 additions & 71 deletions
This file was deleted.

0 commit comments

Comments
 (0)