CDropDownButton new feature request

Hi Beni,

We once discussed, in a previous forum, CMenus and CDropDownButtons.

And we explained that DropDownButtons have the additional feature of saving the action of the last child menu element clicked, so that further clicks of the dropDownButton will take that saved action, instead of displaying the child menu elements. In order to display the children elements, one would then click on the adjacent arrow.

So far so good :slight_smile:

Now, what I’m looking for, is something (I think called SplitButton), very similar to CDropDownButton, with a little twist.

Instead of saving the action of the last child menu element clicked, I want to bind some default action to this (let’s call split) splitButton.

Hence, a splitButton:
-would look exactly like a CDropDownButton
-clicking on the button part will never show the children (maybe except if no default action is attached)
-instead, clicking on the button part will always take a predefined action (which might be that of one of the child menu elements, but which will never change based on history)
-finally, the adjacent arrow will serve to display its children.

An example of this sort of button is the „New“ drop-down button in the toolbar of eclipse.

Whereas the „Run“ dropDownButton has a behavior similar to that of a CDropDownButton (i.e. runs latest selected run), clicking the „New“ button always triggers the same action (New wizard), regardless of selection history.

Thanks a lot,
Shant

If you have an action like a CButton, call “setDropDownSelectable(false)” and this action will no longer appear on the CDropDownButton itself.

Choose one child where you set “drop down selectable” to “true”, and use “CDropDownButton.setSelection” to preselect this child.

That should already be the behavior you just described.

Fair enough :slight_smile:

But what if the drop-down needs to take an action different from all of its children?

This is the case of the Print drop-down, for instance, in Internet Explorer (see attachment). Clicking on the button part of Print takes an action different from all of its three child menu items.

Hm, ohm, this is a bit of a hack but it could work: create a button that cannot be shown in a menu (hence not in a drop-down-menu), but add it to the drop-down-action anyway and call the “setSelection” method with it.

We already spoke a little bit how to create a button that does not appear everywhere, here.

Hi Beni,

Well, I had thought of a similar workaround too: i.e. same idea of having an additional child menu item, calling „setSelection“ on the drop-down menu to preselect it, and finally hiding this item. Except that, to hide the menu item, I didn’t think at that time of making it „cannot be shown“ as you once explained here, but instead use the setVisible API you recently provided.

However, I was surprised that when the action was set to invisible (using setVisible which uses the VisibilityFilters, etc.), this trick didn’t work anymore, in other words, the drop-down couldn’t take the action of an invisible menu item!

First question: why is that?

Since the method above didn’t work, I tried to make the menu item „cannot be shown“ as you once explained here, as follows:

I created a subclass of CommonSimpleButtonAction (which I called InvisibleCommonSimpleButtonAction) in which I just did an Override of createView to always return null (since in this case, I want my ‚hack‘ menu item invisible everywhere).

Then I created a class called InvisibleCButton, in which I copied the code of CButton, except that I changed the second line of the default constructor to:
init(new InvisibleCommonSimpleButtonAction(this));

Second question: are the steps described above correct so far?

However, the trick didn’t work here neither. In other words, the drop-down couldn’t take the action of a menu item whose createView returns null. Or at least I couldn’t :confused:

Third question: did I do anything wrong? did you try the trick you suggested and it worked?

Thanks a lot,
Shant

No, I did not test the workaround. It just sounded like it should work without problems.

The steps look ok, and the drop-down-button itself should not care about the “createView” method because it copies text and icon directly.

Anyway, I’ll try to implement this workaround and report back in the evening.

I have to admit, there were some issues. Seems like the drop-down-button did not like actions without view. I’ve updated the drop-down-button, now it works. Here are the new files. And here is a test:


import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

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

import bibliothek.gui.Dockable;
import bibliothek.gui.dock.action.view.ActionViewConverter;
import bibliothek.gui.dock.action.view.ViewTarget;
import bibliothek.gui.dock.common.CControl;
import bibliothek.gui.dock.common.CLocation;
import bibliothek.gui.dock.common.DefaultSingleCDockable;
import bibliothek.gui.dock.common.action.CAction;
import bibliothek.gui.dock.common.action.CButton;
import bibliothek.gui.dock.common.action.CDropDownButton;
import bibliothek.gui.dock.common.action.core.CommonSimpleButtonAction;
import bibliothek.gui.dock.themes.basic.action.dropdown.ButtonDropDownHandler;

