Displaying text for actions

Hi,

Currently actions added to dockables appear with their icon (if any), and their text is shown as a tooltip. Also, their text appears whenever you right-click on the dockable tab.

Is it possible to display the text of actions instead of (or next to) their icon?

Although usually displaying text might be bulky and not practical, this could be useful in some special cases (whenever the action has no icon for example).

Thanks a lot,
Shant

At the moment you would need to implement a new button to show the text (this is possible, but requires some work), so the short answer is: no there is no simple solution.

It is a feature I was thinking of implementing. I will not make any promises, but I might have a closer look on it this or next weekend.

Thank you Beni!

I decided to have some fun and implement the feature. It is available in 1.1.1p6c (I’ll upload that version in the evening, the changes are already in the Git repository).

When using Common, you can call “setShowTextOnButtons” for any action, like in the example below. If you use Core you will have to install a “ButtonContentFilter” using “DockAction.BUTTON_CONTENT_FILTER” as key.

The buttons also support custom font and colors. If you need these things let me know, so I can write you some code explaining how to set up that customization.


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.dock.common.CControl;
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.theme.ThemeMap;

public class Dock12 {
	public static void main( String[] args ){
		JFrame frame = new JFrame();
		frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

		CControl control = new CControl( frame );
		
		control.setTheme( ThemeMap.KEY_ECLIPSE_THEME );
		
		frame.add( control.getContentArea() );
		
		DefaultSingleCDockable dockable = new DefaultSingleCDockable( "e", "E", createTestButton(), createTestButton() );
		control.addDockable( dockable );
		dockable.setVisible( true );
		
		frame.setBounds( 20, 20, 400, 400 );
		frame.setVisible( true );
	}
	
	public static class TestIcon implements Icon{
		@Override
		public void paintIcon( Component c, Graphics g, int x, int y ){
			g.setColor( Color.GREEN );
			g.fillOval( x, y, 16, 16 );
		}

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

		@Override
		public int getIconHeight(){
			return 16;
		}
	}
	
	public static CAction createTestButton(){
		final CButton button = new CButton( "Text", new TestIcon() );
		button.setTooltip( "Click me and I show/hide my text" );
		
		button.addActionListener( new ActionListener(){
			@Override
			public void actionPerformed( ActionEvent e ){
				button.setShowTextOnButtons( !button.isShowTextOnButtons() );
			}
		} );
		return button;
	}
}

Beni you are fantastic! Thank you so much! :smiley:

As for the font/color customization, sure I’ll be glad if you can show me a small demo (for the usage in Common), but it’s not something urgent, so please take your time.

Thanks again,
Shant

A “small” example showing how to work with the font. Colors are very similar, the example will follow soon.


import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;

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

import bibliothek.gui.dock.action.DockAction;
import bibliothek.gui.dock.common.CControl;
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.core.CommonDockAction;
import bibliothek.gui.dock.common.theme.ThemeMap;
import bibliothek.gui.dock.themes.font.ButtonFont;
import bibliothek.gui.dock.util.Priority;
import bibliothek.gui.dock.util.UIValue;
import bibliothek.gui.dock.util.font.DockFont;
import bibliothek.gui.dock.util.font.FontBridge;
import bibliothek.gui.dock.util.font.FontManager;
import bibliothek.gui.dock.util.font.FontModifier;
import bibliothek.gui.dock.util.font.GenericFontModifier;
import bibliothek.gui.dock.util.font.GenericFontModifier.Modify;

/**
 * How to set the font of a CAction in a button in 1.1.1p6c.
 * 
 * At the moment this feature is not supported directly by Common, instead clients need to install a 
 * filter (a instance of {@link FontBridge}) at the {@link FontManager} and decide for each {@link UIValue} 
 * what kind of {@link FontModifier} to apply.
 * 
 * The filter itself knows how is currently showing some text, and thus it can inform the components about
 * {@link FontModifier}s that change. In this example clicking on a button will trigger the update.
 */
public class Dock12 {
	public static void main( String[] args ){
		JFrame frame = new JFrame();
		frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

		CControl control = new CControl( frame );
		
		control.setTheme( ThemeMap.KEY_ECLIPSE_THEME );
		
		// here we install our new custom filter
		control.getController().getFonts().publish( Priority.CLIENT, ButtonFont.KIND_BUTTON_FONT, new TestFontBridge() );
		
		frame.add( control.getContentArea() );
		
		DefaultSingleCDockable dockable = new DefaultSingleCDockable( "e", "E", new TestButton(), new TestButton() );
		control.addDockable( dockable );
		dockable.setVisible( true );
		
		frame.setBounds( 20, 20, 400, 400 );
		frame.setVisible( true );
	}
	
