jafea7-ctbrec-v5.3.0-based/client/src/main/java/ctbrec/ui/PreviewPopupHandler.java

191 lines
6.6 KiB
Java

package ctbrec.ui;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ctbrec.Config;
import ctbrec.ui.controls.StreamPreview;
import javafx.application.Platform;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Point2D;
import javafx.scene.Node;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableRow;
import javafx.scene.control.TableView;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import javafx.stage.Popup;
public class PreviewPopupHandler implements EventHandler<MouseEvent> {
private static final Logger LOG = LoggerFactory.getLogger(PreviewPopupHandler.class);
private static final int offset = 10;
private long timeForPopupOpen = TimeUnit.SECONDS.toMillis(1);
private long timeForPopupClose = 400;
private Popup popup = new Popup();
private Node parent;
private StreamPreview streamPreview;
private JavaFxModel model;
private volatile long openCountdown = -1;
private volatile long closeCountdown = -1;
private volatile long lastModelChange = -1;
private volatile boolean changeModel = false;
public PreviewPopupHandler(Node parent) {
this.parent = parent;
streamPreview = new StreamPreview();
streamPreview.setStyle("-fx-background-color: -fx-outer-border, -fx-inner-border, -fx-base;"+
"-fx-background-insets: 0 0 -1 0, 0, 1, 2;" +
"-fx-background-radius: 10px, 10px, 10px, 10px;" +
"-fx-padding: 1;" +
"-fx-effect: dropshadow(gaussian, rgba(0, 0, 0, 0.8), 20, 0, 0, 0);");
popup.getContent().add(streamPreview);
StackPane.setMargin(streamPreview, new Insets(5));
createTimerThread();
}
@Override
public void handle(MouseEvent event) {
if(!isInPreviewColumn(event) || !Config.getInstance().getSettings().livePreviews) {
closeCountdown = timeForPopupClose;
return;
}
if(event.getEventType() == MouseEvent.MOUSE_CLICKED && event.getButton() == MouseButton.PRIMARY) {
model = getModel(event);
popup.setX(event.getScreenX()+ offset);
popup.setY(event.getScreenY()+ offset);
showPopup();
openCountdown = -1;
} else if(event.getEventType() == MouseEvent.MOUSE_ENTERED) {
popup.setX(event.getScreenX()+ offset);
popup.setY(event.getScreenY()+ offset);
JavaFxModel newModel = getModel(event);
if(newModel != null) {
closeCountdown = -1;
boolean modelChanged = newModel != this.model;
this.model = newModel;
if(popup.isShowing()) {
openCountdown = -1;
if(modelChanged) {
lastModelChange = System.currentTimeMillis();
changeModel = true;
streamPreview.stop();
}
} else {
openCountdown = timeForPopupOpen;
}
}
} else if(event.getEventType() == MouseEvent.MOUSE_EXITED) {
openCountdown = -1;
closeCountdown = timeForPopupClose;
model = null;
} else if(event.getEventType() == MouseEvent.MOUSE_MOVED) {
popup.setX(event.getScreenX() + offset);
popup.setY(event.getScreenY() + offset);
}
}
private boolean isInPreviewColumn(MouseEvent event) {
@SuppressWarnings("unchecked")
TableRow<JavaFxModel> row = (TableRow<JavaFxModel>) event.getSource();
TableView<JavaFxModel> table = row.getTableView();
double columnOffset = 0;
double width = 0;
for (TableColumn<JavaFxModel, ?> col : table.getColumns()) {
columnOffset += width;
width = col.getWidth();
if(Objects.equals(col.getId(), "preview")) {
Point2D screenToLocal = table.screenToLocal(event.getScreenX(), event.getScreenY());
double x = screenToLocal.getX();
return x >= columnOffset && x <= columnOffset + width;
}
}
return false;
}
private JavaFxModel getModel(MouseEvent event) {
@SuppressWarnings("unchecked")
TableRow<JavaFxModel> row = (TableRow<JavaFxModel>) event.getSource();
TableView<JavaFxModel> table = row.getTableView();
int rowIndex = row.getIndex();
if(rowIndex < table.getItems().size()) {
return table.getItems().get(rowIndex);
} else {
return null;
}
}
private void showPopup() {
startStream(model);
}
private void startStream(JavaFxModel model) {
Platform.runLater(() -> {
streamPreview.startStream(model);
popup.show(parent.getScene().getWindow());
});
}
private void hidePopup() {
Platform.runLater(() -> {
popup.setX(-1000);
popup.setY(-1000);
popup.hide();
streamPreview.stop();
});
}
private void createTimerThread() {
Thread timerThread = new Thread(() -> {
while(true) {
openCountdown--;
if(openCountdown == 0) {
openCountdown = -1;
if(model != null) {
showPopup();
}
}
closeCountdown--;
if(closeCountdown == 0) {
hidePopup();
closeCountdown = -1;
}
openCountdown = Math.max(openCountdown, -1);
closeCountdown = Math.max(closeCountdown, -1);
long now = System.currentTimeMillis();
long diff = (now - lastModelChange);
if(changeModel && diff > 400) {
changeModel = false;
if(model != null) {
startStream(model);
}
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
LOG.error("PreviewPopupTimer interrupted");
break;
}
}
});
timerThread.setDaemon(true);
timerThread.setPriority(Thread.MIN_PRIORITY);
timerThread.setName("PreviewPopupTimer");
timerThread.start();
}
}