Don't push that button!

I improved my button handling so that the proper buttons grey out
whenever things are happening. I ended up taking a page from JavaFX's
book and having a map from an enum to stored buttons. I also made the
plot saving thing work, since that seems to have broken at some point,
and improved some documentation.
This commit is contained in:
Justin Kunimune 2018-01-22 09:27:51 -10:00
parent a9b5978b9c
commit d6eb4ddcbf
6 changed files with 129 additions and 93 deletions

View File

@ -33,13 +33,11 @@ import javafx.application.Platform;
import javafx.embed.swing.SwingFXUtils; import javafx.embed.swing.SwingFXUtils;
import javafx.geometry.Insets; import javafx.geometry.Insets;
import javafx.geometry.Pos; import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.chart.BarChart; import javafx.scene.chart.BarChart;
import javafx.scene.chart.CategoryAxis; import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.NumberAxis; import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart.Data; import javafx.scene.chart.XYChart.Data;
import javafx.scene.chart.XYChart.Series; import javafx.scene.chart.XYChart.Series;
import javafx.scene.control.Button;
import javafx.scene.control.Label; import javafx.scene.control.Label;
import javafx.scene.control.Separator; import javafx.scene.control.Separator;
import javafx.scene.image.Image; import javafx.scene.image.Image;
@ -86,7 +84,6 @@ public class MapAnalyzer extends MapApplication {
private Flag cropAtIDL; private Flag cropAtIDL;
private MutableDouble graticuleSpacing; private MutableDouble graticuleSpacing;
private Button updateBtn;
private Text avgSizeDistort, avgShapeDistort; private Text avgSizeDistort, avgShapeDistort;
private ImageView mapDisplay; private ImageView mapDisplay;
private Region charts; private Region charts;
@ -110,18 +107,17 @@ public class MapAnalyzer extends MapApplication {
@Override @Override
protected Node makeWidgets() { protected Region makeWidgets() {
this.cropAtIDL = new Flag(true); this.cropAtIDL = new Flag(true);
this.graticuleSpacing = new MutableDouble(15); this.graticuleSpacing = new MutableDouble(15);
final Node projectionSelector = buildProjectionSelector(Procedure.NONE); final Region projectionSelector = buildProjectionSelector(Procedure.NONE);
final Node parameterSelector = buildParameterSelector(Procedure.NONE); final Region parameterSelector = buildParameterSelector(Procedure.NONE);
final Node optionPane = buildOptionPane(cropAtIDL, graticuleSpacing); final Region optionPane = buildOptionPane(cropAtIDL, graticuleSpacing);
final Node textDisplay = buildTextDisplay(); final Region textDisplay = buildTextDisplay();
this.updateBtn = buildUpdateButton(this::calculateAndUpdate); final Region updateBtn = buildUpdateButton("Calculate", this::calculateAndUpdate);
this.updateBtn.setText("Calculate"); //I don't need to follow your darn conventions! final Region saveMapBtn = buildSaveButton(true, "map", RASTER_TYPES,
final Button saveMapBtn = buildSaveButton(true, "map", RASTER_TYPES,
RASTER_TYPES[0], ()->true, this::calculateAndSaveMap); RASTER_TYPES[0], ()->true, this::calculateAndSaveMap);
final Button savePltBtn = buildSaveButton(true, "plots", RASTER_TYPES, final Region savePltBtn = buildSaveButton(true, "plots", RASTER_TYPES,
RASTER_TYPES[0], ()->true, this::calculateAndSavePlot); RASTER_TYPES[0], ()->true, this::calculateAndSavePlot);
final HBox buttons = new HBox(H_SPACE, updateBtn, saveMapBtn, savePltBtn); final HBox buttons = new HBox(H_SPACE, updateBtn, saveMapBtn, savePltBtn);
buttons.setAlignment(Pos.CENTER); buttons.setAlignment(Pos.CENTER);
@ -149,7 +145,7 @@ public class MapAnalyzer extends MapApplication {
} }
private Node buildTextDisplay() { private Region buildTextDisplay() {
this.avgSizeDistort = new Text("..."); this.avgSizeDistort = new Text("...");
this.avgShapeDistort = new Text("..."); this.avgShapeDistort = new Text("...");
final Text txt = new Text("Blue areas are dilated, red areas are compressed, and black areas are stretched."); final Text txt = new Text("Blue areas are dilated, red areas are compressed, and black areas are stretched.");
@ -188,6 +184,8 @@ public class MapAnalyzer extends MapApplication {
private void calculateAndUpdate() { private void calculateAndUpdate() {
disable(ButtonType.UPDATE_MAP, ButtonType.SAVE_MAP, ButtonType.SAVE_GRAPH);
Platform.runLater(() -> { Platform.runLater(() -> {
sizeChart.getData().clear(); sizeChart.getData().clear();
shapeChart.getData().clear(); shapeChart.getData().clear();
@ -202,6 +200,8 @@ public class MapAnalyzer extends MapApplication {
mapDisplay.setImage(makeGraphic(distortionM)); mapDisplay.setImage(makeGraphic(distortionM));
enable(ButtonType.SAVE_MAP);
final double[][][] distortionG = proj.calculateDistortion(Projection.globe(GLOBE_RES)); final double[][][] distortionG = proj.calculateDistortion(Projection.globe(GLOBE_RES));
Platform.runLater(() -> { Platform.runLater(() -> {
@ -212,28 +212,38 @@ public class MapAnalyzer extends MapApplication {
avgSizeDistort.setText(format(Math2.stdDev(distortionG[0]))); avgSizeDistort.setText(format(Math2.stdDev(distortionG[0])));
avgShapeDistort.setText(format(Math2.mean(distortionG[1]))); avgShapeDistort.setText(format(Math2.mean(distortionG[1])));
enable(ButtonType.UPDATE_MAP, ButtonType.SAVE_GRAPH);
}); });
} }
private void calculateAndSavePlot(File file, ProgressBarDialog pBar) { private void calculateAndSavePlot(File file, ProgressBarDialog pBar) {
disable(ButtonType.SAVE_GRAPH);
pBar.setProgress(-1); pBar.setProgress(-1);
final String filename = file.getName(); Platform.runLater(() -> {
final String extension = filename.substring(filename.lastIndexOf('.')+1); charts.snapshot((snapRes) -> {
try { final String filename = file.getName();
final WritableImage out = new WritableImage( final String extension = filename.substring(filename.lastIndexOf('.')+1);
(int) charts.getWidth(), (int) charts.getHeight()); try {
Platform.runLater(() -> charts.snapshot(null,out)); ImageIO.write(SwingFXUtils.fromFXImage(snapRes.getImage(), null),
while (out.getProgress() < 1) {} extension, file);
ImageIO.write(SwingFXUtils.fromFXImage(out, null), extension, file); //save } catch (IOException e) {
} catch (IOException e) { showError("Failure!",
showError("Failure!", "Could not access "+file.getAbsolutePath()+". It's possible that another program has it open.");
"Could not access "+file.getAbsolutePath()+". It's possible that another program has it open."); } finally {
} enable(ButtonType.SAVE_GRAPH);
}
return null;
}, null, null);
});
} }
private void calculateAndSaveMap(File file, ProgressBarDialog pBar) { private void calculateAndSaveMap(File file, ProgressBarDialog pBar) {
disable(ButtonType.SAVE_MAP);
loadParameters(); loadParameters();
final Projection proj = this.getProjection(); final Projection proj = this.getProjection();
final double[][][] distortion = proj.calculateDistortion(proj.map(FINE_SAMP_NUM), pBar); //calculate final double[][][] distortion = proj.calculateDistortion(proj.map(FINE_SAMP_NUM), pBar); //calculate
@ -248,6 +258,8 @@ public class MapAnalyzer extends MapApplication {
} catch (IOException e) { } catch (IOException e) {
showError("Failure!", showError("Failure!",
"Could not access "+file.getAbsolutePath()+". It's possible that another program has it open."); "Could not access "+file.getAbsolutePath()+". It's possible that another program has it open.");
} finally {
enable(ButtonType.SAVE_MAP);
} }
} }

View File

@ -23,8 +23,12 @@
*/ */
package apps; package apps;
import java.awt.Desktop;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.lang.reflect.Array; import java.lang.reflect.Array;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import java.util.function.BooleanSupplier; import java.util.function.BooleanSupplier;
@ -46,7 +50,6 @@ import javafx.scene.control.CheckBox;
import javafx.scene.control.ComboBox; import javafx.scene.control.ComboBox;
import javafx.scene.control.Control; import javafx.scene.control.Control;
import javafx.scene.control.Label; import javafx.scene.control.Label;
import javafx.scene.control.ListCell;
import javafx.scene.control.MenuButton; import javafx.scene.control.MenuButton;
import javafx.scene.control.MenuItem; import javafx.scene.control.MenuItem;
import javafx.scene.control.Slider; import javafx.scene.control.Slider;
@ -154,7 +157,9 @@ public abstract class MapApplication extends Application {
{ 0., 0.,-90.,-147.,-35., -45., 30., -145., 154. } }; { 0., 0.,-90.,-147.,-35., -45., 30., -145., 154. } };
final private String name; private final Map<ButtonType, Button> buttons = new HashMap<ButtonType, Button>();
private String name;
private Stage root; private Stage root;
private ComboBox<Projection> projectionChooser; private ComboBox<Projection> projectionChooser;
private GridPane paramGrid; private GridPane paramGrid;
@ -202,7 +207,7 @@ public abstract class MapApplication extends Application {
FileChooser.ExtensionFilter defaultExtension, FileChooser.ExtensionFilter defaultExtension,
Consumer<File> inputSetter) { Consumer<File> inputSetter) {
final Label label = new Label("Current input:"); final Label label = new Label("Current input:");
final Text inputLabel = new Text("None"); final Text inputLabel = new Text("Basic"+defaultExtension.getExtensions().get(0).substring(1)); //this line kind of cheats, since it assumes the first input will be called "Basic", but I couldn't figure out a good way for this to update when the subclass programatically sets the input
final FileChooser inputChooser = new FileChooser(); //TODO: remember last directory final FileChooser inputChooser = new FileChooser(); //TODO: remember last directory
inputChooser.setInitialDirectory(new File("input")); inputChooser.setInitialDirectory(new File("input"));
@ -223,7 +228,7 @@ public abstract class MapApplication extends Application {
} }
if (file != null) { if (file != null) {
final File f = file; final File f = file;
trigger(loadButton, () -> inputSetter.accept(f)); new Thread(() -> inputSetter.accept(f)).start();
inputLabel.setText(f.getName()); inputLabel.setText(f.getName());
} }
}); });
@ -236,6 +241,7 @@ public abstract class MapApplication extends Application {
} }
}); });
buttons.put(ButtonType.LOAD_INPUT, loadButton);
VBox output = new VBox(V_SPACE, new HBox(H_SPACE, label, inputLabel), loadButton); VBox output = new VBox(V_SPACE, new HBox(H_SPACE, label, inputLabel), loadButton);
output.setAlignment(Pos.CENTER); output.setAlignment(Pos.CENTER);
return output; return output;
@ -429,10 +435,10 @@ public abstract class MapApplication extends Application {
* Create a default button that will update the map * Create a default button that will update the map
* @return the button * @return the button
*/ */
protected Button buildUpdateButton(Runnable mapUpdater) { protected Region buildUpdateButton(String text, Runnable mapUpdater) {
final Button updateButton = new Button("Update map"); final Button updateButton = new Button(text);
updateButton.setOnAction((event) -> { updateButton.setOnAction((event) -> {
trigger(updateButton, mapUpdater); new Thread(mapUpdater).start();
}); });
updateButton.setTooltip(new Tooltip( updateButton.setTooltip(new Tooltip(
"Update the current map with your parameters")); "Update the current map with your parameters"));
@ -445,6 +451,7 @@ public abstract class MapApplication extends Application {
} }
}); });
this.buttons.put(ButtonType.UPDATE_MAP, updateButton);
return updateButton; return updateButton;
} }
@ -459,7 +466,7 @@ public abstract class MapApplication extends Application {
* @param calculateAndSaver The callback that saves the thing * @param calculateAndSaver The callback that saves the thing
* @return the button, ready to be pressed * @return the button, ready to be pressed
*/ */
protected Button buildSaveButton(boolean bindCtrlS, String savee, protected Region buildSaveButton(boolean bindCtrlS, String savee,
FileChooser.ExtensionFilter[] allowedExtensions, FileChooser.ExtensionFilter[] allowedExtensions,
FileChooser.ExtensionFilter defaultExtension, FileChooser.ExtensionFilter defaultExtension,
BooleanSupplier settingCollector, BooleanSupplier settingCollector,
@ -490,10 +497,13 @@ public abstract class MapApplication extends Application {
final ProgressBarDialog pBar = new ProgressBarDialog(); final ProgressBarDialog pBar = new ProgressBarDialog();
pBar.setContentText("Finalizing "+savee+"..."); pBar.setContentText("Finalizing "+savee+"...");
pBar.show(); pBar.show();
trigger(saveButton, () -> { new Thread(() -> {
calculateAndSaver.accept(f, pBar); calculateAndSaver.accept(f, pBar);
Platform.runLater(pBar::close); Platform.runLater(pBar::close);
}); //TODO: I think I might want to automatically open the image try {
Desktop.getDesktop().open(f.getParentFile());
} catch (IOException e) {} //if you can't open the file for any reason, just don't worry about it
}).start();
} }
} }
}); });
@ -507,6 +517,10 @@ public abstract class MapApplication extends Application {
} }
}); });
if (savee.equals("map"))
this.buttons.put(ButtonType.SAVE_MAP, saveButton);
else
this.buttons.put(ButtonType.SAVE_GRAPH, saveButton);
return saveButton; return saveButton;
} }
@ -526,6 +540,18 @@ public abstract class MapApplication extends Application {
} }
protected void disable(ButtonType... buttons) {
for (ButtonType bt: buttons)
this.buttons.get(bt).setDisable(true);
}
protected void enable(ButtonType... buttons) {
for (ButtonType bt: buttons)
this.buttons.get(bt).setDisable(false);
}
private void chooseProjectionFromExpandedList(Projection lastProjection) { private void chooseProjectionFromExpandedList(Projection lastProjection) {
final ProjectionSelectionDialog selectDialog = new ProjectionSelectionDialog(); final ProjectionSelectionDialog selectDialog = new ProjectionSelectionDialog();
@ -604,20 +630,6 @@ public abstract class MapApplication extends Application {
} }
private static void trigger(Button btn, Runnable task) {
btn.setDisable(true);
new Thread(() -> {
try {
task.run();
} catch (Exception e) {
e.printStackTrace();
} finally {
btn.setDisable(false);
}
}).start();
}
private static void link(Slider sld, Spinner<Double> spn, int i, double[] doubles, private static void link(Slider sld, Spinner<Double> spn, int i, double[] doubles,
DoubleUnaryOperator converter, Procedure callback, Flag isChanging, Flag suppressListeners) { DoubleUnaryOperator converter, Procedure callback, Flag isChanging, Flag suppressListeners) {
sld.valueChangingProperty().addListener((observable, prev, now) -> { //link spinner to slider sld.valueChangingProperty().addListener((observable, prev, now) -> { //link spinner to slider
@ -658,4 +670,10 @@ public abstract class MapApplication extends Application {
}); });
} }
protected enum ButtonType {
LOAD_INPUT, UPDATE_MAP, SAVE_MAP, SAVE_GRAPH;
}
} }