	public static class TestIcon implements Icon{
		@Override
		public void paintIcon( Component c, Graphics g, int x, int y ){
			g.setColor( Color.GREEN );
			g.fillOval( x, y, 16, 16 );
		}

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

		@Override
		public int getIconHeight(){
			return 16;
		}
	}
	
	/**
	 * This listener is added to a {@link TestButton} and receives an event if the
	 * property {@link TestButton#customFont} changed.
	 */
	public static interface CustomActionListener{
		public void fontChanged( TestButton action );
	}
	
	/**
	 * A {@link CButton} with an additional property {@link #customFont}.
	 */
	public static class TestButton extends CButton{
		private List<CustomActionListener> listeners = new ArrayList<CustomActionListener>();
		private boolean customFont;
		
		public TestButton(){
			setText( "Text" );
			setTooltip( "Click me and I make my font bold and italic" );
			setShowTextOnButtons( true );
			setIcon( new TestIcon() );
			
			addActionListener( new ActionListener(){
				@Override
				public void actionPerformed( ActionEvent e ){
					setCustomFont( !isCustomFont() );
				}
			} );
		}
		
		public boolean isCustomFont(){
			return customFont;
		}
		
		public void setCustomFont( boolean customFont ){
			this.customFont = customFont;
			for( CustomActionListener listener : listeners ){
				listener.fontChanged( this );
			}
		}
		
		public void addCustomListener( CustomActionListener listener ){
			listeners.add( listener );
		}
		
		public void removeCustomListener( CustomActionListener listener ){
			listeners.remove( listener );
		}
	}
	
	/**
	 * This filter is put between the map containing all fonts, and the components that show some text.
	 * 
	 * This filter is not optimized: if some action is shown at n different locations, then any change of
	 * {@link TestButton#customFont} will be propagated n times to n different components. But it is very unusual if
	 * n is greater than 1, and as good as impossible that n is greater than 2. 
	 */
	public static class TestFontBridge implements FontBridge, CustomActionListener{
		private Collection<ButtonFont> uiValues = new HashSet<ButtonFont>();
		
		// we will receive "ButtonFont"s which act as observer, this method tells whether such an 
		// object represents one of our custom buttons.
		public TestButton getAction( ButtonFont value ){
			DockAction action = value.getAction();
			if( action instanceof CommonDockAction ){
				CAction commonAction = ((CommonDockAction)action).getAction();
				if( commonAction instanceof TestButton ){
					return (TestButton)commonAction;
				}
			}
			return null;
		}
		
		@Override
		public void add( String id, DockFont uiValue ){
			if( id.equals( DockFont.ID_BUTTON )){
				ButtonFont value = (ButtonFont)uiValue;
				TestButton button = getAction( value );
				if( button != null ){
					uiValues.add( value );
					button.addCustomListener( this );
				}
			}
		}

		@Override
		public void remove( String id, DockFont uiValue ){
			if( id.equals( DockFont.ID_BUTTON )){
				ButtonFont value = (ButtonFont)uiValue;
				TestButton button = getAction( value );
				if( button != null ){
					uiValues.remove( value );
					button.removeCustomListener( this );
				}
			}
		}

		@Override
		public void fontChanged( TestButton action ){
			// If the property of a button changes, we just update all observers that are associated with this action. 
			for( ButtonFont value : uiValues ){
				if( getAction( value ) == action ){
					set( value.getId(), null, value );
				}
			}
		}
		
		@Override
		public void set( String id, FontModifier value, DockFont uiValue ){
			TestButton button = getAction( (ButtonFont)uiValue );
			if( id.equals( DockFont.ID_BUTTON ) && button != null ){
				if( button.isCustomFont() ){
					GenericFontModifier modifier = new GenericFontModifier();
					modifier.setItalic( Modify.ON );
					modifier.setBold( Modify.ON );
					uiValue.set( modifier );
				}
				else{
					GenericFontModifier modifier = new GenericFontModifier();
					modifier.setItalic( Modify.OFF );
					modifier.setBold( Modify.OFF );
					uiValue.set( modifier );
				}
			}
			else{
				uiValue.set( value );
			}
		}
	}
}

And here the example for color, almost identical to the example for fonts:


import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;

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

import bibliothek.gui.dock.action.DockAction;
import bibliothek.gui.dock.common.CControl;
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.core.CommonDockAction;
import bibliothek.gui.dock.common.theme.ThemeMap;
import bibliothek.gui.dock.themes.color.ActionColor;
import bibliothek.gui.dock.util.Priority;
import bibliothek.gui.dock.util.color.ColorBridge;
import bibliothek.gui.dock.util.color.DockColor;

