CWorkingArea

Hi Beni,

Using the dock.zip source you have provided and the updated code my application is working perfectly :slight_smile: Thank you!!!

Regarding the popupmenu on the dockable:
In my case, I may have different popupmenus on each dockable. And I don’t know, my application how many dockables has.

  1. Is it feasible, upon creation of the dockable to append elements on it’s popupmenu?
  2. Is it feasible to hide those additional menus from the title bar of the dokbales?

Thank you

You can add/remove actions from the (Default)DockActionSource at any time. The popup menu will be updated every time it is opened. You could also store one or more DockActionSources directly in your Dockable object, thus every Dockable could have its custom set of actions.

If you extend a DockAction you can override the „createView“ method and return null for those places where the action should not appear.

Hi,

You could also store one or more DockActionSources directly in your Dockable object, thus every Dockable could have its custom set of actions.

How could I implement this? Should I use

        source.add(new CustomAction());
        source.add(new CustomAction());
        source.add(new CustomAction());
       then how to set the actions into the dockable?

or

dockableA.insertAction(index, action)

or something else?

Thank you

Your requirements are kind of changing the entire time… what exactly do you want to do? With storing the source in the Dockables I meant making a subclass, like in the example below.

You could also use your second approach, but in that case the action would appear independent of the current location of the Dockable. And overriding “createView” gets harder because CActions are wrappers around DockActions - there is an additional level of indirection to cover.


import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;

import javax.swing.Icon;
import javax.swing.JFrame;

import bibliothek.gui.DockStation;
import bibliothek.gui.Dockable;
import bibliothek.gui.dock.StackDockStation;
import bibliothek.gui.dock.action.ActionGuard;
import bibliothek.gui.dock.action.DefaultDockActionSource;
import bibliothek.gui.dock.action.DockActionSource;
import bibliothek.gui.dock.action.LocationHint;
import bibliothek.gui.dock.action.actions.SimpleButtonAction;
import bibliothek.gui.dock.action.view.ActionViewConverter;
import bibliothek.gui.dock.action.view.ViewTarget;
import bibliothek.gui.dock.common.CContentArea;
import bibliothek.gui.dock.common.CControl;
import bibliothek.gui.dock.common.CLocation;
import bibliothek.gui.dock.common.DefaultSingleCDockable;
import bibliothek.gui.dock.common.intern.CDockable;
import bibliothek.gui.dock.common.intern.CommonDockable;

public class Dock70 {
	public static void main( String[] args ){
		JFrame frame = new JFrame();
		CControl control = new CControl( frame );

		// here we install our custom ActionGuard
		control.getController().addActionGuard( new CustomActionGuard() );

		frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
		frame.setBounds( 20, 20, 500, 400 );
		CContentArea area = control.getContentArea();
		frame.add( area );

		DefaultSingleCDockable dockableA = new CustomDockable( "test a", "Test A" );
		DefaultSingleCDockable dockableB = new CustomDockable( "test b", "Test B" );
		DefaultSingleCDockable dockableC = new CustomDockable( "test c", "Test C" );

		control.addDockable( dockableA );
		control.addDockable( dockableB );
		control.addDockable( dockableC );

		dockableA.setVisible( true );
		dockableB.setLocation( dockableA.getBaseLocation().aside() );
		dockableB.setVisible( true );
		dockableC.setLocation( CLocation.base().minimalEast() );
		dockableC.setVisible( true );

		frame.setVisible( true );
	}

	// Custom dockable storing some additional actions
	private static class CustomDockable extends DefaultSingleCDockable{
		private DefaultDockActionSource customActions;
		
		public CustomDockable( String id, String title ){
			super( id, title );
			
			customActions = new DefaultDockActionSource( new LocationHint( LocationHint.ACTION_GUARD, LocationHint.LEFT ) );
			customActions.add( new CustomAction() );
			customActions.add( new CustomAction() );
			customActions.add( new CustomAction() );
		}
		
		public DefaultDockActionSource getCustomActions(){
			return customActions;
		}
	}
	
	private static class CustomActionGuard implements ActionGuard{
		@Override
		public boolean react( Dockable dockable ){
			// We can define any rule we want to decide which dockable should receive
			// our actions and which should not

			// in this case we make sure only the dockable "dockableA/B/C" from the 
			// main-method receive the actions
			if( !(dockable instanceof CommonDockable) ){
				return false;
			}
			CDockable cdockable = ((CommonDockable)dockable).getDockable();
	
			DockStation parent = dockable.getDockParent();

			// and in your code this would be the class "CStackDockStation" and not
			// yust "StackDockStation"
			return parent instanceof StackDockStation && cdockable instanceof CustomDockable;
		}

		@Override
		public DockActionSource getSource( Dockable dockable ){
			return ((CustomDockable)((CommonDockable)dockable).getDockable()).getCustomActions();
		}
	}

	// there are a number of different actions available, but the button-action is the
	// most basic.
	private static class CustomAction extends SimpleButtonAction{
		public CustomAction(){
			setIcon( new RectIcon() );
			setText( "Hello" );
		}

		@Override
		public void action( Dockable dockable ){
			// note that these casts will always work because of the checks our CustomActionGuard performs
			DefaultSingleCDockable cdockable = (DefaultSingleCDockable)((CommonDockable)dockable).getDockable();
			System.out.println( "Ping: " + cdockable.getTitleText() );
		}
		
		@Override
		public <V> V createView( ViewTarget<V> target, ActionViewConverter converter, Dockable dockable ){
			if( target == ViewTarget.MENU || target == ViewTarget.DROP_DOWN ){
				return super.createView( target, converter, dockable );
			}
			else{
				return null;
			}
		}
	}

	// just add something to look at :-)
	private static class RectIcon implements Icon{
		public int getIconHeight(){
			return 16;
		}

		public int getIconWidth(){
			return 16;
		}

