Merge branch 'C_keybindings' into 'master'
C keybindings AC: * All keybindings can be easily changed in the start screen * Buttons are replacable on clicking on the current button assigned. * When the current button assigned is clicked the text should turn "blank" and return to with text after a new button has been pressed or escape has been pressed. * There cannot be more than one active replace button at a time. * Reset to default should reset to the keys defined by the P.O (but with UP, DOWN instead of PG_UP, PG_DWN) * Buttons should not save until the user exits with "save" See merge request !35
This commit is contained in:
@@ -0,0 +1,247 @@
|
|||||||
|
package visualiser.Controllers;
|
||||||
|
|
||||||
|
import javafx.application.Platform;
|
||||||
|
import javafx.fxml.FXML;
|
||||||
|
import javafx.fxml.FXMLLoader;
|
||||||
|
import javafx.scene.Parent;
|
||||||
|
import javafx.scene.Scene;
|
||||||
|
import javafx.scene.control.Button;
|
||||||
|
import javafx.scene.control.ListView;
|
||||||
|
import javafx.scene.input.KeyCode;
|
||||||
|
import javafx.scene.input.KeyEvent;
|
||||||
|
import javafx.scene.layout.AnchorPane;
|
||||||
|
import javafx.stage.Modality;
|
||||||
|
import javafx.stage.Stage;
|
||||||
|
import javafx.stage.WindowEvent;
|
||||||
|
import visualiser.gameController.Keys.ControlKey;
|
||||||
|
import visualiser.gameController.Keys.KeyFactory;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static visualiser.app.App.keyFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controller for the scene used to display and update current key bindings.
|
||||||
|
*/
|
||||||
|
public class KeyBindingsController {
|
||||||
|
private @FXML Button btnSave;
|
||||||
|
private @FXML Button btnCancel;
|
||||||
|
private @FXML Button btnReset;
|
||||||
|
private @FXML ListView lstControl;
|
||||||
|
private @FXML ListView lstKey;
|
||||||
|
private @FXML ListView lstDescription;
|
||||||
|
private @FXML AnchorPane anchor;
|
||||||
|
private KeyFactory newKeyFactory;
|
||||||
|
private Boolean changed = false; // keyBindings have been modified
|
||||||
|
private Button currentButton = null; // last button clicked
|
||||||
|
|
||||||
|
public void initialize(){
|
||||||
|
// create new key factory to modify, keeping the existing one safe
|
||||||
|
newKeyFactory = copyExistingFactory();
|
||||||
|
initializeTable();
|
||||||
|
populateTable();
|
||||||
|
setKeyListener();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets up table before populating it.
|
||||||
|
* Set up includes headings, CSS styling and modifying default properties.
|
||||||
|
*/
|
||||||
|
public void initializeTable(){
|
||||||
|
// set the headings for each column
|
||||||
|
lstKey.getItems().add("Key");
|
||||||
|
lstControl.getItems().add("Command");
|
||||||
|
lstDescription.getItems().add("Description");
|
||||||
|
lstKey.getSelectionModel().select(0);
|
||||||
|
lstControl.getSelectionModel().select(0);
|
||||||
|
lstDescription.getSelectionModel().select(0);
|
||||||
|
|
||||||
|
// add CSS stylesheet once the scene has been created
|
||||||
|
lstKey.sceneProperty().addListener((obs, oldScene, newScene) -> {
|
||||||
|
if (newScene != null) {
|
||||||
|
newScene.getStylesheets().add("/css/keyBindings.css");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// stop the columns from being selectable, so only the buttons are
|
||||||
|
lstKey.getSelectionModel().selectedItemProperty()
|
||||||
|
.addListener((observable, oldvalue, newValue) ->
|
||||||
|
Platform.runLater(() ->
|
||||||
|
lstKey.getSelectionModel().select(0)));
|
||||||
|
lstDescription.getSelectionModel().selectedItemProperty()
|
||||||
|
.addListener((observable, oldvalue, newValue) ->
|
||||||
|
Platform.runLater(() ->
|
||||||
|
lstDescription.getSelectionModel().select(0)));
|
||||||
|
lstControl.getSelectionModel().selectedItemProperty()
|
||||||
|
.addListener((observable, oldvalue, newValue) ->
|
||||||
|
Platform.runLater(() ->
|
||||||
|
lstControl.getSelectionModel().select(0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Populates the table with commands and their key binding details.
|
||||||
|
*/
|
||||||
|
public void populateTable(){
|
||||||
|
// add each command to the table
|
||||||
|
for (Map.Entry<String, ControlKey> entry : newKeyFactory.getKeyState().entrySet()) {
|
||||||
|
// create button for command
|
||||||
|
Button button = new Button(entry.getKey());
|
||||||
|
button.setMinWidth(120);
|
||||||
|
button.setId(entry.getValue().toString());
|
||||||
|
button.setOnAction(e -> currentButton = button);
|
||||||
|
// display details for command in table
|
||||||
|
lstControl.getItems().add(entry.getValue());
|
||||||
|
lstKey.getItems().add(button);
|
||||||
|
lstDescription.getItems().add(entry.getValue().getProtocolCode());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes a copy of the {@link KeyFactory} that does not modify the original.
|
||||||
|
* @return new keyfactory to be modified
|
||||||
|
*/
|
||||||
|
public KeyFactory copyExistingFactory(){
|
||||||
|
newKeyFactory = new KeyFactory();
|
||||||
|
Map<String, ControlKey> oldKeyState = keyFactory.getKeyState();
|
||||||
|
Map<String, ControlKey> newKeyState = new HashMap<>();
|
||||||
|
|
||||||
|
// copy over commands and their keys
|
||||||
|
for (Map.Entry<String, ControlKey> entry : oldKeyState.entrySet()){
|
||||||
|
newKeyState.put(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
newKeyFactory.setKeyState(newKeyState);
|
||||||
|
return newKeyFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a listener for the base anchorpane for key presses.
|
||||||
|
* It updates the current key bindings of the {@link KeyFactory} if
|
||||||
|
* required.
|
||||||
|
*/
|
||||||
|
public void setKeyListener(){
|
||||||
|
anchor.addEventFilter(KeyEvent.KEY_PRESSED, event -> {
|
||||||
|
// if esc, cancel current button click
|
||||||
|
if (event.getCode() == KeyCode.ESCAPE){
|
||||||
|
btnCancel.requestFocus();
|
||||||
|
currentButton = null;
|
||||||
|
}
|
||||||
|
// if a button was clicked
|
||||||
|
else if (currentButton != null) {
|
||||||
|
// check if a button is already mapped to this key
|
||||||
|
for (int i = 1; i < lstKey.getItems().size(); i++) {
|
||||||
|
Button button = (Button)lstKey.getItems().get(i);
|
||||||
|
// update buttons text and remove key binding from command
|
||||||
|
if (button.getText().equals(event.getCode().toString())) {
|
||||||
|
button.setText("");
|
||||||
|
newKeyFactory.updateKey(button.getId(), button.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// update text on the button
|
||||||
|
currentButton.setText(event.getCode().toString());
|
||||||
|
// update the control key
|
||||||
|
newKeyFactory.updateKey(event.getCode().toString(),
|
||||||
|
currentButton.getId());
|
||||||
|
// remove current button selection
|
||||||
|
currentButton = null;
|
||||||
|
changed = true;
|
||||||
|
btnCancel.requestFocus();
|
||||||
|
}
|
||||||
|
event.consume();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancel and exits the key bindings menu. Changes are not forced to be
|
||||||
|
* saved or fixed if invalid, and instead are defaulted back to the last
|
||||||
|
* successful saved state.
|
||||||
|
*/
|
||||||
|
public void cancel(){
|
||||||
|
((Stage)btnCancel.getScene().getWindow()).close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets all key bindings to the built-in defaults.
|
||||||
|
*/
|
||||||
|
public void reset(){
|
||||||
|
lstKey.getItems().clear();
|
||||||
|
lstControl.getItems().clear();
|
||||||
|
lstDescription.getItems().clear();
|
||||||
|
newKeyFactory = new KeyFactory();
|
||||||
|
initializeTable();
|
||||||
|
populateTable();
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replace existing {@link KeyFactory} with the modified key bindings.
|
||||||
|
*/
|
||||||
|
public void save(){
|
||||||
|
if (isFactoryValid()) {
|
||||||
|
keyFactory = newKeyFactory;
|
||||||
|
newKeyFactory = new KeyFactory();
|
||||||
|
changed = false;
|
||||||
|
keyFactory.save(); // save persistently
|
||||||
|
loadNotification("Key bindings were successfully saved.", false);
|
||||||
|
} else {
|
||||||
|
loadNotification("One or more key bindings are missing. " +
|
||||||
|
"Failed to save.", true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks the {@link KeyFactory} being modified is valid and that no
|
||||||
|
* commands are missing a key binding.
|
||||||
|
* @return True if valid, false if invalid
|
||||||
|
*/
|
||||||
|
public Boolean isFactoryValid(){
|
||||||
|
for (Map.Entry<String, ControlKey> entry : newKeyFactory.getKeyState().entrySet
|
||||||
|
()) {
|
||||||
|
if (entry.getKey().toString()==entry.getValue().toString()){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method used to stop a user from exiting key bindings without saving
|
||||||
|
* their changes to the {@link KeyFactory}.
|
||||||
|
* @param we {@link WindowEvent} close request to be consumed if settings
|
||||||
|
* have not been successfully saved.
|
||||||
|
*/
|
||||||
|
public void onExit(WindowEvent we){
|
||||||
|
// if modified KeyFactory hasn't been saved
|
||||||
|
if (changed){
|
||||||
|
loadNotification("Please cancel or save your changes before exiting" +
|
||||||
|
".", true);
|
||||||
|
we.consume();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads a popup window giving confirmation/warning of user activity.
|
||||||
|
* @param message the message to be displayed to the user
|
||||||
|
* @param warning true if the message to be displayed is due to user error
|
||||||
|
*/
|
||||||
|
public void loadNotification(String message, Boolean warning){
|
||||||
|
Parent root = null;
|
||||||
|
FXMLLoader loader = new FXMLLoader(getClass().getResource
|
||||||
|
("/visualiser/scenes/notification.fxml"));
|
||||||
|
try {
|
||||||
|
root = loader.load();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
NotificationController controller = loader.getController();
|
||||||
|
Stage stage = new Stage();
|
||||||
|
stage.setScene(new Scene(root));
|
||||||
|
stage.centerOnScreen();
|
||||||
|
stage.initModality(Modality.APPLICATION_MODAL);
|
||||||
|
stage.show();
|
||||||
|
// displays given message in the window
|
||||||
|
controller.setMessage(message, warning);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package visualiser.Controllers;
|
||||||
|
|
||||||
|
import javafx.fxml.FXML;
|
||||||
|
import javafx.scene.control.Label;
|
||||||
|
import javafx.scene.paint.Color;
|
||||||
|
import javafx.scene.text.Text;
|
||||||
|
import javafx.stage.Stage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controller for a popup notification regarding user activity.
|
||||||
|
*/
|
||||||
|
public class NotificationController {
|
||||||
|
private @FXML Label lblDescription;
|
||||||
|
private @FXML Text txtMessage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes the popup window once clicked.
|
||||||
|
*/
|
||||||
|
public void ok(){
|
||||||
|
((Stage)lblDescription.getScene().getWindow()).close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays the appropriate popup notification.
|
||||||
|
* @param message message for the user
|
||||||
|
* @param warning if true warning text shown, if false success text shown
|
||||||
|
*/
|
||||||
|
public void setMessage(String message, Boolean warning){
|
||||||
|
lblDescription.setText(message);
|
||||||
|
if (!warning){
|
||||||
|
txtMessage.setText("Success!");
|
||||||
|
txtMessage.setFill(Color.GREEN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,7 +10,6 @@ import javafx.collections.transformation.SortedList;
|
|||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.scene.chart.LineChart;
|
import javafx.scene.chart.LineChart;
|
||||||
import javafx.scene.control.*;
|
import javafx.scene.control.*;
|
||||||
import javafx.scene.control.Label;
|
|
||||||
import javafx.scene.input.KeyCode;
|
import javafx.scene.input.KeyCode;
|
||||||
import javafx.scene.input.KeyEvent;
|
import javafx.scene.input.KeyEvent;
|
||||||
import javafx.scene.layout.AnchorPane;
|
import javafx.scene.layout.AnchorPane;
|
||||||
@@ -23,7 +22,6 @@ import shared.model.Leg;
|
|||||||
import visualiser.app.App;
|
import visualiser.app.App;
|
||||||
import visualiser.gameController.ControllerClient;
|
import visualiser.gameController.ControllerClient;
|
||||||
import visualiser.gameController.Keys.ControlKey;
|
import visualiser.gameController.Keys.ControlKey;
|
||||||
import visualiser.gameController.Keys.KeyFactory;
|
|
||||||
import visualiser.model.*;
|
import visualiser.model.*;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -33,6 +31,7 @@ import java.util.ResourceBundle;
|
|||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import static visualiser.app.App.keyFactory;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -113,7 +112,7 @@ public class RaceController extends Controller {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initialize(URL location, ResourceBundle resources) {
|
public void initialize(URL location, ResourceBundle resources) {
|
||||||
KeyFactory keyFactory = KeyFactory.getFactory();
|
// KeyFactory keyFactory = KeyFactory.getFactory();
|
||||||
infoTableShow = true;
|
infoTableShow = true;
|
||||||
|
|
||||||
// Initialise keyboard handler
|
// Initialise keyboard handler
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package visualiser.Controllers;
|
package visualiser.Controllers;
|
||||||
|
|
||||||
|
import javafx.event.EventHandler;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.fxml.FXMLLoader;
|
import javafx.fxml.FXMLLoader;
|
||||||
import javafx.scene.Parent;
|
import javafx.scene.Parent;
|
||||||
@@ -9,6 +10,7 @@ import javafx.scene.control.RadioButton;
|
|||||||
import javafx.scene.layout.AnchorPane;
|
import javafx.scene.layout.AnchorPane;
|
||||||
import javafx.stage.Modality;
|
import javafx.stage.Modality;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
|
import javafx.stage.WindowEvent;
|
||||||
import visualiser.app.App;
|
import visualiser.app.App;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -87,18 +89,26 @@ public class TitleController extends Controller {
|
|||||||
* Called when control button is pressed. New pop up window displaying controls
|
* Called when control button is pressed. New pop up window displaying controls
|
||||||
*/
|
*/
|
||||||
public void controlBtnPressed(){
|
public void controlBtnPressed(){
|
||||||
FXMLLoader loader = new FXMLLoader();
|
|
||||||
loader.setLocation(getClass().getResource("/visualiser/scenes/controls.fxml"));
|
|
||||||
Parent layout;
|
|
||||||
try {
|
try {
|
||||||
layout = loader.load();
|
FXMLLoader loader = new FXMLLoader();
|
||||||
|
loader.setLocation(getClass().getResource("/visualiser/scenes/keyBindings.fxml"));
|
||||||
|
Parent layout = loader.load();
|
||||||
Scene scene = new Scene(layout);
|
Scene scene = new Scene(layout);
|
||||||
Stage popupStage = new Stage();
|
Stage popupStage = new Stage();
|
||||||
popupStage.setResizable(false);
|
popupStage.setResizable(false);
|
||||||
popupStage.setTitle("Game Controls");
|
popupStage.setTitle("Game Controls");
|
||||||
popupStage.initModality(Modality.WINDOW_MODAL);
|
popupStage.initModality(Modality.WINDOW_MODAL);
|
||||||
|
popupStage.centerOnScreen();
|
||||||
popupStage.setScene(scene);
|
popupStage.setScene(scene);
|
||||||
popupStage.showAndWait();
|
popupStage.show();
|
||||||
|
KeyBindingsController controller = loader.getController();
|
||||||
|
popupStage.setOnCloseRequest(new EventHandler<WindowEvent>() {
|
||||||
|
public void handle(WindowEvent we) {
|
||||||
|
if (we.getEventType() == WindowEvent.WINDOW_CLOSE_REQUEST) {
|
||||||
|
controller.onExit(we);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
} catch (Exception e){
|
} catch (Exception e){
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package visualiser.app;
|
|||||||
import javafx.animation.FadeTransition;
|
import javafx.animation.FadeTransition;
|
||||||
import javafx.application.Application;
|
import javafx.application.Application;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
import javafx.beans.property.ReadOnlyObjectProperty;
|
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
import javafx.concurrent.Task;
|
import javafx.concurrent.Task;
|
||||||
@@ -15,7 +14,6 @@ import javafx.geometry.Rectangle2D;
|
|||||||
import javafx.scene.Parent;
|
import javafx.scene.Parent;
|
||||||
import javafx.scene.Scene;
|
import javafx.scene.Scene;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
import javafx.scene.control.ListView;
|
|
||||||
import javafx.scene.control.ProgressBar;
|
import javafx.scene.control.ProgressBar;
|
||||||
import javafx.scene.effect.DropShadow;
|
import javafx.scene.effect.DropShadow;
|
||||||
import javafx.scene.image.Image;
|
import javafx.scene.image.Image;
|
||||||
@@ -29,19 +27,17 @@ import javafx.stage.StageStyle;
|
|||||||
import javafx.stage.WindowEvent;
|
import javafx.stage.WindowEvent;
|
||||||
import javafx.util.Duration;
|
import javafx.util.Duration;
|
||||||
import visualiser.Controllers.MainController;
|
import visualiser.Controllers.MainController;
|
||||||
|
import visualiser.gameController.Keys.KeyFactory;
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class App extends Application {
|
public class App extends Application {
|
||||||
|
|
||||||
|
|
||||||
private static Stage stage;
|
private static Stage stage;
|
||||||
private Pane splashLayout;
|
private Pane splashLayout;
|
||||||
private ProgressBar loadProgress;
|
private ProgressBar loadProgress;
|
||||||
private Label progressText;
|
private Label progressText;
|
||||||
private static final int SPLASH_WIDTH = 676;
|
private static final int SPLASH_WIDTH = 676;
|
||||||
private static final int SPLASH_HEIGHT = 227;
|
private static final int SPLASH_HEIGHT = 227;
|
||||||
|
public static KeyFactory keyFactory = new KeyFactory();
|
||||||
public static App app;
|
public static App app;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -55,6 +51,9 @@ public class App extends Application {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init() {
|
public void init() {
|
||||||
|
// load the user's personalised key bindings
|
||||||
|
keyFactory.load();
|
||||||
|
|
||||||
ImageView splash = new ImageView(new Image(
|
ImageView splash = new ImageView(new Image(
|
||||||
getClass().getClassLoader().getResourceAsStream("images/splashScreen.png")
|
getClass().getClassLoader().getResourceAsStream("images/splashScreen.png")
|
||||||
));
|
));
|
||||||
|
|||||||
@@ -3,10 +3,11 @@ package visualiser.gameController;
|
|||||||
import javafx.animation.AnimationTimer;
|
import javafx.animation.AnimationTimer;
|
||||||
import javafx.scene.Scene;
|
import javafx.scene.Scene;
|
||||||
import visualiser.gameController.Keys.ControlKey;
|
import visualiser.gameController.Keys.ControlKey;
|
||||||
import visualiser.gameController.Keys.KeyFactory;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
import static visualiser.app.App.keyFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class for checking what keys are currently being used
|
* Class for checking what keys are currently being used
|
||||||
*/
|
*/
|
||||||
@@ -18,7 +19,7 @@ public class InputChecker {
|
|||||||
* @param scene Scene the controller is to run in parallel with.
|
* @param scene Scene the controller is to run in parallel with.
|
||||||
*/
|
*/
|
||||||
public void runWithScene(Scene scene){
|
public void runWithScene(Scene scene){
|
||||||
KeyFactory keyFactory = KeyFactory.getFactory();
|
// KeyFactory keyFactory = KeyFactory.getFactory();
|
||||||
|
|
||||||
scene.setOnKeyPressed(event -> {
|
scene.setOnKeyPressed(event -> {
|
||||||
String codeString = event.getCode().toString();
|
String codeString = event.getCode().toString();
|
||||||
|
|||||||
@@ -9,11 +9,9 @@ public class DownWindKey extends ControlKey {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for Control
|
* Constructor for Control
|
||||||
* @param name name of the key
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public DownWindKey(String name) {
|
public DownWindKey() {
|
||||||
super(name, BoatActionEnum.DOWNWIND);
|
super("Downwind", BoatActionEnum.DOWNWIND);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
package visualiser.gameController.Keys;
|
package visualiser.gameController.Keys;
|
||||||
|
|
||||||
|
import java.beans.XMLDecoder;
|
||||||
|
import java.beans.XMLEncoder;
|
||||||
|
import java.io.*;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@@ -13,30 +16,17 @@ public class KeyFactory {
|
|||||||
private Map<String, ControlKey> keyState;
|
private Map<String, ControlKey> keyState;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Singleton instance to enforce consistent key state
|
* Constructor for key state, set up initial state of each action.
|
||||||
*/
|
*/
|
||||||
private static KeyFactory theFactory = new KeyFactory();
|
public KeyFactory() {
|
||||||
|
|
||||||
/**
|
|
||||||
* Singleton constructor for key state, set up initial state of each action.
|
|
||||||
*/
|
|
||||||
private KeyFactory() {
|
|
||||||
this.keyState = new HashMap<>();
|
this.keyState = new HashMap<>();
|
||||||
keyState.put("Z", new ZoomInKey("Zoom In"));
|
keyState.put("Z", new ZoomInKey());
|
||||||
keyState.put("X", new ZoomOutKey("Zoom Out"));
|
keyState.put("X", new ZoomOutKey());
|
||||||
keyState.put("SPACE", new VMGKey("VMG"));
|
keyState.put("SPACE", new VMGKey());
|
||||||
keyState.put("SHIFT", new SailsToggleKey("Toggle Sails"));
|
keyState.put("SHIFT", new SailsToggleKey());
|
||||||
keyState.put("ENTER", new TackGybeKey("Tack/Gybe"));
|
keyState.put("ENTER", new TackGybeKey());
|
||||||
keyState.put("UP", new UpWindKey("Upwind"));
|
keyState.put("UP", new UpWindKey());
|
||||||
keyState.put("DOWN", new DownWindKey("Downwind"));
|
keyState.put("DOWN", new DownWindKey());
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get singleton instance of KeyFactory to interact with key state
|
|
||||||
* @return automatically constructed KeyFactory
|
|
||||||
*/
|
|
||||||
public static KeyFactory getFactory() {
|
|
||||||
return theFactory;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -48,4 +38,86 @@ public class KeyFactory {
|
|||||||
return keyState.get(key);
|
return keyState.get(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Map<String, ControlKey> getKeyState() {
|
||||||
|
return keyState;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setKeyState(Map<String, ControlKey> keyState) {
|
||||||
|
this.keyState = keyState;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the key bound to a particular command in the keystate.
|
||||||
|
* @param newKey the new key value for the command
|
||||||
|
* @param command the command to be updated
|
||||||
|
*/
|
||||||
|
public void updateKey(String newKey, String command){
|
||||||
|
ControlKey controlKey = null;
|
||||||
|
String oldKey = null;
|
||||||
|
for (Map.Entry<String, ControlKey> entry : keyState.entrySet()) {
|
||||||
|
// if this is the correct command
|
||||||
|
if (entry.getValue().toString()==command){
|
||||||
|
controlKey = entry.getValue();
|
||||||
|
oldKey = entry.getKey();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
keyState.remove(oldKey, controlKey);
|
||||||
|
keyState.put(newKey, controlKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Persistently saves the keybindings the user has set.
|
||||||
|
*/
|
||||||
|
public void save(){
|
||||||
|
try {
|
||||||
|
// open the filestream and write to it
|
||||||
|
FileOutputStream fos = new FileOutputStream(
|
||||||
|
System.getProperty("user.dir")+
|
||||||
|
"/settings/keyBindings.xml");
|
||||||
|
XMLEncoder xmlEncoder = new XMLEncoder(fos);
|
||||||
|
xmlEncoder.writeObject(this.keyState);
|
||||||
|
xmlEncoder.close();
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the persistently saved keybindings the user has set.
|
||||||
|
*/
|
||||||
|
public void load(){
|
||||||
|
try {
|
||||||
|
// access settings folder, create if it doesn't exist
|
||||||
|
File settingsFolder = new File(
|
||||||
|
System.getProperty("user.dir")+"/settings");
|
||||||
|
if (!settingsFolder.exists()){
|
||||||
|
settingsFolder.mkdir();
|
||||||
|
}
|
||||||
|
|
||||||
|
// access keybindings xml file, create if it doesn't exist
|
||||||
|
File savedFile = new File(
|
||||||
|
settingsFolder+"/keyBindings.xml");
|
||||||
|
if (!savedFile.exists()){
|
||||||
|
savedFile.createNewFile();
|
||||||
|
FileOutputStream fos = new FileOutputStream(savedFile);
|
||||||
|
XMLEncoder xmlEncoder = new XMLEncoder(fos);
|
||||||
|
xmlEncoder.writeObject(this.keyState);
|
||||||
|
xmlEncoder.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// load the saved settings into the game
|
||||||
|
InputStream is = new FileInputStream(savedFile);
|
||||||
|
XMLDecoder xmlDecoder = new XMLDecoder(is);
|
||||||
|
Map<String, ControlKey> savedKeyState
|
||||||
|
= (Map<String, ControlKey>)xmlDecoder.readObject();
|
||||||
|
xmlDecoder.close();
|
||||||
|
this.keyState = savedKeyState;
|
||||||
|
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,11 +10,9 @@ public class SailsToggleKey extends ControlKey {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for Control
|
* Constructor for Control
|
||||||
* @param name name of the key
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public SailsToggleKey(String name) {
|
public SailsToggleKey() {
|
||||||
super(name, BoatActionEnum.NOT_A_STATUS);
|
super("Toggle Sails", BoatActionEnum.NOT_A_STATUS);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -9,11 +9,9 @@ public class TackGybeKey extends ControlKey {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for Control
|
* Constructor for Control
|
||||||
* @param name name of the key
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public TackGybeKey(String name) {
|
public TackGybeKey() {
|
||||||
super(name, BoatActionEnum.TACK_GYBE);
|
super("Tack/Gybe", BoatActionEnum.TACK_GYBE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -9,11 +9,9 @@ public class UpWindKey extends ControlKey {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for Control
|
* Constructor for Control
|
||||||
* @param name name of the key
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public UpWindKey(String name) {
|
public UpWindKey() {
|
||||||
super(name, BoatActionEnum.UPWIND);
|
super("Upwind", BoatActionEnum.UPWIND);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package visualiser.gameController.Keys;
|
package visualiser.gameController.Keys;
|
||||||
|
|
||||||
import javafx.scene.input.KeyCode;
|
|
||||||
import network.Messages.Enums.BoatActionEnum;
|
import network.Messages.Enums.BoatActionEnum;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -10,11 +9,9 @@ public class VMGKey extends ControlKey{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for Control
|
* Constructor for Control
|
||||||
*
|
|
||||||
* @param name name of the key
|
|
||||||
*/
|
*/
|
||||||
public VMGKey(String name) {
|
public VMGKey() {
|
||||||
super(name, BoatActionEnum.AUTO_PILOT);
|
super("VMG", BoatActionEnum.AUTO_PILOT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ package visualiser.gameController.Keys;
|
|||||||
*/
|
*/
|
||||||
public class ZoomInKey extends ControlKey {
|
public class ZoomInKey extends ControlKey {
|
||||||
|
|
||||||
public ZoomInKey(String name) {
|
public ZoomInKey() {
|
||||||
super(name);
|
super("Zoom In");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -7,11 +7,9 @@ public class ZoomOutKey extends ControlKey{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for Control
|
* Constructor for Control
|
||||||
* @param name name of the key
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public ZoomOutKey(String name) {
|
public ZoomOutKey() {
|
||||||
super(name);
|
super("Zoom Out");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
.list-view .list-cell {
|
||||||
|
-fx-cell-size: 40;
|
||||||
|
-fx-font-family: "Tahoma";
|
||||||
|
-fx-background-color: #fffff0;
|
||||||
|
-fx-alignment: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-view .list-cell:even {
|
||||||
|
-fx-background-color: #ffffdc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-view .list-cell:selected {
|
||||||
|
-fx-background-color: #f9e5c3;
|
||||||
|
-fx-font-family: "Comic Sans MS";
|
||||||
|
-fx-font-weight: bold;
|
||||||
|
-fx-font-size: 18;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
-fx-background-color: linear-gradient(#acdeff 50%, #a9c8ff 100%);
|
||||||
|
-fx-background-radius: 4px;
|
||||||
|
-fx-border-radius: 4px;
|
||||||
|
-fx-text-fill: #242d35;
|
||||||
|
-fx-font-size: 12px;
|
||||||
|
-fx-font-family: "Courier New";
|
||||||
|
-fx-border-color: #a9c8ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button:focused {
|
||||||
|
-fx-background-color: white;
|
||||||
|
-fx-border-color: #0056bd;
|
||||||
|
}
|
||||||
|
|
||||||
|
#anchor {
|
||||||
|
-fx-background-color: #fdfac3;
|
||||||
|
}
|
||||||
|
#menu{
|
||||||
|
-fx-background-color: linear-gradient(#acdeff 50%, #a9c8ff 100%);
|
||||||
|
-fx-background-radius: 4px;
|
||||||
|
-fx-border-radius: 4px;
|
||||||
|
-fx-text-fill: #242d35;
|
||||||
|
-fx-font-size: 12px;
|
||||||
|
-fx-font-family: "Verdana";
|
||||||
|
-fx-border-color: #a9c8ff;
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<?import javafx.scene.control.Button?>
|
||||||
|
<?import javafx.scene.control.Label?>
|
||||||
|
<?import javafx.scene.control.ListView?>
|
||||||
|
<?import javafx.scene.layout.AnchorPane?>
|
||||||
|
<?import javafx.scene.text.Font?>
|
||||||
|
|
||||||
|
<AnchorPane id="anchor" fx:id="anchor" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="471.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="visualiser.Controllers.KeyBindingsController">
|
||||||
|
<children>
|
||||||
|
<Label fx:id="lblTitle" layoutX="172.0" layoutY="14.0" text="Key Bindings">
|
||||||
|
<font>
|
||||||
|
<Font name="Comic Sans MS" size="44.0" />
|
||||||
|
</font>
|
||||||
|
</Label>
|
||||||
|
<Button id="menu" fx:id="btnCancel" layoutX="430.0" layoutY="428.0"
|
||||||
|
mnemonicParsing="false" onAction="#cancel" prefWidth="160.0" text="Cancel" AnchorPane.bottomAnchor="18.0" AnchorPane.rightAnchor="20.0" />
|
||||||
|
<ListView fx:id="lstControl" focusTraversable="false" layoutX="27.0" layoutY="88.0" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="322.0" prefWidth="150.0" />
|
||||||
|
<ListView fx:id="lstKey" focusTraversable="false" layoutX="176.0" layoutY="88.0" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="322.0" prefWidth="150.0" />
|
||||||
|
<ListView fx:id="lstDescription" focusTraversable="false" layoutX="325.0" layoutY="88.0" prefHeight="322.0" prefWidth="250.0" />
|
||||||
|
<Button id="menu" fx:id="btnSave" layoutX="220.0" layoutY="428.0" mnemonicParsing="false" onAction="#save" prefWidth="160.0" text="Save" AnchorPane.bottomAnchor="18.0" />
|
||||||
|
<Button id="menu" fx:id="btnReset" layoutX="20.0" layoutY="428.0" mnemonicParsing="false" onAction="#reset" prefWidth="160.0" text="Reset to Default" AnchorPane.bottomAnchor="18.0" AnchorPane.leftAnchor="20.0" />
|
||||||
|
</children>
|
||||||
|
</AnchorPane>
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<?import javafx.scene.control.Button?>
|
||||||
|
<?import javafx.scene.control.Label?>
|
||||||
|
<?import javafx.scene.layout.Pane?>
|
||||||
|
<?import javafx.scene.text.Font?>
|
||||||
|
<?import javafx.scene.text.Text?>
|
||||||
|
|
||||||
|
<Pane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="100.0" prefWidth="300.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="visualiser.Controllers.NotificationController">
|
||||||
|
<children>
|
||||||
|
<Button fx:id="btnOk" layoutX="110.0" layoutY="65.0" mnemonicParsing="false" onAction="#ok" prefWidth="80.0" text="Ok" />
|
||||||
|
<Text fx:id="txtMessage" fill="RED" layoutY="23.0" strokeType="OUTSIDE" strokeWidth="0.0" text="Warning!" textAlignment="CENTER" wrappingWidth="300.0">
|
||||||
|
<font>
|
||||||
|
<Font name="System Bold" size="14.0" />
|
||||||
|
</font>
|
||||||
|
</Text>
|
||||||
|
<Label fx:id="lblDescription" alignment="CENTER" layoutY="36.0" prefHeight="17.0" prefWidth="300.0" textAlignment="CENTER" />
|
||||||
|
</children>
|
||||||
|
</Pane>
|
||||||
Reference in New Issue
Block a user