Smart menu for full screen mode (MS Windows)

This commit is contained in:
Vassiliy Kudryashov
2013-02-27 22:51:46 +04:00
parent 14581d8075
commit e304c21cce
@@ -29,11 +29,21 @@ import com.intellij.openapi.actionSystem.impl.WeakTimerListener;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.wm.ex.WindowManagerEx;
import com.intellij.ui.ScreenUtil;
import com.intellij.util.ui.Animator;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.awt.event.AWTEventListener;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.util.ArrayList;
/**
@@ -43,6 +53,17 @@ import java.util.ArrayList;
* @author Vladimir Kondratyev
*/
public class IdeMenuBar extends JMenuBar {
private static final int COLLAPSED_HEIGHT = 2;
private enum State {
EXPANDED, COLLAPSING, COLLAPSED, EXPANDING, TEMPORARY_EXPANDED;
boolean isInProgress() {
return this == COLLAPSING || this == EXPANDING;
}
}
private final MyTimerListener myTimerListener;
private ArrayList<AnAction> myVisibleActions;
private ArrayList<AnAction> myNewVisibleActions;
@@ -52,6 +73,13 @@ public class IdeMenuBar extends JMenuBar {
private final Disposable myDisposable = Disposer.newDisposable();
private boolean DISABLED = false;
@Nullable private final Animator myAnimator;
@Nullable private final Timer myActivationWatcher;
@NotNull private State myState = State.EXPANDED;
private double myProgress = 0;
private boolean myMouseInside = false;
private boolean myActivated = false;
public IdeMenuBar(ActionManagerEx actionManager, DataManager dataManager) {
myActionManager = actionManager;
myTimerListener = new MyTimerListener();
@@ -59,6 +87,121 @@ public class IdeMenuBar extends JMenuBar {
myNewVisibleActions = new ArrayList<AnAction>();
myPresentationFactory = new MenuItemPresentationFactory();
myDataManager = dataManager;
if (SystemInfo.isWindows) {
myAnimator = new Animator("MenuBarAnimator", 8, 300, false) {
@Override
public void paintNow(int frame, int totalFrames, int cycle) {
myProgress = (1 - Math.cos(Math.PI * ((float)frame / totalFrames))) / 2;
revalidate();
repaint();
}
@Override
protected void paintCycleEnd() {
myProgress = 1;
switch (myState) {
case COLLAPSING:
setState(State.COLLAPSED);
break;
case EXPANDING:
setState(State.TEMPORARY_EXPANDED);
break;
default:
}
revalidate();
repaint();
}
};
Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
@Override
public void eventDispatched(AWTEvent event) {
MouseEvent mouseEvent = (MouseEvent)event;
Component component = mouseEvent.getComponent();
Component deepestComponent = SwingUtilities.getDeepestComponentAt(mouseEvent.getComponent(), mouseEvent.getX(), mouseEvent.getY());
if (deepestComponent != null) {
component = deepestComponent;
}
if (myState != State.EXPANDED && !myState.isInProgress()) {
myMouseInside = myActivated || isDescendingFrom(component, IdeMenuBar.this);
if (myMouseInside && myState == State.COLLAPSED) {
setState(State.EXPANDING);
restartAnimator();
}
else if (!myMouseInside && myState != State.COLLAPSING && myState != State.COLLAPSED) {
setState(State.COLLAPSING);
restartAnimator();
}
}
}
}, AWTEvent.MOUSE_MOTION_EVENT_MASK | AWTEvent.MOUSE_EVENT_MASK);
myActivationWatcher = new Timer(100, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (myState == State.EXPANDED || myState == State.EXPANDING)
return;
boolean activated = isActivated();
if (myActivated && !activated && myState == State.TEMPORARY_EXPANDED) {
myActivated = false;
setState(State.COLLAPSING);
restartAnimator();
}
if (activated)
myActivated = true;
}
});
}
else {
myAnimator = null;
myActivationWatcher = null;
}
}
private static boolean isDescendingFrom(@Nullable Component a, @NotNull Component b) {
while (a != null) {
if (a == b) {
return true;
}
if (a instanceof JPopupMenu) {
a = ((JPopupMenu)a).getInvoker();
} else {
a = a.getParent();
}
}
return false;
}
private boolean isActivated() {
int index = getSelectionModel().getSelectedIndex();
if (index ==-1)
return false;
return getMenu(index).isPopupMenuVisible();
}
private void setState(@NotNull State state) {
myState = state;
}
@Override
public Dimension getPreferredSize() {
Dimension dimension = super.getPreferredSize();
if (myState.isInProgress()) {
dimension.height =
COLLAPSED_HEIGHT + (int)((myState == State.COLLAPSING ? (1 - myProgress) : myProgress) * (dimension.height - COLLAPSED_HEIGHT));
}
else if (myState == State.COLLAPSED) {
dimension.height = COLLAPSED_HEIGHT;
}
return dimension;
}
private void restartAnimator() {
if (myAnimator != null) {
myAnimator.reset();
myAnimator.resume();
}
}
/**
@@ -68,8 +211,24 @@ public class IdeMenuBar extends JMenuBar {
public void addNotify() {
super.addNotify();
updateMenuActions();
if (!ScreenUtil.isStandardAddRemoveNotify(this))
if (!ScreenUtil.isStandardAddRemoveNotify(this)) {
Window window = SwingUtilities.getWindowAncestor(this);
if (window instanceof IdeFrameImpl) {
boolean fullScreen = WindowManagerEx.getInstanceEx().isFullScreen((IdeFrameImpl)window);
if (fullScreen) {
setState(State.COLLAPSING);
restartAnimator();
} else {
if (myAnimator != null) {
myAnimator.suspend();
}
setState(State.EXPANDED);
revalidate();
repaint();
}
}
return;
}
// Add updater for menus
myActionManager.addTimerListener(1000, new WeakTimerListener(myActionManager, myTimerListener));
UISettingsListener UISettingsListener = new UISettingsListener() {
@@ -80,6 +239,9 @@ public class IdeMenuBar extends JMenuBar {
};
UISettings.getInstance().addUISettingsListener(UISettingsListener, myDisposable);
Disposer.register(ApplicationManager.getApplication(), myDisposable);
if (myActivationWatcher != null) {
myActivationWatcher.start();
}
}
/**
@@ -88,6 +250,12 @@ public class IdeMenuBar extends JMenuBar {
@Override
public void removeNotify() {
if (ScreenUtil.isStandardAddRemoveNotify(this)) {
if (myActivationWatcher != null) {
myActivationWatcher.stop();
}
if (myAnimator != null) {
myAnimator.suspend();
}
Disposer.dispose(myDisposable);
}
super.removeNotify();
@@ -144,6 +312,21 @@ public class IdeMenuBar extends JMenuBar {
}
}
@Override
protected void paintChildren(Graphics g) {
if (SystemInfo.isWindows && myState.isInProgress()) {
Graphics2D g2 = (Graphics2D)g;
AffineTransform oldTransform = g2.getTransform();
AffineTransform newTransform = oldTransform != null ? new AffineTransform(oldTransform) : new AffineTransform();
newTransform.concatenate(AffineTransform.getTranslateInstance(0, getHeight() - super.getPreferredSize().height));
g2.setTransform(newTransform);
super.paintChildren(g2);
g2.setTransform(oldTransform);
} else {
super.paintChildren(g);
}
}
/**
* Hacks a problem under Alloy LaF which draws menu bar in different background menu items are drawn in.
*/