Merge branch 'story35_create_annotation_view' into 'develop'

Story35 create annotation view

## Addresses issue #9 and story 35

# Change Log
* Styled application using CSS (Issue #9)
* User can select to only show important annotations using the annotation slider
* Added view to select important annotations
* Important annotations are updated in real-time

# Testing
* Unit tests in test/java/seng302/visualizer/annotations/*
* Controllers have been tested manually

# Acceptance Criteria

* There is a mechanism to chose the ‘important’ annotations while viewing a race.

* Any number of annotations (from zero to the number of annotations) can be chosen.

* If the partial annotations toggle is active, choosing an annotation makes that annotation immediately visible for all boats, and deselecting an annotation should likewise remove it from all boats.

* When the partial annotations toggle becomes active, all annotations chosen as ‘important’, and only those annotations, should be shown.

See merge request !27
This commit is contained in:
Peter Galloway
2017-05-14 22:00:02 +12:00
12 changed files with 596 additions and 79 deletions
@@ -1,31 +1,31 @@
package seng302.controllers; package seng302.controllers;
import javafx.animation.*; import javafx.animation.AnimationTimer;
import javafx.beans.property.SimpleDoubleProperty; import javafx.beans.property.SimpleDoubleProperty;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.geometry.Point2D; import javafx.geometry.Point2D;
import javafx.scene.Group; import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.canvas.Canvas; import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext; import javafx.scene.canvas.GraphicsContext;
import javafx.scene.layout.AnchorPane; import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color; import javafx.scene.paint.Color;
import javafx.scene.shape.Polygon;
import javafx.scene.text.Font; import javafx.scene.text.Font;
import javafx.stage.Stage; import seng302.models.BoatGroup;
import seng302.models.*; import seng302.models.Colors;
import seng302.models.RaceObject;
import seng302.models.Yacht;
import seng302.models.mark.*; import seng302.models.mark.*;
import seng302.models.parsers.StreamParser; import seng302.models.parsers.StreamParser;
import seng302.models.parsers.StreamReceiver;
import seng302.models.parsers.packets.BoatPositionPacket;
import seng302.models.parsers.XMLParser; import seng302.models.parsers.XMLParser;
import seng302.models.parsers.XMLParser.RaceXMLObject.CompoundMark; import seng302.models.parsers.XMLParser.RaceXMLObject.CompoundMark;
import seng302.models.parsers.XMLParser.RaceXMLObject.Limit; import seng302.models.parsers.XMLParser.RaceXMLObject.Limit;
import seng302.models.mark.Mark; import seng302.models.parsers.packets.BoatPositionPacket;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.util.*; import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.PriorityBlockingQueue; import java.util.concurrent.PriorityBlockingQueue;
/** /**
@@ -18,12 +18,8 @@ import seng302.models.Yacht;
import seng302.models.parsers.StreamParser; import seng302.models.parsers.StreamParser;
import seng302.models.parsers.XMLParser; import seng302.models.parsers.XMLParser;
import java.io.IOException; import java.io.IOException;
import java.net.URL; import java.net.URL;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.ResourceBundle; import java.util.ResourceBundle;
import java.util.Timer; import java.util.Timer;
import java.util.TimerTask; import java.util.TimerTask;
@@ -50,12 +46,13 @@ public class Controller implements Initializable {
@FXML @FXML
private Label realTime; private Label realTime;
private XMLParser xmlParser; private boolean switchedToRaceView = false;
private void setContentPane(String jfxUrl){ private void setContentPane(String jfxUrl){
try{ try{
contentPane.getChildren().removeAll(); contentPane.getChildren().removeAll();
contentPane.getChildren().clear(); contentPane.getChildren().clear();
contentPane.getStylesheets().add(getClass().getResource("/css/master.css").toString());
contentPane.getChildren().addAll((Pane) FXMLLoader.load(getClass().getResource(jfxUrl))); contentPane.getChildren().addAll((Pane) FXMLLoader.load(getClass().getResource(jfxUrl)));
} }
catch(javafx.fxml.LoadException e){ catch(javafx.fxml.LoadException e){
@@ -68,9 +65,8 @@ public class Controller implements Initializable {
@Override @Override
public void initialize(URL location, ResourceBundle resources) { public void initialize(URL location, ResourceBundle resources) {
//DateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss"); contentPane.getStylesheets().add(getClass().getResource("/css/master.css").toString());
//format.setTimeZone(TimeZone.getTimeZone("GMT-8")); teamList.getStylesheets().add(getClass().getResource("/css/master.css").toString());
//realTime.setText(format.format(new Date()));
} }
/** /**
@@ -78,7 +74,6 @@ public class Controller implements Initializable {
*/ */
public void startStream() { public void startStream() {
if (StreamParser.isStreamStatus()) { if (StreamParser.isStreamStatus()) {
xmlParser = StreamParser.getXmlObject();
streamButton.setVisible(false); streamButton.setVisible(false);
realTime.setVisible(true); realTime.setVisible(true);
timeTillLive.setVisible(true); timeTillLive.setVisible(true);
@@ -90,7 +85,9 @@ public class Controller implements Initializable {
public void run() { public void run() {
Platform.runLater(() -> { Platform.runLater(() -> {
if (StreamParser.isRaceStarted()) { if (StreamParser.isRaceStarted()) {
if (!switchedToRaceView) {
switchToRaceView(); switchToRaceView();
}
timer.cancel(); timer.cancel();
} }
if (StreamParser.isRaceFinished()) { if (StreamParser.isRaceFinished()) {
@@ -133,12 +130,15 @@ public class Controller implements Initializable {
} }
public void switchToRaceView() { public void switchToRaceView() {
switchedToRaceView = true;
setContentPane("/views/RaceView.fxml"); setContentPane("/views/RaceView.fxml");
} }
private void updateTeamList() { private void updateTeamList() {
ObservableList<Yacht> data = FXCollections.observableArrayList(); ObservableList<Yacht> data = FXCollections.observableArrayList();
teamList.setItems(data); teamList.setItems(data);
boatNameCol.setCellValueFactory( boatNameCol.setCellValueFactory(
new PropertyValueFactory<>("boatName") new PropertyValueFactory<>("boatName")
); );
@@ -151,18 +151,8 @@ public class Controller implements Initializable {
posCol.setCellValueFactory( posCol.setCellValueFactory(
new PropertyValueFactory<>("position") new PropertyValueFactory<>("position")
); );
// if (StreamParser.isRaceStarted()) {
data.addAll(StreamParser.getBoatsPos().values());
// } else {
// for (Yacht boat : StreamParser.getBoats().values()) {
// boat.setPosition("-");
// data.add(boat);
// }
// }
teamList.refresh();
// posCol.setSortType(TableColumn.SortType.ASCENDING); data.addAll(StreamParser.getBoatsPos().values());
// teamList.getSortOrder().add(posCol); teamList.refresh();
// posCol.setSortable(false);
} }
} }
@@ -1,26 +1,31 @@
package seng302.controllers; package seng302.controllers;
import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;
import javafx.animation.Animation; import javafx.animation.Animation;
import javafx.animation.KeyFrame; import javafx.animation.KeyFrame;
import javafx.animation.Timeline; import javafx.animation.Timeline;
import javafx.beans.value.ChangeListener; import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue; import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader; import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox; import javafx.scene.control.CheckBox;
import javafx.scene.control.Slider; import javafx.scene.control.Slider;
import javafx.scene.layout.AnchorPane; import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.Pane; import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox; import javafx.scene.layout.VBox;
import javafx.scene.paint.Color; import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.scene.text.Text; import javafx.scene.text.Text;
import javafx.stage.Stage; import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.util.Duration; import javafx.util.Duration;
import javafx.util.StringConverter; import javafx.util.StringConverter;
import seng302.controllers.annotations.Annotation;
import seng302.controllers.annotations.ImportantAnnotationController;
import seng302.controllers.annotations.ImportantAnnotationDelegate;
import seng302.controllers.annotations.ImportantAnnotationsState;
import seng302.models.*; import seng302.models.*;
import seng302.models.parsers.ConfigParser;
import seng302.models.parsers.StreamParser; import seng302.models.parsers.StreamParser;
import java.io.IOException; import java.io.IOException;
@@ -29,7 +34,7 @@ import java.util.*;
/** /**
* Created by ptg19 on 29/03/17. * Created by ptg19 on 29/03/17.
*/ */
public class RaceViewController extends Thread{ public class RaceViewController extends Thread implements ImportantAnnotationDelegate{
@FXML @FXML
private VBox positionVbox; private VBox positionVbox;
@FXML @FXML
@@ -43,6 +48,8 @@ public class RaceViewController extends Thread{
@FXML @FXML
private Slider annotationSlider; private Slider annotationSlider;
@FXML @FXML
private Button selectAnnotationBtn;
@FXML
private CanvasController includedCanvasController; private CanvasController includedCanvasController;
private ArrayList<Yacht> startingBoats = new ArrayList<>(); private ArrayList<Yacht> startingBoats = new ArrayList<>();
@@ -52,21 +59,19 @@ public class RaceViewController extends Thread{
private ArrayList<Yacht> boatOrder = new ArrayList<>(); private ArrayList<Yacht> boatOrder = new ArrayList<>();
private Race race; private Race race;
private Stage stage; private Stage stage;
private ImportantAnnotationsState importantAnnotations;
public void initialize() { public void initialize() {
// Load a default important annotation state
importantAnnotations = new ImportantAnnotationsState();
RaceController raceController = new RaceController(); RaceController raceController = new RaceController();
raceController.initializeRace(); raceController.initializeRace();
race = raceController.getRace(); race = raceController.getRace();
for (Yacht boat : race.getBoats()) { for (Yacht boat : race.getBoats()) {
startingBoats.add(boat); startingBoats.add(boat);
} }
// try{
// initializeTimelines();
// }
// catch (Exception e){
// e.printStackTrace();
// }
includedCanvasController.setup(this); includedCanvasController.setup(this);
includedCanvasController.initializeCanvas(); includedCanvasController.initializeCanvas();
@@ -79,9 +84,48 @@ public class RaceViewController extends Thread{
// windDirectionText.setText(String.format("%.1f°", windDirection)); // windDirectionText.setText(String.format("%.1f°", windDirection));
// windArrowText.setRotate(windDirection); // windArrowText.setRotate(windDirection);
includedCanvasController.timer.start(); includedCanvasController.timer.start();
selectAnnotationBtn.setOnAction(event -> {
loadSelectAnnotationView();
});
} }
/**
* The important annotations have been changed, update this view
* @param importantAnnotationsState The current state of the selected annotations
*/
public void importantAnnotationsChanged(ImportantAnnotationsState importantAnnotationsState){
this.importantAnnotations = importantAnnotationsState;
setAnnotations((int)annotationSlider.getValue()); // Refresh the displayed annotations
}
/**
* Loads the "select annotations" view in a new window
*/
private void loadSelectAnnotationView() {
try {
FXMLLoader fxmlLoader = new FXMLLoader();
Stage stage = new Stage();
// Set controller
ImportantAnnotationController controller = new ImportantAnnotationController(this, stage);
fxmlLoader.setController(controller);
// Load FXML and set CSS
fxmlLoader.setLocation(getClass().getResource("/views/importantAnnotationSelectView.fxml"));
Scene scene = new Scene(fxmlLoader.load(), 469, 248);
scene.getStylesheets().add(getClass().getResource("/css/master.css").toString());
stage.initStyle(StageStyle.UNDECORATED);
stage.setScene(scene);
stage.show();
controller.loadState(importantAnnotations);
} catch (IOException e) {
e.printStackTrace();
}
}
private void initializeSettings() { private void initializeSettings() {
displayFps = true; displayFps = true;
@@ -93,13 +137,13 @@ public class RaceViewController extends Thread{
} }
}); });
//SLIFER STUFF BELOW //SLIDER STUFF BELOW
annotationSlider.setLabelFormatter(new StringConverter<Double>() { annotationSlider.setLabelFormatter(new StringConverter<Double>() {
@Override @Override
public String toString(Double n) { public String toString(Double n) {
if (n == 0) return "None"; if (n == 0) return "None";
if (n == 1) return "Low"; if (n == 1) return "Low";
if (n == 2) return "Medium"; if (n == 2) return "Important";
if (n == 3) return "All"; if (n == 3) return "All";
return "All"; return "All";
@@ -112,7 +156,7 @@ public class RaceViewController extends Thread{
return 0d; return 0d;
case "Low": case "Low":
return 1d; return 1d;
case "Medium": case "Important":
return 2d; return 2d;
case "All": case "All":
return 3d; return 3d;
@@ -303,6 +347,7 @@ public class RaceViewController extends Thread{
private void showOrder() { private void showOrder() {
positionVbox.getChildren().clear(); positionVbox.getChildren().clear();
positionVbox.getChildren().removeAll(); positionVbox.getChildren().removeAll();
positionVbox.getStylesheets().add(getClass().getResource("/css/master.css").toString());
// for (Boat boat : boatOrder) { // for (Boat boat : boatOrder) {
// positionVbox.getChildren().add(new Text(boat.getShortName() + " " + boat.getSpeedInKnots() + " Knots")); // positionVbox.getChildren().add(new Text(boat.getShortName() + " " + boat.getSpeedInKnots() + " Knots"));
@@ -310,11 +355,17 @@ public class RaceViewController extends Thread{
for (Yacht boat : StreamParser.getBoatsPos().values()) { for (Yacht boat : StreamParser.getBoatsPos().values()) {
if (boat.getBoatStatus() == 3) { // 3 is finish status if (boat.getBoatStatus() == 3) { // 3 is finish status
positionVbox.getChildren().add(new Text(boat.getPosition() + ". " + Text textToAdd = new Text(boat.getPosition() + ". " +
boat.getShortName() + " (Finished)")); boat.getShortName() + " (Finished)");
textToAdd.setFill(Paint.valueOf("#d3d3d3"));
positionVbox.getChildren().add(textToAdd);
} else { } else {
positionVbox.getChildren().add(new Text(boat.getPosition() + ". " + Text textToAdd = new Text(boat.getPosition() + ". " +
boat.getShortName() + " ")); boat.getShortName() + " ");
textToAdd.setFill(Paint.valueOf("#d3d3d3"));
textToAdd.setStyle("");
positionVbox.getChildren().add(textToAdd);
} }
} }
@@ -376,9 +427,43 @@ public class RaceViewController extends Thread{
return startingBoats; return startingBoats;
} }
/**
* Display the important annotations for a specific BoatGroup
* @param bg The boat group to set the annotations for
*/
private void setBoatGroupImportantAnnotations(BoatGroup bg){
if (importantAnnotations.getAnnotationState(Annotation.NAME)){
bg.setTeamNameObjectVisible(true);
}
else{
bg.setTeamNameObjectVisible(false);
}
if (importantAnnotations.getAnnotationState(Annotation.SPEED)){
bg.setVelocityObjectVisible(true);
}
else{
bg.setVelocityObjectVisible(false);
}
if (importantAnnotations.getAnnotationState(Annotation.TRACK)){
bg.setLineGroupVisible(true);
}
else{
bg.setLineGroupVisible(false);
}
if (importantAnnotations.getAnnotationState(Annotation.WAKE)){
bg.setWakeVisible(true);
}
else{
bg.setWakeVisible(false);
}
}
private void setAnnotations(Integer annotationLevel) { private void setAnnotations(Integer annotationLevel) {
switch (annotationLevel) { switch (annotationLevel) {
// No Annotations
case 0: case 0:
for (RaceObject ro : includedCanvasController.getRaceObjects()) { for (RaceObject ro : includedCanvasController.getRaceObjects()) {
if(ro instanceof BoatGroup) { if(ro instanceof BoatGroup) {
@@ -390,6 +475,7 @@ public class RaceViewController extends Thread{
} }
} }
break; break;
// Low Annotations
case 1: case 1:
for (RaceObject ro : includedCanvasController.getRaceObjects()) { for (RaceObject ro : includedCanvasController.getRaceObjects()) {
if(ro instanceof BoatGroup) { if(ro instanceof BoatGroup) {
@@ -401,17 +487,16 @@ public class RaceViewController extends Thread{
} }
} }
break; break;
// Important Annotations
case 2: case 2:
for (RaceObject ro : includedCanvasController.getRaceObjects()) { for (RaceObject ro : includedCanvasController.getRaceObjects()) {
if(ro instanceof BoatGroup) { if(ro instanceof BoatGroup) {
BoatGroup bg = (BoatGroup) ro; BoatGroup bg = (BoatGroup) ro;
bg.setTeamNameObjectVisible(true); setBoatGroupImportantAnnotations(bg);
bg.setVelocityObjectVisible(false);
bg.setLineGroupVisible(true);
bg.setWakeVisible(false);
} }
} }
break; break;
// All Annotations
case 3: case 3:
for (RaceObject ro : includedCanvasController.getRaceObjects()) { for (RaceObject ro : includedCanvasController.getRaceObjects()) {
if(ro instanceof BoatGroup) { if(ro instanceof BoatGroup) {
@@ -0,0 +1,11 @@
package seng302.controllers.annotations;
/**
* Annotations the user can select as important
*/
public enum Annotation {
SPEED,
WAKE,
TRACK,
NAME
}
@@ -0,0 +1,114 @@
package seng302.controllers.annotations;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;
import seng302.controllers.RaceViewController;
import seng302.controllers.annotations.Annotation;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.ResourceBundle;
public class ImportantAnnotationController implements Initializable {
/*
* JavaFX Outlets
*/
@FXML
private CheckBox boatWakeSelect;
@FXML
private CheckBox boatSpeedSelect;
@FXML
private CheckBox boatTrackSelect;
@FXML
private CheckBox boatNameSelect;
@FXML
private AnchorPane annotationSelectWindow;
@FXML
private Button closeButton;
private ImportantAnnotationDelegate delegate;
private ImportantAnnotationsState importantAnnotationsState;
private Stage stage;
public ImportantAnnotationController(ImportantAnnotationDelegate delegate, Stage stage){
this.delegate = delegate;
importantAnnotationsState = new ImportantAnnotationsState();
this.stage = stage;
}
/**
* Sets whether or not an annotation is considered important, then
* sends an update to the delegate
* @param annotation The annotation
* @param isSet True if annotation is important
*/
private void setAnnotation(Annotation annotation, Boolean isSet){
importantAnnotationsState.setAnnotationState(annotation, isSet);
sendUpdate();
}
/**
* Sends an update to the delegate when the important
* annotations have changed
*/
private void sendUpdate(){
this.delegate.importantAnnotationsChanged(importantAnnotationsState);
}
/**
* Load the current state of the 'important annotations'
* @param currentState hashmap containing the states of each annotation
*/
public void loadState(ImportantAnnotationsState currentState){
this.importantAnnotationsState = currentState;
// Initialise checkboxes
for (Annotation annotation : importantAnnotationsState.getAnnotations()){
switch (annotation){
case WAKE:
boatWakeSelect.setSelected(importantAnnotationsState.getAnnotationState(annotation));
break;
case SPEED:
boatSpeedSelect.setSelected(importantAnnotationsState.getAnnotationState(annotation));
break;
case TRACK:
boatTrackSelect.setSelected(importantAnnotationsState.getAnnotationState(annotation));
break;
case NAME:
boatNameSelect.setSelected(importantAnnotationsState.getAnnotationState(annotation));
break;
default:
break;
}
}
}
/**
* View did load
* @param location .
* @param resources .
*/
@Override
public void initialize(URL location, ResourceBundle resources) {
boatWakeSelect.setOnAction(event -> setAnnotation(Annotation.WAKE, boatWakeSelect.isSelected()));
boatSpeedSelect.setOnAction(event -> setAnnotation(Annotation.SPEED, boatSpeedSelect.isSelected()));
boatTrackSelect.setOnAction(event -> setAnnotation(Annotation.TRACK, boatTrackSelect.isSelected()));
boatNameSelect.setOnAction(event -> setAnnotation(Annotation.NAME, boatNameSelect.isSelected()));
closeButton.setOnAction(event -> stage.close());
}
}
@@ -0,0 +1,16 @@
package seng302.controllers.annotations;
/**
* An ImportantAnnotationDelegate handles updating the important annotations
* displayed to the user on behalf of the ImportantAnnotationController
*/
public interface ImportantAnnotationDelegate {
/**
* The important annotations have been changed, update the
* annotations displayed to the user
* @param importantAnnotationsState The current state of the selected annotations
*/
void importantAnnotationsChanged(ImportantAnnotationsState importantAnnotationsState);
}
@@ -0,0 +1,52 @@
package seng302.controllers.annotations;
import java.util.HashMap;
import java.util.Map;
public class ImportantAnnotationsState {
public static final Boolean DEFAULT_ANNOTATION_STATE = true;
private Map<Annotation, Boolean> currentState;
/**
* Stores the users preference for the annotations
* they consider to be important
*/
public ImportantAnnotationsState(){
this.currentState = new HashMap<>();
initialiseState();
}
/**
* Set each annotation to the default annotation state
*/
private void initialiseState(){
for (Annotation annotation : getAnnotations()){
currentState.put(annotation, DEFAULT_ANNOTATION_STATE);
}
}
/**
* Sets the state (visibility) of an annotation
* @param annotation The annotation to set
* @param visible Whether or not the annotation should be visible
*/
public void setAnnotationState(Annotation annotation, Boolean visible){
this.currentState.put(annotation, visible);
}
/**
* Returns the state (visibility) of a specific annotation
* @param annotation The annotation to check
* @return True if visible, else false
*/
public Boolean getAnnotationState(Annotation annotation){
return this.currentState.containsKey(annotation) && this.currentState.get(annotation);
}
/**
* @return Return an array containing all defined annotations
*/
public Annotation[] getAnnotations(){
return Annotation.class.getEnumConstants();
}
}
+166
View File
@@ -0,0 +1,166 @@
/**
Background colours
*/
.background-blue{
-fx-background-color: #119796;
}
.background-dark{
-fx-background-color: #2C2c36;
}
/**
Exit button with no background
*/
.clear-exit-btn{
-fx-background-insets: 0;
-fx-background-color: #119796;
-fx-border-style: none;
}
/**
Buttons
*/
.blue-ui-btn{
-fx-background-color: #119796;
-fx-text-fill: #fff;
}
.text-white {
-fx-text-fill: white !important;
-fx-fill:white !important;
}
/**
Sliders
*/
.ui-slider .thumb {
-fx-background-color: rgb(60, 60, 60);
-fx-border-radius: 10;
-fx-border-color: darkgray;
}
.ui-slider .track{
-fx-background-color: #119796;
}
.ui-slider .axis{
-fx-tick-label-fill: white;
}
.ui-slider .axis .axis-label{
-fx-text-fill: white;
}
/**
Checkbox
*/
.ui-checkbox .box{
-fx-background-color: white;
-fx-graphic:none;
-fx-shape: none;
}
.ui-checkbox .box .mark{
-fx-background-image: none;
-fx-image: none;
-fx-graphic: none;
-fx-shape: none;
}
.ui-checkbox:selected .box{
-fx-background-color: #119796;
-fx-shape: none;
}
.ui-checkbox:selected .box .mark{
-fx-background-color: #119796;
-fx-shape: none;
-fx-graphic: none;
}
/**
Table
*/
.ui-table{
-fx-background-color: transparent;
}
.ui-table:focused{
-fx-background-color: transparent;
}
.ui-table .column-header-background{
-fx-background-color: white
}
.ui-table .column-header-background .label{
-fx-background-color: transparent;
-fx-text-fill: black;
}
.ui-table .column-header {
-fx-background-color: transparent;
}
.ui-table .table-cell{
-fx-text-fill: white;
-fx-border-style: none;
}
.table-row-cell{
-fx-background-color: #119796;
-fx-background-insets: 0, 0 0 1 0;
-fx-padding: 0.0em; /* 0 */
-fx-border-style: none;
}
.table-row-cell:odd{
-fx-background-color: #0e6d6c;
-fx-background-insets: 0, 0 0 1 0;
-fx-padding: 0.0em; /* 0 */
-fx-border-style: none;
}
.table-row-cell:selected {
-fx-background-color: #005797;
-fx-background-insets: 0;
-fx-border-style: none;
}
/**
Remove scroll bars
*/
.ui-table *.scroll-bar:horizontal *.increment-button,
.ui-table *.scroll-bar:horizontal *.decrement-button {
-fx-background-color: null;
-fx-background-radius: 0;
-fx-background-insets: 0;
-fx-padding: 0;
}
.ui-table *.scroll-bar:horizontal *.increment-arrow,
.ui-table *.scroll-bar:horizontal *.decrement-arrow {
-fx-background-color: null;
-fx-background-radius: 0;
-fx-background-insets: 0;
-fx-padding: 0;
-fx-shape: null;
}
.ui-table *.scroll-bar:vertical *.increment-arrow,
.ui-table *.scroll-bar:vertical *.decrement-arrow {
-fx-background-color: null;
-fx-background-radius: 0;
-fx-background-insets: 0;
-fx-padding: 0;
-fx-shape: null;
}
.ui-table *.scroll-bar:vertical *.increment-button,
.ui-table *.scroll-bar:vertical *.decrement-button {
-fx-background-color: null;
-fx-background-radius: 0;
-fx-background-insets: 0;
-fx-padding: 0;
}
+13 -13
View File
@@ -9,7 +9,7 @@
<AnchorPane fx:id="contentPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="seng302.controllers.Controller"> <AnchorPane fx:id="contentPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="seng302.controllers.Controller">
<children> <children>
<GridPane nodeOrientation="LEFT_TO_RIGHT" prefWidth="800.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> <GridPane nodeOrientation="LEFT_TO_RIGHT" prefWidth="800.0" style="-fx-background-color: #2C2c36;" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<columnConstraints> <columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" /> <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints> </columnConstraints>
@@ -18,23 +18,23 @@
<RowConstraints maxHeight="52.0" minHeight="52.0" prefHeight="52.0" vgrow="SOMETIMES" /> <RowConstraints maxHeight="52.0" minHeight="52.0" prefHeight="52.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="0.0" percentHeight="8.0" prefHeight="0.0" vgrow="SOMETIMES" /> <RowConstraints maxHeight="0.0" percentHeight="8.0" prefHeight="0.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="28.0" vgrow="SOMETIMES" /> <RowConstraints maxHeight="28.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="55.0" minHeight="55.0" percentHeight="5.0" prefHeight="55.0" vgrow="SOMETIMES" /> <RowConstraints maxHeight="55.0" minHeight="55.0" percentHeight="9.0" prefHeight="55.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="0.0" minHeight="0.0" percentHeight="23.0" prefHeight="0.0" vgrow="SOMETIMES" /> <RowConstraints maxHeight="0.0" minHeight="0.0" percentHeight="29.0" prefHeight="0.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="93.0" minHeight="72.0" prefHeight="72.0" vgrow="SOMETIMES" /> <RowConstraints maxHeight="93.0" minHeight="72.0" prefHeight="72.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="283.0" minHeight="262.0" prefHeight="283.0" vgrow="SOMETIMES" /> <RowConstraints maxHeight="283.0" minHeight="262.0" prefHeight="283.0" vgrow="SOMETIMES" />
</rowConstraints> </rowConstraints>
<children> <children>
<Label alignment="CENTER" text="Welcome to Race Vision" GridPane.halignment="CENTER" GridPane.valignment="BOTTOM"> <Label alignment="CENTER" text="Welcome to Race Vision" textFill="WHITE" GridPane.halignment="CENTER" GridPane.valignment="BOTTOM">
<font> <font>
<Font size="40.0" /> <Font size="40.0" />
</font> </font>
</Label> </Label>
<Label text="Your live AC35 livestream" GridPane.halignment="CENTER" GridPane.rowIndex="1"> <Label text="Your live AC35 livestream" textFill="WHITE" GridPane.halignment="CENTER" GridPane.rowIndex="1">
<font> <font>
<Font size="20.0" /> <Font size="20.0" />
</font> </font>
</Label> </Label>
<Label text="Livestream Status:" GridPane.halignment="CENTER" GridPane.rowIndex="2" GridPane.valignment="BOTTOM"> <Label text="Livestream Status:" textFill="WHITE" GridPane.halignment="CENTER" GridPane.rowIndex="2" GridPane.valignment="BOTTOM">
<font> <font>
<Font size="28.0" /> <Font size="28.0" />
</font> </font>
@@ -44,20 +44,20 @@
<Font size="27.0" /> <Font size="27.0" />
</font> </font>
</Label> </Label>
<Button fx:id="streamButton" mnemonicParsing="false" onAction="#startStream" text="Click to stream" GridPane.halignment="CENTER" GridPane.rowIndex="4" /> <Button fx:id="streamButton" mnemonicParsing="false" onAction="#startStream" styleClass="blue-ui-btn" text="Click to stream" GridPane.halignment="CENTER" GridPane.rowIndex="4" />
<Button fx:id="switchToRaceViewButton" disable="true" mnemonicParsing="false" onAction="#switchToRaceView" text="Watch Race" GridPane.halignment="CENTER" GridPane.rowIndex="7" GridPane.valignment="TOP" /> <Button fx:id="switchToRaceViewButton" disable="true" mnemonicParsing="false" onAction="#switchToRaceView" styleClass="blue-ui-btn" text="Watch Race" GridPane.halignment="CENTER" GridPane.rowIndex="7" GridPane.valignment="TOP" />
<TableView fx:id="teamList" maxWidth="500.0" prefHeight="200.0" prefWidth="210.0" GridPane.halignment="CENTER" GridPane.rowIndex="5"> <TableView fx:id="teamList" maxWidth="661.0" prefHeight="324.0" prefWidth="629.0" styleClass="ui-table" GridPane.halignment="CENTER" GridPane.hgrow="NEVER" GridPane.rowIndex="5" GridPane.vgrow="NEVER">
<columns> <columns>
<TableColumn fx:id="posCol" editable="false" maxWidth="74.0" minWidth="74.0" prefWidth="74.0" resizable="false" sortable="false" text="Position" /> <TableColumn fx:id="posCol" editable="false" maxWidth="74.0" minWidth="74.0" prefWidth="74.0" resizable="false" sortable="false" text="Position" />
<TableColumn fx:id="boatNameCol" editable="false" maxWidth="171.0" minWidth="171.0" prefWidth="171.0" resizable="false" sortable="false" text="Boat Name" /> <TableColumn fx:id="boatNameCol" editable="false" maxWidth="171.0" minWidth="171.0" prefWidth="171.0" resizable="false" sortable="false" text="Boat Name" />
<TableColumn fx:id="shortNameCol" editable="false" maxWidth="107.0" minWidth="107.0" prefWidth="107.0" resizable="false" sortable="false" text="Short Name" /> <TableColumn fx:id="shortNameCol" editable="false" maxWidth="155.18472290039062" minWidth="107.0" prefWidth="155.18472290039062" resizable="false" sortable="false" text="Short Name" />
<TableColumn fx:id="countryCol" editable="false" maxWidth="147.0" minWidth="147.0" prefWidth="147.0" resizable="false" sortable="false" text="Country" /> <TableColumn fx:id="countryCol" editable="false" maxWidth="258.9999694824219" minWidth="147.0" prefWidth="258.9999694824219" resizable="false" sortable="false" text="Country" />
</columns> </columns>
<GridPane.margin> <GridPane.margin>
<Insets /> <Insets top="10.0" />
</GridPane.margin> </GridPane.margin>
</TableView> </TableView>
<Label fx:id="realTime" text="Local time" visible="false" GridPane.halignment="CENTER" GridPane.rowIndex="3" GridPane.valignment="BOTTOM" /> <Label fx:id="realTime" text="Local time" textFill="WHITE" visible="false" GridPane.halignment="CENTER" GridPane.rowIndex="3" GridPane.valignment="BOTTOM" />
</children> </children>
</GridPane> </GridPane>
</children> </children>
+14 -13
View File
@@ -28,36 +28,37 @@
<RowConstraints /> <RowConstraints />
</rowConstraints> </rowConstraints>
<children> <children>
<AnchorPane prefHeight="200.0" prefWidth="200.0" GridPane.rowSpan="3"> <AnchorPane prefHeight="200.0" prefWidth="200.0" style="-fx-background-color: #2C2c36;" GridPane.rowSpan="3">
<children> <children>
<Label layoutX="11.0" layoutY="259.0" text="Team Position" /> <Label layoutX="11.0" layoutY="259.0" text="Team Position" textFill="WHITE" />
<Label layoutX="13.0" layoutY="432.0" text="Settings" /> <Label layoutX="13.0" layoutY="432.0" text="Settings" textFill="WHITE" />
<Label layoutX="11.0" layoutY="14.0" text="Timer" /> <Label layoutX="11.0" layoutY="14.0" text="Timer" textFill="WHITE" />
<Label layoutX="11.0" layoutY="88.0" text="Wind direction" /> <Label layoutX="11.0" layoutY="88.0" text="Wind direction" textFill="WHITE" />
<Circle fx:id="windBackgroundCircle" blendMode="DARKEN" fill="#76baf8" layoutX="110.0" layoutY="166.0" radius="35.0" stroke="#686868" strokeType="INSIDE" strokeWidth="3.0" /> <Circle fx:id="windBackgroundCircle" blendMode="DARKEN" fill="#3dcdc8" layoutX="110.0" layoutY="166.0" radius="35.0" stroke="#d7d7d7" strokeType="INSIDE" strokeWidth="3.0" />
<Text fx:id="windArrowText" fill="#686868" layoutX="86.0" layoutY="186.0" strokeType="OUTSIDE" strokeWidth="0.0" text="↑"> <Text fx:id="windArrowText" fill="#a8a8a8" layoutX="86.0" layoutY="186.0" strokeType="OUTSIDE" strokeWidth="0.0" text="↑">
<font> <font>
<Font name="AdobeArabic-Regular" size="55.0" /> <Font name="AdobeArabic-Regular" size="55.0" />
</font> </font>
</Text> </Text>
<Text fx:id="windDirectionText" fill="#a8a7a7" layoutX="171.0" layoutY="214.0" strokeType="OUTSIDE" strokeWidth="0.0" text="0.0°" textAlignment="RIGHT"> <Text fx:id="windDirectionText" fill="#d3d3d3" layoutX="171.0" layoutY="214.0" strokeType="OUTSIDE" strokeWidth="0.0" text="0.0°" textAlignment="RIGHT">
<font> <font>
<Font name="System Bold" size="13.0" /> <Font name="System Bold" size="13.0" />
</font> </font>
</Text> </Text>
<CheckBox fx:id="toggleFps" layoutX="21.0" layoutY="453.0" mnemonicParsing="false" prefHeight="18.0" prefWidth="143.0" selected="true" text="Show FPS" /> <CheckBox fx:id="toggleFps" graphicTextGap="0.0" layoutX="21.0" layoutY="453.0" mnemonicParsing="false" prefHeight="18.0" prefWidth="143.0" selected="true" styleClass="ui-checkbox" text="Show FPS" textFill="WHITE" />
<VBox fx:id="positionVbox" layoutX="12.0" layoutY="280.0" prefHeight="140.0" prefWidth="200.0" /> <VBox fx:id="positionVbox" layoutX="12.0" layoutY="280.0" prefHeight="140.0" prefWidth="200.0" styleClass="text-white" />
<Pane layoutX="11.0" layoutY="30.0" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="51.0" prefWidth="193.0"> <Pane layoutX="11.0" layoutY="30.0" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="51.0" prefWidth="193.0">
<children> <children>
<Text fx:id="timerLabel" layoutX="-26.0" layoutY="34.0" strokeType="OUTSIDE" strokeWidth="0.0" text="00:00" textAlignment="CENTER" wrappingWidth="246.0"> <Text fx:id="timerLabel" fill="#f8f8f8" layoutX="-26.0" layoutY="34.0" strokeType="OUTSIDE" strokeWidth="0.0" text="00:00" textAlignment="CENTER" wrappingWidth="246.0">
<font> <font>
<Font size="25.0" /> <Font size="25.0" />
</font> </font>
</Text> </Text>
</children> </children>
</Pane> </Pane>
<Slider fx:id="annotationSlider" blockIncrement="1.0" layoutX="38.0" layoutY="527.0" majorTickUnit="1.0" max="3.0" minorTickCount="0" prefHeight="51.0" prefWidth="170.0" showTickLabels="true" showTickMarks="true" snapToTicks="true" /> <Slider fx:id="annotationSlider" blockIncrement="1.0" layoutX="38.0" layoutY="527.0" majorTickUnit="1.0" max="3.0" minorTickCount="0" prefHeight="51.0" prefWidth="170.0" showTickLabels="true" showTickMarks="true" snapToTicks="true" styleClass="ui-slider" />
<Label layoutX="10.0" layoutY="499.0" text="Annotations" /> <Label layoutX="10.0" layoutY="499.0" text="Annotations" textFill="WHITE" />
<Button fx:id="selectAnnotationBtn" layoutX="35.0" layoutY="578.0" mnemonicParsing="false" prefHeight="18.0" prefWidth="170.0" styleClass="blue-ui-btn" text="Select Annotations" textFill="WHITE" />
</children> </children>
</AnchorPane> </AnchorPane>
<AnchorPane fx:id="contentAnchorPane" prefHeight="960.0" prefWidth="1280.0" style="-fx-background-color: skyblue;" GridPane.columnIndex="1" GridPane.halignment="LEFT" GridPane.rowSpan="2147483647" GridPane.valignment="TOP"> <AnchorPane fx:id="contentAnchorPane" prefHeight="960.0" prefWidth="1280.0" style="-fx-background-color: skyblue;" GridPane.columnIndex="1" GridPane.halignment="LEFT" GridPane.rowSpan="2147483647" GridPane.valignment="TOP">
@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.text.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<AnchorPane fx:id="annotationSelectWindow" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="248.0" prefWidth="469.0" styleClass="background-blue" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<children>
<Text fill="WHITE" layoutX="26.0" layoutY="52.0" strokeType="OUTSIDE" strokeWidth="0.0" text="Select important annotations">
<font>
<Font size="24.0" />
</font>
</Text>
<CheckBox fx:id="boatWakeSelect" layoutX="26.0" layoutY="80.0" mnemonicParsing="false" style="-fx-border-width: 0; -fx-background-insets: 0;" text="Boat Wakes" textFill="#e7e7e7" />
<CheckBox fx:id="boatSpeedSelect" layoutX="26.0" layoutY="111.0" mnemonicParsing="false" text="Boat Speed" textFill="#e7e7e7" />
<CheckBox fx:id="boatTrackSelect" layoutX="26.0" layoutY="142.0" mnemonicParsing="false" text="Boat Tracks" textFill="#e7e7e7" />
<CheckBox fx:id="boatNameSelect" layoutX="26.0" layoutY="175.0" mnemonicParsing="false" text="Boat Name" textFill="#e7e7e7" />
<Button fx:id="closeButton" layoutX="424.0" layoutY="-1.0" mnemonicParsing="false" prefHeight="11.0" prefWidth="49.0" style=": 0;" text="X" textFill="#ffffff4e">
<font>
<Font size="24.0" />
</font>
<styleClass>
<String fx:value="background-blue" />
<String fx:value="clearExitButton" />
</styleClass>
</Button>
</children>
</AnchorPane>
@@ -0,0 +1,53 @@
package seng302.visualizer.annotations;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import seng302.controllers.annotations.Annotation;
import seng302.controllers.annotations.ImportantAnnotationsState;
import static org.junit.Assert.assertEquals;
public class TestImportantAnnotationState {
private ImportantAnnotationsState importantAnnotationsState;
@Before
public void setUpForTest(){
importantAnnotationsState = new ImportantAnnotationsState();
}
@After
public void tearDownAfterTest(){
importantAnnotationsState = null;
}
/**
* Check whether each annotation has its default value set to the default value when
* the class is initialized
*/
@Test
public void testDefaultValueSet(){
for (Annotation annotation : importantAnnotationsState.getAnnotations()){
assertEquals(ImportantAnnotationsState.DEFAULT_ANNOTATION_STATE,
importantAnnotationsState.getAnnotationState(annotation));
}
}
/**
* Check whether an annotations state can be changed
*/
@Test
public void testAnnotationStateChange(){
Annotation[] annotations = importantAnnotationsState.getAnnotations();
// do not run test if there are no annotations
if (annotations.length <= 0){
return;
}
Boolean currentAnnotationState = importantAnnotationsState.getAnnotationState(annotations[0]);
importantAnnotationsState.setAnnotationState(annotations[0], !currentAnnotationState);
assertEquals(!currentAnnotationState, importantAnnotationsState.getAnnotationState(annotations[0]));
}
}