/**
 * This example shows how to play with custom colors for the text on buttons.
 * 
 * Custom colors are not directly supported by Common, so we have to use the methods offered by Core. In our
 * case we install a custom filter (an instanceof of "ColorBridge") which will modify the colors.
 */
public class Dock13 {
	public static void main( String[] args ){
		JFrame frame = new JFrame();
		frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

		CControl control = new CControl( frame );
		
		control.setTheme( ThemeMap.KEY_ECLIPSE_THEME );
		
		// here we install our new custom filter
		control.getController().getColors().publish( Priority.CLIENT, ActionColor.KIND_ACTION_COLOR, new TestColorBridge() );
		
		frame.add( control.getContentArea() );
		
		DefaultSingleCDockable dockable = new DefaultSingleCDockable( "e", "E", new TestButton(), new TestButton() );
		control.addDockable( dockable );
		dockable.setVisible( true );
		
		frame.setBounds( 20, 20, 400, 400 );
		frame.setVisible( true );
	}
	
	public static class TestIcon implements Icon{
		@Override
		public void paintIcon( Component c, Graphics g, int x, int y ){
			g.setColor( Color.GREEN );
			g.fillOval( x, y, 16, 16 );
		}

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

		@Override
		public int getIconHeight(){
			return 16;
		}
	}
	
	/**
	 * This listener is added to a {@link TestButton} and receives an event if the
	 * property {@link TestButton#customColor} changed.
	 */
	public static interface CustomActionListener{
		public void colorChanged( TestButton action );
	}
	
	/**
	 * A {@link CButton} with an additional property {@link #customColor}.
	 */
	public static class TestButton extends CButton{
		private List<CustomActionListener> listeners = new ArrayList<CustomActionListener>();
		private boolean customColor;
		
		public TestButton(){
			setText( "Text" );
			setTooltip( "Click me and I make my font bold and italic" );
			setShowTextOnButtons( true );
			setIcon( new TestIcon() );
			
			addActionListener( new ActionListener(){
				@Override
				public void actionPerformed( ActionEvent e ){
					setCustomColor( !isCustomColor() );
				}
			} );
		}
		
		public boolean isCustomColor(){
			return customColor;
		}
		
		public void setCustomColor( boolean customColor ){
			this.customColor = customColor;
			for( CustomActionListener listener : listeners ){
				listener.colorChanged( this );
			}
		}
		
		public void addCustomListener( CustomActionListener listener ){
			listeners.add( listener );
		}
		
		public void removeCustomListener( CustomActionListener listener ){
			listeners.remove( listener );
		}
	}
	
	/**
	 * This filter is responsible for modifying the color of buttons showing a {@link TestButton}.
	 */
	public static class TestColorBridge implements ColorBridge, CustomActionListener{
		private Collection<ActionColor> uiValues = new HashSet<ActionColor>();
		
		// we will receive "ButtonFont"s which act as observer, this method tells whether such an 
		// object represents one of our custom buttons.
		public TestButton getAction( ActionColor value ){
			DockAction action = value.getAction();
			if( action instanceof CommonDockAction ){
				CAction commonAction = ((CommonDockAction)action).getAction();
				if( commonAction instanceof TestButton ){
					return (TestButton)commonAction;
				}
			}
			return null;
		}
		
		@Override
		public void add( String id, DockColor uiValue ){
			ActionColor value = (ActionColor)uiValue;
			TestButton button = getAction( value );
			if( button != null ){
				uiValues.add( value );
				button.addCustomListener( this );
			}
		}

		@Override
		public void remove( String id, DockColor uiValue ){
			ActionColor value = (ActionColor)uiValue;
			TestButton button = getAction( value );
			if( button != null ){
				uiValues.remove( value );
				button.removeCustomListener( this );
			}
		}

		@Override
		public void colorChanged( TestButton action ){
			// If the property of a button changes, we just update all observers that are associated with this action. 
			for( ActionColor value : uiValues ){
				if( getAction( value ) == action ){
					set( value.getId(), null, value );
				}
			}
		}
		
		@Override
		public void set( String id, Color value, DockColor uiValue ){
			/*
			 * There are many possible values for "id". Have a look at these classes
			 * and their annotation "ColorCodes" to find all the different id's that are
			 * used:
			 * 
			 * MiniButton
			 * RoundRectButton
			 * RoundRectDropDownButton
			 * RoundButton
			 * RoundDropDownButton
			 */
			
			TestButton button = getAction( (ActionColor)uiValue );
			if( button != null ){
				if( button.isCustomColor() ){
					uiValue.set( Color.RED );
				}
				else{
					uiValue.set( null );
				}
			}
			else{
				uiValue.set( value );
			}
		}
	}
}

Thank you Beni for the generous examples!

I’ll take my time going through them. :slight_smile: