2022-09-26 19:09:02 +02:00
|
|
|
package io.gitlab.jfronny.inceptum.gtk.menu;
|
|
|
|
|
2022-09-29 17:53:49 +02:00
|
|
|
import io.gitlab.jfronny.commons.throwable.ThrowingRunnable;
|
|
|
|
import io.gitlab.jfronny.inceptum.common.Utils;
|
2022-09-26 19:09:02 +02:00
|
|
|
import io.gitlab.jfronny.inceptum.gtk.util.I18n;
|
2022-12-17 21:53:21 +01:00
|
|
|
import org.gtk.gio.MenuItem;
|
|
|
|
import org.gtk.gio.*;
|
|
|
|
import org.gtk.glib.Variant;
|
|
|
|
import org.gtk.glib.VariantType;
|
|
|
|
import org.gtk.gtk.Application;
|
|
|
|
import org.gtk.gtk.PopoverMenu;
|
2023-01-13 19:34:29 +01:00
|
|
|
import org.jetbrains.annotations.Nullable;
|
2022-12-17 21:53:21 +01:00
|
|
|
|
|
|
|
import java.util.LinkedHashMap;
|
|
|
|
import java.util.List;
|
|
|
|
import java.util.Map;
|
|
|
|
import java.util.Objects;
|
2022-11-04 17:02:24 +01:00
|
|
|
import java.util.function.BiFunction;
|
|
|
|
import java.util.function.Consumer;
|
2022-09-26 19:09:02 +02:00
|
|
|
|
|
|
|
public class MenuBuilder {
|
|
|
|
private static final Object LOCK = new Object();
|
|
|
|
|
|
|
|
private static Menu getRootMenu(Application app) {
|
|
|
|
synchronized (LOCK) {
|
2022-12-17 21:53:21 +01:00
|
|
|
var currentMenu = app.menubar;
|
|
|
|
if (currentMenu == null) {
|
2022-09-26 19:09:02 +02:00
|
|
|
var menu = new Menu();
|
2022-12-17 21:53:21 +01:00
|
|
|
app.menubar = menu;
|
2022-09-26 19:09:02 +02:00
|
|
|
return menu;
|
|
|
|
} else {
|
2023-01-10 21:20:01 +01:00
|
|
|
return (Menu) currentMenu;
|
2022-09-26 19:09:02 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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(ActionMap map, Menu menu, String prefix) {
|
2022-09-29 17:53:49 +02:00
|
|
|
if (!prefix.isEmpty() && !prefix.endsWith(".")) prefix += ".";
|
2022-09-26 19:09:02 +02:00
|
|
|
this.map = Objects.requireNonNull(map);
|
|
|
|
this.menu = Objects.requireNonNull(menu);
|
|
|
|
this.prefix = Objects.requireNonNull(prefix);
|
|
|
|
}
|
|
|
|
|
2023-01-13 19:34:29 +01:00
|
|
|
public BuiltButtonItem button(String name, ThrowingRunnable<?> onClick) {
|
2022-09-26 19:09:02 +02:00
|
|
|
return literalButton(name, I18n.get("menu." + prefix + name), onClick);
|
|
|
|
}
|
|
|
|
|
2023-01-13 19:34:29 +01:00
|
|
|
public BuiltButtonItem literalButton(String internalName, String label, ThrowingRunnable<?> onClick) {
|
2022-09-26 19:09:02 +02:00
|
|
|
internalName = prefix + internalName;
|
2023-01-13 19:34:29 +01:00
|
|
|
SimpleAction action = new SimpleAction(internalName, null);
|
|
|
|
addAction(internalName, action);
|
|
|
|
action.onActivate(variant -> {
|
2022-09-29 17:53:49 +02:00
|
|
|
try {
|
|
|
|
onClick.run();
|
|
|
|
} catch (Throwable e) {
|
|
|
|
Utils.LOGGER.error("Could not execute action", e);
|
|
|
|
}
|
|
|
|
});
|
2023-01-13 19:34:29 +01:00
|
|
|
MenuItem menuItem = new MenuItem(label, "app." + internalName);
|
|
|
|
menu.appendItem(menuItem);
|
|
|
|
action.enabled = true;
|
|
|
|
return new BuiltButtonItem(action, menuItem);
|
2022-09-26 19:09:02 +02:00
|
|
|
}
|
|
|
|
|
2023-01-13 19:34:29 +01:00
|
|
|
public BuiltToggleItem toggle(String name, boolean initial, Consumer<Boolean> onToggle) {
|
2022-09-26 19:09:02 +02:00
|
|
|
name = prefix + name;
|
2023-01-13 19:34:29 +01:00
|
|
|
SimpleAction action = SimpleAction.newStateful(name, null, Variant.newBoolean(initial));
|
|
|
|
addAction(name, action);
|
|
|
|
action.onActivate(variant -> {
|
|
|
|
boolean state = !action.getState().getBoolean();
|
|
|
|
action.state = Variant.newBoolean(state);
|
|
|
|
onToggle.accept(state);
|
2022-09-26 19:09:02 +02:00
|
|
|
});
|
2023-01-13 19:34:29 +01:00
|
|
|
MenuItem menuItem = new MenuItem(I18n.get("menu." + name), "app." + name);
|
|
|
|
menu.appendItem(menuItem);
|
|
|
|
return new BuiltToggleItem(action, menuItem);
|
2022-09-26 19:09:02 +02:00
|
|
|
}
|
|
|
|
|
2023-01-13 19:34:29 +01:00
|
|
|
public <T> BuiltRadioItem<T> radio(String name, T initial, List<T> options, Consumer<T> onCheck) {
|
|
|
|
return literalRadio(name, initial, options, (i, t) -> I18n.get("menu." + prefix + name, i), onCheck);
|
2022-09-26 19:09:02 +02:00
|
|
|
}
|
|
|
|
|
2023-01-13 19:34:29 +01:00
|
|
|
public <T> BuiltRadioItem<T> literalRadio(String name, T initial, List<T> options, BiFunction<Integer, T, String> stringifier, Consumer<T> onCheck) {
|
2022-09-26 19:09:02 +02:00
|
|
|
Objects.requireNonNull(options);
|
|
|
|
name = prefix + name;
|
2023-01-13 19:34:29 +01:00
|
|
|
SimpleAction action = SimpleAction.newStateful(name, new VariantType("i"), Variant.newInt32(options.indexOf(initial)));
|
|
|
|
addAction(name, action);
|
|
|
|
action.onActivate(variant -> {
|
|
|
|
action.state = variant;
|
|
|
|
onCheck.accept(options.get(variant.getInt32()));
|
2022-09-26 19:09:02 +02:00
|
|
|
});
|
|
|
|
int i = 0;
|
|
|
|
for (T option : options) {
|
2022-12-17 21:53:21 +01:00
|
|
|
menu.appendItem(new MenuItem(stringifier.apply(i, option), "app." + name + "(" + i + ")"));
|
2022-09-26 19:09:02 +02:00
|
|
|
i++;
|
|
|
|
}
|
2023-01-13 19:34:29 +01:00
|
|
|
return new BuiltRadioItem<>(action, options);
|
2022-09-26 19:09:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public MenuBuilder submenu(String name) {
|
2023-01-13 19:34:29 +01:00
|
|
|
return literalSubmenu(name, I18n.get("menu." + prefix + name));
|
|
|
|
}
|
|
|
|
|
|
|
|
public MenuBuilder literalSubmenu(String name, String label) {
|
2022-09-26 19:09:02 +02:00
|
|
|
name = prefix + name;
|
|
|
|
Menu submenu = new Menu();
|
2023-01-13 19:34:29 +01:00
|
|
|
menu.appendSubmenu(label, submenu);
|
2022-09-29 17:53:49 +02:00
|
|
|
return new MenuBuilder(map, submenu, name);
|
2022-09-26 19:09:02 +02:00
|
|
|
}
|
|
|
|
|
2023-01-13 19:34:29 +01:00
|
|
|
public MenuBuilder section(String name) {
|
|
|
|
return literalSection(name, I18n.get("section." + prefix + name));
|
|
|
|
}
|
|
|
|
|
|
|
|
public MenuBuilder literalSection(String name, @Nullable String label) {
|
|
|
|
name = prefix + name;
|
|
|
|
Menu section = new Menu();
|
|
|
|
menu.appendSection(label, section);
|
|
|
|
return new MenuBuilder(map, section, name);
|
|
|
|
}
|
|
|
|
|
2022-09-26 19:09:02 +02:00
|
|
|
public void clear() {
|
|
|
|
menu.removeAll();
|
|
|
|
refs.forEach((name, action) -> {
|
2022-12-17 21:53:21 +01:00
|
|
|
map.removeAction(name);
|
2022-09-26 19:09:02 +02:00
|
|
|
});
|
|
|
|
refs.clear();
|
|
|
|
}
|
|
|
|
|
2022-12-17 21:53:21 +01:00
|
|
|
private void addAction(String name, SimpleAction action) {
|
|
|
|
map.addAction(action);
|
|
|
|
refs.put(name, action);
|
2022-09-26 19:09:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public Menu getMenu() {
|
|
|
|
return menu;
|
|
|
|
}
|
|
|
|
|
|
|
|
public PopoverMenu asPopover() {
|
2022-12-17 21:53:21 +01:00
|
|
|
return PopoverMenu.newFromModel(menu);
|
2022-09-26 19:09:02 +02:00
|
|
|
}
|
|
|
|
}
|