/*******************************************************************************
* Copyright (c) 2007, 2008 Gregory Jordan
*
* This file is part of PhyloWidget.
*
* PhyloWidget is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 2 of the License, or (at your option) any later
* version.
*
* PhyloWidget is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* PhyloWidget. If not, see <http://www.gnu.org/licenses/>.
*/
package org.andrewberman.ui.menu;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
import org.andrewberman.ui.Point;
import org.andrewberman.ui.ifaces.Positionable;
import processing.core.PApplet;
/**
* A <code>Toolbar</code> is a menu that acts more or less like a
* Windows-style toolbar. The two main options for the Toolbar class are:
* <code>fullWidth</code>, which if set to true will draw itself across the
* entire width of the screen, and <code>isModal</code>, which if set to true
* will make the toolbar grab modal focus from the FocusManager when one of its
* menus is opened.
*
* @author Greg
*/
public class Toolbar extends Menu
{
RoundRectangle2D.Float roundRect = new RoundRectangle2D.Float(0, 0, 0, 0,
0, 0);
Rectangle2D.Float buffRect = new Rectangle2D.Float(0, 0, 0, 0);
/**
* If set to true, the toolbar will take up the entire width of the PApplet.
*/
public boolean fullWidth;
/**
* If true, this option will cause the menu to grab modal focus from the
* FocusManager upon opening.
*/
public boolean isModal;
public int orientation = HORIZONTAL;
public static final int HORIZONTAL = 0;
public static final int VERTICAL = 1;
public Toolbar(PApplet app)
{
super(app);
layout();
open();
}
protected boolean isActive()
{
return hasOpenChildren();
}
public void setAutoDim(boolean auto)
{
this.autoDim = auto;
}
public void setOptions()
{
super.setOptions();
/*
* Override some default options from the Menu class.
*/
useCameraCoordinates = true;
clickToggles = true;
hoverNavigable = true;
clickAwayBehavior = Menu.CLICKAWAY_COLLAPSES;
// actionOnMouseDown = true;
useHandCursor = true;
autoDim = false;
fullWidth = false;
isModal = true;
/*
* Do some automatic positioning.
*/
float sw = getStyle().getF("f.strokeWeight");
if (fullWidth)
{
x = sw;
y = sw;
} else if (!useCameraCoordinates)
{
x = sw;
y = sw;
}
}
public void draw()
{
if (fullWidth)
setFullWidth();
super.draw();
}
@Override
public void open(MenuItem i)
{
super.open(i);
context.focus().setFocus(this);
}
@Override
public void close(MenuItem item)
{
super.close(item);
if (!isActive())
context.focus().removeFromFocus(this);
}
@Override
public void close()
{
closeMyChildren();
kbFocus = null;
}
public void drawBefore()
{
if (orientation == HORIZONTAL)
MenuUtils.drawDoubleGradientRect(this, x, y, width, height);
else
MenuUtils.drawVerticalGradientRect(this, x, y, width, height);
}
public MenuItem create(String name)
{
ToolbarItem ti = new ToolbarItem();
if (orientation == HORIZONTAL)
ti.setLayoutMode(ToolbarItem.LAYOUT_BELOW);
else
ti.setLayoutMode(ToolbarItem.LAYOUT_RIGHT);
ti.drawChildrenTriangle = true;
ti.setName(name);
return ti;
}
protected void clickaway()
{
super.clickaway();
if (isModal)
{
context.focus().removeFromFocus(this);
}
}
public synchronized void layout()
{
float px = getStyle().getF("f.padX");
float py = getStyle().getF("f.padY");
float xOffset = px;
float yOffset = py;
for (int i = 0; i < items.size(); i++)
{
MenuItem item = (MenuItem) items.get(i);
item.calcPreferredSize();
float itemWidth = item.getWidth();
float itemHeight = item.getHeight();
if (item instanceof Positionable)
{
Positionable pos = (Positionable) item;
pos.setPosition(x + xOffset, y + yOffset);
}
if (orientation == HORIZONTAL)
xOffset += itemWidth;
else
yOffset += itemHeight;
}
/*
* Set this Toolbar's width and height.
*/
float maxHeight = getMaxHeight();
float maxWidth = getMaxWidth();
if (orientation == HORIZONTAL)
{
if (!fullWidth)
setWidth(xOffset + px);
else
setFullWidth();
setHeight(maxHeight + py * 2);
} else
{
setHeight(yOffset + py);
setWidth(maxWidth + px * 2);
}
for (int i = 0; i < items.size(); i++)
{
MenuItem item = items.get(i);
if (orientation == HORIZONTAL)
{
item.setHeight(maxHeight);
} else
{
item.setWidth(maxWidth);
}
}
/*
* Trigger the recursive layout.
*/
super.layout();
}
void setFullWidth()
{
float sw = getStyle().getF("f.strokeWeight");
if (orientation == HORIZONTAL)
{
width = canvas.width - sw * 2;
} else
{
height = canvas.height - sw * 2;
}
}
@Override
public void setState(MenuItem i, int s)
{
if (!isActive())
hoverNavigable = false;
super.setState(i, s);
if (i.parent == this && isActive() && s != MenuItem.UP)
{
closeMyChildren();
open(i);
}
hoverNavigable = true;
}
protected void getRect(Rectangle2D.Float rect, Rectangle2D.Float buff)
{
super.getRect(rect, buff);
if (isOpen())
{
buff.setRect(x, y, width, height);
Rectangle2D.union(rect, buff, rect);
}
}
protected void itemMouseEvent(MouseEvent e, Point pt)
{
super.itemMouseEvent(e, pt);
if (isActive() && autoDim)
aTween.continueTo(fullAlpha);
// if (e.getID() == MouseEvent.MOUSE_PRESSED)
// {
// if (clickedInside)
// System.out.println("HEY");
// }
// if (isActive() && isModal)
// {
// context.focus().setModalFocus(this);
// }
}
protected void focusToItem(MenuItem i)
{
kbFocus = i;
close(this);
MenuItem parent = i.parent;
while (parent != null)
{
open(parent);
parent = parent.parent;
}
hoverNavigable = false;
setState(i, MenuItem.OVER);
hoverNavigable = true;
}
void focusWrap(MenuItem base, int dir)
{
int index = base.parent.items.indexOf(base);
if (dir > 0)
index++;
else if (dir < 0)
index--;
if (index > base.parent.items.size() - 1)
index = 0;
else if (index < 0)
index = base.parent.items.size() - 1;
focusToItem(base.parent.items.get(index));
}
@Override
public void keyEvent(KeyEvent e)
{
super.keyEvent(e);
if (context.focus().getFocusedObject() != this)
return;
// System.out.println("EVENT!");
if (kbFocus == null)
{
items.get(0).setState(MenuItem.OVER);
}
int code = e.getKeyCode();
int type = e.getID();
if (type != KeyEvent.KEY_PRESSED)
return;
MenuItem p = kbFocus.parent;
switch (code)
{
case (KeyEvent.VK_ENTER):
if (kbFocus.hasChildren())
{
focusToItem(kbFocus.items.get(0));
} else
{
kbFocus.performAction();
}
break;
case (KeyEvent.VK_RIGHT):
if (p == this)
{
focusWrap(kbFocus, 1);
} else
{
if (kbFocus.hasChildren() && kbFocus.isEnabled())
{
focusToItem(kbFocus.items.get(0));
} else
{
/*
* Finds the currently open top-level menuitem, and move
* one to the right. Should wrap around to the left if
* necessary.
*/
for (int i = 0; i < items.size(); i++)
{
MenuItem m = items.get(i);
if (m.isAncestorOf(kbFocus))
{
focusWrap(m, 1);
// System.out.println(kbFocus);
focusToItem(kbFocus.items.get(0));
break;
}
}
}
}
break;
case (KeyEvent.VK_LEFT):
if (p == this)
{
focusWrap(kbFocus, -1);
} else if (p.parent == this)
{
focusWrap(p, -1);
focusToItem(kbFocus.items.get(0));
} else
{
focusToItem(p);
}
break;
case (KeyEvent.VK_DOWN):
if (p == this)
{
focusToItem(kbFocus.items.get(0));
} else
{
focusWrap(kbFocus, 1);
}
break;
case (KeyEvent.VK_UP):
if (p == this)
{
focusToItem(kbFocus.items.get(0));
} else
{
focusWrap(kbFocus, -1);
}
break;
}
// System.out.println(kbFocus);
}
protected boolean containsPoint(Point pt)
{
// buffRect.setRect(x, y, width, height);
// return buffRect.contains(pt);
return false;
}
public int getOrientation()
{
return orientation;
}
public void setOrientation(int orientation)
{
this.orientation = orientation;
}
}