Start working on instance settings
All checks were successful
ci/woodpecker/push/docs Pipeline was successful
ci/woodpecker/push/woodpecker Pipeline was successful

This commit is contained in:
Johannes Frohnmeyer 2023-01-24 18:25:18 +01:00
parent 442d462843
commit bdd86c7683
Signed by: Johannes
GPG Key ID: E76429612C2929F4
17 changed files with 327 additions and 62 deletions

View File

@ -25,6 +25,6 @@ tasks.compileJava {
tasks.runShadow {
workingDir = rootProject.projectDir
environment("GTK_DEBUG", "interactive:actions")
jvmArgs!!.addAll(listOf("--enable-preview", "--enable-native-access=ALL-UNNAMED"))
environment("GTK_DEBUG", "interactive") // interactive:actions
jvmArgs("--enable-preview", "--enable-native-access=ALL-UNNAMED")
}

View File

@ -1,19 +1,24 @@
package io.gitlab.jfronny.inceptum.gtk;
import org.gtk.gio.ApplicationFlags;
import org.gtk.glib.GLib;
import org.gtk.gtk.Application;
import io.gitlab.jfronny.inceptum.common.*;
import io.gitlab.jfronny.inceptum.gtk.window.MainWindow;
import io.gitlab.jfronny.inceptum.launcher.LauncherEnv;
import org.gtk.gio.ApplicationFlags;
import org.gtk.glib.GLib;
import org.gtk.gtk.Application;
import java.io.IOException;
import java.util.*;
public class GtkMain {
public static final String ID = "io.gitlab.jfronny.inceptum";
private static final Queue<Runnable> SCHEDULED = new ArrayDeque<>();
public static void schedule(Runnable task) {
SCHEDULED.add(Objects.requireNonNull(task));
}
public static void main(String[] args) throws IOException {
LauncherEnv.initialize(GtkEnvBackend.INSTANCE);
Utils.LOGGER.info("Launching Inceptum v" + BuildMetadata.VERSION);
@ -28,10 +33,6 @@ public class GtkMain {
}
}
public static void schedule(Runnable task) {
SCHEDULED.add(Objects.requireNonNull(task));
}
public static int showGui(String[] args) throws IOException {
var app = new Application(ID, ApplicationFlags.FLAGS_NONE);
app.onActivate(() -> {
@ -56,6 +57,6 @@ public class GtkMain {
return false;
});
});
return app.run(args.length, args);
return app.run(args);
}
}

View File

