package io.gitlab.jfronny.inceptum.gtk.control; import io.github.jwharm.javagi.Signal; import io.gitlab.jfronny.commons.io.JFiles; import io.gitlab.jfronny.commons.ref.R; import io.gitlab.jfronny.inceptum.common.MetaHolder; import io.gitlab.jfronny.inceptum.common.Utils; 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.launcher.LauncherEnv; import io.gitlab.jfronny.inceptum.launcher.system.instance.*; import io.gitlab.jfronny.inceptum.launcher.system.launch.LaunchType; import org.gnome.adw.ActionRow; import org.gtk.gio.ActionMap; import org.gtk.gio.Menu; import org.gtk.gtk.Stack; import org.gtk.gtk.*; import java.io.IOException; import java.nio.file.Files; import java.util.*; import java.util.function.Consumer; public class InstanceListEntryFactory extends SignalListItemFactory { public InstanceListEntryFactory(List instanceList, ActionMap actionMap) { super(); onSetup(item -> { var thumbnail = new InstanceThumbnail(); thumbnail.name = "inceptum-thumbnail"; var launch = new Button(); launch.addCssClass("flat"); launch.name = "inceptum-launch"; launch.iconName = "media-playback-start-symbolic"; launch.tooltipText = I18n.get("instance.launch"); launch.hasTooltip = true; var menu = new MenuButton(); menu.addCssClass("flat"); menu.iconName = "view-more-symbolic"; menu.menuModel = new Menu(); var row = new ActionRow(); row.margin = 8; row.name = "inceptum-row"; row.activatableWidget = launch; row.addPrefix(thumbnail); row.addSuffix(launch); row.addSuffix(menu); var clicked = new GestureClick(); clicked.onPressed((nPress, x, y) -> { if (nPress == 2) launch.emitClicked(launch); }); row.addController(clicked); var rightClicked = new GestureClick(); rightClicked.button = 3; rightClicked.onPressed((nPress, x, y) -> { if (nPress == 1) menu.emitActivate(menu); }); row.addController(rightClicked); ((ListItem) item).setChild(row); }); Map>> toDisconnect = new HashMap<>(); onBind(item -> { Decomposed li = Decomposed.of((ListItem) item, instanceList); li.row.title = li.instance.toString(); li.thumbnail.bind(li.instance); //TODO fix menu not interactable var menuBuilder = new MenuBuilder(actionMap, li.menu, li.instance.id); var launchSection = menuBuilder.literalSection("launch", null); launchSection.literalButton("launch.client", I18n.get("instance.launch.client"), () -> GtkMenubar.launch(li.instance, LaunchType.Client)) .iconName = "media-playback-start-symbolic"; launchSection.literalButton("launch.server", I18n.get("instance.launch.server"), () -> GtkMenubar.launch(li.instance, LaunchType.Server)) .iconName = "network-server-symbolic"; var settingsSection = menuBuilder.literalSection("settings", null); settingsSection.literalButton("settings", I18n.get("instance.settings"), () -> { //TODO open settings }).iconName = "document-edit-symbolic"; settingsSection.literalButton("directory", I18n.get("instance.directory"), () -> Utils.openFile(li.instance.path.toFile())) .iconName = "folder-symbolic"; settingsSection.literalButton("copy", I18n.get("instance.copy"), () -> { LauncherEnv.getInput(I18n.get("instance.copy.prompt"), I18n.get("instance.copy.details"), InstanceNameTool.getNextValid(li.instance.name), s -> { try { JFiles.copyRecursive(li.instance.path, MetaHolder.INSTANCE_DIR.resolve(InstanceNameTool.getNextValid(s))); } catch (IOException e) { LauncherEnv.showError("Could not copy instance", e); } }, R::nop); }).iconName = "edit-copy-symbolic"; settingsSection.literalButton("delete", I18n.get("instance.delete"), () -> { LauncherEnv.showOkCancel("This instance will be removed forever (a long time)", "Are you sure?", () -> { try { JFiles.deleteRecursive(li.instance.path); } catch (IOException e) { LauncherEnv.showError("Could not delete the instance", e); } }, R::nop); }).iconName = "edit-delete-symbolic"; //TODO kill current instance Consumer> dc = s -> toDisconnect.computeIfAbsent(li.instance.id, $ -> new HashSet<>()).add(s); dc.accept(li.launch.onClicked(() -> GtkMenubar.launch(li.instance, LaunchType.Client))); }); onUnbind(item -> { Decomposed li = Decomposed.of((ListItem) item, instanceList); li.menu.removeAll(); toDisconnect.get(li.instance.id).forEach(Signal::disconnect); }); } private record Decomposed(Instance instance, ActionRow row, InstanceThumbnail thumbnail, Button launch, Menu menu) { public static Decomposed of(ListItem item, List instanceList) { Instance instance = instanceList.get(((ListIndexItem) item.getItem()).getIntValue()); ActionRow row = (ActionRow) item.child; Box prefixes = (Box) row.firstChild.firstChild; Box suffixes = (Box) row.firstChild.lastChild; InstanceThumbnail thumbnail = InstanceThumbnail.castFrom((Stack) prefixes.firstChild); Button launch = (Button) suffixes.firstChild; MenuButton menuButton = (MenuButton) launch.nextSibling; return new Decomposed(instance, row, thumbnail, launch, (Menu) menuButton.menuModel); } } }