commit 55b39a0a4a5d855a9ac4df787fd4f3f4df092592 parent 700bb4f70ed39ffe91bca312cd9f99d9814c1084 Author: Christos Margiolis <christos@margiolis.net> Date: Fri, 11 Jun 2021 15:47:48 +0300 java project is slow Diffstat:
21 files changed, 533 insertions(+), 163 deletions(-)
diff --git a/c_os2/ex2/ex2.c b/c_os2/ex2/ex2.c @@ -26,7 +26,7 @@ struct foo { pthread_barrier_t bar; }; -static void *threaded_stuff(void *); +static void *threaded_callback(void *); static void *emalloc(size_t); static void usage(void); diff --git a/cpp_oop/game/Engine.cc b/cpp_oop/game/Engine.cc @@ -11,6 +11,7 @@ enum Color { LAST }; +/* TODO get player name */ Engine::Engine(const char *mapfile, const char *scorefile) { if (!init_curses()) diff --git a/java_development/population/.classpath b/java_development/population/.classpath @@ -1,12 +1,12 @@ <?xml version="1.0" encoding="UTF-8"?> <classpath> <classpathentry kind="src" path="src"/> + <classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/JavaFX"/> + <classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/POI"/> <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"> <attributes> <attribute name="module" value="true"/> </attributes> </classpathentry> - <classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/JavaFX"/> - <classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/POI"/> - <classpathentry kind="output" path="bin"/> + <classpathentry kind="output" path="bin/"/> </classpath> diff --git a/java_development/population/.settings/org.eclipse.jdt.core.prefs b/java_development/population/.settings/org.eclipse.jdt.core.prefs @@ -1,8 +1,15 @@ eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning org.eclipse.jdt.core.compiler.release=disabled org.eclipse.jdt.core.compiler.source=1.8 diff --git a/java_development/population/bin/population/Chart.class b/java_development/population/bin/population/Chart.class Binary files differ. diff --git a/java_development/population/bin/population/Country.class b/java_development/population/bin/population/Country.class Binary files differ. diff --git a/java_development/population/bin/population/ExcelParser.class b/java_development/population/bin/population/ExcelParser.class Binary files differ. diff --git a/java_development/population/bin/population/Main.class b/java_development/population/bin/population/Main.class Binary files differ. diff --git a/java_development/population/bin/population/MainWindow.class b/java_development/population/bin/population/MainWindow.class Binary files differ. diff --git a/java_development/population/bin/population/Toast.class b/java_development/population/bin/population/Toast.class Binary files differ. diff --git a/java_development/population/population.jar b/java_development/population/population.jar Binary files differ. diff --git a/java_development/population/res/wpp2019_population_density.xlsx b/java_development/population/res/wpp2019_population_density.xlsx Binary files differ. diff --git a/java_development/population/res/wpp2019_population_female.xlsx b/java_development/population/res/wpp2019_population_female.xlsx Binary files differ. diff --git a/java_development/population/res/wpp2019_population_male.xlsx b/java_development/population/res/wpp2019_population_male.xlsx Binary files differ. diff --git a/java_development/population/run.sh b/java_development/population/run.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +/usr/local/openjdk11/bin/java \ + --module-path /usr/local/openjfx14/lib \ + --add-modules javafx.controls,javafx.fxml \ + -jar population.jar \ + res/wpp2019_population_both_sexes.xlsx diff --git a/java_development/population/src/population/Chart.java b/java_development/population/src/population/Chart.java @@ -0,0 +1,234 @@ +package population; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import javafx.geometry.Insets; +import javafx.geometry.Pos; +import javafx.scene.Scene; +import javafx.scene.chart.LineChart; +import javafx.scene.chart.NumberAxis; +import javafx.scene.chart.XYChart; +import javafx.scene.control.Button; +import javafx.scene.control.ComboBox; +import javafx.scene.layout.HBox; +import javafx.scene.layout.VBox; +import javafx.stage.Modality; +import javafx.stage.Stage; +import javafx.stage.StageStyle; + +public class Chart { + private final int WIDTH = 1280; + private final int HEIGHT = 1000; + private Stage stg; + private VBox vb; + private HBox hb; + private Button btn_close; + private Button btn_clear; + private ComboBox<String> cb_ctry; + private ComboBox<Integer> cb_yearfrom; + private ComboBox<Integer> cb_yearto; + private NumberAxis xaxis; + private NumberAxis yaxis; + private LineChart<Number, Number> lc; + private ArrayList<XYChart.Series<Number, Number>> sr; + private List<Country> countries; + + Chart(List<Country> countries) { + this.countries = countries; + stg = mkstage(); + xaxis = mkxaxis("Year"); + yaxis = mkyaxis("Population"); + sr = new ArrayList<XYChart.Series<Number, Number>>(); + lc = mklinechart(xaxis, yaxis, stg); + btn_close = mkclosebtn(stg, "Close"); + btn_clear = mkclearbtn(stg, sr, lc, "Clear"); + cb_ctry = mkctrylist(sr, lc, "Country"); + cb_yearfrom = mkyearcb(Country.STARTING_YEAR); + cb_yearto = mkyearcb(Country.LAST_YEAR); + + /* Change timeline values. */ + cb_yearfrom.setOnAction(ev -> { + if (cb_yearfrom.getValue() < cb_yearto.getValue()) + xaxis.setLowerBound(cb_yearfrom.getValue()); + }); + cb_yearto.setOnAction(ev -> { + if (cb_yearto.getValue() > cb_yearfrom.getValue()) + xaxis.setUpperBound(cb_yearto.getValue()); + }); + } + + private Stage mkstage() { + Stage stg = new Stage(); + + stg.setWidth(WIDTH); + stg.setHeight(HEIGHT); + stg.initStyle(StageStyle.UTILITY); + stg.initModality(Modality.WINDOW_MODAL); + return stg; + } + + private NumberAxis mkxaxis(String str) { + NumberAxis xaxis = new NumberAxis(); + + xaxis.setLabel(str); + /* + * By default, the chart isn't resized properly + * so we'll do it ourselves. + */ + xaxis.setLowerBound(Country.STARTING_YEAR); + xaxis.setUpperBound(Country.LAST_YEAR); + /* No. Stop auto resizing. */ + xaxis.setAutoRanging(false); + return xaxis; + } + + private NumberAxis mkyaxis(String str) { + NumberAxis yaxis = new NumberAxis(); + + yaxis.setLabel(str); + return yaxis; + } + + private XYChart.Series<Number, Number> mkseries(String str) { + XYChart.Series<Number, Number> sr; + + sr = new XYChart.Series<Number, Number>(); + sr.setName(str); + return sr; + } + + private LineChart<Number, Number> mklinechart( + NumberAxis xaxis, + NumberAxis yaxis, + Stage stg) { + LineChart<Number, Number> lc; + + lc = new LineChart<Number, Number>(xaxis, yaxis); + + /* Fit to screen. */ + lc.prefWidthProperty().bind(stg.widthProperty()); + lc.prefHeightProperty().bind(stg.heightProperty()); + + /* + * The animations look stupid when there's already another + * chart present. + */ + lc.setAnimated(false); + + /* Do not draw nodes, just the line. */ + lc.setCreateSymbols(false); + + return lc; + } + + private Button mkclosebtn(Stage stg, String str) { + Button btn_close = new Button(str); + + btn_close.setOnAction(ev -> { + stg.close(); + }); + return btn_close; + } + + private Button mkclearbtn( + Stage stg, + ArrayList<XYChart.Series<Number, Number>> sr, + LineChart<Number, Number> lc, + String str) { + Button btn_clear = new Button(str); + + btn_clear.setOnAction(ev -> { + lc.getData().clear(); + sr.forEach(s -> s.getData().clear()); + sr.clear(); + }); + return btn_clear; + } + + private ComboBox<Integer> mkyearcb(Integer n) { + ComboBox<Integer> cb = new ComboBox<Integer>(); + + for (int i = Country.STARTING_YEAR; i <= Country.LAST_YEAR; i++) + cb.getItems().add(i); + /* + * Set default values from the beginning, otherwise the + * very first action will not work properly as the value + * in one of the ComboBoxes will be empty. + */ + cb.setValue(n); + return cb; + } + + private ComboBox<String> mkctrylist( + ArrayList<XYChart.Series<Number, Number>> sr, + LineChart<Number, Number> lc, + String str) { + ComboBox<String> cb_ctry = new ComboBox<String>(); + + countries.forEach(c -> cb_ctry.getItems().add(c.getName())); + cb_ctry.setPromptText(str); + /* + * Sort countries by name, since by default + * each country is sorted by its index. + */ + Collections.sort(cb_ctry.getItems()); + + /* Add population data for selected country to the chart. */ + cb_ctry.setOnAction(ev -> { + Country c = null; + Iterator<Map.Entry<Integer, Integer>> it; + Map.Entry<Integer, Integer> ent; + String ctryname; + + /* Search country by selection name. */ + ctryname = cb_ctry.getValue(); + for (Country ctry : countries) { + if (ctry.getName().equals(ctryname)) { + c = ctry; + break; + } + } + /* Possibly a useless check. */ + if (c == null) + return; + + sr.add(mkseries(c.getName())); + /* + * Iterate through the population data and make + * the chart. + */ + it = c.getPopulation().entrySet().iterator(); + while (it.hasNext()) { + ent = it.next(); + sr.get(sr.size()-1).getData().add( + new XYChart.Data<Number, Number>( + ent.getKey(), ent.getValue())); + } + lc.getData().add(sr.get(sr.size()-1)); + }); + return cb_ctry; + } + + public void show() { + /* Create bottom panel. */ + hb = new HBox(); + hb.setSpacing(5); + hb.setAlignment(Pos.CENTER); + hb.getChildren().addAll(cb_yearfrom, cb_yearto, + cb_ctry, btn_clear, btn_close); + /* + * Combine the chart and bottom panel, and display + * the scene. + */ + vb = new VBox(); + vb.setSpacing(5); + vb.setPadding(new Insets(10, 10, 10, 10)); + vb.getChildren().addAll(lc, hb); + stg.setTitle("Population Chart"); + stg.setScene(new Scene(vb, 400, 200)); + stg.show(); + } +} diff --git a/java_development/population/src/population/Country.java b/java_development/population/src/population/Country.java @@ -3,6 +3,8 @@ package population; import java.util.HashMap; public class Country { + public static final int STARTING_YEAR = 1950; + public static int LAST_YEAR; private String index; private String variant = ""; private String name = ""; @@ -11,8 +13,8 @@ public class Country { private String type = ""; private String pntcode; private HashMap<Integer, Integer> population; - private String recentpop; - + private String curpop; + Country(String index, String variant, String name, String notes, String ctrycode, String type, String pntcode, HashMap<Integer, Integer> population) { @@ -24,8 +26,9 @@ public class Country { this.type = type; this.pntcode = pntcode; this.population = population; - recentpop = String.valueOf( - population.get(Main.STARTING_YEAR + population.size() - 1)); + LAST_YEAR = STARTING_YEAR + this.population.size() - 1; + setCurpop(LAST_YEAR); + } /* @@ -64,7 +67,11 @@ public class Country { return population; } - public String getRecentpop() { - return recentpop; + public String getCurpop() { + return curpop; + } + + public void setCurpop(Integer i) { + curpop = String.valueOf(population.get(i)); } } diff --git a/java_development/population/src/population/ExcelParser.java b/java_development/population/src/population/ExcelParser.java @@ -44,10 +44,9 @@ public class ExcelParser { private Country read_country(XSSFRow row) throws Exception { final int MIN_CELLNUM = 7; - Country ctry; Iterator<Cell> cit; Cell cell; - Integer year = Main.STARTING_YEAR; + Integer year = Country.STARTING_YEAR; String[] fields = new String[MIN_CELLNUM]; HashMap<Integer, Integer> population = new HashMap<Integer, Integer>(); Integer n; @@ -98,17 +97,13 @@ public class ExcelParser { population.put(year++, dtoi(cell.getNumericCellValue() * 1000)); } - ctry = new Country(fields[0], fields[1], fields[2], fields[3], + + return new Country(fields[0], fields[1], fields[2], fields[3], fields[4], fields[5], fields[6], population); - - return ctry; } private Integer dtoi(double n) { - Double d; - - d = Double.valueOf(n); - return Integer.valueOf(d.intValue()); + return Integer.valueOf(Double.valueOf(n).intValue()); } public List<Country> get_countries() { diff --git a/java_development/population/src/population/Main.java b/java_development/population/src/population/Main.java @@ -1,158 +1,19 @@ package population; -import java.io.*; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; import javafx.application.Application; -import javafx.application.Platform; -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; -import javafx.geometry.Insets; -import javafx.geometry.Pos; -import javafx.scene.Scene; -import javafx.scene.control.Button; -import javafx.scene.control.Label; -import javafx.scene.control.TableColumn; -import javafx.scene.control.TableRow; -import javafx.scene.control.TableView; -import javafx.scene.control.cell.PropertyValueFactory; -import javafx.scene.layout.HBox; -import javafx.scene.layout.VBox; import javafx.stage.Stage; public class Main extends Application { - public static final int STARTING_YEAR = 1950; private final String APP_TITLE = "Population Statistics"; - List<Country> countries; @Override public void start(Stage stg) throws Exception { - Parameters params; - List<String> args; - ExcelParser ep; - String path = ""; - VBox vb; - HBox btns; - TableView<Country> tbv; - - /* Parse Excel file. */ - params = getParameters(); - args = params.getRaw(); - try { - path = args.get(0); - ep = new ExcelParser(path); - } catch (FileNotFoundException e) { - err(stg, path + ": no such file"); - return; - } catch (IndexOutOfBoundsException e) { - err(stg, "usage: population xlsx_file"); - return; - } catch (IOException e) { - err(stg, path + ": io error"); - return; - } - countries = ep.get_countries(); - - /* Set up GUI. */ - tbv = mktable(stg); - btns = mkbtns(); - vb = mkvbox(tbv, btns); - stg.setTitle(APP_TITLE); - stg.setScene(new Scene(vb)); - stg.show(); - } - - /* TODO: make it an actual popup error window? */ - private void err(Stage stg, String errstr) { - Label lbl = new Label(errstr); - lbl.setAlignment(Pos.CENTER); - Scene scene = new Scene(lbl); - - stg.setScene(scene); - stg.show(); - } - - private HBox mkbtns() { - HBox hb; - Button btn_chart; - Button btn_exit; - - hb = new HBox(); - btn_exit = new Button("Exit"); - btn_exit.setOnAction(value -> { - Platform.exit(); - System.exit(0); - }); - btn_chart = new Button("Chart"); - btn_chart.setOnAction(value -> { - mkchart(); - }); - hb.getChildren().addAll(btn_chart, btn_exit); - hb.setSpacing(5); - hb.setAlignment(Pos.CENTER); - return hb; - } - - private TableView<Country> mktable(Stage stg) { - TableView<Country> tbv; - TableColumn<Country, String> tbc; - List<Column> cols; - ObservableList<Country> addrs; - - cols = new ArrayList<Column>(Arrays.asList( - new Column("Index", "index"), - new Column("Variant", "variant"), - new Column("Country", "name"), - new Column("Notes", "notes"), - new Column("Country Code", "ctrycode"), - new Column("Type", "type"), - new Column("Parent Code", "pntcode"), - new Column("Population", "recentpop") - )); - tbv = new TableView<Country>(); - addrs = FXCollections.observableArrayList(countries); - for (Column col : cols) { - tbc = new TableColumn<Country, String>(col.get_name()); - tbc.setCellValueFactory( - new PropertyValueFactory<Country, String>( - col.get_fieldname())); - tbv.getColumns().add(tbc); - } - tbv.setRowFactory(tv -> { - TableRow<Country> row = new TableRow<Country>(); - row.setOnMouseClicked(ev -> { - if (ev.getClickCount() == 2 && !row.isEmpty()) { - Country c = row.getItem(); - /* TODO: implement toast */ - System.out.println( - c.getIndex() + "," + - c.getName() + "," + - c.getRecentpop()); - } - }); - return row; - }); - tbv.setItems(addrs); - tbv.prefWidthProperty().bind(stg.widthProperty()); - tbv.prefHeightProperty().bind(stg.heightProperty()); - return tbv; - } - - private VBox mkvbox(TableView<Country> tbv, HBox btns) { - VBox vb; - - vb = new VBox(); - vb.setSpacing(5); - vb.setPadding(new Insets(10, 10, 10, 10)); - vb.getChildren().addAll(tbv, btns); - return vb; - } - - private void mkchart() { - + MainWindow mw = new MainWindow(stg, APP_TITLE); + + mw.setup(getParameters().getRaw().get(0)); + mw.show(); } - + public static void main(String[] args) { launch(args); } diff --git a/java_development/population/src/population/MainWindow.java b/java_development/population/src/population/MainWindow.java @@ -0,0 +1,175 @@ +package population; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import javafx.application.Platform; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import javafx.geometry.Insets; +import javafx.geometry.Pos; +import javafx.scene.Scene; +import javafx.scene.control.Alert; +import javafx.scene.control.Alert.AlertType; +import javafx.scene.control.Button; +import javafx.scene.control.ButtonType; +import javafx.scene.control.ComboBox; +import javafx.scene.control.TableColumn; +import javafx.scene.control.TableRow; +import javafx.scene.control.TableView; +import javafx.scene.control.cell.PropertyValueFactory; +import javafx.scene.layout.HBox; +import javafx.scene.layout.VBox; +import javafx.stage.FileChooser; +import javafx.stage.FileChooser.ExtensionFilter; +import javafx.stage.Stage; + +public class MainWindow { + private final int WIDTH = 1000; + private final int HEIGHT = 900; + private List<Country> countries; + private TableView<Country> tbv; + private HBox btns; + private Stage stg; + private String title; + + MainWindow(Stage stg, String title) { + this.stg = stg; + this.title = title; + } + + public void setup(String path) { + ExcelParser ep; + + try { + ep = new ExcelParser(path); + countries = ep.get_countries(); + } catch (FileNotFoundException e) { + err(path + ": no such file"); + return; + } catch (IndexOutOfBoundsException e) { + err("usage: population xlsx_file"); + return; + } catch (IOException e) { + err(path + ": io error"); + return; + } catch (Exception e) { + err(e.getMessage()); + return; + } + mktable(); + mkbtns(); + stg.setTitle(title + " - " + path); + stg.setWidth(WIDTH); + stg.setHeight(HEIGHT); + } + + public void show() { + stg.setScene(new Scene(mkvbox(tbv, btns))); + stg.show(); + } + + private void err(String errstr) { + Alert alert; + + alert = new Alert(AlertType.ERROR, errstr, ButtonType.CLOSE); + alert.showAndWait(); + } + + private void mkbtns() { + ComboBox<String> cb; + Button btn_file; + Button btn_chart; + Button btn_exit; + + btn_file = new Button("Load File"); + btn_file.setOnAction(ev -> { + FileChooser fc = new FileChooser(); + fc.setTitle("Load File"); + fc.getExtensionFilters().add( + new ExtensionFilter("XLSX Files", "*.xlsx")); + setup(fc.showOpenDialog(stg).getAbsolutePath()); + }); + + btn_chart = new Button("Chart"); + btn_chart.setOnAction(ev -> { + Chart chart = new Chart(countries); + chart.show(); + }); + + btn_exit = new Button("Exit"); + btn_exit.setOnAction(ev -> { + Platform.exit(); + System.exit(0); + }); + + cb = new ComboBox<String>(); + for (int i = Country.STARTING_YEAR; i <= Country.LAST_YEAR; i++) + cb.getItems().add(String.valueOf(i)); + cb.setPromptText("Year"); + cb.setOnAction(ev -> { + for (Country ctry : countries) { + ctry.setCurpop(Integer.valueOf(cb.getValue())); + tbv.refresh(); + } + }); + + btns = new HBox(); + btns.getChildren().addAll(btn_file, cb, btn_chart, btn_exit); + btns.setSpacing(5); + btns.setAlignment(Pos.CENTER); + } + + private void mktable() { + TableColumn<Country, String> tbc; + List<Column> cols; + ObservableList<Country> addrs; + + cols = new ArrayList<Column>(Arrays.asList( + new Column("Index", "index"), + new Column("Variant", "variant"), + new Column("Country", "name"), + new Column("Notes", "notes"), + new Column("Country Code", "ctrycode"), + new Column("Type", "type"), + new Column("Parent Code", "pntcode"), + new Column("Population", "curpop") + )); + tbv = new TableView<Country>(); + addrs = FXCollections.observableArrayList(countries); + for (Column col : cols) { + tbc = new TableColumn<Country, String>(col.get_name()); + /* Why is this line so long? */ + tbc.setCellValueFactory( + new PropertyValueFactory<Country, String>( + col.get_fieldname())); + tbv.getColumns().add(tbc); + } + tbv.setRowFactory(tv -> { + TableRow<Country> row = new TableRow<Country>(); + row.setOnMouseClicked(ev -> { + if (ev.getClickCount() == 2 && !row.isEmpty()) { + Country c = row.getItem(); + Toast toast = new Toast(c, stg); + toast.show(); + } + }); + return row; + }); + tbv.setItems(addrs); + /* Fit to screen. */ + tbv.prefWidthProperty().bind(stg.widthProperty()); + tbv.prefHeightProperty().bind(stg.heightProperty()); + } + + private VBox mkvbox(TableView<Country> tbv, HBox btns) { + VBox vb = new VBox(); + + vb.setSpacing(5); + vb.setPadding(new Insets(10, 10, 10, 10)); + vb.getChildren().addAll(tbv, btns); + return vb; + } +} diff --git a/java_development/population/src/population/Toast.java b/java_development/population/src/population/Toast.java @@ -0,0 +1,83 @@ +package population; + +import javafx.animation.KeyFrame; +import javafx.animation.KeyValue; +import javafx.animation.Timeline; +import javafx.scene.Scene; +import javafx.scene.layout.StackPane; +import javafx.scene.paint.Color; +import javafx.scene.text.Font; +import javafx.scene.text.FontWeight; +import javafx.scene.text.Text; +import javafx.stage.Stage; +import javafx.stage.StageStyle; +import javafx.util.Duration; + +public class Toast { + private final int WIDTH_MARGIN = 20; + private final int HEIGHT = 50; + private final int FADEOUT_DUR = 500; + private final int FADEIN_DUR = 500; + private final int TOAST_DUR = 2500; + private final int FONT_SIZE = 14; + private final String FONT = "Verdana"; + private Stage stg; + private Text txt; + private String style; + + Toast(Country ctry, Stage owner) { + stg = new Stage(); + txt = new Text(ctry.getIndex() + ", " + + ctry.getName() + ", " + + ctry.getCurpop()); + style = "-fx-background-radius: 20;" + + "-fx-background-color: rgba(0, 0, 0, 0.18);" + + "-fx-padding: 50px;"; + + txt.setFill(Color.BLUE); + txt.setFont(Font.font(FONT, FontWeight.BOLD, FONT_SIZE)); + stg.setWidth(txt.getLayoutBounds().getWidth() + WIDTH_MARGIN); + stg.setHeight(HEIGHT); + stg.setResizable(false); + stg.initOwner(owner); + stg.initStyle(StageStyle.TRANSPARENT); + } + + public void show() { + StackPane root = new StackPane(txt); + Scene scene = new Scene(root); + Timeline fintml; + KeyFrame finkey; + + root.setStyle(style); + root.setOpacity(0); + scene.setFill(Color.TRANSPARENT); + stg.setScene(scene); + stg.show(); + fintml = new Timeline(); + finkey = new KeyFrame(Duration.millis(FADEIN_DUR), + new KeyValue(stg.getScene().getRoot().opacityProperty(), 1)); + fintml.getKeyFrames().add(finkey); + fintml.setOnFinished(ev -> closing_animation()); + fintml.play(); + } + + private void closing_animation() { + new Thread(() -> { + try { + Thread.sleep(TOAST_DUR); + } catch (InterruptedException e) { + e.printStackTrace(); + } + Timeline fouttml = new Timeline(); + KeyFrame foutkey = + new KeyFrame(Duration.millis(FADEOUT_DUR), + new KeyValue(stg.getScene() + .getRoot() + .opacityProperty(), 0)); + fouttml.getKeyFrames().add(foutkey); + fouttml.setOnFinished(e -> stg.close()); + fouttml.play(); + }).start(); + } +}