From 5f57460d2c7ae2b2de5505b6c9dd31935efd0a5f Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Tue, 12 Jan 2016 22:41:22 +0300 Subject: [PATCH] IDEA-149395 Fix viewport to support translucent scroll bars --- .../intellij/ui/components/JBViewport.java | 133 ++++++++++++++++++ .../keymap/impl/IdeMouseEventDispatcher.java | 5 +- 2 files changed, 136 insertions(+), 2 deletions(-) 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 c990d17bee2a..4acfe5f38cd2 100644 --- a/platform/platform-api/src/com/intellij/ui/components/JBViewport.java +++ b/platform/platform-api/src/com/intellij/ui/components/JBViewport.java @@ -16,6 +16,9 @@ package com.intellij.ui.components; import com.intellij.openapi.ui.TypingTarget; +import com.intellij.openapi.util.SystemInfo; +import com.intellij.openapi.util.registry.Registry; +import com.intellij.ui.components.JBScrollPane.Alignment; import com.intellij.ui.table.JBTable; import com.intellij.util.ui.ComponentWithEmptyText; import com.intellij.util.ui.StatusText; @@ -32,6 +35,20 @@ public class JBViewport extends JViewport implements ZoomableViewport { @Override public void layoutContainer(Container parent) { + if (parent instanceof JViewport && Registry.is("ide.scroll.new.layout")) { + JViewport viewport = (JViewport)parent; + Component view = viewport.getView(); + if (view != null) { + JScrollPane pane = getScrollPane(viewport); + if (pane != null) { + doLayout(pane, viewport, view); + } + else { + super.layoutContainer(parent); + } + } + return; + } JBViewport viewport = (JBViewport)parent; Component view = viewport.getView(); JBScrollPane scrollPane = UIUtil.getParentOfType(JBScrollPane.class, parent); @@ -155,4 +172,120 @@ public class JBViewport extends JViewport implements ZoomableViewport { public boolean isPaintingNow() { return myPaintingNow; } + + @Override + public Color getBackground() { + Component view = getView(); + return view != null && view.isBackgroundSet() + ? view.getBackground() + : super.getBackground(); + } + + @Override + public Dimension getExtentSize() { + Dimension size = super.getExtentSize(); + if (SystemInfo.isMac) return size; + JScrollPane pane = getScrollPane(this); + if (pane != null) { + JScrollBar vsb = pane.getVerticalScrollBar(); + if (null != getAlignment(vsb)) { + int width = vsb.getWidth(); + if (size.width > width) size.width -= width; + } + JScrollBar hsb = pane.getHorizontalScrollBar(); + if (null != getAlignment(hsb)) { + int height = hsb.getHeight(); + if (size.height > height) size.height -= height; + } + } + return size; + } + + /** + * Returns the alignment of the specified scroll bar + * if and only if the specified scroll bar + * is located over the corresponding viewport. + * + * @param bar the scroll bar to process + * @return the scroll bar alignment or {@code null} + */ + private static Alignment getAlignment(JScrollBar bar) { + if (bar != null && bar.isVisible() && !bar.isOpaque()) { + Object property = bar.getClientProperty(Alignment.class); + if (property instanceof Alignment) return (Alignment)property; + } + return null; + } + + /** + * Returns the parent scroll pane of the specified viewport + * if and only if the specified viewport is a main viewport. + * + * @param viewport the viewport to process + * @return the parent scroll pane or {@code null} + */ + private static JScrollPane getScrollPane(JViewport viewport) { + Container parent = viewport.getParent(); + if (parent instanceof JScrollPane) { + JScrollPane pane = (JScrollPane)parent; + if (viewport == pane.getViewport()) return pane; + } + return null; + } + + private static void doLayout(JScrollPane pane, JViewport viewport, Component view) { + Dimension actualSize = viewport.getSize(); + Dimension extentSize = viewport.getExtentSize(); + Dimension viewPreferredSize = view.getPreferredSize(); + Dimension viewSize = new Dimension(viewPreferredSize); + Point viewPosition = viewport.getViewPosition(); + + Scrollable scrollable = null; + if (view instanceof Scrollable) { + scrollable = (Scrollable)view; + if (scrollable.getScrollableTracksViewportWidth()) viewSize.width = actualSize.width; + if (scrollable.getScrollableTracksViewportHeight()) viewSize.height = actualSize.height; + } + // If the new viewport size would leave empty space to the right of the view, + // right justify the view or left justify the view + // when the width of the view is smaller than the container. + int maxX = viewSize.width - extentSize.width; + if (scrollable == null || pane.getComponentOrientation().isLeftToRight()) { + if (viewPosition.x > maxX) { + viewPosition.x = Math.max(0, maxX); + } + } + else { + // NOT SUPPORTED YET + viewPosition.x = maxX < 0 ? maxX : Math.max(0, Math.min(maxX, viewPosition.x)); + } + // If the new viewport size would leave empty space below the view, + // bottom justify the view or top justify the view + // when the height of the view is smaller than the container. + int maxY = viewSize.height - extentSize.height; + if (viewPosition.y > maxY) { + viewPosition.y = Math.max(0, maxY); + } + // If we haven't been advised about how the viewports size should change wrt to the viewport, + // i.e. if the view isn't an instance of Scrollable, then adjust the views size as follows. + if (scrollable == null) { + // If the origin of the view is showing and the viewport is bigger than the views preferred size, + // then make the view the same size as the viewport. + if (viewPosition.x == 0 && actualSize.width > viewPreferredSize.width) viewSize.width = actualSize.width; + if (viewPosition.y == 0 && actualSize.height > viewPreferredSize.height) viewSize.height = actualSize.height; + } + // do not force viewport size on editor component, e.g. EditorTextField and LanguageConsole + if (!(view instanceof TypingTarget)) { + if (ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER == pane.getHorizontalScrollBarPolicy()) { + viewPosition.x = 0; + viewSize.width = actualSize.width; + } + if (ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER == pane.getVerticalScrollBarPolicy()) { + viewPosition.y = 0; + viewSize.height = actualSize.height; + } + } + viewport.setViewPosition(viewPosition); + viewport.setViewSize(viewSize); + } } diff --git a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/IdeMouseEventDispatcher.java b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/IdeMouseEventDispatcher.java index ebf050ed819c..c1bf68c84ad9 100644 --- a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/IdeMouseEventDispatcher.java +++ b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/IdeMouseEventDispatcher.java @@ -314,7 +314,8 @@ public final class IdeMouseEventDispatcher { private static JScrollBar findHorizontalScrollBar(Component c) { if (c == null) return null; if (c instanceof JScrollPane) { - return ((JScrollPane)c).getHorizontalScrollBar(); + JScrollBar scrollBar = ((JScrollPane)c).getHorizontalScrollBar(); + return scrollBar != null && scrollBar.isVisible() ? scrollBar : null; } if (isDiagramViewComponent(c)) { @@ -323,7 +324,7 @@ public final class IdeMouseEventDispatcher { if (view.getComponent(i) instanceof JScrollBar) { final JScrollBar scrollBar = (JScrollBar)view.getComponent(i); if (scrollBar.getOrientation() == Adjustable.HORIZONTAL) { - return scrollBar; + return scrollBar.isVisible() ? scrollBar : null; } } }