Inceptum/launcher-gtk/src/main/java/io/gitlab/jfronny/inceptum/gtk/menu/MenuBuilder.java

138 lines
4.8 KiB
Java
Raw Normal View History

package io.gitlab.jfronny.inceptum.gtk.menu;
import ch.bailu.gtk.GTK;
import ch.bailu.gtk.gio.MenuItem;
import ch.bailu.gtk.gio.*;
import ch.bailu.gtk.glib.Variant;
import ch.bailu.gtk.glib.VariantType;
import ch.bailu.gtk.gtk.Application;
import ch.bailu.gtk.gtk.PopoverMenu;
import ch.bailu.gtk.type.Pointer;
import ch.bailu.gtk.type.Str;
import io.gitlab.jfronny.commons.throwable.ThrowingRunnable;
import io.gitlab.jfronny.inceptum.common.Utils;
import io.gitlab.jfronny.inceptum.gtk.util.I18n;
import java.util.*;
import java.util.function.*;
public class MenuBuilder {
private static final Object LOCK = new Object();
private static Menu getRootMenu(Application app) {
synchronized (LOCK) {
var currentMenu = app.getMenubar();
if (currentMenu.equals(Pointer.NULL)) {
var menu = new Menu();
app.setMenubar(menu);
return menu;
} else {
return new Menu(currentMenu.cast());
}
}
}
private final ActionMap map;
private final Map<String, Action> refs = new LinkedHashMap<>();
private final Menu menu;
private final String prefix;
public MenuBuilder(Application app) {
this(app, getRootMenu(app), "");
}
public MenuBuilder(Application app, Menu menu, String prefix) {
this(new ActionMap(app.cast()), menu, prefix);
}
public MenuBuilder(ActionMap map, Menu menu, String prefix) {
if (!prefix.isEmpty() && !prefix.endsWith(".")) prefix += ".";
this.map = Objects.requireNonNull(map);
this.menu = Objects.requireNonNull(menu);
this.prefix = Objects.requireNonNull(prefix);
}
public ButtonItem button(String name, ThrowingRunnable<?> onClick) {
return literalButton(name, I18n.get("menu." + prefix + name), onClick);
}
public ButtonItem literalButton(String internalName, String label, ThrowingRunnable<?> onClick) {
internalName = prefix + internalName;
SimpleAction sAct = new SimpleAction(new Str(internalName), null);
addAction(internalName, sAct);
sAct.onActivate(v -> {
try {
onClick.run();
} catch (Throwable e) {
Utils.LOGGER.error("Could not execute action", e);
}
});
menu.appendItem(new MenuItem(new Str(label), new Str("app." + internalName)));
return new ButtonItem(sAct);
}
public ToggleItem toggle(String name, boolean initial, Consumer<Boolean> action) {
name = prefix + name;
SimpleAction sAct = SimpleAction.newStatefulSimpleAction(new Str(name), null, Variant.newBooleanVariant(GTK.is(initial)));
Action rAct = addAction(name, sAct);
sAct.onActivate(parameter -> {
boolean state = !GTK.is(rAct.getState().getBoolean());
sAct.setState(Variant.newBooleanVariant(GTK.is(state)));
action.accept(state);
});
menu.appendItem(new MenuItem(I18n.str("menu." + name), new Str("app." + name)));
return new ToggleItem(sAct);
}
public <T> RadioItem<T> radio(String name, T initial, List<T> options, Consumer<T> action) {
return literalRadio(name, initial, options, (i, t) -> I18n.get("menu." + name, i), action);
}
public <T> RadioItem<T> literalRadio(String name, T initial, List<T> options, BiFunction<Integer, T, String> stringifier, Consumer<T> action) {
Objects.requireNonNull(options);
name = prefix + name;
SimpleAction sAct = SimpleAction.newStatefulSimpleAction(new Str(name), new VariantType(new Str("i")), Variant.newInt32Variant(options.indexOf(initial)));
addAction(name, sAct);
sAct.onActivate(parameter -> {
sAct.setState(parameter);
action.accept(options.get(parameter.getInt32()));
});
int i = 0;
for (T option : options) {
menu.appendItem(new MenuItem(new Str(stringifier.apply(i, option)), new Str("app." + name + "(" + i + ")")));
i++;
}
return new RadioItem<>(sAct, options);
}
public MenuBuilder submenu(String name) {
name = prefix + name;
Menu submenu = new Menu();
menu.appendSubmenu(I18n.str("menu." + name), submenu);
return new MenuBuilder(map, submenu, name);
}
public void clear() {
menu.removeAll();
refs.forEach((name, action) -> {
map.removeAction(new Str(name));
});
refs.clear();
}
private Action addAction(String name, SimpleAction action) {
Action rAct = new Action(action.cast());
map.addAction(rAct);
refs.put(name, rAct);
return rAct;
}
public Menu getMenu() {
return menu;
}
public PopoverMenu asPopover() {
return PopoverMenu.newFromModelPopoverMenu(menu);
}
}