blob: 97a2e78f89f0d18b2df807a55cc012024f92ba70 [file] [log] [blame]
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.ui;
import com.intellij.openapi.wm.IdeFocusManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* User: Vassiliy.Kudryashov
*/
public class JBCardLayout extends CardLayout {
public enum SwipeDirection {FORWARD, BACKWARD, AUTO}
private Map<String, Component> myMap = new LinkedHashMap<String, Component>();
private int mySwipeTime = 200;//default value, provide setter if need
private int mySwipeSteps = 20;//default value, provide setter if need
private final Timer myTimer = new Timer(Math.max(1, mySwipeTime / mySwipeSteps), null);
private Component mySwipeFrom = null;
private Component mySwipeTo = null;
public JBCardLayout() {
this(0, 0);
}
public JBCardLayout(int hgap, int vgap) {
super(hgap, vgap);
}
@Override
public void addLayoutComponent(String name, Component comp) {
super.addLayoutComponent(name, comp);
myMap.put(name, comp);
}
@Override
public void removeLayoutComponent(Component comp) {
stopSwipeIfNeed();
super.removeLayoutComponent(comp);
for (Iterator<Map.Entry<String, Component>> iterator = myMap.entrySet().iterator(); iterator.hasNext(); ) {
Map.Entry<String, Component> entry = iterator.next();
if (entry.getValue() == comp) {
iterator.remove();
break;
}
}
}
@Override
public void layoutContainer(Container parent) {
if (!myTimer.isRunning()) {
super.layoutContainer(parent);
}
}
public void swipe(@NotNull final Container parent, @NotNull final String name, @NotNull SwipeDirection direction) {
swipe(parent, name, direction, null);
}
public void swipe(@NotNull final Container parent, @NotNull final String name, @NotNull SwipeDirection direction,
final @Nullable Runnable onDone) {
stopSwipeIfNeed();
mySwipeFrom = findVisible(parent);
mySwipeTo = myMap.get(name);
if (mySwipeTo == null) return;
if (mySwipeFrom == null || mySwipeFrom == mySwipeTo) {
super.show(parent, name);
if (onDone != null) {
onDone.run();
}
return;
}
final boolean isForward;
if (direction == SwipeDirection.AUTO) {
boolean b = true;
for (Component component : myMap.values()) {
if (component == mySwipeFrom || component == mySwipeTo) {
b = component == mySwipeFrom;
break;
}
}
isForward = b;
}
else {
isForward = direction == SwipeDirection.FORWARD;
}
final double[] linearProgress = new double[1];
linearProgress[0] = 0;
final long startTime = System.currentTimeMillis();
ActionListener listener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
long timePassed = System.currentTimeMillis() - startTime;
if (timePassed >= mySwipeTime) {
Component currentFocusComponent = IdeFocusManager.getGlobalInstance().getFocusedDescendantFor(parent);
show(parent, name);
if (currentFocusComponent != null) currentFocusComponent.requestFocusInWindow();
if (onDone != null) {
onDone.run();
}
return;
}
linearProgress[0] = Math.min(1, Math.max(0, (float)timePassed / mySwipeTime));
double naturalProgress = (1 - Math.cos(Math.PI * linearProgress[0])) / 2;
Rectangle bounds = parent.getBounds();
Insets insets = parent.getInsets();
bounds.setLocation(insets.left, insets.top);
bounds.width -= insets.left + insets.right;
bounds.height -= insets.top + insets.bottom;
Rectangle r = new Rectangle(bounds);
int x = (int)((naturalProgress * r.width));
r.translate(isForward ? -x : x, 0);
mySwipeFrom.setBounds(r);
Rectangle r2 = new Rectangle(bounds);
r2.translate(isForward ? r2.width - x : x - r2.width, 0);
mySwipeTo.setVisible(true);
mySwipeTo.setBounds(r2);
parent.repaint();
}
};
for (ActionListener actionListener : myTimer.getActionListeners()) {
myTimer.removeActionListener(actionListener);
}
myTimer.addActionListener(listener);
myTimer.start();
}
private void stopSwipeIfNeed() {
if (myTimer.isRunning()) {
myTimer.stop();
mySwipeFrom = null;
if (mySwipeTo != null) {
mySwipeTo.setVisible(false);
mySwipeTo = null;
}
}
}
@Nullable
private static Component findVisible(Container parent) {
for (int i = 0; i < parent.getComponentCount(); i++) {
Component component = parent.getComponent(i);
if (component.isVisible()) return component;
}
return null;
}
@Override
public void first(Container parent) {
stopSwipeIfNeed();
super.first(parent);
}
@Override
public void next(Container parent) {
stopSwipeIfNeed();
super.next(parent);
}
@Override
public void previous(Container parent) {
stopSwipeIfNeed();
super.previous(parent);
}
@Override
public void last(Container parent) {
stopSwipeIfNeed();
super.last(parent);
}
@Override
public void show(Container parent, String name) {
stopSwipeIfNeed();
super.show(parent, name);
}
public static void main(String[] args) throws IOException {
final JBCardLayout cardLayout = new JBCardLayout();
JFrame f = new JFrame();
JPanel p = new JPanel(new BorderLayout());
final JPanel centerPanel = new JPanel(cardLayout);
for (int i = 0; i < 10; i++) {
JLabel l = new JLabel("Page #" + (i + 1), SwingConstants.CENTER);
l.setOpaque(true);
int red = 50 + (int)(Math.random() * 100);
int green = 50 + (int)(Math.random() * 100);
int blue = 50 + (int)(Math.random() * 100);
l.setForeground(new Color(red, green, blue));
red = 255 - (int)(Math.random() * 55);
green = 255 - (int)(Math.random() * 55);
blue = 255 - (int)(Math.random() * 55);
l.setBackground(new Color(red, green, blue));
l.setFont(l.getFont().deriveFont(40F));
centerPanel.add(l, "page" + i);
}
final int[] cursor = new int[1];
JButton prevButton = new JButton("<<");
JButton nextButton = new JButton(">>");
prevButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
cursor[0]--;
if (cursor[0] < 0) {
cursor[0] = 9;
}
cardLayout.swipe(centerPanel, "page" + cursor[0], SwipeDirection.BACKWARD);
}
});
nextButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
cursor[0] = (cursor[0] + 1) % 10;
cardLayout.swipe(centerPanel, "page" + cursor[0], SwipeDirection.FORWARD);
}
});
p.setLayout(new BorderLayout());
p.add(prevButton, BorderLayout.WEST);
p.add(centerPanel, BorderLayout.CENTER);
p.add(nextButton, BorderLayout.EAST);
f.setContentPane(p);
f.setSize(new Dimension(600, 800));
f.setLocationRelativeTo(null);
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.setVisible(true);
}
public Component findComponentById(String id) {
return myMap.get(id);
}
}