		public void paintIcon( Component c, Graphics g, int x, int y ){
			g.setColor( Color.GREEN );
			g.fillRect( x+1, y+1, 14, 14 );
		}
	}
}```

Hi,

Your requirements are kind of changing the entire time…

I’ll try to exaplain in details my requirements :slight_smile:
My framework offers the possibilty to the user to define popupmenus on each components. So my target is to add popup menus on my framework components.
Since my framework components are using DefaultSingleCDockable and CStack I need to define menus on those 2 components.
For the CStack, I will loop on its children DefaultSingleCDockable and add the popupmenu. In that way the popup menu will appear everywhere on the CStack

Note that in my framework, I have two types of menu items: static and dynamic

  1. static menu items : built initially on the creation of the components and used everytime the popupmenu is shown
  2. dynamic menu items: built every time the user right click on the components. Some business requires that the menu items changes based on the staus or time for example

For the static menu items and based on your example I can see the implementation. Any advice for the dynamic menu items? Is their any way to be notified when the user right click in order to show the popupmenu? something like menuwillbecomevisible notification?

what exactly do you want to do? With storing the source in the Dockables I meant making a subclass, like in the example below.

While reading the API, I noticed that for the Dockable class we can define ActionSource then add the ActionSource to the dockable. I thought this is what you are talking about

DefaultDockActionSource source = new DefaultDockActionSource(new LocationHint(LocationHint.DOCKABLE, LocationHint.LEFT));
source.add(new Action());
// Sets the below defined action to this Dockable
customDefaultDockable.setActionOffers(source);

But after reading your example (thank you for it), I got your point and I’m using the way you’ve provided in the example.

Thank you

Ok, now the picture is much clearer.

Dynamic menus: I’ll create a listener interface for that event, the menus are always created by the same code so a listener basically is 3 more lines of code. And once the listener exists you can update (or replace) the DockActionSources before the menu opens.

Hi,

I’m thinking of a work around, please advice if it works

Behind your “menu actions” implementation, and in order to display the actions in a popupmenu are you using a JPopupMenu?
If yes, is there any way to get this JPopupMenu?
For my side, it will be great , much easier and consistent with other component popupmenu implementation if I can add/remove directly to/from JPopupMenu directly.

Thank you

That can be arranged. I would add an interface that constructs the menu, and it is up to the interface how the menu really looks like (like all the other strategy-interfaces that float around).

Hi,

Thank you :slight_smile:

I’ll be waiting for the new interface

Ok, these are two new libraries for you to play around. I wanted to make the popup menus customizeable for some time, but I never started… so your request was very appreciated :wink:

An example is following shortly.

You can now set the “ActionPopupMenuFactory”, this factory creates new “ActionPopupMenu”. The ActionPopupMenu basically is a wrapper around JPopupMenu, but the framework is no longer interested in what exactly you use as menu (feel free to create a JFrame…).

These menus are used for all the popup menus that are ever shown by the framework: normal popup menus when the user right clicks onto a component, but also popup menus that appear when clicking on a MenuDockAction. You can distinguish the cases by looking at the “source” object that is given to the factory, exactly like in the example.


import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;

import javax.swing.Icon;
import javax.swing.JFrame;

import bibliothek.gui.Dockable;
import bibliothek.gui.dock.DockElementRepresentative;
import bibliothek.gui.dock.action.DefaultDockActionSource;
import bibliothek.gui.dock.action.DockActionSource;
import bibliothek.gui.dock.action.MultiDockActionSource;
import bibliothek.gui.dock.action.actions.SimpleButtonAction;
import bibliothek.gui.dock.action.popup.ActionPopupMenu;
import bibliothek.gui.dock.action.popup.ActionPopupMenuFactory;
import bibliothek.gui.dock.action.popup.DefaultActionPopupMenu;
import bibliothek.gui.dock.common.CContentArea;
import bibliothek.gui.dock.common.CControl;
import bibliothek.gui.dock.common.CLocation;
import bibliothek.gui.dock.common.DefaultSingleCDockable;
import bibliothek.gui.dock.common.action.CDropDownButton;
import bibliothek.gui.dock.common.action.CMenu;
import bibliothek.gui.dock.common.intern.CommonDockable;

public class Dock71 {
	public static void main( String[] args ){
		JFrame frame = new JFrame();
		CControl control = new CControl( frame );

		// installing our custom menu factory
		control.getController().setPopupMenuFactory( new CustomPopupFactory() );
		control.getController().getPopupController().setAllowEmptyMenu( true );
		
		frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
		frame.setBounds( 20, 20, 500, 400 );
		CContentArea area = control.getContentArea();
		frame.add( area );

		DefaultSingleCDockable dockableA = new DefaultSingleCDockable( "test a", "Test A" );
		DefaultSingleCDockable dockableB = new DefaultSingleCDockable( "test b", "Test B" );
		DefaultSingleCDockable dockableC = new DefaultSingleCDockable( "test c", "Test C" );

		// these menus should not be affected
		dockableA.addAction( new CMenu( "Test", new RectIcon() ) );
		dockableA.addAction( new CDropDownButton( "Test2", new RectIcon() ) );
		
		control.addDockable( dockableA );
		control.addDockable( dockableB );
		control.addDockable( dockableC );

		dockableA.setVisible( true );
		dockableB.setLocation( dockableA.getBaseLocation().aside() );
		dockableB.setVisible( true );
		dockableC.setLocation( CLocation.base().minimalEast() );
		dockableC.setVisible( true );

		frame.setVisible( true );
	}
	
	// this is our custom menu factory. Clients are completely free in how the menu should look like, they
	// can even choose not to use a JPopupMenu at all.
	private static class CustomPopupFactory implements ActionPopupMenuFactory{
		@Override
		public ActionPopupMenu createMenu( Component owner, Dockable dockable, DockActionSource actions, Object source ){
			if( !(source instanceof DockElementRepresentative )){
				return new DefaultActionPopupMenu( dockable, actions );	
			}
			
			DefaultDockActionSource newActions = new DefaultDockActionSource();
			newActions.add( new CustomAction() );
			newActions.add( new CustomAction() );
			newActions.add( new CustomAction() );
			
			MultiDockActionSource finalActions = new MultiDockActionSource( newActions, actions );
			
			return new DefaultActionPopupMenu( dockable, finalActions );
		}
	}
	
	// there are a number of different actions available, but the button-action is the
	// most basic.
	private static class CustomAction extends SimpleButtonAction{
		public CustomAction(){
			setIcon( new RectIcon() );
			setText( "Hello" );
		}

		@Override
		public void action( Dockable dockable ){
			// note that these casts will always work because of the checks our CustomActionGuard performs
			DefaultSingleCDockable cdockable = (DefaultSingleCDockable)((CommonDockable)dockable).getDockable();
			System.out.println( "Ping: " + cdockable.getTitleText() );
		}
	}

	// just add something to look at :-)
	private static class RectIcon implements Icon{
		public int getIconHeight(){
			return 16;
		}

		public int getIconWidth(){
			return 16;
		}

		public void paintIcon( Component c, Graphics g, int x, int y ){
			g.setColor( Color.GREEN );
			g.fillRect( x+1, y+1, 14, 14 );
		}
	}
}```

Thank you… I’m working with the new code, still not finished my implementation… I’ll keep you updated

How can I set the south station as a default flap station?
For example, if in the example above, I minimize a dockable, it will directly go to the north station at left. Is it feasible to customize it to go initially to the south flap station and if possible at right?

Thank you

Currently the only option is to set the default location of each dockable like this:

		control.getLocationManager().setLocation( cdockable.intern(), ExtendedMode.MINIMIZED, CLocation.base().minimalSouth() );```
... you'll need to have the dockable registered at the CControl, otherwise no meta information is stored for it.

Hi,

Thank you. It is working fine

In the below example, how can I add the below restriction:

  1. I don’t want to drag a screen from it’s CStack to the “log” CStack and vice versa
  2. I don’t want to enable the drag of a screen to near the Navigation dockable
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

import bibliothek.gui.DockController;
import bibliothek.gui.DockStation;
import bibliothek.gui.Dockable;
import bibliothek.gui.dock.StackDockStation;
import bibliothek.gui.dock.action.DockActionSource;
import bibliothek.gui.dock.common.CContentArea;
import bibliothek.gui.dock.common.CControl;
import bibliothek.gui.dock.common.CGrid;
import bibliothek.gui.dock.common.CLocation;
import bibliothek.gui.dock.common.CStation;
import bibliothek.gui.dock.common.DefaultSingleCDockable;
import bibliothek.gui.dock.common.SingleCDockable;
import bibliothek.gui.dock.common.group.CGroupBehavior;
import bibliothek.gui.dock.common.intern.AbstractDockableCStation;
import bibliothek.gui.dock.common.intern.CControlAccess;
import bibliothek.gui.dock.common.intern.CDockable;
import bibliothek.gui.dock.common.intern.CommonDockable;
import bibliothek.gui.dock.common.intern.station.CommonDockStation;
import bibliothek.gui.dock.common.intern.ui.CSingleParentRemover;
import bibliothek.gui.dock.common.mode.CNormalModeArea;
import bibliothek.gui.dock.common.mode.ExtendedMode;
import bibliothek.gui.dock.common.perspective.CStationPerspective;
import bibliothek.gui.dock.common.theme.ThemeMap;
import bibliothek.gui.dock.event.DockStationAdapter;
import bibliothek.gui.dock.facile.mode.Location;
import bibliothek.gui.dock.facile.mode.LocationMode;
import bibliothek.gui.dock.facile.mode.ModeAreaListener;
import bibliothek.gui.dock.layout.DockableProperty;
import bibliothek.gui.dock.support.mode.AffectedSet;
import bibliothek.gui.dock.util.DirectWindowProvider;
import bibliothek.gui.dock.util.DockUtilities;

import bibliothek.util.Path;


public class Dock65 {
    private static Integer counter = 1;


    public Dock65() {
    }


    public static void main(String[] args) { 
        JFrame frame = new JFrame();
        final CControl control = new CControl();
        control.setGroupBehavior(CGroupBehavior.TOPMOST);
        CContentArea contentArea = control.getContentArea();
        final CGrid grid = new CGrid(control);
        control.getController().setSingleParentRemover(new CustomSingleParentRemover(control));
        control.setTheme(ThemeMap.KEY_ECLIPSE_THEME);
        control.setRootWindow(new DirectWindowProvider(frame));
        CStack consolestack = new CStack("Navigation");
        consolestack.setHideIfEmpty(true);
        control.addStation(consolestack, true);

        DefaultSingleCDockable dockable = new DefaultSingleCDockable("Log");
        dockable.setCloseable(true);
        // Set the title of a dockable
        dockable.setTitleText("Log");
        control.addDockable(dockable);
        consolestack.getStation().add(dockable.intern(), 0);
//        dockable.setWorkingArea(consolestack);
        dockable.setVisible(true);
        grid.add(0, 50, 50, 15, consolestack);
        control.getContentArea().deploy(grid);

        NaviagtionCDockable navigationDockable = new NaviagtionCDockable("Tree");
        grid.add(0, 11, 2, 40, navigationDockable);
        navigationDockable.setTitleText("Navigation");
        control.getContentArea().deploy(grid);

        final CStack screensstack = new CStack("screens");
        control.addStation(screensstack, true);
        grid.add(40, 11, 48, 40, screensstack);
        control.getContentArea().deploy(grid);
        navigationDockable.getOpenScreen().addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    String id = "Title " + counter++;
                    DefaultSingleCDockable dockable = new DefaultSingleCDockable(id, id);
                    control.addDockable(dockable);
                    screensstack.getStation().add(dockable.intern(), 0);
                    dockable.setCloseable(true);
                    dockable.setWorkingArea(screensstack);
                    dockable.setVisible(true);
                }
            });
        frame.add(contentArea);
        frame.setSize(500, 500);
        frame.setVisible(true);
    }


    private static class CStack extends AbstractDockableCStation<StackDockStation> implements CNormalModeArea, SingleCDockable {
        private boolean hideIfEmpty;


        public CStack(String id) {
            CStackDockStation delegate = new CStackDockStation(this);
            CLocation stationLocation = new CLocation() {
                @Override
                public CLocation getParent() {
                    return null;
                }

                @Override
                public String findRoot() {
                    return getUniqueId();
                }

                @Override
                public DockableProperty findProperty(DockableProperty successor) {
                    return successor;
                }

                @Override
                public ExtendedMode findMode() {
                    return ExtendedMode.NORMALIZED;
                }

                @Override
                public CLocation aside() {
                    return this;
                }
            };
            init(delegate, id, stationLocation, delegate);
        }


        public void setHideIfEmpty(boolean hideIfEmpty) {
            this.hideIfEmpty = hideIfEmpty;
        }

        @Override
        public CStationPerspective createPerspective() { /* For this example we do not support perspectives. */
            throw new IllegalStateException("not implemented");
        }

        @Override
        public boolean isNormalModeChild(Dockable dockable) {
            return isChild(dockable);
        }

        @Override
        public DockableProperty getLocation(Dockable child) {
            return DockUtilities.getPropertyChain(getStation(), child);
        }

        @Override
        public void setLocation(Dockable dockable, DockableProperty location, AffectedSet set) {
            set.add(dockable);
            if (isChild(dockable)) {
                getStation().move(dockable, location);
            } else {
                if (!getStation().drop(dockable, location)) {
                    getStation().drop(dockable);
                }
            }
        }

        @Override
        public void addModeAreaListener(ModeAreaListener listener) {
            // not required
        }

        @Override
        public Path getTypeId() {
            // not required
            return null;
        }

        @Override
        public boolean autoDefaultArea() {
            return true;
        }

        @Override
        public boolean isChild(Dockable dockable) {
            return dockable.getDockParent() == getStation();
        }

        @Override
        public void removeModeAreaListener(ModeAreaListener listener) {
            // not required
        }

        @Override
        public void setController(DockController controller) {
            // ignore
        }

        @Override
        public void setMode(LocationMode mode) {
            // ignore
        }

        @Override
        public CLocation getCLocation(Dockable dockable) {
            DockableProperty property = DockUtilities.getPropertyChain(getStation(), dockable);
            return getStationLocation().expandProperty(property);
        }

        @Override
        public CLocation getCLocation(Dockable dockable, Location location) {
            DockableProperty property = location.getLocation();
            if (property == null) {
                return getStationLocation();
            }
            return getStationLocation().expandProperty(property);
        }

        @Override
        public boolean respectWorkingAreas() {
            return false;
        }

        @Override
        public boolean isCloseable() {
            return false;
        }

        @Override
        public boolean isExternalizable() {
            return false;
        }

        @Override
        public boolean isMaximizable() {
            return false;
        }

        @Override
        public boolean isMinimizable() {
            return false;
        }

        @Override
        public boolean isStackable() {
            return false;
        }

        @Override
        public boolean isWorkingArea() {
            return false;
        }

        public boolean hideIfEmpty() {
            return hideIfEmpty;
        }

        public DockActionSource[] getSources() {
            return new DockActionSource[] { getClose() };
        }

        /* This method is called by the CControl and allows access to some inner API that is
         * * * hidden from normal clients. */
        @Override
        protected void install(CControlAccess access) {
            access.getLocationManager().getNormalMode().add(this);
        }

        @Override
        protected void uninstall(CControlAccess access) {
            access.getLocationManager().getNormalMode().remove(getUniqueId());
        }
    }

    private static class CStackDockStation extends StackDockStation implements CommonDockStation<StackDockStation, CStackDockStation>, CommonDockable {

        private CStack delegate;


        public CStackDockStation(CStack stack) {
            this.delegate = stack;
            final Runnable makeVisible = new Runnable() {
                @Override
                public void run() {
                    delegate.setVisible(true);
                }
            };
            DockUtilities.disableCheckLayoutLocked();
            addDockStationListener(new DockStationAdapter() {
                    @Override
                    public void dockableAdded(DockStation station, Dockable dockable) {
                        DockController controller = delegate.getControl().getOwner().getController();
                        controller.getHierarchyLock().onRelease(makeVisible);
                    }
                });
        }


        @Override
        public CDockable getDockable() {
            return delegate;
        }

        @Override
        public DockActionSource[] getSources() {
            return delegate.getSources();
        }

        @Override
        public CStation<StackDockStation> getStation() {
            return delegate;
        }

        @Override
        public StackDockStation getDockStation() {
            return this;
        }

        @Override
        public CStackDockStation asDockStation() {
            return this;
        }

        @Override
        public CommonDockable asDockable() {
            return this;
        }
    }

    private static class NaviagtionCDockable extends DefaultSingleCDockable {
        JButton openScreenBtn = new JButton();
        private JPanel panel = new JPanel();


        public NaviagtionCDockable(String title) {
            super(title);
            setTitleText(title);
            panel = new JPanel();
            panel.setOpaque(true);
            add(panel);
            openScreenBtn = new JButton("Open screen");
            panel.add(openScreenBtn);
        }


        public JButton getOpenScreen() {
            return openScreenBtn;
        }
    }

    private static class CustomSingleParentRemover extends CSingleParentRemover {
        public CustomSingleParentRemover(CControl control) {
            super(control);
        }


        @Override
        protected boolean shouldTest(DockStation station) {
            if (isCStack(station)) {
                return true;
            }
            return super.shouldTest(station);
        }

        @Override
        protected boolean test(DockStation station) {
            if (isCStack(station)) {
                if ((station.getDockableCount() > 0) || (station.asDockable().getDockParent() == null)) {
                    return false;
                } else {
                    CStack stack = (CStack) ((CommonDockStation<?, ?>) station).getStation();
                    // stack.setVisible(false);  this line caused problems, let's do this manually
                    Dockable dockable = station.asDockable();
                    stack.getControl().getLocationManager().store(dockable);
                    stack.getControl().getOwner().intern().hide(dockable);
                    return false;
                        // because CStack is a root station
                }
            }
            return super.test(station);
        }

        private boolean isCStack(DockStation station) {
            if (station instanceof CommonDockStation<?, ?>) {
                if (((CommonDockStation<?, ?>) station).getStation() instanceof CStack) {
                    return true;
                }
            }
            return false;
        }
    }
}

Thank you

Sorry for the delay. Such problems are best solved with a DockAcceptance. Implement the interface, forbid any combination of stations and Dockable you don’t want, install the interface with “DockController.addAcceptance”.

Hi,

Could you please advice how can I add a tooltip to the dockable title?

For example, In Eclipse, Internet Explorer or Chrome, if I put the mouse over the tab title I got a tooltip

Thanks

There is a method “DefaultCDockable.setTitleToolTip” which sets a tooltip. I just checked, the EclipseTheme does not support the tooltip, I’ll add/fix that feature during the weekend.

Thank you for your answer, I’ll be waiting for that feature

Thanks

Hi,

Any news regarding this issue?

Thanks

It is implemented now, I just did not yet upload the new library. I’ll upload the library today or tomorrow.