mirror of
https://github.com/praktimarc/kst4contest.git
synced 2026-08-24 11:06:59 +02:00
Add persistent map analysis toggle and improve compact layout for smaller screens. Solves (#69)
This commit is contained in:
@@ -497,7 +497,9 @@ So kann der Contest-Operator auf einem Blick sehen, welche Stationen wann und ü
|
|||||||
|
|
||||||
KST4Contest kann wiederkehrende CQ-Nachrichten in den öffentlichen Chat senden. Beide Chat-Kategorien verwenden ein gemeinsames Intervall, besitzen aber jeweils einen eigenen Aktivierungsschalter und Nachrichtentext. Globale Variablen wie `MYQRG`, `SECONDQRG` oder `MYLOCATOR` werden unmittelbar vor jeder Aussendung aktualisiert.
|
KST4Contest kann wiederkehrende CQ-Nachrichten in den öffentlichen Chat senden. Beide Chat-Kategorien verwenden ein gemeinsames Intervall, besitzen aber jeweils einen eigenen Aktivierungsschalter und Nachrichtentext. Globale Variablen wie `MYQRG`, `SECONDQRG` oder `MYLOCATOR` werden unmittelbar vor jeder Aussendung aktualisiert.
|
||||||
|
|
||||||
|
|
||||||
Der Beacon ist für längeres CQ-Rufen auf einer festen Frequenz gedacht. Beim Absuchen oder häufigen Wechseln der QRG sollte er ausgeschaltet werden, damit keine inzwischen falsche Frequenz verbreitet wird. Details: [Konfiguration – Beacon Settings](de-Konfiguration#beacon-settings-automatischer-beacon).
|
Der Beacon ist für längeres CQ-Rufen auf einer festen Frequenz gedacht. Beim Absuchen oder häufigen Wechseln der QRG sollte er ausgeschaltet werden, damit keine inzwischen falsche Frequenz verbreitet wird. Details: [Konfiguration – Beacon Settings](de-Konfiguration#beacon-settings-automatischer-beacon).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Simplelogfile
|
## Simplelogfile
|
||||||
@@ -510,7 +512,7 @@ Dateibasierte Log-Auswertung per Regex. Details: [Log-Synchronisation](Log-Synch
|
|||||||
|
|
||||||
Ein separates Fenster zeigt den QSO-Fluss zwischen anderen Stationen. Besonders interessant in ruhigeren Nacht-Stunden während des Contests, wenn weniger Verkehr herrscht.
|
Ein separates Fenster zeigt den QSO-Fluss zwischen anderen Stationen. Besonders interessant in ruhigeren Nacht-Stunden während des Contests, wenn weniger Verkehr herrscht.
|
||||||
|
|
||||||
Dieses Fenster kann miniaturisiert werden, wenn es nicht benötigt wird. Zukünftig geplant: Filterung auf Stationen im ausgewählten QTF.
|
Dieses Fenster kann minimiert werden, wenn es nicht benötigt wird. Zukünftig geplant: Filterung auf Stationen im ausgewählten QTF.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ public class ChatPreferences {
|
|||||||
* Reading must stay backwards compatible: missing/unknown tags should fall back to defaults.
|
* Reading must stay backwards compatible: missing/unknown tags should fall back to defaults.
|
||||||
*/
|
*/
|
||||||
// private static final int CONFIG_VERSION = 2;
|
// private static final int CONFIG_VERSION = 2;
|
||||||
public static final int CONFIG_VERSION = 4;
|
public static final int CONFIG_VERSION = 5;
|
||||||
|
|
||||||
// Prefer writing tag names that mirror variable names (human readable). Keep legacy tags for compatibility.
|
// Prefer writing tag names that mirror variable names (human readable). Keep legacy tags for compatibility.
|
||||||
private static final String TAG_CONFIG_VERSION = "configVersion";
|
private static final String TAG_CONFIG_VERSION = "configVersion";
|
||||||
@@ -339,6 +339,7 @@ public class ChatPreferences {
|
|||||||
|
|
||||||
private double[] GUIstationMapStageSceneSizeHW = new double[] { 1000, 800 };
|
private double[] GUIstationMapStageSceneSizeHW = new double[] { 1000, 800 };
|
||||||
private double[] GUIstationMapStagePositionXY = new double[] { Double.NaN, Double.NaN };
|
private double[] GUIstationMapStagePositionXY = new double[] { Double.NaN, Double.NaN };
|
||||||
|
private boolean GUIstationMapPathAnalysisVisible = true;
|
||||||
|
|
||||||
|
|
||||||
/*********************************************************************************
|
/*********************************************************************************
|
||||||
@@ -635,6 +636,14 @@ public class ChatPreferences {
|
|||||||
this.GUIstationMapStagePositionXY = GUIstationMapStagePositionXY;
|
this.GUIstationMapStagePositionXY = GUIstationMapStagePositionXY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isGUIstationMapPathAnalysisVisible() {
|
||||||
|
return GUIstationMapPathAnalysisVisible;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGUIstationMapPathAnalysisVisible(boolean GUIstationMapPathAnalysisVisible) {
|
||||||
|
this.GUIstationMapPathAnalysisVisible = GUIstationMapPathAnalysisVisible;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isGuiOptions_defaultFilterNothing() {
|
public boolean isGuiOptions_defaultFilterNothing() {
|
||||||
return guiOptions_defaultFilterNothing;
|
return guiOptions_defaultFilterNothing;
|
||||||
}
|
}
|
||||||
@@ -2048,6 +2057,12 @@ public class ChatPreferences {
|
|||||||
);
|
);
|
||||||
guiOptions.appendChild(GUIstationMapStagePositionXY);
|
guiOptions.appendChild(GUIstationMapStagePositionXY);
|
||||||
|
|
||||||
|
Element GUIstationMapPathAnalysisVisible = doc.createElement("GUIstationMapPathAnalysisVisible");
|
||||||
|
GUIstationMapPathAnalysisVisible.setTextContent(
|
||||||
|
String.valueOf(this.isGUIstationMapPathAnalysisVisible())
|
||||||
|
);
|
||||||
|
guiOptions.appendChild(GUIstationMapPathAnalysisVisible);
|
||||||
|
|
||||||
/****************************************************************************************
|
/****************************************************************************************
|
||||||
****************************** now write this XML! *************************************
|
****************************** now write this XML! *************************************
|
||||||
****************************************************************************************/
|
****************************************************************************************/
|
||||||
@@ -2783,6 +2798,17 @@ public class ChatPreferences {
|
|||||||
this.getGUIstationMapStagePositionXY()
|
this.getGUIstationMapStagePositionXY()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Files written before config version 5 do not contain this value.
|
||||||
|
* Keep the default true in that case so existing users discover the
|
||||||
|
* path-analysis feature before choosing to hide it themselves.
|
||||||
|
*/
|
||||||
|
this.setGUIstationMapPathAnalysisVisible(getBoolean(
|
||||||
|
element,
|
||||||
|
this.isGUIstationMapPathAnalysisVisible(),
|
||||||
|
"GUIstationMapPathAnalysisVisible"
|
||||||
|
));
|
||||||
|
|
||||||
// Splitpane divider positions
|
// Splitpane divider positions
|
||||||
String s1 = getText(element, null, "GUIselectedCallSignSplitPane_dividerposition");
|
String s1 = getText(element, null, "GUIselectedCallSignSplitPane_dividerposition");
|
||||||
if (s1 != null) {
|
if (s1 != null) {
|
||||||
|
|||||||
@@ -0,0 +1,73 @@
|
|||||||
|
package kst4contest.test;
|
||||||
|
|
||||||
|
import kst4contest.model.ChatPreferences;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.io.TempDir;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
class ChatPreferencesStationMapVisibilityTest {
|
||||||
|
|
||||||
|
@TempDir
|
||||||
|
Path temporaryDirectory;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void pathAnalysisIsVisibleByDefault() {
|
||||||
|
ChatPreferences preferences = new ChatPreferences();
|
||||||
|
|
||||||
|
assertTrue(preferences.isGUIstationMapPathAnalysisVisible());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void hiddenPathAnalysisStateSurvivesXmlRoundTrip() throws IOException {
|
||||||
|
Path preferencesFile = temporaryDirectory.resolve("preferences.xml");
|
||||||
|
|
||||||
|
ChatPreferences writtenPreferences = new ChatPreferences();
|
||||||
|
writtenPreferences.setStoreAndRestorePreferencesFileName(
|
||||||
|
preferencesFile.toString());
|
||||||
|
writtenPreferences.setGUIstationMapPathAnalysisVisible(false);
|
||||||
|
writtenPreferences.writePreferencesToXmlFile();
|
||||||
|
|
||||||
|
String writtenXml = Files.readString(preferencesFile);
|
||||||
|
assertTrue(writtenXml.contains(
|
||||||
|
"<GUIstationMapPathAnalysisVisible>false"
|
||||||
|
+ "</GUIstationMapPathAnalysisVisible>"));
|
||||||
|
|
||||||
|
ChatPreferences restoredPreferences = new ChatPreferences();
|
||||||
|
restoredPreferences.setStoreAndRestorePreferencesFileName(
|
||||||
|
preferencesFile.toString());
|
||||||
|
restoredPreferences.readPreferencesFromXmlFile();
|
||||||
|
|
||||||
|
assertFalse(restoredPreferences.isGUIstationMapPathAnalysisVisible());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void legacyXmlWithoutVisibilitySettingKeepsAnalysisDiscoverable()
|
||||||
|
throws IOException {
|
||||||
|
|
||||||
|
Path legacyPreferencesFile =
|
||||||
|
temporaryDirectory.resolve("legacy-preferences.xml");
|
||||||
|
|
||||||
|
Files.writeString(legacyPreferencesFile, """
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<praktiKST>
|
||||||
|
<configVersion>4</configVersion>
|
||||||
|
<guiOptions>
|
||||||
|
<GUIstationMapStageSceneSizeHW>1000.0;800.0</GUIstationMapStageSceneSizeHW>
|
||||||
|
</guiOptions>
|
||||||
|
</praktiKST>
|
||||||
|
""");
|
||||||
|
|
||||||
|
ChatPreferences restoredPreferences = new ChatPreferences();
|
||||||
|
restoredPreferences.setStoreAndRestorePreferencesFileName(
|
||||||
|
legacyPreferencesFile.toString());
|
||||||
|
restoredPreferences.readPreferencesFromXmlFile();
|
||||||
|
|
||||||
|
assertTrue(restoredPreferences.isGUIstationMapPathAnalysisVisible());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -28,6 +28,8 @@ import javafx.scene.control.ScrollPane;
|
|||||||
import javafx.scene.layout.Priority;
|
import javafx.scene.layout.Priority;
|
||||||
import javafx.scene.layout.Region;
|
import javafx.scene.layout.Region;
|
||||||
import javafx.scene.layout.ColumnConstraints;
|
import javafx.scene.layout.ColumnConstraints;
|
||||||
|
import javafx.geometry.Pos;
|
||||||
|
import javafx.scene.layout.HBox;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Standalone station map window.
|
* Standalone station map window.
|
||||||
@@ -49,6 +51,9 @@ public final class StationMapView {
|
|||||||
*/
|
*/
|
||||||
private static final boolean MAP_DEBUG_LOGGING = false;
|
private static final boolean MAP_DEBUG_LOGGING = false;
|
||||||
|
|
||||||
|
private static final double MINIMUM_HEIGHT_WITH_PATH_ANALYSIS = 650.0;
|
||||||
|
private static final double MINIMUM_HEIGHT_WITHOUT_PATH_ANALYSIS = 420.0;
|
||||||
|
|
||||||
private final PathProfileChart detailPathProfileChart = new PathProfileChart();
|
private final PathProfileChart detailPathProfileChart = new PathProfileChart();
|
||||||
private final Label detailPathModeValue = new Label("-");
|
private final Label detailPathModeValue = new Label("-");
|
||||||
|
|
||||||
@@ -76,6 +81,12 @@ public final class StationMapView {
|
|||||||
private VBox detailPane;
|
private VBox detailPane;
|
||||||
|
|
||||||
private final Label statusLabel = new Label("Station map not initialized yet.");
|
private final Label statusLabel = new Label("Station map not initialized yet.");
|
||||||
|
|
||||||
|
private final Label pathAnalysisHiddenHintLabel = new Label("Path analysis is hidden.");
|
||||||
|
private final Button pathAnalysisVisibilityButton = new Button();
|
||||||
|
private final Tooltip pathAnalysisVisibilityTooltip = new Tooltip();
|
||||||
|
|
||||||
|
|
||||||
private final Label detailCallsignValue = new Label("-");
|
private final Label detailCallsignValue = new Label("-");
|
||||||
private final Label detailLocatorValue = new Label("-");
|
private final Label detailLocatorValue = new Label("-");
|
||||||
private final Label detailQrbValue = new Label("-");
|
private final Label detailQrbValue = new Label("-");
|
||||||
@@ -138,8 +149,12 @@ public final class StationMapView {
|
|||||||
private PathAnalysisResult lastPathAnalysisResult = PathAnalysisResult.waitingForSelection("");
|
private PathAnalysisResult lastPathAnalysisResult = PathAnalysisResult.waitingForSelection("");
|
||||||
|
|
||||||
private VBox mapAndProfilePane;
|
private VBox mapAndProfilePane;
|
||||||
|
private VBox profileSection;
|
||||||
|
private VBox pathAnalysisSection;
|
||||||
private ScrollPane detailScrollPane;
|
private ScrollPane detailScrollPane;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private final Label detailPathLosValue = new Label("-");
|
private final Label detailPathLosValue = new Label("-");
|
||||||
private final Label detailPathWorstClearanceValue = new Label("-");
|
private final Label detailPathWorstClearanceValue = new Label("-");
|
||||||
|
|
||||||
@@ -287,6 +302,14 @@ public final class StationMapView {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
pathAnalysisVisibilityButton.setMinWidth(Region.USE_PREF_SIZE);
|
||||||
|
pathAnalysisVisibilityButton.setTooltip(pathAnalysisVisibilityTooltip);
|
||||||
|
pathAnalysisVisibilityButton.setOnAction(event ->
|
||||||
|
setPathAnalysisVisible(!profileSection.isVisible(), true));
|
||||||
|
|
||||||
|
pathAnalysisHiddenHintLabel.setMinWidth(Region.USE_PREF_SIZE);
|
||||||
|
pathAnalysisHiddenHintLabel.setStyle("-fx-font-style: italic; -fx-opacity: 0.85;");
|
||||||
|
|
||||||
webView.setFocusTraversable(true);
|
webView.setFocusTraversable(true);
|
||||||
webView.setPickOnBounds(true);
|
webView.setPickOnBounds(true);
|
||||||
|
|
||||||
@@ -323,7 +346,8 @@ public final class StationMapView {
|
|||||||
webView.widthProperty().addListener((obs, oldValue, newValue) -> requestMapInvalidateSize());
|
webView.widthProperty().addListener((obs, oldValue, newValue) -> requestMapInvalidateSize());
|
||||||
webView.heightProperty().addListener((obs, oldValue, newValue) -> requestMapInvalidateSize());
|
webView.heightProperty().addListener((obs, oldValue, newValue) -> requestMapInvalidateSize());
|
||||||
|
|
||||||
VBox profileSection = createProfileSection();
|
profileSection = createProfileSection();
|
||||||
|
|
||||||
|
|
||||||
mapAndProfilePane = new VBox(6, webView, profileSection);
|
mapAndProfilePane = new VBox(6, webView, profileSection);
|
||||||
mapAndProfilePane.setPadding(new Insets(0));
|
mapAndProfilePane.setPadding(new Insets(0));
|
||||||
@@ -349,10 +373,9 @@ public final class StationMapView {
|
|||||||
mapAndProfilePane.widthProperty().subtract(20)
|
mapAndProfilePane.widthProperty().subtract(20)
|
||||||
);
|
);
|
||||||
|
|
||||||
detailPane = new VBox(10,
|
pathAnalysisSection = createPathAnalysisSection();
|
||||||
createSelectedStationSection(),
|
detailPane = new VBox(10, createSelectedStationSection(), pathAnalysisSection);
|
||||||
createPathAnalysisSection()
|
|
||||||
);
|
|
||||||
detailPane.setPadding(new Insets(10));
|
detailPane.setPadding(new Insets(10));
|
||||||
|
|
||||||
detailPane.setMinWidth(0);
|
detailPane.setMinWidth(0);
|
||||||
@@ -364,8 +387,14 @@ public final class StationMapView {
|
|||||||
detailScrollPane.setFitToWidth(true);
|
detailScrollPane.setFitToWidth(true);
|
||||||
detailScrollPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
|
detailScrollPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
|
||||||
detailScrollPane.setVbarPolicy(ScrollPane.ScrollBarPolicy.AS_NEEDED);
|
detailScrollPane.setVbarPolicy(ScrollPane.ScrollBarPolicy.AS_NEEDED);
|
||||||
detailScrollPane.setMinWidth(300);
|
/*
|
||||||
|
* Allow the details pane to be reduced far enough to leave more room for the
|
||||||
|
* map. At its minimum width, a callsign with up to ten characters remains
|
||||||
|
* readable.
|
||||||
|
*/
|
||||||
|
detailScrollPane.setMinWidth(210);
|
||||||
detailScrollPane.setPrefWidth(350);
|
detailScrollPane.setPrefWidth(350);
|
||||||
|
|
||||||
detailScrollPane.setMaxWidth(Double.MAX_VALUE);
|
detailScrollPane.setMaxWidth(Double.MAX_VALUE);
|
||||||
|
|
||||||
detailScrollPane.setFitToWidth(true);
|
detailScrollPane.setFitToWidth(true);
|
||||||
@@ -378,8 +407,7 @@ public final class StationMapView {
|
|||||||
SplitPane.setResizableWithParent(detailScrollPane, true);
|
SplitPane.setResizableWithParent(detailScrollPane, true);
|
||||||
|
|
||||||
rootPane = new BorderPane();
|
rootPane = new BorderPane();
|
||||||
rootPane.setTop(statusLabel);
|
rootPane.setTop(createMapHeader());
|
||||||
BorderPane.setMargin(statusLabel, new Insets(8));
|
|
||||||
rootPane.setCenter(mainSplitPane);
|
rootPane.setCenter(mainSplitPane);
|
||||||
|
|
||||||
double[] size = chatPreferences.getGUIstationMapStageSceneSizeHW();
|
double[] size = chatPreferences.getGUIstationMapStageSceneSizeHW();
|
||||||
@@ -390,7 +418,12 @@ public final class StationMapView {
|
|||||||
scene = new Scene(rootPane, initialWidth, initialHeight);
|
scene = new Scene(rootPane, initialWidth, initialHeight);
|
||||||
|
|
||||||
stage.setMinWidth(900);
|
stage.setMinWidth(900);
|
||||||
stage.setMinHeight(650);
|
stage.setMinHeight(resolveMinimumStationMapHeight(
|
||||||
|
chatPreferences.isGUIstationMapPathAnalysisVisible()));
|
||||||
|
|
||||||
|
stage.setScene(scene);
|
||||||
|
setPathAnalysisVisible(chatPreferences.isGUIstationMapPathAnalysisVisible(), false);
|
||||||
|
applyThemeFromPreferences();
|
||||||
|
|
||||||
stage.setScene(scene);
|
stage.setScene(scene);
|
||||||
applyThemeFromPreferences();
|
applyThemeFromPreferences();
|
||||||
@@ -446,6 +479,91 @@ public final class StationMapView {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an always-visible header for the map status and analysis controls.
|
||||||
|
*
|
||||||
|
* Keeping the control outside the sections that it hides is important: users
|
||||||
|
* must always have an obvious way to restore a previously hidden analysis.
|
||||||
|
*/
|
||||||
|
private HBox createMapHeader() {
|
||||||
|
// The status may be shortened before the show/hide control is ever clipped.
|
||||||
|
statusLabel.setMinWidth(0);
|
||||||
|
statusLabel.setMaxWidth(Double.MAX_VALUE);
|
||||||
|
statusLabel.setTextOverrun(OverrunStyle.ELLIPSIS);
|
||||||
|
|
||||||
|
HBox header = new HBox(
|
||||||
|
10,
|
||||||
|
statusLabel,
|
||||||
|
pathAnalysisHiddenHintLabel,
|
||||||
|
pathAnalysisVisibilityButton
|
||||||
|
);
|
||||||
|
header.setAlignment(Pos.CENTER_LEFT);
|
||||||
|
header.setPadding(new Insets(8));
|
||||||
|
HBox.setHgrow(statusLabel, Priority.ALWAYS);
|
||||||
|
return header;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows or hides both parts of the path analysis as one logical feature.
|
||||||
|
*
|
||||||
|
* Both visible and managed must be changed. A node that is merely invisible
|
||||||
|
* would still reserve layout space and the map would not grow into that area.
|
||||||
|
* The current analysis result remains attached to the controls and is
|
||||||
|
* immediately available again when the user restores the sections.
|
||||||
|
*
|
||||||
|
* @param visible true to show the profile and detailed analysis
|
||||||
|
* @param persist true when the change was explicitly requested by the user
|
||||||
|
*/
|
||||||
|
private void setPathAnalysisVisible(boolean visible, boolean persist) {
|
||||||
|
profileSection.setVisible(visible);
|
||||||
|
profileSection.setManaged(visible);
|
||||||
|
|
||||||
|
pathAnalysisSection.setVisible(visible);
|
||||||
|
pathAnalysisSection.setManaged(visible);
|
||||||
|
|
||||||
|
pathAnalysisHiddenHintLabel.setVisible(!visible);
|
||||||
|
pathAnalysisHiddenHintLabel.setManaged(!visible);
|
||||||
|
|
||||||
|
pathAnalysisVisibilityButton.setText(
|
||||||
|
visible ? "Hide path analysis" : "Show path analysis");
|
||||||
|
pathAnalysisVisibilityButton.setAccessibleText(
|
||||||
|
visible ? "Hide path analysis" : "Show path analysis");
|
||||||
|
pathAnalysisVisibilityButton.setStyle(
|
||||||
|
visible ? "" : "-fx-font-weight: bold;");
|
||||||
|
|
||||||
|
pathAnalysisVisibilityTooltip.setText(visible
|
||||||
|
? "Hide the path profile and detailed path analysis. You can show them again at any time."
|
||||||
|
: "Show the path profile and detailed path analysis.");
|
||||||
|
|
||||||
|
pathAnalysisVisibilityButton.setAccessibleHelp(
|
||||||
|
pathAnalysisVisibilityTooltip.getText());
|
||||||
|
|
||||||
|
if (!visible) {
|
||||||
|
/*
|
||||||
|
* Do not leave a profile hover marker on the map after its chart was
|
||||||
|
* hidden.
|
||||||
|
*/
|
||||||
|
showProfileHoverPointOnMap(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
stage.setMinHeight(resolveMinimumStationMapHeight(visible));
|
||||||
|
|
||||||
|
if (persist) {
|
||||||
|
chatPreferences.setGUIstationMapPathAnalysisVisible(visible);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rootPane != null) {
|
||||||
|
rootPane.requestLayout();
|
||||||
|
Platform.runLater(this::requestMapInvalidateSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private double resolveMinimumStationMapHeight(boolean pathAnalysisVisible) {
|
||||||
|
return pathAnalysisVisible
|
||||||
|
? MINIMUM_HEIGHT_WITH_PATH_ANALYSIS
|
||||||
|
: MINIMUM_HEIGHT_WITHOUT_PATH_ANALYSIS;
|
||||||
|
}
|
||||||
|
|
||||||
private VBox createSelectedStationSection() {
|
private VBox createSelectedStationSection() {
|
||||||
GridPane detailGrid = new GridPane();
|
GridPane detailGrid = new GridPane();
|
||||||
detailGrid.setHgap(8);
|
detailGrid.setHgap(8);
|
||||||
@@ -494,13 +612,18 @@ public final class StationMapView {
|
|||||||
gridPane.getColumnConstraints().clear();
|
gridPane.getColumnConstraints().clear();
|
||||||
|
|
||||||
ColumnConstraints labelColumn = new ColumnConstraints();
|
ColumnConstraints labelColumn = new ColumnConstraints();
|
||||||
labelColumn.setMinWidth(105);
|
labelColumn.setMinWidth(70);
|
||||||
labelColumn.setPrefWidth(115);
|
labelColumn.setPrefWidth(115);
|
||||||
labelColumn.setMaxWidth(130);
|
labelColumn.setMaxWidth(130);
|
||||||
labelColumn.setHgrow(Priority.NEVER);
|
labelColumn.setHgrow(Priority.NEVER);
|
||||||
|
|
||||||
ColumnConstraints valueColumn = new ColumnConstraints();
|
ColumnConstraints valueColumn = new ColumnConstraints();
|
||||||
valueColumn.setMinWidth(180);
|
|
||||||
|
/*
|
||||||
|
* Reserve enough space for a callsign with up to ten characters, while still
|
||||||
|
* allowing the details pane to become considerably narrower.
|
||||||
|
*/
|
||||||
|
valueColumn.setMinWidth(85);
|
||||||
valueColumn.setHgrow(Priority.ALWAYS);
|
valueColumn.setHgrow(Priority.ALWAYS);
|
||||||
|
|
||||||
gridPane.getColumnConstraints().addAll(labelColumn, valueColumn);
|
gridPane.getColumnConstraints().addAll(labelColumn, valueColumn);
|
||||||
@@ -1530,8 +1653,11 @@ public final class StationMapView {
|
|||||||
return 768.0;
|
return 768.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double minimumHeight = resolveMinimumStationMapHeight(
|
||||||
|
chatPreferences.isGUIstationMapPathAnalysisVisible());
|
||||||
|
|
||||||
// Avoid restoring very large old test sizes after the layout changed.
|
// Avoid restoring very large old test sizes after the layout changed.
|
||||||
if (storedSize[1] < 650.0 || storedSize[1] > 1100.0) {
|
if (storedSize[1] < minimumHeight || storedSize[1] > 1100.0) {
|
||||||
return 768.0;
|
return 768.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user