More widening.
git-svn-id: https://samskivert.googlecode.com/svn/trunk@2516 6335cc39-0255-0410-8fd6-9bcaacd3b74c
This commit is contained in:
@@ -44,15 +44,14 @@ import com.samskivert.util.ObserverList;
|
|||||||
import com.samskivert.util.RunAnywhere;
|
import com.samskivert.util.RunAnywhere;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides a radial menu with iconic menu items that expand to include
|
* Provides a radial menu with iconic menu items that expand to include textual descriptions when
|
||||||
* textual descriptions when moused over.
|
* moused over.
|
||||||
*/
|
*/
|
||||||
public class RadialMenu
|
public class RadialMenu
|
||||||
implements MouseMotionListener, MouseListener
|
implements MouseMotionListener, MouseListener
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* The interface used to communicate back to the component that hosts
|
* The interface used to communicate back to the component that hosts this menu.
|
||||||
* this menu.
|
|
||||||
*/
|
*/
|
||||||
public static interface Host
|
public static interface Host
|
||||||
{
|
{
|
||||||
@@ -62,10 +61,9 @@ public class RadialMenu
|
|||||||
public Component getComponent ();
|
public Component getComponent ();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Requests the bounds of the visible region in which we'll be
|
* Requests the bounds of the visible region in which we'll be rendering the menu. The menu
|
||||||
* rendering the menu. The menu will be constrained to fit within
|
* will be constrained to fit within these bounds starting with a natural position around
|
||||||
* these bounds starting with a natural position around the
|
* the supplied target bounds and adjusting minimally to fit.
|
||||||
* supplied target bounds and adjusting minimally to fit.
|
|
||||||
*/
|
*/
|
||||||
public Rectangle getViewBounds ();
|
public Rectangle getViewBounds ();
|
||||||
|
|
||||||
@@ -75,34 +73,30 @@ public class RadialMenu
|
|||||||
public void repaintRect (int x, int y, int width, int height);
|
public void repaintRect (int x, int y, int width, int height);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instructs the host component to stop rendering this menu
|
* Instructs the host component to stop rendering this menu because it has been popped
|
||||||
* because it has been popped down.
|
* down.
|
||||||
*/
|
*/
|
||||||
public void menuDeactivated (RadialMenu menu);
|
public void menuDeactivated (RadialMenu menu);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to determine at the time that a menu is shown, whether its
|
* Used to determine at the time that a menu is shown, whether its items should be included
|
||||||
* items should be included and/or enabled. Predicate methods are
|
* and/or enabled. Predicate methods are called immediately before showing a radial menu and
|
||||||
* called immediately before showing a radial menu and thus should not
|
* thus should not perform complicated computations. They generally will check some simple
|
||||||
* perform complicated computations. They generally will check some
|
* model to determine a menu item's status.
|
||||||
* simple model to determine a menu item's status.
|
|
||||||
*/
|
*/
|
||||||
public static interface Predicate
|
public static interface Predicate
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* If true, the menu will be included in the character menu when
|
* If true, the menu will be included in the character menu when it is displayed.
|
||||||
* it is displayed.
|
|
||||||
*
|
*
|
||||||
* @param menu the menu that will include or not include the item
|
* @param menu the menu that will include or not include the item in question.
|
||||||
* in question.
|
|
||||||
* @param item the menu item that will or will not be included.
|
* @param item the menu item that will or will not be included.
|
||||||
*/
|
*/
|
||||||
public boolean isIncluded (RadialMenu menu, RadialMenuItem item);
|
public boolean isIncluded (RadialMenu menu, RadialMenuItem item);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If true, the menu will be enabled when displayed in a
|
* If true, the menu will be enabled when displayed in a character's menu.
|
||||||
* character's menu.
|
|
||||||
*
|
*
|
||||||
* @param menu the menu that contains the item in question.
|
* @param menu the menu that contains the item in question.
|
||||||
* @param item the menu item that will or will not be enabled.
|
* @param item the menu item that will or will not be enabled.
|
||||||
@@ -111,8 +105,7 @@ public class RadialMenu
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An additional interface that can be implemented by the predicate
|
* An additional interface that can be implemented by the predicate to display extra status.
|
||||||
* to display extra status.
|
|
||||||
*/
|
*/
|
||||||
public static interface IconPredicate extends Predicate
|
public static interface IconPredicate extends Predicate
|
||||||
{
|
{
|
||||||
@@ -130,32 +123,27 @@ public class RadialMenu
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a menu item to the menu. The menu should not currently be
|
* Adds a menu item to the menu. The menu should not currently be active.
|
||||||
* active.
|
|
||||||
*
|
*
|
||||||
* @param command the command to be issued when the item is selected.
|
* @param command the command to be issued when the item is selected.
|
||||||
* @param label the textual label to be displayed with the menu item.
|
* @param label the textual label to be displayed with the menu item.
|
||||||
* @param icon the icon to display next to the menu text or null if no
|
* @param icon the icon to display next to the menu text or null if no
|
||||||
* icon is desired.
|
* icon is desired.
|
||||||
* @param predicate a predicate that will be used to determine whether
|
* @param predicate a predicate that will be used to determine whether or not this menu item
|
||||||
* or not this menu item should be included in the menu and enabled
|
* should be included in the menu and enabled when it is shown.
|
||||||
* when it is shown.
|
|
||||||
*
|
*
|
||||||
* @return the item that was added to the menu. It can be modified
|
* @return the item that was added to the menu. It can be modified while the menu is not being
|
||||||
* while the menu is not being displayed.
|
* displayed.
|
||||||
*/
|
*/
|
||||||
public RadialMenuItem addMenuItem (String command, String label,
|
public RadialMenuItem addMenuItem (String command, String label, Image icon, Predicate predicate)
|
||||||
Image icon, Predicate predicate)
|
|
||||||
{
|
{
|
||||||
RadialMenuItem item = new RadialMenuItem(
|
RadialMenuItem item = new RadialMenuItem(command, label, new ImageIcon(icon), predicate);
|
||||||
command, label, new ImageIcon(icon), predicate);
|
|
||||||
addMenuItem(item);
|
addMenuItem(item);
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds an already constructed menu item to the menu. The menu should
|
* Adds an already constructed menu item to the menu. The menu should not currently be active.
|
||||||
* not currently be active.
|
|
||||||
*
|
*
|
||||||
* @param item the menu item instance to be added.
|
* @param item the menu item instance to be added.
|
||||||
*/
|
*/
|
||||||
@@ -168,8 +156,7 @@ public class RadialMenu
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds an already constructed menu item to the menu. The menu should
|
* Adds an already constructed menu item to the menu. The menu should not currently be active.
|
||||||
* not currently be active.
|
|
||||||
*
|
*
|
||||||
* @param item the menu item instance to be added.
|
* @param item the menu item instance to be added.
|
||||||
*/
|
*/
|
||||||
@@ -187,8 +174,7 @@ public class RadialMenu
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes the first menu item that matches the specified command from
|
* Removes the first menu item that matches the specified command from this menu.
|
||||||
* this menu.
|
|
||||||
*
|
*
|
||||||
* @return true if a matching menu item was removed, false if not.
|
* @return true if a matching menu item was removed, false if not.
|
||||||
*/
|
*/
|
||||||
@@ -218,9 +204,8 @@ public class RadialMenu
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a listener that will be notified when a menu item is
|
* Adds a listener that will be notified when a menu item is selected. When the the menu is
|
||||||
* selected. When the the menu is popped down, all listeners will be
|
* popped down, all listeners will be cleared.
|
||||||
* cleared.
|
|
||||||
*/
|
*/
|
||||||
public void addActionListener (ActionListener listener)
|
public void addActionListener (ActionListener listener)
|
||||||
{
|
{
|
||||||
@@ -228,8 +213,7 @@ public class RadialMenu
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the optional centerpiece icon to be displayed in the center of
|
* Sets the optional centerpiece icon to be displayed in the center of the menu.
|
||||||
* the menu.
|
|
||||||
*/
|
*/
|
||||||
public void setCenterIcon (Icon icon)
|
public void setCenterIcon (Icon icon)
|
||||||
{
|
{
|
||||||
@@ -237,19 +221,15 @@ public class RadialMenu
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Activates the radial menu, rendering a menu around the prescribed
|
* Activates the radial menu, rendering a menu around the prescribed bounds. It is expected
|
||||||
* bounds. It is expected that the host component will subsequently
|
* that the host component will subsequently call {@link #render} if the menu invalidates the
|
||||||
* call {@link #render} if the menu invalidates the region of the
|
* region of the component occupied by the menu and requests it to repaint.
|
||||||
* component occupied by the menu and requests it to repaint.
|
|
||||||
*
|
*
|
||||||
* @param host the host component within which the radial menu is
|
* @param host the host component within which the radial menu is displayed.
|
||||||
* displayed.
|
* @param bounds the bounds of the object that was clicked to activate the menu.
|
||||||
* @param bounds the bounds of the object that was clicked to activate
|
* @param argument a reference to an object that will be provided along with the command that
|
||||||
* the menu.
|
* is issued if the user selects a menu item (unless that item has an overriding argument, in
|
||||||
* @param argument a reference to an object that will be provided
|
* which case the overriding argument will be used).
|
||||||
* along with the command that is issued if the user selects a menu
|
|
||||||
* item (unless that item has an overriding argument, in which case
|
|
||||||
* the overriding argument will be used).
|
|
||||||
*/
|
*/
|
||||||
public void activate (Host host, Rectangle bounds, Object argument)
|
public void activate (Host host, Rectangle bounds, Object argument)
|
||||||
{
|
{
|
||||||
@@ -258,15 +238,12 @@ public class RadialMenu
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Activates the radial menu, rendering a menu around the prescribed
|
* Activates the radial menu, rendering a menu around the prescribed bounds. It is expected
|
||||||
* bounds. It is expected that the host component will subsequently
|
* that the host component will subsequently call {@link #render} if the menu invalidates the
|
||||||
* call {@link #render} if the menu invalidates the region of the
|
* region of the component occupied by the menu and requests it to repaint.
|
||||||
* component occupied by the menu and requests it to repaint.
|
|
||||||
*
|
*
|
||||||
* @param host the host component within which the radial menu is
|
* @param host the host component within which the radial menu is displayed.
|
||||||
* displayed.
|
* @param bounds the bounds of the object that was clicked to activate the menu.
|
||||||
* @param bounds the bounds of the object that was clicked to activate
|
|
||||||
* the menu.
|
|
||||||
*/
|
*/
|
||||||
public void activate (Host host, Rectangle bounds)
|
public void activate (Host host, Rectangle bounds)
|
||||||
{
|
{
|
||||||
@@ -296,10 +273,9 @@ public class RadialMenu
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the argument provided to this menu when {@link #activate}
|
* Returns the argument provided to this menu when {@link #activate} was called. This will only
|
||||||
* was called. This will only be non-null while the menu is active and
|
* be non-null while the menu is active and only then if an argument was provided in the call
|
||||||
* only then if an argument was provided in the call to {@link
|
* to {@link #activate}.
|
||||||
* #activate}.
|
|
||||||
*/
|
*/
|
||||||
public Object getActivationArgument ()
|
public Object getActivationArgument ()
|
||||||
{
|
{
|
||||||
@@ -363,8 +339,7 @@ public class RadialMenu
|
|||||||
}
|
}
|
||||||
// we have to wait and render the active item last
|
// we have to wait and render the active item last
|
||||||
if (item != _activeItem) {
|
if (item != _activeItem) {
|
||||||
item.render(host, this, gfx, x + item.closedBounds.x,
|
item.render(host, this, gfx, x + item.closedBounds.x, y + item.closedBounds.y);
|
||||||
y + item.closedBounds.y);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -419,8 +394,8 @@ public class RadialMenu
|
|||||||
_activeItem.setActive(true);
|
_activeItem.setActive(true);
|
||||||
repaint = true;
|
repaint = true;
|
||||||
|
|
||||||
// if we got here with a mouse moved, we've definately
|
// if we got here with a mouse moved, we've definately made the decision to be
|
||||||
// made the decision to be in non drag mode
|
// in non drag mode
|
||||||
if (event.getID() == MouseEvent.MOUSE_MOVED) {
|
if (event.getID() == MouseEvent.MOUSE_MOVED) {
|
||||||
_msMode = true;
|
_msMode = true;
|
||||||
}
|
}
|
||||||
@@ -462,9 +437,8 @@ public class RadialMenu
|
|||||||
long when = RunAnywhere.getWhen(event);
|
long when = RunAnywhere.getWhen(event);
|
||||||
if (!_msMode &&
|
if (!_msMode &&
|
||||||
(when < _poptime + DRAGMODE_DELAY)) {
|
(when < _poptime + DRAGMODE_DELAY)) {
|
||||||
// if the dragmode delay time hasn't passed, then we're
|
// if the dragmode delay time hasn't passed, then we're going to leave the menu up
|
||||||
// going to leave the menu up because the user wants it
|
// because the user wants it to behave like a MS Windows menu.
|
||||||
// to behave like a MS Windows menu.
|
|
||||||
_msMode = true;
|
_msMode = true;
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -501,8 +475,7 @@ public class RadialMenu
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lays the radial menu items out based on the currently configured
|
* Lays the radial menu items out based on the currently configured bounds information.
|
||||||
* bounds information.
|
|
||||||
*/
|
*/
|
||||||
protected void layout ()
|
protected void layout ()
|
||||||
{
|
{
|
||||||
@@ -537,16 +510,14 @@ public class RadialMenu
|
|||||||
}
|
}
|
||||||
gfx.dispose();
|
gfx.dispose();
|
||||||
|
|
||||||
// use the maximum of either width or height and make a circle
|
// use the maximum of either width or height and make a circle around that
|
||||||
// around that
|
|
||||||
double radius = Math.max(_tbounds.height, _tbounds.width) / 2;
|
double radius = Math.max(_tbounds.height, _tbounds.width) / 2;
|
||||||
|
|
||||||
// be sure to add a gap and space for the menu item itself
|
// be sure to add a gap and space for the menu item itself
|
||||||
radius += (5 + maxwid/2);
|
radius += (5 + maxwid/2);
|
||||||
|
|
||||||
// compute the angle between menu items (we use the diameter of
|
// compute the angle between menu items (we use the diameter of the menu items as an
|
||||||
// the menu items as an approximate measure of the distance along
|
// approximate measure of the distance along the circumference)
|
||||||
// the circumference)
|
|
||||||
double theta = (maxwid + 10) / radius ;
|
double theta = (maxwid + 10) / radius ;
|
||||||
|
|
||||||
// now position each item accordingly
|
// now position each item accordingly
|
||||||
@@ -586,8 +557,8 @@ public class RadialMenu
|
|||||||
_bounds.add(item.openBounds);
|
_bounds.add(item.openBounds);
|
||||||
}
|
}
|
||||||
|
|
||||||
// now translate everything from the center of the target bounds
|
// now translate everything from the center of the target bounds to the upper left of the
|
||||||
// to the upper left of the menu bounds
|
// menu bounds
|
||||||
if (_centerLabel != null) {
|
if (_centerLabel != null) {
|
||||||
_centerLabel.openBounds.translate(-_bounds.x, -_bounds.y);
|
_centerLabel.openBounds.translate(-_bounds.x, -_bounds.y);
|
||||||
_centerLabel.closedBounds.translate(-_bounds.x, -_bounds.y);
|
_centerLabel.closedBounds.translate(-_bounds.x, -_bounds.y);
|
||||||
@@ -598,28 +569,25 @@ public class RadialMenu
|
|||||||
item.closedBounds.translate(-_bounds.x, -_bounds.y);
|
item.closedBounds.translate(-_bounds.x, -_bounds.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
// the origin was at the center of the encircled rectangle; we
|
// the origin was at the center of the encircled rectangle; we need to translate it such
|
||||||
// need to translate it such that the origin of our bounds are in
|
// that the origin of our bounds are in screen coordinates and at the upper left rather
|
||||||
// screen coordinates and at the upper left rather than the center
|
// than the center
|
||||||
_bounds.x += (_tbounds.x + _tbounds.width/2);
|
_bounds.x += (_tbounds.x + _tbounds.width/2);
|
||||||
_bounds.y += (_tbounds.y + _tbounds.height/2);
|
_bounds.y += (_tbounds.y + _tbounds.height/2);
|
||||||
|
|
||||||
// now make sure the whole shebang is fully visible within the
|
// now make sure the whole shebang is fully visible within the host component
|
||||||
// host component
|
|
||||||
Rectangle hbounds = _host.getViewBounds();
|
Rectangle hbounds = _host.getViewBounds();
|
||||||
Point pos = SwingUtil.fitRectInRect(_bounds, hbounds);
|
Point pos = SwingUtil.fitRectInRect(_bounds, hbounds);
|
||||||
_bounds.setLocation(pos);
|
_bounds.setLocation(pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Requests that our host component repaint the part of itself that we
|
* Requests that our host component repaint the part of itself that we occupy.
|
||||||
* occupy.
|
|
||||||
*/
|
*/
|
||||||
protected void repaint ()
|
protected void repaint ()
|
||||||
{
|
{
|
||||||
// only repaint the area that we overlap
|
// only repaint the area that we overlap
|
||||||
_host.repaintRect(_bounds.x, _bounds.y,
|
_host.repaintRect(_bounds.x, _bounds.y, _bounds.width+1, _bounds.height+1);
|
||||||
_bounds.width+1, _bounds.height+1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Our host component. */
|
/** Our host component. */
|
||||||
@@ -631,8 +599,8 @@ public class RadialMenu
|
|||||||
/** The bounds that all of our menu items occupy. */
|
/** The bounds that all of our menu items occupy. */
|
||||||
protected Rectangle _bounds;
|
protected Rectangle _bounds;
|
||||||
|
|
||||||
/** The argument object, which will be delivered along with a posted
|
/** The argument object, which will be delivered along with a posted command when a menu item
|
||||||
* command when a menu item is selected. */
|
* is selected. */
|
||||||
protected Object _argument;
|
protected Object _argument;
|
||||||
|
|
||||||
/** The centerpiece icon or null if there is none. */
|
/** The centerpiece icon or null if there is none. */
|
||||||
@@ -642,31 +610,28 @@ public class RadialMenu
|
|||||||
protected RadialLabelSausage _centerLabel;
|
protected RadialLabelSausage _centerLabel;
|
||||||
|
|
||||||
/** Our menu items. */
|
/** Our menu items. */
|
||||||
protected ArrayList<RadialMenuItem> _items =
|
protected ArrayList<RadialMenuItem> _items = new ArrayList<RadialMenuItem>();
|
||||||
new ArrayList<RadialMenuItem>();
|
|
||||||
|
|
||||||
/** The item that has the mouse over it presently, and the default item
|
/** The item that has the mouse over it presently, and the default item if we're double
|
||||||
* if we're double clicked. */
|
* clicked. */
|
||||||
protected RadialMenuItem _activeItem, _defaultItem;
|
protected RadialMenuItem _activeItem, _defaultItem;
|
||||||
|
|
||||||
/** The amount of time the user must hold down the mouse in order
|
/** The amount of time the user must hold down the mouse in order to put it in drag mode, after
|
||||||
* to put it in drag mode, after which the first mouse-up will pop
|
* which the first mouse-up will pop down the menu. */
|
||||||
* down the menu. */
|
|
||||||
protected static final long DRAGMODE_DELAY = 1000L;
|
protected static final long DRAGMODE_DELAY = 1000L;
|
||||||
|
|
||||||
/** The amount of time after the menu has been popped up before we
|
/** The amount of time after the menu has been popped up before we accept selections. */
|
||||||
* accept selections. */
|
|
||||||
protected static final long DEBOUNCE_DELAY = 200L;
|
protected static final long DEBOUNCE_DELAY = 200L;
|
||||||
|
|
||||||
/** How quickly a second click must arrive for us to count it as a double
|
/** How quickly a second click must arrive for us to count it as a double click and not two
|
||||||
* click and not two single clicks. */
|
* single clicks. */
|
||||||
protected static final long DOUBLECLICK_DELAY = 400L;
|
protected static final long DOUBLECLICK_DELAY = 400L;
|
||||||
|
|
||||||
/** The time at which the menu was popped up. */
|
/** The time at which the menu was popped up. */
|
||||||
protected long _poptime;
|
protected long _poptime;
|
||||||
|
|
||||||
/** Whether we're popping the menu up in microsoft mode, where the
|
/** Whether we're popping the menu up in microsoft mode, where the user does not need to drag
|
||||||
* user does not need to drag to the item they want to select. */
|
* to the item they want to select. */
|
||||||
protected boolean _msMode = false;
|
protected boolean _msMode = false;
|
||||||
|
|
||||||
/** This hijacks and holds onto the previous mouse listeners. */
|
/** This hijacks and holds onto the previous mouse listeners. */
|
||||||
|
|||||||
Reference in New Issue
Block a user