diff --git a/platform/platform-api/src/com/intellij/ui/components/JBViewport.java b/platform/platform-api/src/com/intellij/ui/components/JBViewport.java index c1f65c4561f9..0ab304d1ef13 100644 --- a/platform/platform-api/src/com/intellij/ui/components/JBViewport.java +++ b/platform/platform-api/src/com/intellij/ui/components/JBViewport.java @@ -18,14 +18,16 @@ package com.intellij.ui.components; import com.intellij.ui.table.JBTable; import com.intellij.util.ui.ComponentWithEmptyText; import com.intellij.util.ui.StatusText; +import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; import java.awt.event.ContainerEvent; import java.awt.event.ContainerListener; -public class JBViewport extends JViewport { +public class JBViewport extends JViewport implements ZoomableViewport { private StatusText myEmptyText; + private ZoomingDelegate myZoomer; public JBViewport() { addContainerListener(new ContainerListener() { @@ -50,16 +52,40 @@ public class JBViewport extends JViewport { } @Override - public Dimension getPreferredSize() { - return super.getPreferredSize(); //To change body of overridden methods use File | Settings | File Templates. + public void paint(Graphics g) { + if (myZoomer != null && myZoomer.isActive()) { + myZoomer.paint(g); + } + else { + super.paint(g); + + if (myEmptyText != null) { + myEmptyText.paint(this, g); + } + } + } + + @Nullable + @Override + public Magnificator getMagnificator() { + JComponent view = (JComponent)getView(); + return view != null ? (Magnificator)view.getClientProperty(Magnificator.CLIENT_PROPERTY_KEY) : null; } @Override - public void paint(Graphics g) { - super.paint(g); + public void magnificationStarted(Point at) { + myZoomer = new ZoomingDelegate((JComponent)getView(), this); + myZoomer.magnificationStarted(at); + } - if (myEmptyText != null) { - myEmptyText.paint(this, g); - } + @Override + public void magnificationFinished(double magnification) { + myZoomer.magnificationFinished(magnification); + myZoomer = null; + } + + @Override + public void magnify(double magnification) { + myZoomer.magnify(magnification); } } diff --git a/platform/platform-api/src/com/intellij/ui/components/Magnificator.java b/platform/platform-api/src/com/intellij/ui/components/Magnificator.java new file mode 100644 index 000000000000..cc60e7fbf195 --- /dev/null +++ b/platform/platform-api/src/com/intellij/ui/components/Magnificator.java @@ -0,0 +1,29 @@ +/* + * Copyright 2000-2011 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. + */ + +/* + * @author max + */ +package com.intellij.ui.components; + +import com.intellij.openapi.util.Key; + +import java.awt.*; + +public interface Magnificator { + Key CLIENT_PROPERTY_KEY = Key.create("MagnifiableComponent"); + Point magnify(double scale, Point at); +} diff --git a/platform/platform-api/src/com/intellij/ui/components/ZoomableViewport.java b/platform/platform-api/src/com/intellij/ui/components/ZoomableViewport.java new file mode 100644 index 000000000000..4c40ba03041d --- /dev/null +++ b/platform/platform-api/src/com/intellij/ui/components/ZoomableViewport.java @@ -0,0 +1,32 @@ +/* + * Copyright 2000-2011 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. + */ + +/* + * @author max + */ +package com.intellij.ui.components; + +import org.jetbrains.annotations.Nullable; + +import java.awt.*; + +public interface ZoomableViewport { + @Nullable + Magnificator getMagnificator(); + void magnificationStarted(Point at); + void magnificationFinished(double magnification); + void magnify(double magnification); +} diff --git a/platform/platform-api/src/com/intellij/ui/components/ZoomingDelegate.java b/platform/platform-api/src/com/intellij/ui/components/ZoomingDelegate.java new file mode 100644 index 000000000000..0ddd352b194c --- /dev/null +++ b/platform/platform-api/src/com/intellij/ui/components/ZoomingDelegate.java @@ -0,0 +1,125 @@ +/* + * Copyright 2000-2011 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. + */ + +/* + * @author max + */ +package com.intellij.ui.components; + +import com.intellij.ui.Gray; + +import javax.swing.*; +import java.awt.*; +import java.awt.image.BufferedImage; + +public class ZoomingDelegate { + private final JComponent myContentComponent; + private final JComponent myViewportComponent; + + private BufferedImage myCachedImage; + private Point myMagnificationPoint; + private double myMagnification; + + public ZoomingDelegate(JComponent contentComponent, JComponent viewportComponent) { + myContentComponent = contentComponent; + myViewportComponent = viewportComponent; + } + + public void paint(Graphics g) { + if (myCachedImage != null && myMagnificationPoint != null && myMagnification != 0) { + double scale = magnificationToScale(myMagnification); + int xoffset = (int)(myMagnificationPoint.x - myMagnificationPoint.x * scale); + int yoffset = (int)(myMagnificationPoint.y - myMagnificationPoint.y * scale); + + Rectangle clip = g.getClipBounds(); + + g.setColor(Gray._120); + g.fillRect(clip.x, clip.y, clip.width, clip.height); + + Graphics2D translated = (Graphics2D)g.create(); + translated.translate(xoffset, yoffset); + translated.scale(scale, scale); + + translated.drawImage(myCachedImage, 0, 0, null); + } + } + + public void magnificationStarted(Point at) { + myMagnificationPoint = at; + } + + public void magnificationFinished(double magnification) { + if (myMagnification != 0) { + Magnificator magnificator = ((ZoomableViewport)myViewportComponent).getMagnificator(); + + if (magnificator != null) { + Point inContent = convertToContentCoordinates(myMagnificationPoint); + + final Point inContentScaled = magnificator.magnify(magnificationToScale(magnification), inContent); + + int voffset = inContentScaled.y - myMagnificationPoint.y; + int hoffset = inContentScaled.x - myMagnificationPoint.x; + myViewportComponent.repaint(); + myViewportComponent.validate(); + + scrollTo(voffset, hoffset); + } + } + + myMagnificationPoint = null; + myMagnification = 0; + myCachedImage = null; + } + + protected void scrollTo(int voffset, int hoffset) { + JViewport viewport = (JViewport)myViewportComponent; + JScrollPane pane = (JScrollPane)viewport.getParent(); + JScrollBar vsb = pane.getVerticalScrollBar(); + vsb.setValue(voffset); + JScrollBar hsb = pane.getHorizontalScrollBar(); + hsb.setValue(hoffset); + } + + protected Point convertToContentCoordinates(Point point) { + return SwingUtilities.convertPoint(myViewportComponent, point, myContentComponent); + } + + public boolean isActive() { + return myCachedImage != null; + } + + private static double magnificationToScale(double magnification) { + return magnification < 0 ? 1f / (1 - magnification) : (1 + magnification); + } + + public void magnify(double magnification) { + if (myMagnification != magnification) { + myMagnification = magnification; + + if (myCachedImage == null) { + Rectangle bounds = myViewportComponent.getBounds(); + BufferedImage image = new BufferedImage(bounds.width, bounds.height, BufferedImage.TYPE_INT_RGB); + + Graphics graphics = image.getGraphics(); + graphics.setClip(0, 0, bounds.width, bounds.height); + myViewportComponent.paint(graphics); + + myCachedImage = image; + } + } + myViewportComponent.repaint(); + } +} diff --git a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/MacGestureAdapter.java b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/MacGestureAdapter.java index 32538508f7a0..a0404c9e99d5 100644 --- a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/MacGestureAdapter.java +++ b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/MacGestureAdapter.java @@ -16,9 +16,16 @@ package com.intellij.openapi.actionSystem.impl; import com.apple.eawt.event.*; +import com.intellij.openapi.actionSystem.ActionManager; +import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.wm.IdeFrame; +import com.intellij.ui.components.Magnificator; +import com.intellij.ui.components.ZoomableViewport; import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.MouseEvent; /** * User: anna @@ -28,6 +35,7 @@ class MacGestureAdapter extends GestureAdapter { double magnification; private final IdeFrame myFrame; private MouseGestureManager myManager; + private ZoomableViewport myMagnifyingViewport; public MacGestureAdapter(MouseGestureManager manager, IdeFrame frame) { myFrame = frame; @@ -38,35 +46,63 @@ class MacGestureAdapter extends GestureAdapter { @Override public void gestureBegan(GesturePhaseEvent event) { - myManager.activateTrackpad(); magnification = 0; + + Point mouse = MouseInfo.getPointerInfo().getLocation(); + SwingUtilities.convertPointFromScreen(mouse, myFrame.getComponent()); + Component deepest = SwingUtilities.getDeepestComponentAt(myFrame.getComponent(), mouse.x, mouse.y); + ZoomableViewport viewport = (ZoomableViewport) SwingUtilities.getAncestorOfClass(ZoomableViewport.class, deepest); + if (viewport != null) { + Magnificator magnificator = viewport.getMagnificator(); + + if (magnificator != null) { + Point at = MouseInfo.getPointerInfo().getLocation(); + SwingUtilities.convertPointFromScreen(at, (JComponent)viewport); + viewport.magnificationStarted(at); + myMagnifyingViewport = viewport; + } + } } @Override public void gestureEnded(GesturePhaseEvent event) { - myManager.activateTrackpad(); - if (magnification != 0) { - MouseGestureManager.processMagnification(myFrame, magnification); + if (myMagnifyingViewport != null) { + myMagnifyingViewport.magnificationFinished(magnification); + myMagnifyingViewport = null; magnification = 0; } } @Override public void swipedLeft(SwipeEvent event) { - myManager.activateTrackpad(); - myManager.processLeftSwipe(myFrame); + ActionManager actionManager = ActionManager.getInstance(); + AnAction forward = actionManager.getAction("Forward"); + if (forward == null) return; + + actionManager.tryToExecute(forward, createMouseEventWrapper(myFrame), null, null, false); } @Override public void swipedRight(SwipeEvent event) { - myManager.activateTrackpad(); - myManager.processRightSwipe(myFrame); + ActionManager actionManager = ActionManager.getInstance(); + AnAction back = actionManager.getAction("Back"); + if (back == null) return; + + actionManager.tryToExecute(back, createMouseEventWrapper(myFrame), null, null, false); } + private static MouseEvent createMouseEventWrapper(IdeFrame frame) { + return new MouseEvent(frame.getComponent(), ActionEvent.ACTION_PERFORMED, System.currentTimeMillis(), 0, 0, 0, 0, false, 0); + } + + @Override public void magnify(MagnificationEvent event) { myManager.activateTrackpad(); magnification += event.getMagnification(); + if (myMagnifyingViewport != null) { + myMagnifyingViewport.magnify(magnification); + } } public void remove(JComponent cmp) { diff --git a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/MouseGestureManager.java b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/MouseGestureManager.java index 7e4ae8bb03fd..d644c7120f7e 100644 --- a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/MouseGestureManager.java +++ b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/MouseGestureManager.java @@ -39,14 +39,11 @@ import java.util.Map; public class MouseGestureManager implements ApplicationComponent { private static final Logger LOG = Logger.getInstance("MouseGestureManager"); - private ActionManagerImpl myActionManager; private Map myListeners = new HashMap(); private boolean HAS_TRACKPAD = false; - - public MouseGestureManager(ActionManagerImpl actionManager) { - myActionManager = actionManager; + public MouseGestureManager() { } public void add(final IdeFrame frame) { @@ -76,38 +73,6 @@ public class MouseGestureManager implements ApplicationComponent { return HAS_TRACKPAD; } - protected static void processMagnification(IdeFrame frame, double magnification) { - Point mouse = MouseInfo.getPointerInfo().getLocation(); - SwingUtilities.convertPointFromScreen(mouse, frame.getComponent()); - Component componentAt = SwingUtilities.getDeepestComponentAt(frame.getComponent(), mouse.x, mouse.y); - if (componentAt != null) { - Editor editor = PlatformDataKeys.EDITOR.getData(DataManager.getInstance().getDataContext(componentAt)); - if (editor != null) { - double currentSize = editor.getColorsScheme().getEditorFontSize(); - int defaultFontSize = EditorColorsManager.getInstance().getGlobalScheme().getEditorFontSize(); - ((EditorEx)editor).setFontSize((int)(Math.max(currentSize + magnification * 3, defaultFontSize))); - } - } - } - - protected void processLeftSwipe(IdeFrame frame) { - AnAction forward = myActionManager.getAction("Forward"); - if (forward == null) return; - - myActionManager.tryToExecute(forward, createMouseEventWrapper(frame), null, null, false); - } - - protected void processRightSwipe(IdeFrame frame) { - AnAction back = myActionManager.getAction("Back"); - if (back == null) return; - - myActionManager.tryToExecute(back, createMouseEventWrapper(frame), null, null, false); - } - - private static MouseEvent createMouseEventWrapper(IdeFrame frame) { - return new MouseEvent(frame.getComponent(), ActionEvent.ACTION_PERFORMED, System.currentTimeMillis(), 0, 0, 0, 0, false, 0); - } - public void remove(IdeFrame frame) { if (!Registry.is("actionSystem.mouseGesturesEnabled")) return; diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorComponentImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorComponentImpl.java index deaef127e15c..50a87000b721 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorComponentImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorComponentImpl.java @@ -19,21 +19,21 @@ import com.intellij.ide.IdeEventQueue; import com.intellij.ide.ui.UISettings; import com.intellij.openapi.actionSystem.DataProvider; import com.intellij.openapi.actionSystem.PlatformDataKeys; +import com.intellij.openapi.editor.VisualPosition; +import com.intellij.ui.components.Magnificator; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.impl.ApplicationImpl; +import com.intellij.openapi.editor.colors.EditorColorsManager; import com.intellij.openapi.editor.ex.util.EditorUtil; import com.intellij.openapi.ui.Queryable; import com.intellij.openapi.ui.TypingTarget; import com.intellij.openapi.util.ActionCallback; -import com.intellij.util.ReflectionUtil; import com.intellij.util.ui.UIUtil; import javax.swing.*; import java.awt.*; import java.awt.event.ComponentEvent; -import java.awt.event.FocusEvent; import java.awt.event.InputMethodEvent; -import java.awt.im.InputContext; import java.awt.im.InputMethodRequests; import java.util.Map; @@ -46,6 +46,19 @@ public class EditorComponentImpl extends JComponent implements Scrollable, DataP enableInputMethods(true); setFocusCycleRoot(true); setOpaque(true); + + putClientProperty(Magnificator.CLIENT_PROPERTY_KEY, new Magnificator() { + @Override + public Point magnify(double scale, Point at) { + VisualPosition magnificationPosition = myEditor.xyToVisualPosition(at); + + double currentSize = myEditor.getColorsScheme().getEditorFontSize(); + int defaultFontSize = EditorColorsManager.getInstance().getGlobalScheme().getEditorFontSize(); + myEditor.setFontSize((int)(double)(int)(Math.max(currentSize * scale, defaultFontSize))); + + return myEditor.visualPositionToXY(magnificationPosition); + } + }); } public EditorImpl getEditor() {