@ -25,7 +25,7 @@ public class GtkMenubar {
public static void create(Application app) {
var menu = new MenuBuilder(app);
var file = menu.submenu("file");
file.button("new", NewInstanceWindow::createAndShow);
file.button("new", () -> new NewInstanceWindow(app).show());
file.button("redownload", () -> {
//TODO
});

View File

@ -1,41 +0,0 @@
package io.gitlab.jfronny.inceptum.gtk;
import org.gtk.gio.ApplicationFlags;
import org.gtk.gtk.*;
import io.gitlab.jfronny.commons.ref.R;
public class TestStart {
public static void main(String[] args) {
var app = new Application(GtkMain.ID, ApplicationFlags.FLAGS_NONE);
app.onActivate(() -> {
var button = Button.newWithLabel("Test");
button.onClicked(TestStart::test);
var window = new ApplicationWindow(app);
window.setDefaultSize(200, 50);
window.title = "Inceptum";
window.child = button;
window.show();
GtkEnvBackend.INSTANCE.dialogParent = window;
window.onCloseRequest(() -> {
GtkEnvBackend.INSTANCE.dialogParent = null;
return false;
});
});
System.exit(app.run(args.length, args));
}
private static void test() {
GtkEnvBackend backend = GtkEnvBackend.INSTANCE;
backend.getInput("Ae", "IoU\naee", "Def", R::nop, R::nop);
// backend.showInfo("Some message", "Title");
// backend.showError("Yes!", "AAee");
// backend.showError("Nes!", new ArrayIndexOutOfBoundsException("Top 500 cheese"));
// backend.showOkCancel("Some Message\nYes!", "TitL", () -> backend.showInfo("Pressed OK", "OK"), () -> backend.showError("Pressed CANCEL", "CANCEL"));
// backend.getInput("This is a prompt", """
// These are some extremely interesting and detailed (hence the name) details!
// This is a second line, since these details
// are just THAT important!""", "Default", value -> backend.showInfo("Received " + value, "Input"), () -> backend.showInfo("Got no input :/", "Input"));
}
}

View File

@ -0,0 +1,45 @@
package io.gitlab.jfronny.inceptum.gtk.control;
import io.gitlab.jfronny.commons.LazySupplier;
import io.gitlab.jfronny.inceptum.gtk.GtkMain;
import io.gitlab.jfronny.inceptum.gtk.util.I18n;
import manifold.util.concurrent.Cache;
import org.gtk.gtk.*;
import org.jetbrains.annotations.PropertyKey;
import java.io.InputStream;
import java.util.function.Supplier;
public class ILabel extends Label {
private static Supplier<CssProvider> provider = new LazySupplier<>(() -> {
CssProvider provider = new CssProvider();
try (InputStream is = GtkMain.class.getClassLoader().getResourceAsStream("inceptum.css")) {
provider.loadFromData(is.readAllBytes());
} catch (Throwable t) {
throw new RuntimeException(t);
}
return provider;
});
public ILabel(@PropertyKey(resourceBundle = I18n.BUNDLE) String str) {
this(str, Mode.NORMAL);
}
public ILabel(@PropertyKey(resourceBundle = I18n.BUNDLE) String str, Mode mode) {
super(I18n.get(str));
switch (mode) {
case HEADING -> addCssClass("heading");
case SUBTITLE -> {
addCssClass("jf-subtitle");
styleContext.addProvider(provider.get(), Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
}
case NORMAL -> {}
}
}
public enum Mode {
NORMAL,
HEADING,
SUBTITLE
}
}

View File

@ -0,0 +1,29 @@
package io.gitlab.jfronny.inceptum.gtk.control;
import io.gitlab.jfronny.inceptum.gtk.util.I18n;
import org.gtk.gtk.*;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.PropertyKey;
public class IRow extends Box {
public IRow(@PropertyKey(resourceBundle = I18n.BUNDLE) String title, @PropertyKey(resourceBundle = I18n.BUNDLE) @Nullable String subtitle) {
super(Orientation.HORIZONTAL, 40);
margin = 8;
Widget head;
ILabel lab = new ILabel(title);
lab.halign = Align.START;
if (subtitle != null) {
Box headB = new Box(Orientation.VERTICAL, 0);
headB.append(lab);
ILabel lab1 = new ILabel(subtitle, ILabel.Mode.SUBTITLE);
lab1.halign = Align.START;
headB.append(lab1);
head = headB;
} else {
head = lab;
}
head.halign = Align.START;
head.valign = Align.CENTER;
append(head);
}
}

View File

@ -0,0 +1,26 @@
package io.gitlab.jfronny.inceptum.gtk.control;
import org.gtk.gtk.*;
import java.util.function.Consumer;
public class ISEntry extends Entry {
public ISEntry(String content) {
setContent(content);
hexpand = true;
halign = Align.FILL;
valign = Align.CENTER;
}
public String getContent() {
return buffer.text;
}
public void setContent(String content) {
buffer = EntryBuffer.builder().setText(content).build();
}
public void onChanged(Consumer<String> s) {
super.onChanged(() -> s.accept(buffer.text));
}
}

View File

@ -9,6 +9,7 @@ import io.gitlab.jfronny.inceptum.gtk.GtkMenubar;
import io.gitlab.jfronny.inceptum.gtk.menu.MenuBuilder;
import io.gitlab.jfronny.inceptum.gtk.util.I18n;
import io.gitlab.jfronny.inceptum.gtk.util.ListIndexItem;
import io.gitlab.jfronny.inceptum.gtk.window.InstanceSettingsWindow;
import io.gitlab.jfronny.inceptum.launcher.LauncherEnv;
import io.gitlab.jfronny.inceptum.launcher.system.instance.Instance;
import io.gitlab.jfronny.inceptum.launcher.system.instance.InstanceNameTool;
@ -23,7 +24,7 @@ import java.util.*;
import java.util.function.Consumer;
public class InstanceListEntryFactory extends SignalListItemFactory {
public InstanceListEntryFactory(List<Instance> instanceList) {
public InstanceListEntryFactory(Application app, List<Instance> instanceList) {
super();
onSetup(item -> {
ListItem li = (ListItem) item;
@ -81,7 +82,8 @@ public class InstanceListEntryFactory extends SignalListItemFactory {
.iconName = "network-server-symbolic";
var settingsSection = menuBuilder.literalSection("settings", null);
settingsSection.literalButton("settings", I18n.get("instance.settings"), () -> {
//TODO open settings
//TODO keep track of properties windows and don't allow opening two
new InstanceSettingsWindow(app, li.instance).show();
}).iconName = "document-edit-symbolic";
settingsSection.literalButton("directory", I18n.get("instance.directory"),
() -> Utils.openFile(li.instance.path.toFile()))

View File

@ -5,7 +5,7 @@ import org.jetbrains.annotations.PropertyKey;
import java.util.ResourceBundle;
public class I18n {
private static final String BUNDLE = "inceptum";
public static final String BUNDLE = "inceptum";
private static final ResourceBundle bundle = ResourceBundle.getBundle(BUNDLE);
public static String get(@PropertyKey(resourceBundle = BUNDLE) String key) {

View File

@ -1,5 +1,6 @@
package io.gitlab.jfronny.inceptum.gtk.window;
import io.gitlab.jfronny.inceptum.gtk.GtkMain;
import org.gtk.gtk.AboutDialog;
import org.gtk.gtk.License;
import io.gitlab.jfronny.inceptum.common.BuildMetadata;

View File

@ -0,0 +1,164 @@
package io.gitlab.jfronny.inceptum.gtk.window;
import io.gitlab.jfronny.commons.ArgumentsTokenizer;
import io.gitlab.jfronny.inceptum.common.MetaHolder;
import io.gitlab.jfronny.inceptum.gtk.GtkMain;
import io.gitlab.jfronny.inceptum.gtk.control.*;
import io.gitlab.jfronny.inceptum.gtk.util.I18n;
import io.gitlab.jfronny.inceptum.launcher.LauncherEnv;
import io.gitlab.jfronny.inceptum.launcher.system.instance.*;
import org.gnome.adw.*;
import org.gnome.adw.HeaderBar;
import org.gtk.gobject.BindingFlags;
import org.gtk.gtk.*;
import org.gtk.gtk.Application;
import org.gtk.gtk.Window;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
public class InstanceSettingsWindow extends Window {
//TODO improve by having multiple lists on one page
public InstanceSettingsWindow(Application app, Instance instance) {
this.application = app;
ViewStack stack = new ViewStack();
HeaderBar header = new HeaderBar();
ViewSwitcherTitle viewSwitcher = new ViewSwitcherTitle();
viewSwitcher.stack = stack;
header.titleWidget = viewSwitcher;
titlebar = header;
ScrolledWindow scroll = new ScrolledWindow();
scroll.setPolicy(PolicyType.NEVER, PolicyType.AUTOMATIC);
scroll.child = stack;
scroll.vexpand = true;
ViewSwitcherBar bottomBar = new ViewSwitcherBar();
bottomBar.stack = stack;
viewSwitcher.bindProperty("title-visible", bottomBar, "reveal", BindingFlags.DEFAULT);
Box view = new Box(Orientation.VERTICAL, 0);
view.append(scroll);
view.append(bottomBar);
child = view;
// General settings
{
var box = new Box(Orientation.VERTICAL, 8);
box.marginHorizontal = 24;
box.marginTop = 12;
{
Frame frame = new Frame(null);
ListBox lb = new ListBox();
lb.selectionMode = SelectionMode.NONE;
frame.child = lb;
box.append(frame);
{
var row = new IRow("instance.settings.general.name", "instance.settings.general.name.placeholder");
ISEntry entry = new ISEntry(instance.name);
entry.maxLength = 64;
entry.placeholderText = I18n.get("instance.settings.general.name.placeholder");
row.append(entry);
Button apply = Button.newWithLabel(I18n.get("instance.settings.apply"));
apply.valign = Align.CENTER;
apply.onClicked(() -> {
try {
Path newPath = MetaHolder.INSTANCE_DIR.resolve(InstanceNameTool.getNextValid(entry.content));
Files.move(instance.path, newPath);
close();
new InstanceSettingsWindow(application, InstanceList.read(newPath)).show();
} catch (IOException e) {
LauncherEnv.showError("Could not rename", e);
}
});
entry.onChanged(s -> {
apply.sensitive = !s.equals(instance.name);
});
apply.sensitive = false;
row.append(apply);
lb.append(row);
}
}
{
box.append(new ILabel("instance.settings.general.args", ILabel.Mode.HEADING));
Frame frame = new Frame(null);
ListBox lb = new ListBox();
lb.selectionMode = SelectionMode.NONE;
frame.child = lb;
box.append(frame);
{
var row = new IRow("instance.settings.general.args.jvm", "instance.settings.general.args.jvm.subtitle");
ISEntry entry = new ISEntry(ArgumentsTokenizer.join(instance.meta.arguments.jvm.toArray(String[]::new)));
entry.onChanged(s -> {
instance.meta.arguments = instance.meta.arguments.withJvm(List.of(ArgumentsTokenizer.tokenize(s)));
instance.writeMeta();
});
row.append(entry);
lb.append(row);
}
{
var row = new IRow("instance.settings.general.args.client", "instance.settings.general.args.client.subtitle");
ISEntry entry = new ISEntry(ArgumentsTokenizer.join(instance.meta.arguments.client.toArray(String[]::new)));
entry.onChanged(s -> {
instance.meta.arguments = instance.meta.arguments.withClient(List.of(ArgumentsTokenizer.tokenize(s)));
instance.writeMeta();
});
row.append(entry);
lb.append(row);
}
{
var row = new IRow("instance.settings.general.args.server", "instance.settings.general.args.server.subtitle");
ISEntry entry = new ISEntry(ArgumentsTokenizer.join(instance.meta.arguments.server.toArray(String[]::new)));
entry.onChanged(s -> {
instance.meta.arguments = instance.meta.arguments.withServer(List.of(ArgumentsTokenizer.tokenize(s)));
instance.writeMeta();
});
row.append(entry);
lb.append(row);
}
}
//TODO: Implement
/*
General
- Open Directory (button)
- Version (dropdown) + checkbox: "show snapshots"
- Fabric support (checkbox) + dropdown: Loader version
- Delete (button) -> confirmation + delete
- Custom Java (checkbox) + String: path
*/
stack.addTitledWithIcon(box, null, I18n.get("instance.settings.general"), "preferences-other-symbolic");
}
// Mods
{
var box = new Box(Orientation.VERTICAL, 0);
box.marginHorizontal = 24;
box.marginTop = 12;
//TODO: Implement
/*
Mods:
- show "currently unsupported in GTK UI (idk how I'd visualize this)
*/
stack.addTitledWithIcon(box, null, I18n.get("instance.settings.mods"), "package-x-generic-symbolic");
}
// Export
{
var box = new Box(Orientation.VERTICAL, 0);
box.marginHorizontal = 24;
box.marginTop = 12;
//TODO: Implement
/*
Export:
- CurseForge (button) -> see imgui
- Modrinth (button) -> see imgui
- MultiMC (button) -> see imgui
*/
stack.addTitledWithIcon(box, null, I18n.get("instance.settings.export"), "send-to-symbolic");
}
}
}

View File

@ -1,5 +1,6 @@
package io.gitlab.jfronny.inceptum.gtk.window;
import io.gitlab.jfronny.inceptum.gtk.GtkMain;
import io.gitlab.jfronny.inceptum.gtk.util.ListIndexModel;
import io.gitlab.jfronny.inceptum.launcher.system.launch.LaunchType;
import org.gnome.adw.Clamp;
@ -40,7 +41,7 @@ public class MainWindow extends ApplicationWindow {
HeaderBar header = new HeaderBar();
Button newButton = new Button();
newButton.iconName = "list-add-symbolic";
newButton.onClicked(NewInstanceWindow::createAndShow);
newButton.onClicked(() -> new NewInstanceWindow(app).show());
MenuButton accountsButton = new MenuButton();
accountsButton.iconName = "avatar-default-symbolic";
@ -83,7 +84,7 @@ public class MainWindow extends ApplicationWindow {
instanceListIndex = new ListIndexModel(instanceList.size());
var singleSelection = new NoSelection(instanceListIndex);
ListView listView = new ListView(singleSelection, new InstanceListEntryFactory(instanceList));
ListView listView = new ListView(singleSelection, new InstanceListEntryFactory(app, instanceList));
listView.addCssClass("rich-list");
listView.showSeparators = true;
listView.onActivate(position -> {

View File

@ -1,7 +1,14 @@
package io.gitlab.jfronny.inceptum.gtk.window;
public class NewInstanceWindow {
public static void createAndShow() {
//TODO
import io.gitlab.jfronny.inceptum.gtk.GtkMain;
import org.gtk.gtk.*;
public class NewInstanceWindow extends Window {
public NewInstanceWindow(Application app) {
this.application = app;
child = new Label("This feature has not (yet) been implemented for this UI. Please try the CLI or ImGUI UI");
//TODO setup wizard (--> NC Tasks)
}
}

View File

@ -0,0 +1,5 @@
/* the AdwActionRow is broken, so I implemented my own */
.jf-subtitle {
opacity: 0.7;
font-size: smaller;
}

View File

@ -38,3 +38,16 @@ instance.copy=Duplicate
instance.delete=Delete
instance.copy.prompt=New Name
instance.copy.details=Please enter a name for the new instance
instance.settings.general=General
instance.settings.general.name=Name
instance.settings.general.name.placeholder=Name of this Instance
instance.settings.apply=Apply
instance.settings.general.args.jvm=JVM
instance.settings.general.args=Arguments
instance.settings.general.args.jvm.subtitle=Arguments passed to the JVM
instance.settings.general.args.client=Client
instance.settings.general.args.server=Server
instance.settings.general.args.client.subtitle=Arguments to add to Minecraft Clients
instance.settings.general.args.server.subtitle=Arguments to add to Minecraft Servers
instance.settings.export=Export
instance.settings.mods=Mods

View File

@ -38,3 +38,16 @@ instance.copy=Klonen
instance.delete=Löschen
instance.copy.prompt=Neuer Name
instance.copy.details=Gib den Namen für die neue Instanz ein
instance.settings.general=Allgemein
instance.settings.general.name=Name
instance.settings.general.name.placeholder=Name dieser Instanz
instance.settings.apply=Anwenden
instance.settings.general.args.jvm=JVM
instance.settings.general.args=Argumente
instance.settings.general.args.jvm.subtitle=Argumente für die JVM
instance.settings.general.args.client=Client
instance.settings.general.args.server=Server
instance.settings.general.args.client.subtitle=Argumente für Minecraft-Clients
instance.settings.general.args.server.subtitle=Argumente für Minecraft-Server
instance.settings.export=Export
instance.settings.mods=Mods

View File

@ -6,7 +6,7 @@ import io.gitlab.jfronny.inceptum.common.GsonPreset;
import java.util.List;
import java.util.Objects;
@GSerializable
@GSerializable(configure = GsonPreset.Config.class)
public class InstanceMeta {
public String version;
public String java;
@ -33,7 +33,6 @@ public class InstanceMeta {
return Objects.hash(version, java, minMem, maxMem, lastLaunched, arguments);
}
@GSerializable(configure = GsonPreset.Config.class)
public record Arguments(List<String> jvm, List<String> client, List<String> server) {
public Arguments withJvm(List<String> jvm) {