简化 VersionIconType 相关代码 (#2669)
This commit is contained in:
@@ -43,7 +43,9 @@ import org.jackhuang.hmcl.util.versioning.VersionNumber;
|
|||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
@@ -52,7 +54,6 @@ import java.util.stream.Collectors;
|
|||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import static org.jackhuang.hmcl.setting.ConfigHolder.config;
|
import static org.jackhuang.hmcl.setting.ConfigHolder.config;
|
||||||
import static org.jackhuang.hmcl.ui.FXUtils.newBuiltinImage;
|
|
||||||
import static org.jackhuang.hmcl.util.Logging.LOG;
|
import static org.jackhuang.hmcl.util.Logging.LOG;
|
||||||
import static org.jackhuang.hmcl.util.Pair.pair;
|
import static org.jackhuang.hmcl.util.Pair.pair;
|
||||||
|
|
||||||
@@ -263,36 +264,43 @@ public class HMCLGameRepository extends DefaultGameRepository {
|
|||||||
|
|
||||||
public Image getVersionIconImage(String id) {
|
public Image getVersionIconImage(String id) {
|
||||||
if (id == null || !isLoaded())
|
if (id == null || !isLoaded())
|
||||||
return newBuiltinImage("/assets/img/grass.png");
|
return VersionIconType.DEFAULT.getIcon();
|
||||||
|
|
||||||
VersionSetting vs = getLocalVersionSettingOrCreate(id);
|
VersionSetting vs = getLocalVersionSettingOrCreate(id);
|
||||||
VersionIconType iconType = Optional.ofNullable(vs).map(VersionSetting::getVersionIcon).orElse(VersionIconType.DEFAULT);
|
VersionIconType iconType = vs != null ? Lang.requireNonNullElse(vs.getVersionIcon(), VersionIconType.DEFAULT) : VersionIconType.DEFAULT;
|
||||||
|
|
||||||
if (iconType == VersionIconType.DEFAULT) {
|
if (iconType == VersionIconType.DEFAULT) {
|
||||||
Version version = getVersion(id).resolve(this);
|
Version version = getVersion(id).resolve(this);
|
||||||
File iconFile = getVersionIconFile(id);
|
File iconFile = getVersionIconFile(id);
|
||||||
if (iconFile.exists())
|
if (iconFile.exists()) {
|
||||||
return new Image("file:" + iconFile.getAbsolutePath());
|
try (InputStream inputStream = new FileInputStream(iconFile)) {
|
||||||
else if (LibraryAnalyzer.isModded(this, version)) {
|
return new Image(inputStream);
|
||||||
|
} catch (IOException e) {
|
||||||
|
LOG.log(Level.WARNING, "Failed to load version icon of " + id, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LibraryAnalyzer.isModded(this, version)) {
|
||||||
LibraryAnalyzer libraryAnalyzer = LibraryAnalyzer.analyze(version);
|
LibraryAnalyzer libraryAnalyzer = LibraryAnalyzer.analyze(version);
|
||||||
if (libraryAnalyzer.has(LibraryAnalyzer.LibraryType.FABRIC))
|
if (libraryAnalyzer.has(LibraryAnalyzer.LibraryType.FABRIC))
|
||||||
return newBuiltinImage("/assets/img/fabric.png");
|
return VersionIconType.FABRIC.getIcon();
|
||||||
else if (libraryAnalyzer.has(LibraryAnalyzer.LibraryType.FORGE))
|
else if (libraryAnalyzer.has(LibraryAnalyzer.LibraryType.FORGE))
|
||||||
return newBuiltinImage("/assets/img/forge.png");
|
return VersionIconType.FORGE.getIcon();
|
||||||
else if (libraryAnalyzer.has(LibraryAnalyzer.LibraryType.NEO_FORGE))
|
else if (libraryAnalyzer.has(LibraryAnalyzer.LibraryType.NEO_FORGE))
|
||||||
return newBuiltinImage("/assets/img/neoforge.png");
|
return VersionIconType.NEO_FORGE.getIcon();
|
||||||
else if (libraryAnalyzer.has(LibraryAnalyzer.LibraryType.QUILT))
|
else if (libraryAnalyzer.has(LibraryAnalyzer.LibraryType.QUILT))
|
||||||
return newBuiltinImage("/assets/img/quilt.png");
|
return VersionIconType.QUILT.getIcon();
|
||||||
else if (libraryAnalyzer.has(LibraryAnalyzer.LibraryType.OPTIFINE))
|
else if (libraryAnalyzer.has(LibraryAnalyzer.LibraryType.OPTIFINE))
|
||||||
return newBuiltinImage("/assets/img/command.png");
|
return VersionIconType.COMMAND.getIcon();
|
||||||
else if (libraryAnalyzer.has(LibraryAnalyzer.LibraryType.LITELOADER))
|
else if (libraryAnalyzer.has(LibraryAnalyzer.LibraryType.LITELOADER))
|
||||||
return newBuiltinImage("/assets/img/chicken.png");
|
return VersionIconType.CHICKEN.getIcon();
|
||||||
else
|
else
|
||||||
return newBuiltinImage("/assets/img/furnace.png");
|
return VersionIconType.FURNACE.getIcon();
|
||||||
} else
|
}
|
||||||
return newBuiltinImage("/assets/img/grass.png");
|
|
||||||
|
return VersionIconType.DEFAULT.getIcon();
|
||||||
} else {
|
} else {
|
||||||
return newBuiltinImage(iconType.getResourceUrl());
|
return iconType.getIcon();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,9 @@
|
|||||||
*/
|
*/
|
||||||
package org.jackhuang.hmcl.setting;
|
package org.jackhuang.hmcl.setting;
|
||||||
|
|
||||||
|
import javafx.scene.image.Image;
|
||||||
|
import org.jackhuang.hmcl.ui.FXUtils;
|
||||||
|
|
||||||
public enum VersionIconType {
|
public enum VersionIconType {
|
||||||
DEFAULT("/assets/img/grass.png"),
|
DEFAULT("/assets/img/grass.png"),
|
||||||
|
|
||||||
@@ -39,7 +42,7 @@ public enum VersionIconType {
|
|||||||
this.resourceUrl = resourceUrl;
|
this.resourceUrl = resourceUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getResourceUrl() {
|
public Image getIcon() {
|
||||||
return resourceUrl;
|
return FXUtils.newBuiltinImage(resourceUrl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -101,11 +101,10 @@ public final class FXUtils {
|
|||||||
public static final String DEFAULT_MONOSPACE_FONT = OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS ? "Consolas" : "Monospace";
|
public static final String DEFAULT_MONOSPACE_FONT = OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS ? "Consolas" : "Monospace";
|
||||||
|
|
||||||
private static final Map<String, Image> builtinImageCache = new ConcurrentHashMap<>();
|
private static final Map<String, Image> builtinImageCache = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
private static final Map<String, Path> remoteImageCache = new ConcurrentHashMap<>();
|
private static final Map<String, Path> remoteImageCache = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
public static void shutdown() {
|
public static void shutdown() {
|
||||||
for (Map.Entry<String, Path> entry: remoteImageCache.entrySet()) {
|
for (Map.Entry<String, Path> entry : remoteImageCache.entrySet()) {
|
||||||
try {
|
try {
|
||||||
Files.deleteIfExists(entry.getValue());
|
Files.deleteIfExists(entry.getValue());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@@ -686,13 +685,11 @@ public final class FXUtils {
|
|||||||
* @see ResourceNotFoundError
|
* @see ResourceNotFoundError
|
||||||
*/
|
*/
|
||||||
public static Image newBuiltinImage(String url) {
|
public static Image newBuiltinImage(String url) {
|
||||||
return builtinImageCache.computeIfAbsent(url, s -> {
|
try {
|
||||||
try {
|
return builtinImageCache.computeIfAbsent(url, Image::new);
|
||||||
return new Image(s);
|
} catch (IllegalArgumentException e) {
|
||||||
} catch (IllegalArgumentException e) {
|
throw new ResourceNotFoundError("Cannot access image: " + url, e);
|
||||||
throw new ResourceNotFoundError("Cannot access image: " + s, e);
|
}
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import javafx.scene.input.MouseEvent;
|
|||||||
import javafx.scene.layout.*;
|
import javafx.scene.layout.*;
|
||||||
import org.jackhuang.hmcl.download.LibraryAnalyzer;
|
import org.jackhuang.hmcl.download.LibraryAnalyzer;
|
||||||
import org.jackhuang.hmcl.setting.Theme;
|
import org.jackhuang.hmcl.setting.Theme;
|
||||||
|
import org.jackhuang.hmcl.setting.VersionIconType;
|
||||||
import org.jackhuang.hmcl.ui.construct.RipplerContainer;
|
import org.jackhuang.hmcl.ui.construct.RipplerContainer;
|
||||||
import org.jackhuang.hmcl.util.i18n.I18n;
|
import org.jackhuang.hmcl.util.i18n.I18n;
|
||||||
|
|
||||||
@@ -46,7 +47,7 @@ import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
|||||||
*/
|
*/
|
||||||
public class InstallerItem extends Control {
|
public class InstallerItem extends Control {
|
||||||
private final String id;
|
private final String id;
|
||||||
private final String imageUrl;
|
private final VersionIconType iconType;
|
||||||
public final StringProperty libraryVersion = new SimpleStringProperty();
|
public final StringProperty libraryVersion = new SimpleStringProperty();
|
||||||
public final StringProperty incompatibleLibraryName = new SimpleStringProperty();
|
public final StringProperty incompatibleLibraryName = new SimpleStringProperty();
|
||||||
public final StringProperty dependencyName = new SimpleStringProperty();
|
public final StringProperty dependencyName = new SimpleStringProperty();
|
||||||
@@ -73,30 +74,30 @@ public class InstallerItem extends Control {
|
|||||||
|
|
||||||
switch (id) {
|
switch (id) {
|
||||||
case "game":
|
case "game":
|
||||||
imageUrl = "/assets/img/grass.png";
|
iconType = VersionIconType.GRASS;
|
||||||
break;
|
break;
|
||||||
case "fabric":
|
case "fabric":
|
||||||
case "fabric-api":
|
case "fabric-api":
|
||||||
imageUrl = "/assets/img/fabric.png";
|
iconType = VersionIconType.FABRIC;
|
||||||
break;
|
break;
|
||||||
case "forge":
|
case "forge":
|
||||||
imageUrl = "/assets/img/forge.png";
|
iconType = VersionIconType.FORGE;
|
||||||
break;
|
break;
|
||||||
case "liteloader":
|
case "liteloader":
|
||||||
imageUrl = "/assets/img/chicken.png";
|
iconType = VersionIconType.CHICKEN;
|
||||||
break;
|
break;
|
||||||
case "optifine":
|
case "optifine":
|
||||||
imageUrl = "/assets/img/command.png";
|
iconType = VersionIconType.COMMAND;
|
||||||
break;
|
break;
|
||||||
case "quilt":
|
case "quilt":
|
||||||
case "quilt-api":
|
case "quilt-api":
|
||||||
imageUrl = "/assets/img/quilt.png";
|
iconType = VersionIconType.QUILT;
|
||||||
break;
|
break;
|
||||||
case "neoforge":
|
case "neoforge":
|
||||||
imageUrl = "/assets/img/neoforge.png";
|
iconType = VersionIconType.NEO_FORGE;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
imageUrl = null;
|
iconType = null;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -221,8 +222,8 @@ public class InstallerItem extends Control {
|
|||||||
pane.pseudoClassStateChanged(LIST_ITEM, control.style == Style.LIST_ITEM);
|
pane.pseudoClassStateChanged(LIST_ITEM, control.style == Style.LIST_ITEM);
|
||||||
pane.pseudoClassStateChanged(CARD, control.style == Style.CARD);
|
pane.pseudoClassStateChanged(CARD, control.style == Style.CARD);
|
||||||
|
|
||||||
if (control.imageUrl != null) {
|
if (control.iconType != null) {
|
||||||
ImageView view = new ImageView(FXUtils.newBuiltinImage(control.imageUrl));
|
ImageView view = new ImageView(control.iconType.getIcon());
|
||||||
Node node = FXUtils.limitingSize(view, 32, 32);
|
Node node = FXUtils.limitingSize(view, 32, 32);
|
||||||
node.setMouseTransparent(true);
|
node.setMouseTransparent(true);
|
||||||
node.getStyleClass().add("installer-item-image");
|
node.getStyleClass().add("installer-item-image");
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ import javafx.beans.InvalidationListener;
|
|||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
import javafx.scene.control.ListCell;
|
import javafx.scene.control.ListCell;
|
||||||
import javafx.scene.image.Image;
|
|
||||||
import javafx.scene.layout.*;
|
import javafx.scene.layout.*;
|
||||||
import org.jackhuang.hmcl.download.DownloadProvider;
|
import org.jackhuang.hmcl.download.DownloadProvider;
|
||||||
import org.jackhuang.hmcl.download.RemoteVersion;
|
import org.jackhuang.hmcl.download.RemoteVersion;
|
||||||
@@ -42,7 +41,6 @@ import org.jackhuang.hmcl.download.quilt.QuiltAPIRemoteVersion;
|
|||||||
import org.jackhuang.hmcl.download.quilt.QuiltRemoteVersion;
|
import org.jackhuang.hmcl.download.quilt.QuiltRemoteVersion;
|
||||||
import org.jackhuang.hmcl.setting.Theme;
|
import org.jackhuang.hmcl.setting.Theme;
|
||||||
import org.jackhuang.hmcl.setting.VersionIconType;
|
import org.jackhuang.hmcl.setting.VersionIconType;
|
||||||
import org.jackhuang.hmcl.ui.FXUtils;
|
|
||||||
import org.jackhuang.hmcl.ui.SVG;
|
import org.jackhuang.hmcl.ui.SVG;
|
||||||
import org.jackhuang.hmcl.ui.animation.ContainerAnimations;
|
import org.jackhuang.hmcl.ui.animation.ContainerAnimations;
|
||||||
import org.jackhuang.hmcl.ui.animation.TransitionPane;
|
import org.jackhuang.hmcl.ui.animation.TransitionPane;
|
||||||
@@ -56,7 +54,6 @@ import org.jackhuang.hmcl.ui.wizard.WizardPage;
|
|||||||
import org.jackhuang.hmcl.util.HMCLService;
|
import org.jackhuang.hmcl.util.HMCLService;
|
||||||
import org.jackhuang.hmcl.util.Holder;
|
import org.jackhuang.hmcl.util.Holder;
|
||||||
|
|
||||||
import java.util.EnumMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
@@ -182,8 +179,7 @@ public final class VersionsPage extends BorderPane implements WizardPage, Refres
|
|||||||
btnRefresh.setGraphic(wrap(SVG.REFRESH.createIcon(Theme.blackFill(), -1, -1)));
|
btnRefresh.setGraphic(wrap(SVG.REFRESH.createIcon(Theme.blackFill(), -1, -1)));
|
||||||
|
|
||||||
Holder<RemoteVersionListCell> lastCell = new Holder<>();
|
Holder<RemoteVersionListCell> lastCell = new Holder<>();
|
||||||
EnumMap<VersionIconType, Image> icons = new EnumMap<>(VersionIconType.class);
|
list.setCellFactory(listView -> new RemoteVersionListCell(lastCell));
|
||||||
list.setCellFactory(listView -> new RemoteVersionListCell(lastCell, icons));
|
|
||||||
|
|
||||||
list.setOnMouseClicked(e -> {
|
list.setOnMouseClicked(e -> {
|
||||||
if (list.getSelectionModel().getSelectedIndex() < 0)
|
if (list.getSelectionModel().getSelectedIndex() < 0)
|
||||||
@@ -276,21 +272,15 @@ public final class VersionsPage extends BorderPane implements WizardPage, Refres
|
|||||||
final StackPane pane = new StackPane();
|
final StackPane pane = new StackPane();
|
||||||
|
|
||||||
private final Holder<RemoteVersionListCell> lastCell;
|
private final Holder<RemoteVersionListCell> lastCell;
|
||||||
private final EnumMap<VersionIconType, Image> icons;
|
|
||||||
|
|
||||||
RemoteVersionListCell(Holder<RemoteVersionListCell> lastCell, EnumMap<VersionIconType, Image> icons) {
|
RemoteVersionListCell(Holder<RemoteVersionListCell> lastCell) {
|
||||||
this.lastCell = lastCell;
|
this.lastCell = lastCell;
|
||||||
this.icons = icons;
|
|
||||||
|
|
||||||
pane.getStyleClass().add("md-list-cell");
|
pane.getStyleClass().add("md-list-cell");
|
||||||
StackPane.setMargin(content, new Insets(10, 16, 10, 16));
|
StackPane.setMargin(content, new Insets(10, 16, 10, 16));
|
||||||
pane.getChildren().setAll(ripplerContainer);
|
pane.getChildren().setAll(ripplerContainer);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Image getIcon(VersionIconType type) {
|
|
||||||
return icons.computeIfAbsent(type, iconType -> FXUtils.newBuiltinImage(iconType.getResourceUrl()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateItem(RemoteVersion remoteVersion, boolean empty) {
|
public void updateItem(RemoteVersion remoteVersion, boolean empty) {
|
||||||
super.updateItem(remoteVersion, empty);
|
super.updateItem(remoteVersion, empty);
|
||||||
@@ -317,15 +307,15 @@ public final class VersionsPage extends BorderPane implements WizardPage, Refres
|
|||||||
switch (remoteVersion.getVersionType()) {
|
switch (remoteVersion.getVersionType()) {
|
||||||
case RELEASE:
|
case RELEASE:
|
||||||
content.getTags().setAll(i18n("version.game.release"));
|
content.getTags().setAll(i18n("version.game.release"));
|
||||||
content.setImage(getIcon(VersionIconType.GRASS));
|
content.setImage(VersionIconType.GRASS.getIcon());
|
||||||
break;
|
break;
|
||||||
case SNAPSHOT:
|
case SNAPSHOT:
|
||||||
content.getTags().setAll(i18n("version.game.snapshot"));
|
content.getTags().setAll(i18n("version.game.snapshot"));
|
||||||
content.setImage(getIcon(VersionIconType.COMMAND));
|
content.setImage(VersionIconType.COMMAND.getIcon());
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
content.getTags().setAll(i18n("version.game.old"));
|
content.getTags().setAll(i18n("version.game.old"));
|
||||||
content.setImage(getIcon(VersionIconType.CRAFT_TABLE));
|
content.setImage(VersionIconType.CRAFT_TABLE.getIcon());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -345,7 +335,7 @@ public final class VersionsPage extends BorderPane implements WizardPage, Refres
|
|||||||
else
|
else
|
||||||
iconType = null;
|
iconType = null;
|
||||||
|
|
||||||
content.setImage(iconType != null ? getIcon(iconType) : null);
|
content.setImage(iconType != null ? iconType.getIcon() : null);
|
||||||
if (content.getSubtitle() == null)
|
if (content.getSubtitle() == null)
|
||||||
content.setSubtitle(remoteVersion.getGameVersion());
|
content.setSubtitle(remoteVersion.getGameVersion());
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import javafx.scene.image.ImageView;
|
|||||||
import org.jackhuang.hmcl.event.Event;
|
import org.jackhuang.hmcl.event.Event;
|
||||||
import org.jackhuang.hmcl.setting.Profile;
|
import org.jackhuang.hmcl.setting.Profile;
|
||||||
import org.jackhuang.hmcl.setting.Profiles;
|
import org.jackhuang.hmcl.setting.Profiles;
|
||||||
|
import org.jackhuang.hmcl.setting.VersionIconType;
|
||||||
import org.jackhuang.hmcl.ui.FXUtils;
|
import org.jackhuang.hmcl.ui.FXUtils;
|
||||||
import org.jackhuang.hmcl.ui.WeakListenerHolder;
|
import org.jackhuang.hmcl.ui.WeakListenerHolder;
|
||||||
import org.jackhuang.hmcl.ui.construct.AdvancedListItem;
|
import org.jackhuang.hmcl.ui.construct.AdvancedListItem;
|
||||||
@@ -30,7 +31,6 @@ import org.jackhuang.hmcl.util.Pair;
|
|||||||
|
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import static org.jackhuang.hmcl.ui.FXUtils.newBuiltinImage;
|
|
||||||
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
||||||
|
|
||||||
public class GameAdvancedListItem extends AdvancedListItem {
|
public class GameAdvancedListItem extends AdvancedListItem {
|
||||||
@@ -72,7 +72,7 @@ public class GameAdvancedListItem extends AdvancedListItem {
|
|||||||
Tooltip.uninstall(this,tooltip);
|
Tooltip.uninstall(this,tooltip);
|
||||||
setTitle(i18n("version.empty"));
|
setTitle(i18n("version.empty"));
|
||||||
setSubtitle(i18n("version.empty.add"));
|
setSubtitle(i18n("version.empty.add"));
|
||||||
imageView.setImage(newBuiltinImage("/assets/img/grass.png"));
|
imageView.setImage(VersionIconType.DEFAULT.getIcon());
|
||||||
tooltip.setText("");
|
tooltip.setText("");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ public class VersionIconDialog extends DialogPane {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Node createIcon(VersionIconType type) {
|
private Node createIcon(VersionIconType type) {
|
||||||
ImageView imageView = new ImageView(FXUtils.newBuiltinImage(type.getResourceUrl()));
|
ImageView imageView = new ImageView(type.getIcon());
|
||||||
imageView.setMouseTransparent(true);
|
imageView.setMouseTransparent(true);
|
||||||
RipplerContainer container = new RipplerContainer(imageView);
|
RipplerContainer container = new RipplerContainer(imageView);
|
||||||
FXUtils.setLimitWidth(container, 36);
|
FXUtils.setLimitWidth(container, 36);
|
||||||
|
|||||||
Reference in New Issue
Block a user