Sync with upstream

This commit is contained in:
Frank Schiebel 2024-03-12 17:34:56 +01:00
parent 39a2f13410
commit 66e8fa72bf
135 changed files with 38902 additions and 37757 deletions

View file

@ -1,6 +1,11 @@
package graph;
import imp.*;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleBooleanProperty;
import java.awt.Graphics2D;
import javafx.geometry.Point2D;
import javafx.geometry.Pos;
@ -12,13 +17,18 @@ import java.util.ArrayList;
import java.util.List;
import javafx.scene.control.Tooltip;
import javafx.util.Duration;
import javafx.animation.AnimationTimer;
import java.awt.image.*;
import org.apache.commons.io.FileUtils;
/**
* Der GraphPlotter ist das Herzstueck der Visualisierung und dient als Schnittstelle zur GUI.
*
* @author Thomas Schaller
* @version 09.12.2020 (v6.7)
* @version 07.02.2023 (v7.0)
* v6.9: Context-Menü schließt, wenn an andere Stelle geklickt wird
* v7.0: MouseOver - Infos für Knoten und Kanten, Infos können ausgewählt werden.
*
*/
public class GraphPlotter extends PictureViewer {
// Anfang Attribute
@ -38,6 +48,9 @@ public class GraphPlotter extends PictureViewer {
private GraphElement restrictTo = null;
private Point2D offset = new Point2D(0,0);
private ObjectProperty<Point2D> mouseLocation = new SimpleObjectProperty<Point2D>(new Point2D(0, 0));
private BooleanProperty mouseMoving = new SimpleBooleanProperty();
// private JTextArea jTAMeldungen = new JTextArea("");
// private JScrollPane jTAMeldungenScrollPane = new JScrollPane(jTAMeldungen);
@ -51,36 +64,41 @@ public class GraphPlotter extends PictureViewer {
* @param String hintergrundBild Gibt den Namen eines Hintergrundbildes an
*/
public GraphPlotter() {
options = new GraphOptions();
graph = new Graph();
options = new GraphOptions(graph);
this.setStyle("-fx-background:#FFFFE8");
// add(jTAMeldungenScrollPane, BorderLayout.SOUTH);
setOnMouseClicked(mouseEvent -> mouseClicked(mouseEvent));
// setOnMouseMoved(mouseEvent -> { mouseX = mouseEvent.getSceneX(); mouseY = mouseEvent.getSceneY(); t.hide();});
this.widthProperty().addListener((value, oldWidth, newWidth) -> updateImage());
this.heightProperty().addListener((value, oldWidth, newWidth) -> updateImage());
// t = new Tooltip();
// Tooltip.install(this, t);
// t.setPrefWidth(80);
// t.setWrapText(true);
// t.setHideOnEscape(true);
// t.setStyle("-fx-background: rgba(30,30,30); -fx-text-fill: black; -fx-background-color: rgba(230,230,90,0.8);"+
// "-fx-background-radius: 6px; -fx-background-insets: 0; -fx-padding: 0.667em 0.75em 0.667em 0.75em; "+
// " -fx-effect: dropshadow( three-pass-box , rgba(0,0,0,0.5) , 10, 0.0 , 0 , 3 ); -fx-font-size: 0.85em;");
setOnMouseMoved(e -> mouseLocation.set(new Point2D(e.getSceneX(), e.getSceneY())));
mouseMoving.addListener((obs, wasMoving, isNowMoving) -> {
updateImage();
});
// t.setShowDelay(Duration.seconds(1));
// t.setOnShowing(ev -> {// called just prior to being shown
// Point2D local = this.getContent().sceneToLocal(mouseX, mouseY);
// Knoten k = getKnotenAt((int) local.getX(), (int) local.getY());
// if(k == null) {
// t.hide();
// } else {
// t.setText("Knoten Nr. "+graph.getNummer(k)+"\nWert: "+k.getDoubleWert());
// }
// });
AnimationTimer timer = new AnimationTimer() {
private double lastMouseX ;
private double lastMouseY ;
long lastMouseMovement ;
long MIN_STATIONARY_TIME = 2000;
@Override
public void handle(long timestamp) {
double x = mouseLocation.get().getX();
double y = mouseLocation.get().getY();
if (Math.abs(lastMouseX-x) > 5 || Math.abs(lastMouseY-y)>5) {
lastMouseMovement = timestamp ;
lastMouseX = x;
lastMouseY = y;
}
mouseMoving.set(timestamp - lastMouseMovement < MIN_STATIONARY_TIME);
}
};
timer.start();
}
@ -101,10 +119,10 @@ public class GraphPlotter extends PictureViewer {
public void setRestrictTo(GraphElement k) {
if(restrictTo != k) {
restrictTo = k;
selected.clear();
if (k!= null) selected.add(k);
updateImage();
restrictTo = k;
selected.clear();
if (k!= null) selected.add(k);
updateImage();
}
}
@ -175,7 +193,9 @@ public class GraphPlotter extends PictureViewer {
Point2D local = this.getContent().sceneToLocal(mouseEvent.getSceneX(), mouseEvent.getSceneY());
Knoten k = getKnotenAt((int) local.getX(), (int) local.getY());
if(dragMode == 3 && k==null && getKanteAt((int) local.getX(), (int) local.getY())==null) { // neuer Knoten
graph.neuerKnoten(new Knoten((int)local.getX(), (int) local.getY())) ;
if(getContextMenu() == null) {
graph.neuerKnoten(new Knoten((int)local.getX(), (int) local.getY())) ;
} else { setContextMenu(null); }
} else {
if(dragMode == 2 && k != null && k != dragKnoten) {
graph.neueKante(dragKnoten, k, 0.0);
@ -323,6 +343,9 @@ public class GraphPlotter extends PictureViewer {
}
public Picture updateImage() {
Picture p = new Picture(2000,2000,"FFFFE8");
Graphics2D g = (Graphics2D) p.getImage().getGraphics();
Knoten restrictToKnoten = null;
Kante restrictToKante = null;
if(restrictTo != null && restrictTo instanceof Knoten) restrictToKnoten = (Knoten) restrictTo;
@ -340,8 +363,6 @@ public class GraphPlotter extends PictureViewer {
miny = Math.min(miny,k.getY());
}
Picture p = new Picture(2000,2000,"FFFFE8");
if(restrictToKnoten != null) {
knoten = graph.getNachbarknoten(restrictToKnoten);
kanten = graph.getAusgehendeKanten(restrictToKnoten);
@ -464,15 +485,28 @@ public class GraphPlotter extends PictureViewer {
}
}
if(options.showEdgeWeights && graph.isGewichtet()) {
if(options.showEdgeWeights) {
double my = (startY+startY+endY)/3;
double mx = (startX+startX+endX)/3;
p.fill(255);
p.stroke(0);
p.strokeWeight(1);
p.rect((int) mx-15, (int) my-7, 30, 16);
p.fill(0);
p.text(format(k.getGewicht()), (int) mx, (int) my);
int lh = g.getFontMetrics().getAscent();
List<String> t = k.getKurztext(options.kanteKurztext);
if(t.size() == 1) {
p.rect((int) mx-15, (int) my-(lh+4)/2, 30, lh+4);
p.fill(0);
p.text(t.get(0), (int) mx, (int) my);
}
if(t.size() > 1) {
p.rect((int) mx-15, (int) my-(lh+2), 30, lh*2+4);
p.fill(0);
p.text(t.get(0), (int) mx, (int) my-lh/2);
p.text(t.get(1), (int) mx, (int) my+lh/2);
}
}
}
}
@ -499,7 +533,14 @@ public class GraphPlotter extends PictureViewer {
p.text(""+graph.getNummer(k), k.getX(), k.getY());
} else {
if (options.showVertexValue) {
p.text(format(k.getDoubleWert()), k.getX(), k.getY());
List<String> t = k.getKurztext(options.knotenKurztext);
if(t.size() == 1) {
p.text(t.get(0), k.getX(), k.getY());
} else {
int lh = g.getFontMetrics().getAscent();
p.text(t.get(0), k.getX(), k.getY()-lh/2);
p.text(t.get(1), k.getX(), k.getY()+lh/2);
}
}
}
@ -511,6 +552,43 @@ public class GraphPlotter extends PictureViewer {
}
}
// Tooltip anzeigen, aber nicht wenn im Editiermodus
if(!mouseMoving.get() && !editable) {
Point2D local = this.getContent().sceneToLocal(mouseLocation.get().getX(), mouseLocation.get().getY());
int x = (int) local.getX();
int y = (int) local.getY();
// sowohl bei Kante wie auch Knoten
GraphElement k = getKnotenAt(x,y);
if(k == null) { k = getKanteAt(x,y);}
if(k != null) {
p.fill(200);
p.stroke(0);
p.strokeWeight(2);
List<String> t;
if(k instanceof Knoten) t = k.getLangtext(options.knotenLangtext);
else t = k.getLangtext(options.kanteLangtext);
// Größe des Kastens berechnen
int w = 0;
int lh = g.getFontMetrics().getAscent();
int h = t.size() * lh;
for(int i = 0; i<t.size(); i++) {
int w2 = g.getFontMetrics().stringWidth(t.get(i));
if(w2 > w) w = w2;
}
// Rechteck mit Text ausgeben
p.rect(x, y, w+16, h+10);
p.fill("303030");
for(int i = 0; i<t.size(); i++) {
p.text(t.get(i), x+8, y+(i+1)*lh+3);
}
}
}
this.setImage(p, false);
Picture zugeschnitten = new Picture(maxx-minx+2*options.vertexSize,maxy-miny+2*options.vertexSize);
@ -518,7 +596,6 @@ public class GraphPlotter extends PictureViewer {
return zugeschnitten;
}
public GraphOptions getGraphOptions() {
return options;
}