/* * Copyright (C) 2013 lee * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 this program. If not, see <http://www.gnu.org/licenses/>. */ package org.dlect.ui.layout; import java.awt.Component; import java.awt.Container; import java.awt.Dialog; import java.awt.Dimension; import java.awt.LayoutManager; import java.awt.Window; import java.util.Timer; import java.util.TimerTask; import javax.swing.JViewport; import org.dlect.utils.AdvancedTimer; /** * * @author lee */ public class AnimatedHideLayoutManager implements LayoutManager { private static final double PIXELS_PER_FRAME = 10; private static final long TIMER_DELAY = 1000 / 60; // 60 fps private final Component head; private final Component pane; private final Component parent; private Component topLevelComp; private double movementAmount; private int heightAtLastCalc = -1; private int movementDirection = -1; private double animationPercentage = 0; private AdvancedTimer timer; public AnimatedHideLayoutManager(Component head, Component pane, Component parent) { this.head = head; this.pane = pane; this.parent = parent; } @Override public void addLayoutComponent(String name, Component comp) { // Do Nothing - The elements are given in the constructor. } @Override public void removeLayoutComponent(Component comp) { // Do Nothing - The elements are given in the constructor. } @Override public Dimension preferredLayoutSize(Container parent) { Dimension d = head.getPreferredSize(); Dimension paneD = pane.getPreferredSize(); d.width = Math.max(d.width, paneD.width); d.height += (paneD.height * animationPercentage) / 1.0; return d; } @Override public String toString() { return "AnimatedHideLayoutManager{" + "head=" + head + ", pane=" + pane + ", parent=" + parent + ", animationPercentage=" + animationPercentage + '}'; } @Override public Dimension minimumLayoutSize(Container parent) { return preferredLayoutSize(parent); } @Override public void layoutContainer(Container parent) { head.setLocation(0, 0); int width = parent.getWidth(); Dimension d = new Dimension(head.getPreferredSize()); d.width = width; int headHeight = d.height; head.setSize(d); d.height = pane.getPreferredSize().height; pane.setSize(d); int y = headHeight; y -= (d.height * (1.0 - animationPercentage)); pane.setLocation(0, y); } public boolean animateDown() { movementDirection = 1; return doAnimate(); } public boolean animateUp() { movementDirection = -1; return doAnimate(); } private boolean doAnimate() { updateMovementAmount(); generateTopLevelComponent(); if (timer == null || timer.isCanceled()) { timer = new AdvancedTimer(true); timer.schedule(new AnimationTimerTask(timer), 0, TIMER_DELAY); } return true; } public boolean animateToggle() { movementDirection = -movementDirection; return doAnimate(); } private void generateTopLevelComponent() { if (topLevelComp != null) { return; } topLevelComp = traverseTree(parent); } private Component traverseTree(Component current) throws IllegalStateException { if (current instanceof JViewport || current instanceof Window || current instanceof Dialog) { return current; } if (current.getParent() == null) { throw new IllegalStateException("Can't animate a panel without it having a parent"); } return traverseTree(current.getParent()); } private void updateMovementAmount() { heightAtLastCalc = pane.getHeight(); movementAmount = (PIXELS_PER_FRAME / heightAtLastCalc); } class AnimationTimerTask extends TimerTask { private Timer t; public AnimationTimerTask(Timer t) { super(); this.t = t; } @Override public void run() { animationPercentage += movementAmount * movementDirection; if (animationPercentage >= 1) { animationPercentage = 1; t.cancel(); } else if (animationPercentage <= 0) { animationPercentage = 0; t.cancel(); } parent.invalidate(); topLevelComp.validate(); topLevelComp.doLayout(); } } }