Enhance list entries
This commit is contained in:
parent
62dd7da114
commit
b87889f5b4
@ -19,7 +19,7 @@ public class LaunchCommand extends BaseInstanceCommand {
|
|||||||
public LaunchCommand() {
|
public LaunchCommand() {
|
||||||
super("Launches an instance of the game (client by default). Non-blocking (batch commands will continue if this is ran)",
|
super("Launches an instance of the game (client by default). Non-blocking (batch commands will continue if this is ran)",
|
||||||
"[game arguments...]",
|
"[game arguments...]",
|
||||||
List.of("run", "launch", "start"),
|
List.of("run", "instance.launch", "start"),
|
||||||
List.of(
|
List.of(
|
||||||
new LaunchCommand("Explicitly launch a client", "client", false, false),
|
new LaunchCommand("Explicitly launch a client", "client", false, false),
|
||||||
new LaunchCommand("Launch a server", "server", true, false,
|
new LaunchCommand("Launch a server", "server", true, false,
|
||||||
|
@ -44,21 +44,24 @@ public enum GtkEnvBackend implements LauncherEnv.EnvBackend { //TODO test
|
|||||||
@Override
|
@Override
|
||||||
public void getInput(String prompt, String details, String defaultValue, Consumer<String> ok, Runnable cancel) {
|
public void getInput(String prompt, String details, String defaultValue, Consumer<String> ok, Runnable cancel) {
|
||||||
//TODO spacing
|
//TODO spacing
|
||||||
Dialog dialog = new Dialog();
|
//TODO run on main thread
|
||||||
if (dialogParent != null) dialog.setTransientFor(dialogParent);
|
GtkMain.schedule(() -> {
|
||||||
dialog.setModal(GTK.TRUE);
|
Dialog dialog = new Dialog();
|
||||||
if (dialogParent != null) dialog.setDestroyWithParent(GTK.TRUE);
|
if (dialogParent != null) dialog.setTransientFor(dialogParent);
|
||||||
dialog.setTitle(new Str(prompt));
|
dialog.setModal(GTK.TRUE);
|
||||||
Box box = dialog.getContentArea();
|
if (dialogParent != null) dialog.setDestroyWithParent(GTK.TRUE);
|
||||||
box.append(new Label(new Str(details)));
|
dialog.setTitle(new Str(prompt));
|
||||||
Entry entry = new Entry();
|
Box box = dialog.getContentArea();
|
||||||
Editable entryEditable = new Editable(entry.cast());
|
box.append(new Label(new Str(details)));
|
||||||
entryEditable.setText(new Str(defaultValue));
|
Entry entry = new Entry();
|
||||||
box.append(entry);
|
Editable entryEditable = new Editable(entry.cast());
|
||||||
dialog.addButton(I18n.str("ok"), ResponseType.OK);
|
entryEditable.setText(new Str(defaultValue));
|
||||||
dialog.addButton(I18n.str("cancel"), ResponseType.CANCEL);
|
box.append(entry);
|
||||||
dialog.onResponse(processResponses(dialog, () -> ok.accept(entryEditable.getText().toString()), cancel));
|
dialog.addButton(I18n.str("ok"), ResponseType.OK);
|
||||||
dialog.show();
|
dialog.addButton(I18n.str("cancel"), ResponseType.CANCEL);
|
||||||
|
dialog.onResponse(processResponses(dialog, () -> ok.accept(entryEditable.getText().toString()), cancel));
|
||||||
|
dialog.show();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -67,11 +70,13 @@ public enum GtkEnvBackend implements LauncherEnv.EnvBackend { //TODO test
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void simpleDialog(String markup, String title, int type, int buttons, Runnable ok, Runnable cancel) {
|
private void simpleDialog(String markup, String title, int type, int buttons, Runnable ok, Runnable cancel) {
|
||||||
MessageDialog dialog = new MessageDialog(dialogParent, DialogFlags.MODAL | DialogFlags.DESTROY_WITH_PARENT, type, buttons, null);
|
GtkMain.schedule(() -> {
|
||||||
dialog.setTitle(new Str(title));
|
MessageDialog dialog = new MessageDialog(dialogParent, DialogFlags.MODAL | DialogFlags.DESTROY_WITH_PARENT, type, buttons, null);
|
||||||
dialog.setMarkup(new Str(markup));
|
dialog.setTitle(new Str(title));
|
||||||
dialog.onResponse(processResponses(dialog, ok, cancel));
|
dialog.setMarkup(new Str(markup));
|
||||||
dialog.show();
|
dialog.onResponse(processResponses(dialog, ok, cancel));
|
||||||
|
dialog.show();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private Dialog.OnResponse processResponses(Dialog dialog, @Nullable Runnable ok, @Nullable Runnable cancel) {
|
private Dialog.OnResponse processResponses(Dialog dialog, @Nullable Runnable ok, @Nullable Runnable cancel) {
|
||||||
|
@ -2,6 +2,7 @@ package io.gitlab.jfronny.inceptum.gtk;
|
|||||||
|
|
||||||
import ch.bailu.gtk.GTK;
|
import ch.bailu.gtk.GTK;
|
||||||
import ch.bailu.gtk.gio.ApplicationFlags;
|
import ch.bailu.gtk.gio.ApplicationFlags;
|
||||||
|
import ch.bailu.gtk.glib.Glib;
|
||||||
import ch.bailu.gtk.gtk.Application;
|
import ch.bailu.gtk.gtk.Application;
|
||||||
import ch.bailu.gtk.type.Str;
|
import ch.bailu.gtk.type.Str;
|
||||||
import ch.bailu.gtk.type.Strs;
|
import ch.bailu.gtk.type.Strs;
|
||||||
@ -10,9 +11,11 @@ import io.gitlab.jfronny.inceptum.gtk.window.MainWindow;
|
|||||||
import io.gitlab.jfronny.inceptum.launcher.LauncherEnv;
|
import io.gitlab.jfronny.inceptum.launcher.LauncherEnv;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
public class GtkMain {
|
public class GtkMain {
|
||||||
public static final Str ID = new Str("io.gitlab.jfronny.inceptum");
|
public static final Str ID = new Str("io.gitlab.jfronny.inceptum");
|
||||||
|
private static final Queue<Runnable> SCHEDULED = new ArrayDeque<>();
|
||||||
|
|
||||||
public static void main(String[] args) throws IOException {
|
public static void main(String[] args) throws IOException {
|
||||||
LauncherEnv.initialize(GtkEnvBackend.INSTANCE);
|
LauncherEnv.initialize(GtkEnvBackend.INSTANCE);
|
||||||
@ -28,12 +31,27 @@ public class GtkMain {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void schedule(Runnable task) {
|
||||||
|
SCHEDULED.add(Objects.requireNonNull(task));
|
||||||
|
}
|
||||||
|
|
||||||
public static int showGui(String[] args) throws IOException {
|
public static int showGui(String[] args) throws IOException {
|
||||||
var app = new Application(ID, ApplicationFlags.FLAGS_NONE);
|
var app = new Application(ID, ApplicationFlags.FLAGS_NONE);
|
||||||
app.onActivate(() -> {
|
app.onActivate(() -> {
|
||||||
GtkMenubar.create(app);
|
GtkMenubar.create(app);
|
||||||
var window = new MainWindow(app);
|
var window = new MainWindow(app);
|
||||||
window.show();
|
window.show();
|
||||||
|
Glib.idleAdd(user_data -> {
|
||||||
|
Runnable r;
|
||||||
|
while ((r = SCHEDULED.poll()) != null) {
|
||||||
|
try {
|
||||||
|
r.run();
|
||||||
|
} catch (Throwable t) {
|
||||||
|
Utils.LOGGER.error("Could not run scheduled task", t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return GTK.TRUE;
|
||||||
|
}, null);
|
||||||
GtkEnvBackend.INSTANCE.dialogParent = window;
|
GtkEnvBackend.INSTANCE.dialogParent = window;
|
||||||
window.onCloseRequest(() -> {
|
window.onCloseRequest(() -> {
|
||||||
GtkEnvBackend.INSTANCE.dialogParent = null;
|
GtkEnvBackend.INSTANCE.dialogParent = null;
|
||||||
|
@ -46,32 +46,35 @@ public class GtkMenubar {
|
|||||||
launchMenu.clear();
|
launchMenu.clear();
|
||||||
try {
|
try {
|
||||||
InstanceList.forEach(entry -> {
|
InstanceList.forEach(entry -> {
|
||||||
launchMenu.literalButton(entry.id(), entry.toString(), () -> {
|
launchMenu.literalButton(entry.id(), entry.toString(), () -> launch(entry));
|
||||||
Runnable launch = () -> {
|
|
||||||
try {
|
|
||||||
Steps.reDownload(entry.path(), Steps.createProcessState());
|
|
||||||
} catch (IOException e) {
|
|
||||||
Utils.LOGGER.error("Could not redownload instance, trying to start anyways", e);
|
|
||||||
}
|
|
||||||
InstanceLauncher.launchClient(entry.path(), entry.meta());
|
|
||||||
};
|
|
||||||
if (InstanceLock.isSetupLocked(entry.path())) {
|
|
||||||
LauncherEnv.showError(I18n.get("launch.locked.setup"), I18n.get("launch.locked"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (InstanceLock.isRunningLocked(entry.path())) {
|
|
||||||
LauncherEnv.showOkCancel(I18n.get("launch.locked.running"), I18n.get("launch.locked"), () -> {
|
|
||||||
new Thread(launch).start(); //TODO loom
|
|
||||||
}, R::nop);
|
|
||||||
}
|
|
||||||
new Thread(launch).start();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Utils.LOGGER.error("Could not generate launch menu", e);
|
Utils.LOGGER.error("Could not generate launch menu", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void launch(InstanceList.Entry instance) {
|
||||||
|
//TODO show popup during launch w/ cancel option (lock main UI)
|
||||||
|
Runnable launch = () -> {
|
||||||
|
try {
|
||||||
|
Steps.reDownload(instance.path(), Steps.createProcessState());
|
||||||
|
} catch (IOException e) {
|
||||||
|
Utils.LOGGER.error("Could not redownload instance, trying to start anyways", e);
|
||||||
|
}
|
||||||
|
InstanceLauncher.launchClient(instance.path(), instance.meta());
|
||||||
|
};
|
||||||
|
if (InstanceLock.isSetupLocked(instance.path())) {
|
||||||
|
LauncherEnv.showError(I18n.get("instance.launch.locked.setup"), I18n.get("instance.launch.locked"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (InstanceLock.isRunningLocked(instance.path())) {
|
||||||
|
LauncherEnv.showOkCancel(I18n.get("instance.launch.locked.running"), I18n.get("instance.launch.locked"), () -> {
|
||||||
|
new Thread(launch).start(); //TODO loom
|
||||||
|
}, R::nop);
|
||||||
|
}
|
||||||
|
new Thread(launch).start();
|
||||||
|
}
|
||||||
|
|
||||||
public static void generateAccountsMenu() {
|
public static void generateAccountsMenu() {
|
||||||
Objects.requireNonNull(accountsMenu);
|
Objects.requireNonNull(accountsMenu);
|
||||||
accountsMenu.clear();
|
accountsMenu.clear();
|
||||||
|
@ -5,6 +5,7 @@ import ch.bailu.gtk.gio.ApplicationFlags;
|
|||||||
import ch.bailu.gtk.gtk.*;
|
import ch.bailu.gtk.gtk.*;
|
||||||
import ch.bailu.gtk.type.Str;
|
import ch.bailu.gtk.type.Str;
|
||||||
import ch.bailu.gtk.type.Strs;
|
import ch.bailu.gtk.type.Strs;
|
||||||
|
import io.gitlab.jfronny.inceptum.common.R;
|
||||||
|
|
||||||
public class TestStart {
|
public class TestStart {
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
@ -30,6 +31,7 @@ public class TestStart {
|
|||||||
private static void test() {
|
private static void test() {
|
||||||
GtkEnvBackend backend = GtkEnvBackend.INSTANCE;
|
GtkEnvBackend backend = GtkEnvBackend.INSTANCE;
|
||||||
|
|
||||||
|
backend.getInput("Ae", "IoU\naee", "Def", s -> {}, R::nop);
|
||||||
// backend.showInfo("Some message", "Title");
|
// backend.showInfo("Some message", "Title");
|
||||||
// backend.showError("Yes!", "AAee");
|
// backend.showError("Yes!", "AAee");
|
||||||
// backend.showError("Nes!", new ArrayIndexOutOfBoundsException("Top 500 cheese"));
|
// backend.showError("Nes!", new ArrayIndexOutOfBoundsException("Top 500 cheese"));
|
||||||
|
@ -0,0 +1,54 @@
|
|||||||
|
package io.gitlab.jfronny.inceptum.gtk.control;
|
||||||
|
|
||||||
|
import ch.bailu.gtk.GTK;
|
||||||
|
import ch.bailu.gtk.bridge.ListIndex;
|
||||||
|
import ch.bailu.gtk.gtk.*;
|
||||||
|
import ch.bailu.gtk.type.Str;
|
||||||
|
import io.gitlab.jfronny.inceptum.common.Utils;
|
||||||
|
import io.gitlab.jfronny.inceptum.gtk.GtkMenubar;
|
||||||
|
import io.gitlab.jfronny.inceptum.gtk.util.I18n;
|
||||||
|
import io.gitlab.jfronny.inceptum.launcher.util.InstanceList;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class InstanceGridEntryFactory extends SignalListItemFactory {
|
||||||
|
public InstanceGridEntryFactory(List<InstanceList.Entry> instanceList) {
|
||||||
|
super();
|
||||||
|
//TODO better design
|
||||||
|
onSetup(item -> {
|
||||||
|
var box = new Box(Orientation.HORIZONTAL, 5);
|
||||||
|
|
||||||
|
Label label = new Label(Str.NULL);
|
||||||
|
// label.setXalign(0);
|
||||||
|
label.setWidthChars(20);
|
||||||
|
label.setMarginEnd(10);
|
||||||
|
box.append(label);
|
||||||
|
|
||||||
|
Button launch = new Button();
|
||||||
|
launch.setIconName(new Str("computer-symbolic"));
|
||||||
|
launch.setTooltipText(I18n.str("instance.launch"));
|
||||||
|
launch.setHasTooltip(GTK.TRUE);
|
||||||
|
box.append(launch);
|
||||||
|
|
||||||
|
Button openDir = new Button();
|
||||||
|
openDir.setIconName(new Str("folder-symbolic"));
|
||||||
|
openDir.setTooltipText(I18n.str("instance.directory"));
|
||||||
|
openDir.setHasTooltip(GTK.TRUE);
|
||||||
|
box.append(openDir);
|
||||||
|
|
||||||
|
item.setChild(box);
|
||||||
|
//TODO server launch with network-server-symbolic
|
||||||
|
//TODO kill current instance
|
||||||
|
});
|
||||||
|
onBind(item -> {
|
||||||
|
Label label = new Label(item.getChild().getFirstChild().cast());
|
||||||
|
Button launch = new Button(label.getNextSibling().cast());
|
||||||
|
Button openDir = new Button(launch.getNextSibling().cast());
|
||||||
|
InstanceList.Entry instance = instanceList.get(ListIndex.toIndex(item));
|
||||||
|
label.setText(new Str(instance.toString()));
|
||||||
|
launch.onClicked(() -> GtkMenubar.launch(instance));
|
||||||
|
openDir.onClicked(() -> Utils.openFile(instance.path().toFile()));
|
||||||
|
//TODO edit button document-edit-symbolic -> edit-delete-symbolic, edit-copy-symbolic
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,69 @@
|
|||||||
|
package io.gitlab.jfronny.inceptum.gtk.control;
|
||||||
|
|
||||||
|
import ch.bailu.gtk.GTK;
|
||||||
|
import ch.bailu.gtk.bridge.ListIndex;
|
||||||
|
import ch.bailu.gtk.gtk.*;
|
||||||
|
import ch.bailu.gtk.type.Str;
|
||||||
|
import io.gitlab.jfronny.inceptum.common.Utils;
|
||||||
|
import io.gitlab.jfronny.inceptum.gtk.GtkMenubar;
|
||||||
|
import io.gitlab.jfronny.inceptum.gtk.util.I18n;
|
||||||
|
import io.gitlab.jfronny.inceptum.launcher.util.InstanceList;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class InstanceListEntryFactory extends SignalListItemFactory {
|
||||||
|
public InstanceListEntryFactory(List<InstanceList.Entry> instanceList) {
|
||||||
|
super();
|
||||||
|
onSetup(item -> {
|
||||||
|
var thumbnail = new InstanceThumbnail();
|
||||||
|
|
||||||
|
var label = new Label(Str.NULL);
|
||||||
|
label.setHexpand(GTK.TRUE);
|
||||||
|
|
||||||
|
var launch = new Button();
|
||||||
|
launch.setIconName(new Str("computer-symbolic"));
|
||||||
|
launch.setTooltipText(I18n.str("instance.launch"));
|
||||||
|
launch.setHasTooltip(GTK.TRUE);
|
||||||
|
|
||||||
|
var openDir = new Button();
|
||||||
|
openDir.setIconName(new Str("folder-symbolic"));
|
||||||
|
openDir.setTooltipText(I18n.str("instance.directory"));
|
||||||
|
openDir.setHasTooltip(GTK.TRUE);
|
||||||
|
|
||||||
|
var row = new Box(Orientation.HORIZONTAL, 8);
|
||||||
|
row.append(thumbnail);
|
||||||
|
row.append(label);
|
||||||
|
row.append(launch);
|
||||||
|
row.append(openDir);
|
||||||
|
|
||||||
|
item.setChild(row);
|
||||||
|
|
||||||
|
//TODO server launch with network-server-symbolic
|
||||||
|
//TODO kill current instance
|
||||||
|
});
|
||||||
|
onBind(item -> {
|
||||||
|
InstanceList.Entry instance = instanceList.get(ListIndex.toIndex(item));
|
||||||
|
Box row = new Box(item.getChild().cast());
|
||||||
|
InstanceThumbnail thumbnail = new InstanceThumbnail(row.getFirstChild().cast());
|
||||||
|
Label label = new Label(thumbnail.getNextSibling().cast());
|
||||||
|
Button launch = new Button(label.getNextSibling().cast());
|
||||||
|
Button openDir = new Button(launch.getNextSibling().cast());
|
||||||
|
|
||||||
|
thumbnail.bind(instance);
|
||||||
|
label.setText(new Str(instance.toString()));
|
||||||
|
launch.onClicked(() -> GtkMenubar.launch(instance));
|
||||||
|
openDir.onClicked(() -> Utils.openFile(instance.path().toFile()));
|
||||||
|
|
||||||
|
//TODO why the hell does this crash the VM?
|
||||||
|
// var controller = new EventControllerLegacy();
|
||||||
|
// controller.onEvent(event -> {
|
||||||
|
// if (event.getEventType() == EventType.BUTTON_RELEASE) {
|
||||||
|
// Utils.LOGGER.info("Button " + new ButtonEvent(event.cast()).getButton());
|
||||||
|
// }
|
||||||
|
// return GTK.FALSE;
|
||||||
|
// });
|
||||||
|
// row.addController(controller);
|
||||||
|
//TODO edit button document-edit-symbolic -> edit-delete-symbolic, edit-copy-symbolic
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
package io.gitlab.jfronny.inceptum.gtk.control;
|
||||||
|
|
||||||
|
import ch.bailu.gtk.gtk.*;
|
||||||
|
import ch.bailu.gtk.type.CPointer;
|
||||||
|
import ch.bailu.gtk.type.Str;
|
||||||
|
import io.gitlab.jfronny.inceptum.launcher.util.InstanceList;
|
||||||
|
import io.gitlab.jfronny.inceptum.launcher.util.InstanceLock;
|
||||||
|
|
||||||
|
public class InstanceThumbnail extends Stack {
|
||||||
|
private static final Str SPINNER = new Str("spinner");
|
||||||
|
private static final Str IMAGE = new Str("image");
|
||||||
|
private static final Str GENERIC = new Str("generic");
|
||||||
|
|
||||||
|
public InstanceThumbnail(CPointer pointer) {
|
||||||
|
super(pointer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public InstanceThumbnail() {
|
||||||
|
super();
|
||||||
|
var spinner = new Spinner();
|
||||||
|
var image = new Image();
|
||||||
|
var generic = new Image();
|
||||||
|
generic.setFromIconName(new Str("media-playback-start-symbolic")); //TODO better default icon
|
||||||
|
addNamed(spinner, SPINNER);
|
||||||
|
addNamed(image, IMAGE);
|
||||||
|
addNamed(generic, GENERIC);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void bind(InstanceList.Entry entry) {
|
||||||
|
var spinner = new Spinner(getChildByName(SPINNER).cast());
|
||||||
|
var image = new Image(getChildByName(IMAGE).cast()); //TODO
|
||||||
|
var generic = new Image(getChildByName(GENERIC).cast());
|
||||||
|
//TODO mark instance being played
|
||||||
|
if (InstanceLock.isSetupLocked(entry.path())) {
|
||||||
|
setVisibleChild(spinner);
|
||||||
|
} else if (false) { // if the instance has an image, load the image data and set it as the visible child
|
||||||
|
setVisibleChild(image);
|
||||||
|
} else {
|
||||||
|
setVisibleChild(generic);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,29 +1,47 @@
|
|||||||
package io.gitlab.jfronny.inceptum.gtk.window;
|
package io.gitlab.jfronny.inceptum.gtk.window;
|
||||||
|
|
||||||
import ch.bailu.gtk.GTK;
|
import ch.bailu.gtk.GTK;
|
||||||
|
import ch.bailu.gtk.adw.StatusPage;
|
||||||
|
import ch.bailu.gtk.bridge.ListIndex;
|
||||||
import ch.bailu.gtk.gio.Menu;
|
import ch.bailu.gtk.gio.Menu;
|
||||||
|
import ch.bailu.gtk.glib.Glib;
|
||||||
import ch.bailu.gtk.gtk.*;
|
import ch.bailu.gtk.gtk.*;
|
||||||
import ch.bailu.gtk.type.Str;
|
import ch.bailu.gtk.type.Str;
|
||||||
import io.gitlab.jfronny.inceptum.common.InceptumConfig;
|
import io.gitlab.jfronny.inceptum.common.*;
|
||||||
import io.gitlab.jfronny.inceptum.common.Utils;
|
|
||||||
import io.gitlab.jfronny.inceptum.gtk.GtkMenubar;
|
import io.gitlab.jfronny.inceptum.gtk.GtkMenubar;
|
||||||
|
import io.gitlab.jfronny.inceptum.gtk.control.InstanceGridEntryFactory;
|
||||||
|
import io.gitlab.jfronny.inceptum.gtk.control.InstanceListEntryFactory;
|
||||||
import io.gitlab.jfronny.inceptum.gtk.menu.MenuBuilder;
|
import io.gitlab.jfronny.inceptum.gtk.menu.MenuBuilder;
|
||||||
|
import io.gitlab.jfronny.inceptum.gtk.util.I18n;
|
||||||
|
import io.gitlab.jfronny.inceptum.launcher.util.InstanceList;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
import java.nio.file.*;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static java.nio.file.StandardWatchEventKinds.*;
|
||||||
|
|
||||||
public class MainWindow extends ApplicationWindow {
|
public class MainWindow extends ApplicationWindow {
|
||||||
private final Button listButton;
|
private final Button listButton;
|
||||||
private final Button gridButton;
|
private final Button gridButton;
|
||||||
|
private final Stack stack;
|
||||||
|
private final Box empty;
|
||||||
|
private final ListView listView;
|
||||||
|
private final GridView gridView;
|
||||||
|
private final List<InstanceList.Entry> instanceList;
|
||||||
|
private final ListIndex instanceListIndex;
|
||||||
|
|
||||||
public MainWindow(Application app) {
|
public MainWindow(Application app) {
|
||||||
super(app);
|
super(app);
|
||||||
|
|
||||||
var header = new HeaderBar();
|
HeaderBar header = new HeaderBar();
|
||||||
var newButton = new Button();
|
Button newButton = new Button();
|
||||||
newButton.setIconName(new Str("list-add-symbolic"));
|
newButton.setIconName(new Str("list-add-symbolic"));
|
||||||
newButton.onClicked(NewInstanceWindow::createAndShow);
|
newButton.onClicked(NewInstanceWindow::createAndShow);
|
||||||
|
|
||||||
var accountsButton = new MenuButton();
|
MenuButton accountsButton = new MenuButton();
|
||||||
accountsButton.setIconName(new Str("avatar-default-symbolic"));
|
accountsButton.setIconName(new Str("avatar-default-symbolic"));
|
||||||
accountsButton.setPopover(GtkMenubar.accountsMenu.asPopover());
|
accountsButton.setPopover(GtkMenubar.accountsMenu.asPopover());
|
||||||
|
|
||||||
@ -43,11 +61,13 @@ public class MainWindow extends ApplicationWindow {
|
|||||||
generateWindowBody();
|
generateWindowBody();
|
||||||
});
|
});
|
||||||
|
|
||||||
var uiMenu = new MenuBuilder(app, new Menu(), "hamburger");
|
//TODO search button like boxes
|
||||||
|
|
||||||
|
MenuBuilder uiMenu = new MenuBuilder(app, new Menu(), "hamburger");
|
||||||
uiMenu.button("support", () -> Utils.openWebBrowser(new URI("https://gitlab.com/jfmods/inceptum/-/issues")));
|
uiMenu.button("support", () -> Utils.openWebBrowser(new URI("https://gitlab.com/jfmods/inceptum/-/issues")));
|
||||||
uiMenu.button("preferences", () -> {}); //TODO preferences UI inspired by boxes
|
uiMenu.button("preferences", () -> {}); //TODO preferences UI inspired by boxes
|
||||||
uiMenu.button("about", AboutWindow::createAndShow);
|
uiMenu.button("about", AboutWindow::createAndShow);
|
||||||
var menuButton = new MenuButton();
|
MenuButton menuButton = new MenuButton();
|
||||||
menuButton.setIconName(new Str("open-menu-symbolic"));
|
menuButton.setIconName(new Str("open-menu-symbolic"));
|
||||||
menuButton.setPopover(uiMenu.asPopover());
|
menuButton.setPopover(uiMenu.asPopover());
|
||||||
|
|
||||||
@ -58,18 +78,87 @@ public class MainWindow extends ApplicationWindow {
|
|||||||
header.packEnd(listButton);
|
header.packEnd(listButton);
|
||||||
header.packEnd(accountsButton);
|
header.packEnd(accountsButton);
|
||||||
|
|
||||||
|
instanceList = new ArrayList<>();
|
||||||
|
instanceListIndex = new ListIndex();
|
||||||
|
|
||||||
|
listView = new ListView(instanceListIndex.inSelectionModel(), new InstanceListEntryFactory(instanceList));
|
||||||
|
gridView = new GridView(instanceListIndex.inSelectionModel(), new InstanceGridEntryFactory(instanceList));
|
||||||
|
empty = new Box(Orientation.VERTICAL, 8);
|
||||||
|
empty.setHalign(Align.CENTER);
|
||||||
|
empty.setValign(Align.CENTER);
|
||||||
|
var emptyTitle = new Label(Str.NULL);
|
||||||
|
emptyTitle.setMarkup(I18n.str("main.empty.title"));
|
||||||
|
emptyTitle.setHalign(Align.CENTER);
|
||||||
|
var emptyDescription = new Label(I18n.str("main.empty.description"));
|
||||||
|
emptyDescription.setHalign(Align.CENTER);
|
||||||
|
empty.append(emptyTitle);
|
||||||
|
empty.append(emptyDescription);
|
||||||
|
//TODO empty.setIconName(new Str());
|
||||||
|
stack = new Stack();
|
||||||
|
stack.addChild(listView);
|
||||||
|
stack.addChild(gridView);
|
||||||
|
|
||||||
|
ScrolledWindow scroll = new ScrolledWindow();
|
||||||
|
scroll.setPolicy(PolicyType.NEVER, PolicyType.AUTOMATIC);
|
||||||
|
scroll.setChild(stack);
|
||||||
|
|
||||||
setDefaultSize(360, 720);
|
setDefaultSize(360, 720);
|
||||||
setTitle(new Str("Inceptum"));
|
setTitle(new Str("Inceptum"));
|
||||||
setTitlebar(header);
|
setTitlebar(header);
|
||||||
setShowMenubar(GTK.FALSE);
|
setShowMenubar(GTK.FALSE);
|
||||||
setChild(new TextView());
|
setChild(scroll);
|
||||||
|
|
||||||
generateWindowBody();
|
generateWindowBody();
|
||||||
|
//TODO DropTarget to add mods/instances
|
||||||
|
|
||||||
|
try {
|
||||||
|
setupDirWatcher();
|
||||||
|
} catch (IOException e) {
|
||||||
|
Utils.LOGGER.error("Could not set up watch service, live updates of the instance dir will be unavailable", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupDirWatcher() throws IOException { //TODO test (including after lock state change)
|
||||||
|
WatchService ws = FileSystems.getDefault().newWatchService();
|
||||||
|
MetaHolder.INSTANCE_DIR.register(ws, ENTRY_MODIFY, ENTRY_CREATE, ENTRY_DELETE);
|
||||||
|
int source = Glib.idleAdd(user_data -> {
|
||||||
|
//TODO watch instance dirs for locks
|
||||||
|
WatchKey key = ws.poll();
|
||||||
|
boolean instancesChanged = false;
|
||||||
|
if (key != null) {
|
||||||
|
for (WatchEvent<?> event : key.pollEvents()) {
|
||||||
|
if (event.context() instanceof Path p) {
|
||||||
|
p = MetaHolder.INSTANCE_DIR.resolve(p);
|
||||||
|
instancesChanged |= Files.exists(p.resolve("instance.json"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (instancesChanged) generateWindowBody();
|
||||||
|
return GTK.TRUE;
|
||||||
|
}, null);
|
||||||
|
onCloseRequest(() -> {
|
||||||
|
try {
|
||||||
|
ws.close();
|
||||||
|
} catch (IOException ignored) {
|
||||||
|
}
|
||||||
|
Glib.sourceRemove(source);
|
||||||
|
return GTK.FALSE;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void generateWindowBody() {
|
private void generateWindowBody() {
|
||||||
if (listButton != null) listButton.setVisible(GTK.is(!InceptumConfig.listView));
|
if (listButton != null) listButton.setVisible(GTK.is(!InceptumConfig.listView));
|
||||||
if (gridButton != null) gridButton.setVisible(GTK.is(InceptumConfig.listView));
|
if (gridButton != null) gridButton.setVisible(GTK.is(InceptumConfig.listView));
|
||||||
//TODO create list/grid view
|
try {
|
||||||
|
instanceList.clear();
|
||||||
|
InstanceList.forEach(instanceList::add);
|
||||||
|
instanceListIndex.setSize(instanceList.size());
|
||||||
|
|
||||||
|
if (InstanceList.isEmpty()) stack.setVisibleChild(empty);
|
||||||
|
else if (InceptumConfig.listView) stack.setVisibleChild(listView);
|
||||||
|
else stack.setVisibleChild(gridView);
|
||||||
|
} catch (IOException e) {
|
||||||
|
Utils.LOGGER.error("Could not generate window body", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,9 +21,13 @@ cancel=Cancel
|
|||||||
menu.hamburger.support=Support
|
menu.hamburger.support=Support
|
||||||
menu.hamburger.preferences=Preferences
|
menu.hamburger.preferences=Preferences
|
||||||
menu.hamburger.about=About
|
menu.hamburger.about=About
|
||||||
launch.locked=Can't launch right now
|
instance.launch.locked=Can't launch right now
|
||||||
launch.locked.setup=This instance is currently setting up.\
|
instance.launch.locked.setup=This instance is currently setting up.\
|
||||||
Please wait until that is finished before playing.
|
Please wait until that is finished before playing.
|
||||||
launch.locked.running=This instance is currently running.\
|
instance.launch.locked.running=This instance is currently running.\
|
||||||
Click OK to start a second instance of the game.\
|
Click OK to start a second instance of the game.\
|
||||||
Please be aware that doing so is unsupported and WILL cause issues!
|
Please be aware that doing so is unsupported and WILL cause issues!
|
||||||
|
instance.launch=Launch
|
||||||
|
main.empty.title=# Welcome to Inceptum
|
||||||
|
main.empty.description=To get started, create (or import) a new instance using the + button
|
||||||
|
instance.directory=Open Directory
|
||||||
|
@ -20,10 +20,14 @@ cancel=Abbrechen
|
|||||||
menu.hamburger.support=Unterstützung
|
menu.hamburger.support=Unterstützung
|
||||||
menu.hamburger.preferences=Einstellungen
|
menu.hamburger.preferences=Einstellungen
|
||||||
menu.hamburger.about=Über
|
menu.hamburger.about=Über
|
||||||
launch.locked=Instanz kann momentan nicht gestartet werden
|
instance.launch.locked=Instanz kann momentan nicht gestartet werden
|
||||||
launch.locked.setup=Diese Instanz wird noch eingerichtet.\
|
instance.launch.locked.setup=Diese Instanz wird noch eingerichtet.\
|
||||||
Bitte warte, bis dieser Prozess abgeschlossen ist,\
|
Bitte warte, bis dieser Prozess abgeschlossen ist,\
|
||||||
bevor du sie startest.
|
bevor du sie startest.
|
||||||
launch.locked.running=Diese Instanz läuft bereits.\
|
instance.launch.locked.running=Diese Instanz läuft bereits.\
|
||||||
Bestätigen sie den Start mit OK, um sie ein zweites mal zu starten.\
|
Bestätigen sie den Start mit OK, um sie ein zweites mal zu starten.\
|
||||||
Bitte seien sie sich bewusst, dass dies zu Problemen führen wird und NICHT UNTERSÜTZT ist.
|
Bitte seien sie sich bewusst, dass dies zu Problemen führen wird und NICHT UNTERSÜTZT ist.
|
||||||
|
instance.launch=Starten
|
||||||
|
main.empty.title=# Willkommen bei Inceptum
|
||||||
|
main.empty.description=Importiere oder erstelle um anzufangen eine Instanz mit dem +
|
||||||
|
instance.directory=Verzeichnis öffnen
|
||||||
|
@ -128,10 +128,11 @@ class ModsDirScannerImpl implements ModsDirScanner {
|
|||||||
WatchKey key = service.poll();
|
WatchKey key = service.poll();
|
||||||
if (key != null) {
|
if (key != null) {
|
||||||
for (WatchEvent<?> event : key.pollEvents()) {
|
for (WatchEvent<?> event : key.pollEvents()) {
|
||||||
if (event.context() instanceof Path p)
|
if (event.context() instanceof Path p) {
|
||||||
toScan.add(p);
|
toScan.add(modsDir.resolve(p));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
key.reset();
|
if (!key.reset()) Utils.LOGGER.warn("Could not reset config watch key");
|
||||||
}
|
}
|
||||||
JFiles.listTo(modsDir, path -> {
|
JFiles.listTo(modsDir, path -> {
|
||||||
if (!descriptions.containsKey(path))
|
if (!descriptions.containsKey(path))
|
||||||
|
@ -25,10 +25,9 @@ public class InstanceList {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void forEachLaunchable(Consumer<Entry> target) throws IOException {
|
public static boolean isEmpty() throws IOException {
|
||||||
forEach(entry -> {
|
if (!Files.exists(MetaHolder.INSTANCE_DIR)) return true;
|
||||||
if (!InstanceLock.isLocked(entry.path)) target.accept(entry);
|
return JFiles.list(MetaHolder.INSTANCE_DIR, Files::isDirectory).isEmpty();
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Entry read(Path instancePath) throws IOException {
|
public static Entry read(Path instancePath) throws IOException {
|
||||||
|
Loading…
Reference in New Issue
Block a user