package io.gitlab.jfronny.inceptum.gtk.util; import io.github.jwharm.javagi.*; import io.gitlab.jfronny.inceptum.gtk.GtkMain; import io.gitlab.jfronny.inceptum.gtk.callback.*; import org.gtk.gio.ListModel; import org.gtk.gio.ListModelInterface; import org.gtk.glib.Type; import org.gtk.gobject.*; import org.gtk.gtk.*; import java.lang.foreign.*; import java.lang.invoke.VarHandle; public class ListIndex extends GObject { private static final int PROP_ITEM_TYPE = 1; private static final String PROP_NAME = "item-type"; private static final String TYPE_NAME = "ListIndex"; private static final Type PARENT_TYPE = GObject.getType(); private static final MemoryLayout memoryLayout = MemoryLayout.structLayout( GObject.getMemoryLayout().withName("parent_instance"), Interop.valueLayout.C_INT.withName("index"), Interop.valueLayout.C_INT.withName("size") ).withName(TYPE_NAME); private static Type type; public static Type getType() { if (type == null) { // Register the new gtype type = GObjects.typeRegisterStaticSimple( PARENT_TYPE, TYPE_NAME, (short) ObjectClass.getMemoryLayout().byteSize(), classInit, (short) memoryLayout.byteSize(), instanceInit, TypeFlags.NONE ); GObjects.typeAddInterfaceStatic(type, ListModel.getType(), InterfaceInfo.builder() .setInterfaceInit(interfaceInit) .setInterfaceData(null) .setInterfaceFinalize(null) .build()); } return type; } private static final VarHandle index = memoryLayout.varHandle(MemoryLayout.PathElement.groupElement("index")); private static final VarHandle size = memoryLayout.varHandle(MemoryLayout.PathElement.groupElement("size")); public static ListIndex castFrom(GObject gobject) { if (GObjects.typeCheckInstanceIsA(TypeInstance.fromAddress.marshal(gobject.handle(), Ownership.NONE), getType())) { return new ListIndex(gobject.handle(), gobject.yieldOwnership()); } else { throw new ClassCastException("Object type is not an instance of ListIndex"); } } public static final Marshal fromAddress = (input, ownership) -> input.equals(MemoryAddress.NULL) ? null : new ListIndex(input, ownership); protected ListIndex(Addressable address, Ownership ownership) { super(address, ownership); } public ListIndex(int size) { this(); setSizeIntenal(size); } public ListIndex() { super(new GObject(getType(), PROP_NAME, getType()).handle(), Ownership.FULL); } private static final InstanceInitFunc instanceInit = (instance, gClass) -> fromAddress.marshal(instance.handle(), Ownership.NONE).initInstance(); private void initInstance() { setIndex(0); setSizeIntenal(0); } private static TypeClass parentClass = null; private static final DisposeCallback instanceDispose = pointer -> { if (parentClass == null) System.out.println("ListIndex::instanceDispose (no parent)"); else { InteropException ie = new InteropException("Could not dispose ListIndex"); GtkMain.schedule(() -> { try { var func = (MemoryAddress) ObjectClass.getMemoryLayout() .varHandle(MemoryLayout.PathElement.groupElement("dispose")) .get(MemorySegment.ofAddress(parentClass.handle().address(), ObjectClass.getMemoryLayout().byteSize(), Interop.getScope())); var linked = Linker.nativeLinker().downcallHandle(func, DisposeCallback.DESCRIPTOR); linked.invoke(pointer); } catch (Throwable e) { throw (InteropException) ie.initCause(e); } }); } }; private static final SetPropertyCallback setProperty = (object, propertyId, value, paramSpec) -> { if (propertyId != PROP_ITEM_TYPE) System.out.println("ListIndex::setProperty (unknown property)"); }; private static final GetPropertyCallback getProperty = (object, propertyId, value, paramSpec) -> { if (propertyId == PROP_ITEM_TYPE) value.setGtype(getType()); else System.out.println("ListIndex::getProperty (unknown property)"); }; private static final ClassInitFunc classInit = (klass, data) -> { System.out.println("ListIndex::classInit"); parentClass = klass.peekParent(); ObjectClass objectClass = ObjectClass.fromAddress.marshal(GObjects.typeCheckClassCast(klass, PARENT_TYPE).handle(), Ownership.NONE); objectClass.setDispose(instanceDispose.toCallback()); objectClass.setGetProperty(getProperty.toCallback()); objectClass.setSetProperty(setProperty.toCallback()); ParamSpec paramType = GObjects.paramSpecGtype(PROP_NAME, "", "", PARENT_TYPE, ParamFlags.CONSTRUCT .or(ParamFlags.READWRITE, ParamFlags.STATIC_NAME, ParamFlags.STATIC_NICK, ParamFlags.STATIC_BLURB) ); objectClass.installProperty(PROP_ITEM_TYPE, paramType); }; private static final GetItemTypeCallback getItemType = address -> { System.out.println("ListIndex::getItemType"); return getType().getValue(); }; private static final GetNItemsCallback getNItems = address -> fromAddress.marshal(address, Ownership.NONE).getSize(); private static final GetItemCallback getItem = (inst, position) -> { ListIndex item = fromAddress.marshal(inst, Ownership.NONE).getItem(position); if (item == null) return MemoryAddress.NULL; return item.handle(); }; public ListIndex getItem(int position) { if (position >= getSize() || position <= -1) return null; ListIndex result = new ListIndex(getSize()); result.setIndex(position); return result; } private static final InterfaceInitFunc interfaceInit = (iface, data) -> { System.out.println("ListIndex::interfaceInit"); ListModelInterface lmi = ListModelInterface.fromAddress.marshal(iface.handle(), Ownership.NONE); lmi.setGetItem(getItem.toCallback()); lmi.setGetNItems(getNItems.toCallback()); lmi.setGetItemType(getItemType.toCallback()); }; public int getIndex() { return (int) ListIndex.index.get(MemorySegment.ofAddress((MemoryAddress) handle(), memoryLayout.byteSize(), Interop.getScope())); } public void setIndex(int index) { ListIndex.index.set(MemorySegment.ofAddress((MemoryAddress) handle(), memoryLayout.byteSize(), Interop.getScope()), index); } public int getSize() { return (int) ListIndex.size.get(MemorySegment.ofAddress((MemoryAddress) handle(), memoryLayout.byteSize(), Interop.getScope())); } public void setSize(int size) { int oldSize = getSize(); setSizeIntenal(size); asListModel().itemsChanged(0, oldSize, size); } private void setSizeIntenal(int size) { ListIndex.size.set(MemorySegment.ofAddress((MemoryAddress) handle(), memoryLayout.byteSize(), Interop.getScope()), size); } public ListModel asListModel() { return ListModel.castFrom(this); } public SingleSelection inSingleSelection() { return new SingleSelection(asListModel()); } public SelectionModel inSelectionModel() { return SelectionModel.castFrom(inSingleSelection()); } public static int toIndex(ListItem item) { return castFrom(item.getItem()).getIndex(); } }