View File

@ -36,16 +36,13 @@ import javax.imageio.ImageIO;
import dialogs.MapConfigurationDialog; import dialogs.MapConfigurationDialog;
import dialogs.ProgressBarDialog; import dialogs.ProgressBarDialog;
import javafx.application.Platform;
import javafx.embed.swing.SwingFXUtils; import javafx.embed.swing.SwingFXUtils;
import javafx.geometry.Insets; import javafx.geometry.Insets;
import javafx.geometry.Pos; import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.Separator; import javafx.scene.control.Separator;
import javafx.scene.image.ImageView; import javafx.scene.image.ImageView;
import javafx.scene.layout.HBox; import javafx.scene.layout.HBox;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane; import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox; import javafx.scene.layout.VBox;
import javafx.stage.FileChooser; import javafx.stage.FileChooser;
@ -85,8 +82,7 @@ public class MapDesignerRaster extends MapApplication {
private static final float GRATICULE_WIDTH = 0.5f; private static final float GRATICULE_WIDTH = 0.5f;
private static final Color GRATICULE_COLOR = Color.WHITE; private static final Color GRATICULE_COLOR = Color.WHITE;
private Node aspectSelector; private Region aspectSelector;
private Button updateBtn, saveMapBtn;
private double[] aspect; private double[] aspect;
private Flag cropAtIDL; private Flag cropAtIDL;
private MutableDouble graticuleSpacing; private MutableDouble graticuleSpacing;
@ -106,25 +102,25 @@ public class MapDesignerRaster extends MapApplication {
public void start(Stage root) { public void start(Stage root) {
super.start(root); super.start(root);
new Thread(() -> { new Thread(() -> {
setInput(new File("input/Basic.png")); //TODO: this should cause the buttons to grey out setInput(new File("input/Basic.png"));
updateMap(); updateMap();
}).start(); }).start();
} }
@Override @Override
protected Node makeWidgets() { protected Region makeWidgets() {
this.aspect = new double[3]; this.aspect = new double[3];
this.cropAtIDL = new Flag(false); this.cropAtIDL = new Flag(false);
this.graticuleSpacing = new MutableDouble(15); this.graticuleSpacing = new MutableDouble(15);
final Node inputSelector = buildInputSelector(READABLE_TYPES, final Region inputSelector = buildInputSelector(READABLE_TYPES,
RASTER_TYPES[0], this::setInput); RASTER_TYPES[0], this::setInput);
final Node projectionSelector = buildProjectionSelector(this::hideAspect); final Region projectionSelector = buildProjectionSelector(this::hideAspect);
this.aspectSelector = buildAspectSelector(this.aspect, Procedure.NONE); this.aspectSelector = buildAspectSelector(this.aspect, Procedure.NONE);
final Node parameterSelector = buildParameterSelector(Procedure.NONE); final Region parameterSelector = buildParameterSelector(Procedure.NONE);
final Node optionPane = buildOptionPane(cropAtIDL, graticuleSpacing); final Region optionPane = buildOptionPane(cropAtIDL, graticuleSpacing);
this.updateBtn = buildUpdateButton(this::updateMap); final Region updateBtn = buildUpdateButton("Update Map", this::updateMap);
this.saveMapBtn = buildSaveButton(true, "map", RASTER_TYPES, final Region saveMapBtn = buildSaveButton(true, "map", RASTER_TYPES,
RASTER_TYPES[0], this::collectFinalSettings, this::calculateAndSaveMap); RASTER_TYPES[0], this::collectFinalSettings, this::calculateAndSaveMap);
final HBox buttons = new HBox(H_SPACE, updateBtn, saveMapBtn); final HBox buttons = new HBox(H_SPACE, updateBtn, saveMapBtn);
buttons.setAlignment(Pos.CENTER); buttons.setAlignment(Pos.CENTER);
@ -153,19 +149,15 @@ public class MapDesignerRaster extends MapApplication {
private void setInput(File file) { private void setInput(File file) {
updateBtn.setDisable(true); disable(ButtonType.LOAD_INPUT, ButtonType.UPDATE_MAP, ButtonType.SAVE_MAP);
saveMapBtn.setDisable(true);
try { try {
input = new PixelMap(file); input = new PixelMap(file);
} catch (IOException e) { } catch (IOException e) {
final Alert alert = new Alert(Alert.AlertType.ERROR); showError("File not found!",
alert.setHeaderText("File not found!"); "Couldn't find "+file.getAbsolutePath()+".");
alert.setContentText("Couldn't find "+file.getAbsolutePath()+".");
Platform.runLater(alert::showAndWait);
} finally { } finally {
updateBtn.setDisable(false); enable(ButtonType.LOAD_INPUT, ButtonType.UPDATE_MAP, ButtonType.SAVE_MAP);
saveMapBtn.setDisable(false);
} }
} }
@ -176,8 +168,10 @@ public class MapDesignerRaster extends MapApplication {
private void updateMap() { private void updateMap() {
disable(ButtonType.UPDATE_MAP, ButtonType.SAVE_MAP);
loadParameters(); loadParameters();
display.setImage(SwingFXUtils.toFXImage(makeImage(), null)); display.setImage(SwingFXUtils.toFXImage(makeImage(), null));
enable(ButtonType.UPDATE_MAP, ButtonType.SAVE_MAP);
} }
@ -191,6 +185,8 @@ public class MapDesignerRaster extends MapApplication {
private void calculateAndSaveMap(File file, ProgressBarDialog pBar) { private void calculateAndSaveMap(File file, ProgressBarDialog pBar) {
disable(ButtonType.SAVE_MAP);
final int[] outDims = configDialog.getDims(); final int[] outDims = configDialog.getDims();
final int smoothing = configDialog.getSmoothing(); final int smoothing = configDialog.getSmoothing();
BufferedImage theMap = makeImage(outDims[0], outDims[1], smoothing, pBar); //calculate BufferedImage theMap = makeImage(outDims[0], outDims[1], smoothing, pBar); //calculate
@ -204,6 +200,8 @@ public class MapDesignerRaster extends MapApplication {
} catch (IOException e) { } catch (IOException e) {
showError("Failure!", showError("Failure!",
"Could not access "+file.getAbsolutePath()+". It's possible that another program has it open."); "Could not access "+file.getAbsolutePath()+". It's possible that another program has it open.");
} finally {
enable(ButtonType.SAVE_MAP);
} }
display.setImage(SwingFXUtils.toFXImage(theMap, null)); display.setImage(SwingFXUtils.toFXImage(theMap, null));
} }

View File

@ -35,12 +35,11 @@ import org.xml.sax.SAXException;
import dialogs.ProgressBarDialog; import dialogs.ProgressBarDialog;
import javafx.geometry.Insets; import javafx.geometry.Insets;
import javafx.geometry.Pos; import javafx.geometry.Pos;
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.control.Button;
import javafx.scene.control.Separator; import javafx.scene.control.Separator;
import javafx.scene.layout.HBox; import javafx.scene.layout.HBox;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane; import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox; import javafx.scene.layout.VBox;
import javafx.stage.FileChooser; import javafx.stage.FileChooser;
@ -71,8 +70,7 @@ public class MapDesignerVector extends MapApplication {
private static final FileChooser.ExtensionFilter[] VECTOR_TYPES = { private static final FileChooser.ExtensionFilter[] VECTOR_TYPES = {
new FileChooser.ExtensionFilter("SVG", "*.svg") }; new FileChooser.ExtensionFilter("SVG", "*.svg") };
private Node aspectSelector; private Region aspectSelector;
private Button saveBtn;
private double[] aspect; private double[] aspect;
private SVGMap input; private SVGMap input;
private Canvas viewer; private Canvas viewer;
@ -87,23 +85,26 @@ public class MapDesignerVector extends MapApplication {
@Override @Override
public void start(Stage root) { public void start(Stage root) {
System.out.println("Check 0"); //these are for tracking down that rare BufferOverflowException
super.start(root); super.start(root);
System.out.println("Check 1");
new Thread(() -> { new Thread(() -> {
setInput(new File("input/Basic.svg")); //this automatically updates the map//TODO: this should cause the buttons to grey out setInput(new File("input/Basic.svg")); //this automatically updates the map
}).start(); }).start();
System.out.println("Check 2");
} }
@Override @Override
protected Node makeWidgets() { protected Region makeWidgets() {
this.aspect = new double[3]; this.aspect = new double[3];
final Node inputSelector = buildInputSelector(VECTOR_TYPES, final Region inputSelector = buildInputSelector(VECTOR_TYPES,
VECTOR_TYPES[0], this::setInput); VECTOR_TYPES[0], this::setInput);
final Node projectionSelector = buildProjectionSelector( final Region projectionSelector = buildProjectionSelector(
Procedure.concat(this::updateMap, this::hideAspect)); Procedure.concat(this::updateMap, this::hideAspect));
this.aspectSelector = buildAspectSelector(this.aspect, this::updateMap); this.aspectSelector = buildAspectSelector(this.aspect, this::updateMap);
final Node parameterSelector = buildParameterSelector(this::updateMap); final Region parameterSelector = buildParameterSelector(this::updateMap);
this.saveBtn = buildSaveButton(true, "map", VECTOR_TYPES, final Region saveBtn = buildSaveButton(true, "map", VECTOR_TYPES,
VECTOR_TYPES[0], ()->true, this::calculateAndSaveMap); VECTOR_TYPES[0], ()->true, this::calculateAndSaveMap);
final VBox layout = new VBox(V_SPACE, final VBox layout = new VBox(V_SPACE,
@ -128,7 +129,7 @@ public class MapDesignerVector extends MapApplication {
private void setInput(File file) { private void setInput(File file) {
saveBtn.setDisable(true); disable(ButtonType.LOAD_INPUT, ButtonType.SAVE_MAP);
try { try {
input = new SVGMap(file); input = new SVGMap(file);
@ -139,23 +140,24 @@ public class MapDesignerVector extends MapApplication {
showError("Unreadable file!", showError("Unreadable file!",
"We couldn't read "+file.getAbsolutePath()+". It may be corrupt or an unreadable format."); "We couldn't read "+file.getAbsolutePath()+". It may be corrupt or an unreadable format.");
} catch (ParserConfigurationException e) { } catch (ParserConfigurationException e) {
// TODO: Handle this showError("Parser Configuration Error!",
e.printStackTrace(); "My parser configured incorrectly. I blame you.");
} finally { } finally {
saveBtn.setDisable(false); enable(ButtonType.LOAD_INPUT);
updateMap();
} }
updateMap();
} }
private void hideAspect() { private void hideAspect() {
aspectSelector.setVisible(this.getProjection().hasAspect()); aspectSelector.setVisible(this.getProjection().hasAspect());
} }
private void updateMap() { private void updateMap() {
disable(ButtonType.SAVE_MAP);
loadParameters(); loadParameters();
int maxVtx = this.getParamsChanging() ? FAST_MAX_VTX : DEF_MAX_VTX; int maxVtx = this.getParamsChanging() ? FAST_MAX_VTX : DEF_MAX_VTX;
final Iterable<Path> transformed = map(input, input.length()/maxVtx+1, aspect.clone(), null); final Iterable<Path> transformed = map(input, input.length()/maxVtx+1, aspect.clone(), null);
@ -169,10 +171,14 @@ public class MapDesignerVector extends MapApplication {
viewer.setHeight(IMG_WIDTH); viewer.setHeight(IMG_WIDTH);
} }
drawImage(transformed, viewer); drawImage(transformed, viewer);
enable(ButtonType.SAVE_MAP);
} }
private void calculateAndSaveMap(File file, ProgressBarDialog pBar) { private void calculateAndSaveMap(File file, ProgressBarDialog pBar) {
disable(ButtonType.SAVE_MAP);
loadParameters(); loadParameters();
final List<Path> transformed = map(input, 1, aspect.clone(), pBar::setProgress); //calculate final List<Path> transformed = map(input, 1, aspect.clone(), pBar::setProgress); //calculate
try { try {
@ -183,6 +189,8 @@ public class MapDesignerVector extends MapApplication {
} catch (IOException e) { } catch (IOException e) {
showError("Failure!", showError("Failure!",
"Could not access "+file.getAbsolutePath()+". It's possible that another program has it open."); "Could not access "+file.getAbsolutePath()+". It's possible that another program has it open.");
} finally {
enable(ButtonType.SAVE_MAP);
} }
} }

View File

@ -27,7 +27,7 @@ import maps.Projection.Property;
import maps.Projection.Type; import maps.Projection.Type;
/** /**
* TODO: Write description * A class containing map projections with four-way symmetry and curved parallels.
* *
* @author jkunimune * @author jkunimune
*/ */

View File

@ -43,8 +43,8 @@ public class Dixon {
*/ */
public static double PERIOD_THIRD = 1.7666387503; public static double PERIOD_THIRD = 1.7666387503;
private static final double[] COEF = { 1.000000e0, .625000e-1, .223214e-2, .069754e-3, .020121e-4, private static final double[] COEF = { 1.000000e0, .625000e-1, .223214e-2, .069754e-3,
.005539e-5/*, .001477e-6, .000385e-7, .000099e-8, .000025e-9*/ }; .020121e-4/*, .005539e-5, .001477e-6, .000385e-7, .000099e-8, .000025e-9*/ };
private static final double TOLERANCE = 1e-3; private static final double TOLERANCE = 1e-3;