jace/src/main/java/jace/JaceUIController.java

269 lines
9.3 KiB
Java

/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package jace;
import com.sun.glass.ui.Application;
import jace.cheat.MetaCheat;
import jace.core.Card;
import jace.core.Computer;
import jace.core.Keyboard;
import jace.library.MediaCache;
import jace.library.MediaConsumer;
import jace.library.MediaConsumerParent;
import jace.library.MediaEntry;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.geometry.Insets;
import javafx.scene.control.Label;
import javafx.scene.effect.DropShadow;
import javafx.scene.image.ImageView;
import javafx.scene.input.DragEvent;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.TransferMode;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.CornerRadii;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
/**
*
* @author blurry
*/
public class JaceUIController {
@FXML
private URL location;
@FXML
private AnchorPane rootPane;
@FXML
private StackPane stackPane;
@FXML
private HBox notificationBox;
@FXML
private ImageView appleScreen;
Computer computer;
@FXML
void initialize() {
assert rootPane != null : "fx:id=\"rootPane\" was not injected: check your FXML file 'JaceUI.fxml'.";
assert stackPane != null : "fx:id=\"stackPane\" was not injected: check your FXML file 'JaceUI.fxml'.";
assert notificationBox != null : "fx:id=\"notificationBox\" was not injected: check your FXML file 'JaceUI.fxml'.";
assert appleScreen != null : "fx:id=\"appleScreen\" was not injected: check your FXML file 'JaceUI.fxml'.";
appleScreen.fitWidthProperty().bind(rootPane.widthProperty());
appleScreen.fitHeightProperty().bind(rootPane.heightProperty());
rootPane.setOnDragEntered(this::processDragEnteredEvent);
rootPane.setOnDragExited(this::processDragExitedEvent);
}
public void connectComputer(Computer computer, Stage primaryStage) {
this.computer = computer;
appleScreen.setImage(computer.getVideo().getFrameBuffer());
EventHandler<KeyEvent> keyboardHandler = computer.getKeyboard().getListener();
primaryStage.setOnShowing(evt -> computer.getKeyboard().resetState());
rootPane.setFocusTraversable(true);
rootPane.setOnKeyPressed(keyboardHandler);
rootPane.setOnKeyReleased(keyboardHandler);
rootPane.requestFocus();
}
private void processDragEnteredEvent(DragEvent evt) {
MediaEntry media = null;
if (evt.getDragboard().hasFiles()) {
media = MediaCache.getMediaFromFile(getDraggedFile(evt.getDragboard().getFiles()));
} else if (evt.getDragboard().hasUrl()) {
media = MediaCache.getMediaFromUrl(evt.getDragboard().getUrl());
} else if (evt.getDragboard().hasString()) {
String path = evt.getDragboard().getString();
try {
URI.create(path);
media = MediaCache.getMediaFromUrl(path);
} catch (IllegalArgumentException ex) {
File f = new File(path);
if (f.exists()) {
media = MediaCache.getMediaFromFile(f);
}
}
}
if (media != null) {
evt.acceptTransferModes(TransferMode.LINK, TransferMode.COPY);
startDragEvent(media);
}
}
private void processDragExitedEvent(DragEvent evt) {
endDragEvent();
}
private File getDraggedFile(List<File> files) {
if (files == null || files.isEmpty()) {
return null;
}
for (File f : files) {
if (f.exists()) {
return f;
}
}
return null;
}
HBox drivePanel;
private void startDragEvent(MediaEntry media) {
List<MediaConsumer> consumers = getMediaConsumers();
drivePanel = new HBox();
consumers.stream()
.filter((consumer) -> (consumer.isAccepted(media, media.files.get(0))))
.forEach((consumer) -> {
Label icon = consumer.getIcon().orElse(null);
if (icon == null) {
return;
}
icon.setTextFill(Color.WHITE);
icon.setPadding(new Insets(2.0));
drivePanel.getChildren().add(icon);
icon.setOnDragOver(event -> {
event.acceptTransferModes(TransferMode.ANY);
event.consume();
});
icon.setOnDragDropped(event -> {
System.out.println("Dropping media on " + icon.getText());
try {
computer.pause();
consumer.insertMedia(media, media.files.get(0));
computer.resume();
event.setDropCompleted(true);
event.consume();
} catch (IOException ex) {
Logger.getLogger(JaceUIController.class.getName()).log(Level.SEVERE, null, ex);
}
endDragEvent();
});
});
stackPane.getChildren().add(drivePanel);
drivePanel.setLayoutX(10);
drivePanel.setLayoutY(10);
}
private void endDragEvent() {
stackPane.getChildren().remove(drivePanel);
drivePanel.getChildren().stream().forEach((n) -> {
n.setOnDragDropped(null);
});
}
private List<MediaConsumer> getMediaConsumers() {
List<MediaConsumer> consumers = new ArrayList<>();
for (Optional<Card> card : computer.memory.getAllCards()) {
card.filter(c -> c instanceof MediaConsumerParent).ifPresent(parent -> {
consumers.addAll(Arrays.asList(((MediaConsumerParent) parent).getConsumers()));
});
}
return consumers;
}
Map<Label, Long> iconTTL = new ConcurrentHashMap<>();
void addIndicator(Label icon) {
addIndicator(icon, 250);
}
void addIndicator(Label icon, long TTL) {
if (!iconTTL.containsKey(icon)) {
Application.invokeLater(() -> {
if (!notificationBox.getChildren().contains(icon)) {
notificationBox.getChildren().add(icon);
}
});
}
trackTTL(icon, TTL);
}
void removeIndicator(Label icon) {
Application.invokeLater(() -> {
notificationBox.getChildren().remove(icon);
iconTTL.remove(icon);
});
}
ScheduledExecutorService notificationExecutor = Executors.newSingleThreadScheduledExecutor();
ScheduledFuture ttlCleanupTask = null;
private void trackTTL(Label icon, long TTL) {
iconTTL.put(icon, System.currentTimeMillis() + TTL);
if (ttlCleanupTask == null || ttlCleanupTask.isCancelled()) {
ttlCleanupTask = notificationExecutor.scheduleWithFixedDelay(this::processTTL, 1, 100, TimeUnit.MILLISECONDS);
}
}
private void processTTL() {
Long now = System.currentTimeMillis();
iconTTL.keySet().stream()
.filter((icon) -> (iconTTL.get(icon) <= now))
.forEach((icon) -> {
removeIndicator(icon);
});
if (iconTTL.isEmpty()) {
ttlCleanupTask.cancel(true);
ttlCleanupTask = null;
}
}
public void addMouseListener(EventHandler<MouseEvent> handler) {
appleScreen.addEventHandler(MouseEvent.ANY, handler);
}
public void removeMouseListener(EventHandler<MouseEvent> handler) {
appleScreen.removeEventHandler(MouseEvent.ANY, handler);
}
Label currentNotification = null;
public void displayNotification(String message) {
Label oldNotification = currentNotification;
Label notification = new Label(message);
currentNotification = notification;
notification.setEffect(new DropShadow(2.0, Color.BLACK));
notification.setTextFill(Color.WHITE);
notification.setBackground(new Background(new BackgroundFill(Color.rgb(0,0,80, 0.7), new CornerRadii(5.0), new Insets(-5.0))));
Application.invokeLater(() -> {
stackPane.getChildren().remove(oldNotification);
stackPane.getChildren().add(notification);
});
notificationExecutor.schedule(()->{
Application.invokeLater(() -> {
stackPane.getChildren().remove(notification);
});
}, 4, TimeUnit.SECONDS);
}
}