public class DropDownButtonTest {
	public static void main( String[] args ){
		JFrame frame = new JFrame();
		frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
		CControl control = new CControl( frame );
		frame.add( control.getContentArea() );

		DefaultSingleCDockable dockable = new DefaultSingleCDockable( "d", "Dockable" );
		control.addDockable( dockable );
		dockable.setLocation( CLocation.base().normal() );
		dockable.setVisible( true );

		CDropDownButton menu = new CDropDownButton();
		InvisibleCButton button = new InvisibleCButton( "Hallo", new TestIcon( Color.RED ) );
		button.addActionListener( new ActionListener(){
			@Override
			public void actionPerformed( ActionEvent e ){
				System.out.println( "hallo" );
			}
		} );

		menu.add( button );
		menu.setSelection( button );

		CButton dropButton1 = new CButton( "Test 1", new TestIcon( Color.GRAY ) );
		CButton dropButton2 = new CButton( "Test 1", new TestIcon( Color.DARK_GRAY ) );

		dropButton1.setDropDownSelectable( false );
		dropButton2.setDropDownSelectable( false );

		dropButton1.addActionListener( new ActionListener(){
			@Override
			public void actionPerformed( ActionEvent e ){
				System.out.println( "Test 1" );
			}
		} );
		
		dropButton2.addActionListener( new ActionListener(){
			@Override
			public void actionPerformed( ActionEvent e ){
				System.out.println( "Test 2" );
			}
		} );
		
		menu.add( dropButton1 );
		menu.add( dropButton2 );

		dockable.addAction( menu );

		frame.setBounds( 20, 20, 400, 300 );
		frame.setVisible( true );
	}

	public static class TestIcon implements Icon {
		private Color color;

		public TestIcon( Color color ){
			this.color = color;
		}

		@Override
		public void paintIcon( Component c, Graphics g, int x, int y ){
			g.setColor( color );
			g.fillOval( x, y, 15, 15 );
		}

		@Override
		public int getIconWidth(){
			return 16;
		}

		@Override
		public int getIconHeight(){
			return 16;
		}
	}

	private static class InvisibleCButton extends CButton {
		public InvisibleCButton( String text, Icon icon ){
			super( null );
			init( new InvisibleCommonSimpleButtonAction( this ) );
			setText( text );
			setIcon( icon );
		}
	}

	private static class InvisibleCommonSimpleButtonAction extends CommonSimpleButtonAction {
		public InvisibleCommonSimpleButtonAction( CAction action ){
			super( action );
		}

		@Override
		public <V> V createView( ViewTarget<V> target, ActionViewConverter converter, Dockable dockable ){
			if( target == ViewTarget.DROP_DOWN ) {
				return (V) new ButtonDropDownHandler( this, dockable, null );
			}
			else {
				return null;
			}
		}
	}
}

Hi Beni,

Too bad I didn’t see your latest post till now. I think because I didn’t check the previous post while logged in, so I didn’t receive an email notification about this one. :frowning:

Anyway, thank you Beni, yup it seems the workaround works now.

However, there still seem to be some issues: right-clicking on the dockable to see the actions in pop-up is throwing a NullPointerException (in case an InvisibleCButton is used, of course).

Thanks a lot,
Shant

Oh damn, of course it does, should have had that idea myself. I’ll upload the fix tomorrow.

Ok, the new version is online. Again in the temp folder. You will you will not be able to click on the invisible button if you make a right click - mostly because it is invisible.

Hi Beni,

Unfortunately, I still get the same Exception.

Are you sure the link you provided points to the updated files? It seems like the same link as before.

Thanks,
Shant

Hi again,

Indeed, the problem was just the link. I downloaded latest revision from github, and it works now.

Thank you Beni, I’ll get back to you in case I encounter some other issue.

Thanks again,
Shant

Sorry, I was certain that I replaced the file. Maybe I did not. Anyway, good to know you got the right version.

Thank you Beni!