package com.gwt.ui.client;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
/**
* Realy Simple Accordion panel with the ability to open/close the nested widgets, preferably in a cool animated style.
*
* @author ibouakl
*/
public class AccordionPanel extends Composite {
private Panel aPanel;
private String animField;
private String animBounds;
private static int NUM_FRAMES = 8;
private Widget currentlyExpanded = null;
private Label currentlyExpandedLabel = null;
/**
* Constructor
*
* @param horizontal
*/
public AccordionPanel(boolean horizontal) {
if (horizontal) {
aPanel = new HorizontalPanel();
animField = "width";
animBounds = "scrollWidth";
} else {
aPanel = new VerticalPanel();
animField = "height";
animBounds = "scrollHeight";
}
initWidget(aPanel);
setStylePrimaryName("accordion");
}
public AccordionPanel() {
this(false);
}
/**
* method for adding new widgets to an accordion.
*
* @param label
* @param content
*/
public void add(String label, final Widget content, boolean isExpanded) {
final Label l = new Label(label);
l.setStylePrimaryName(getStylePrimaryName() + "-title");
final SimplePanel sp = new SimplePanel();
sp.setWidget(content);
l.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent arg0) {
expand(l, sp);
}
});
aPanel.add(l);
sp.setStylePrimaryName(getStylePrimaryName() + "-content");
DOM.setStyleAttribute(sp.getElement(), animField, "0px");
DOM.setStyleAttribute(sp.getElement(), "overflow", "hidden");
aPanel.add(sp);
if (isExpanded)
expand(l, sp);
}
private void expand(final Label label, final Widget c) {
if (currentlyExpanded != null)
DOM.setStyleAttribute(currentlyExpanded.getElement(), "overflow", "hidden");
// We create a Timer, whose run method will animate the collapse/expansion. We simultaneously collapse any currently expanded Widget
// and expand the target widget. All we have to do, is fetch the max dimensions from scrollHeight/scrollWidth, and then interpolate
// them down to zero for collapse.
final Timer t = new Timer() {
int frame = 0;
public void run() {
if (currentlyExpanded != null) {
Widget w = currentlyExpanded;
Element elem = w.getElement();
int oSh = DOM.getElementPropertyInt(elem, animBounds);
DOM.setStyleAttribute(elem, animField, "" + ((NUM_FRAMES - frame) * oSh / NUM_FRAMES) + "px");
}
if (currentlyExpanded != c) {
Widget w = c;
Element elem = w.getElement();
int oSh = DOM.getElementPropertyInt(elem, animBounds);
DOM.setStyleAttribute(elem, animField, "" + (frame * oSh / NUM_FRAMES) + "px");
}
frame++;
if (frame <= NUM_FRAMES) {
schedule(10);
} else {
if (currentlyExpanded != null) {
currentlyExpanded.removeStyleDependentName("selected");
currentlyExpandedLabel.removeStyleDependentName("selected");
}
c.addStyleDependentName("selected");
if (currentlyExpanded != c) {
currentlyExpanded = c;
currentlyExpandedLabel = label;
currentlyExpandedLabel.addStyleDependentName("selected");
Element elem = c.getElement();
DOM.setStyleAttribute(elem, "overflow", "auto");
DOM.setStyleAttribute(elem, animField, "auto");
} else {
currentlyExpanded = null;
}
}
}
};
t.schedule(10);
}
}